├── .npmrc
├── static
├── image.png
├── favicon.png
├── img_icon.png
└── icon.svg
├── src
├── lib
│ ├── components
│ │ ├── ui
│ │ │ ├── sonner
│ │ │ │ ├── index.ts
│ │ │ │ └── sonner.svelte
│ │ │ ├── checkbox
│ │ │ │ ├── index.ts
│ │ │ │ └── checkbox.svelte
│ │ │ ├── input
│ │ │ │ ├── index.ts
│ │ │ │ └── input.svelte
│ │ │ ├── label
│ │ │ │ ├── index.ts
│ │ │ │ └── label.svelte
│ │ │ ├── slider
│ │ │ │ ├── index.ts
│ │ │ │ └── slider.svelte
│ │ │ ├── switch
│ │ │ │ ├── index.ts
│ │ │ │ └── switch.svelte
│ │ │ ├── skeleton
│ │ │ │ ├── index.ts
│ │ │ │ └── skeleton.svelte
│ │ │ ├── separator
│ │ │ │ ├── index.ts
│ │ │ │ └── separator.svelte
│ │ │ ├── badge
│ │ │ │ ├── index.ts
│ │ │ │ └── badge.svelte
│ │ │ ├── avatar
│ │ │ │ ├── index.ts
│ │ │ │ ├── avatar-fallback.svelte
│ │ │ │ ├── avatar-image.svelte
│ │ │ │ └── avatar.svelte
│ │ │ ├── button
│ │ │ │ ├── index.ts
│ │ │ │ └── button.svelte
│ │ │ ├── hover-card
│ │ │ │ ├── index.ts
│ │ │ │ └── hover-card-content.svelte
│ │ │ ├── pagination
│ │ │ │ ├── pagination-item.svelte
│ │ │ │ ├── pagination-content.svelte
│ │ │ │ ├── pagination.svelte
│ │ │ │ ├── pagination-ellipsis.svelte
│ │ │ │ ├── index.ts
│ │ │ │ ├── pagination-next-button.svelte
│ │ │ │ ├── pagination-prev-button.svelte
│ │ │ │ └── pagination-link.svelte
│ │ │ ├── select
│ │ │ │ ├── select-group-heading.svelte
│ │ │ │ ├── select-separator.svelte
│ │ │ │ ├── select-scroll-up-button.svelte
│ │ │ │ ├── select-scroll-down-button.svelte
│ │ │ │ ├── select-trigger.svelte
│ │ │ │ ├── index.ts
│ │ │ │ ├── select-item.svelte
│ │ │ │ └── select-content.svelte
│ │ │ ├── dropdown-menu
│ │ │ │ ├── dropdown-menu-separator.svelte
│ │ │ │ ├── dropdown-menu-group-heading.svelte
│ │ │ │ ├── dropdown-menu-shortcut.svelte
│ │ │ │ ├── dropdown-menu-sub-content.svelte
│ │ │ │ ├── dropdown-menu-label.svelte
│ │ │ │ ├── dropdown-menu-item.svelte
│ │ │ │ ├── dropdown-menu-sub-trigger.svelte
│ │ │ │ ├── dropdown-menu-radio-item.svelte
│ │ │ │ ├── dropdown-menu-content.svelte
│ │ │ │ ├── dropdown-menu-checkbox-item.svelte
│ │ │ │ └── index.ts
│ │ │ ├── card
│ │ │ │ ├── card-content.svelte
│ │ │ │ ├── card-footer.svelte
│ │ │ │ ├── card-header.svelte
│ │ │ │ ├── card-description.svelte
│ │ │ │ ├── card.svelte
│ │ │ │ ├── index.ts
│ │ │ │ └── card-title.svelte
│ │ │ └── table
│ │ │ │ ├── table-header.svelte
│ │ │ │ ├── table-body.svelte
│ │ │ │ ├── table-footer.svelte
│ │ │ │ ├── table-caption.svelte
│ │ │ │ ├── table-row.svelte
│ │ │ │ ├── table.svelte
│ │ │ │ ├── table-cell.svelte
│ │ │ │ ├── table-head.svelte
│ │ │ │ └── index.ts
│ │ ├── dashboard
│ │ │ ├── filter-view
│ │ │ │ ├── SearchFilterView.svelte
│ │ │ │ ├── RowsPerPage.svelte
│ │ │ │ ├── FilterCompanyTitle.svelte
│ │ │ │ └── SearchInput.svelte
│ │ │ ├── table-view
│ │ │ │ ├── TableView.svelte
│ │ │ │ └── SortItem.svelte
│ │ │ └── pagination-view
│ │ │ │ └── PaginationView.svelte
│ │ ├── drizz
│ │ │ ├── filter-status
│ │ │ │ └── FilterStatus.svelte
│ │ │ └── table-view
│ │ │ │ ├── DrizzSortItem.svelte
│ │ │ │ └── DrizzTableView.svelte
│ │ └── home
│ │ │ ├── Sidebar.svelte
│ │ │ └── Navbar.svelte
│ ├── utils.ts
│ ├── server
│ │ └── db
│ │ │ ├── index.ts
│ │ │ └── schema.ts
│ ├── types
│ │ ├── drizzUsers.ts
│ │ └── users.ts
│ └── images
│ │ ├── drizzle.svg
│ │ ├── supabase.svg
│ │ ├── svelte.svg
│ │ ├── logo-github-sq-light.svg
│ │ ├── logo-github-sq-dark.svg
│ │ ├── supabase-logo-wordmarkdark.svg
│ │ └── supabase-logo-wordmarklight.svg
├── app.d.ts
├── routes
│ ├── +layout.svelte
│ ├── +page.svelte
│ ├── drizz
│ │ ├── +page.svelte
│ │ └── +page.server.ts
│ ├── +page.server.ts
│ └── about
│ │ └── +page.svelte
├── app.css
└── app.html
├── postcss.config.js
├── .env.example
├── vite.config.ts
├── drizzle
├── meta
│ ├── _journal.json
│ └── 0000_snapshot.json
└── 0000_dazzling_vision.sql
├── .gitignore
├── drizzle.config.ts
├── components.json
├── tsconfig.json
├── comp.md
├── svelte.config.js
├── .github
└── FUNDING.yml
├── LICENSE
├── package.json
├── README.md
├── usage.md
└── tailwind.config.ts
/.npmrc:
--------------------------------------------------------------------------------
1 | engine-strict=true
2 |
--------------------------------------------------------------------------------
/static/image.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SikandarJODD/youva/HEAD/static/image.png
--------------------------------------------------------------------------------
/static/favicon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SikandarJODD/youva/HEAD/static/favicon.png
--------------------------------------------------------------------------------
/static/img_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SikandarJODD/youva/HEAD/static/img_icon.png
--------------------------------------------------------------------------------
/src/lib/components/ui/sonner/index.ts:
--------------------------------------------------------------------------------
1 | export { default as Toaster } from "./sonner.svelte";
2 |
--------------------------------------------------------------------------------
/postcss.config.js:
--------------------------------------------------------------------------------
1 | export default {
2 | plugins: {
3 | tailwindcss: {},
4 | autoprefixer: {}
5 | }
6 | };
7 |
--------------------------------------------------------------------------------
/.env.example:
--------------------------------------------------------------------------------
1 | # Replace with your DB credentials! Supabase DB URL
2 | DATABASE_URL="postgres://user:password@host:port/db-name"
3 |
--------------------------------------------------------------------------------
/src/lib/components/ui/checkbox/index.ts:
--------------------------------------------------------------------------------
1 | import Root from "./checkbox.svelte";
2 | export {
3 | Root,
4 | //
5 | Root as Checkbox,
6 | };
7 |
--------------------------------------------------------------------------------
/src/lib/components/ui/input/index.ts:
--------------------------------------------------------------------------------
1 | import Root from "./input.svelte";
2 |
3 | export {
4 | Root,
5 | //
6 | Root as Input,
7 | };
8 |
--------------------------------------------------------------------------------
/src/lib/components/ui/label/index.ts:
--------------------------------------------------------------------------------
1 | import Root from "./label.svelte";
2 |
3 | export {
4 | Root,
5 | //
6 | Root as Label,
7 | };
8 |
--------------------------------------------------------------------------------
/src/lib/components/ui/slider/index.ts:
--------------------------------------------------------------------------------
1 | import Root from "./slider.svelte";
2 |
3 | export {
4 | Root,
5 | //
6 | Root as Slider,
7 | };
8 |
--------------------------------------------------------------------------------
/src/lib/components/ui/switch/index.ts:
--------------------------------------------------------------------------------
1 | import Root from "./switch.svelte";
2 |
3 | export {
4 | Root,
5 | //
6 | Root as Switch,
7 | };
8 |
--------------------------------------------------------------------------------
/src/lib/components/ui/skeleton/index.ts:
--------------------------------------------------------------------------------
1 | import Root from "./skeleton.svelte";
2 |
3 | export {
4 | Root,
5 | //
6 | Root as Skeleton,
7 | };
8 |
--------------------------------------------------------------------------------
/src/lib/components/ui/separator/index.ts:
--------------------------------------------------------------------------------
1 | import Root from "./separator.svelte";
2 |
3 | export {
4 | Root,
5 | //
6 | Root as Separator,
7 | };
8 |
--------------------------------------------------------------------------------
/src/lib/components/ui/badge/index.ts:
--------------------------------------------------------------------------------
1 | export { default as Badge } from "./badge.svelte";
2 | export { badgeVariants, type BadgeVariant } from "./badge.svelte";
3 |
--------------------------------------------------------------------------------
/vite.config.ts:
--------------------------------------------------------------------------------
1 | import { sveltekit } from '@sveltejs/kit/vite';
2 | import { defineConfig } from 'vite';
3 |
4 | export default defineConfig({
5 | plugins: [sveltekit()]
6 | });
7 |
--------------------------------------------------------------------------------
/src/lib/utils.ts:
--------------------------------------------------------------------------------
1 | import { type ClassValue, clsx } from "clsx";
2 | import { twMerge } from "tailwind-merge";
3 |
4 | export function cn(...inputs: ClassValue[]) {
5 | return twMerge(clsx(inputs));
6 | }
7 |
--------------------------------------------------------------------------------
/drizzle/meta/_journal.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": "7",
3 | "dialect": "postgresql",
4 | "entries": [
5 | {
6 | "idx": 0,
7 | "version": "7",
8 | "when": 1737306628825,
9 | "tag": "0000_dazzling_vision",
10 | "breakpoints": true
11 | }
12 | ]
13 | }
--------------------------------------------------------------------------------
/static/icon.svg:
--------------------------------------------------------------------------------
1 |
3 |
4 |
--------------------------------------------------------------------------------
/drizzle/0000_dazzling_vision.sql:
--------------------------------------------------------------------------------
1 | CREATE TYPE "public"."status" AS ENUM('active', 'inactive', 'sage', 'god');--> statement-breakpoint
2 | CREATE TABLE "all_users" (
3 | "id" serial PRIMARY KEY NOT NULL,
4 | "first_name" text,
5 | "last_name" text,
6 | "email" text,
7 | "company" text,
8 | "status" "status"
9 | );
10 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 |
3 | # Output
4 | .output
5 | .vercel
6 | .netlify
7 | .wrangler
8 | /.svelte-kit
9 | /build
10 |
11 | # OS
12 | .DS_Store
13 | Thumbs.db
14 |
15 | # Env
16 | .env
17 | .env.*
18 | !.env.example
19 | !.env.test
20 |
21 | # Vite
22 | vite.config.js.timestamp-*
23 | vite.config.ts.timestamp-*
24 |
--------------------------------------------------------------------------------
/src/lib/components/ui/avatar/index.ts:
--------------------------------------------------------------------------------
1 | import Root from "./avatar.svelte";
2 | import Image from "./avatar-image.svelte";
3 | import Fallback from "./avatar-fallback.svelte";
4 |
5 | export {
6 | Root,
7 | Image,
8 | Fallback,
9 | //
10 | Root as Avatar,
11 | Image as AvatarImage,
12 | Fallback as AvatarFallback,
13 | };
14 |
--------------------------------------------------------------------------------
/src/lib/server/db/index.ts:
--------------------------------------------------------------------------------
1 | import { drizzle } from 'drizzle-orm/postgres-js'
2 | import postgres from 'postgres'
3 | import { DATABASE_URL } from '$env/static/private';
4 | if (!DATABASE_URL) throw new Error('DATABASE_URL is not set');
5 | let client = postgres(DATABASE_URL)
6 | export let db = drizzle({ client });
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/src/app.d.ts:
--------------------------------------------------------------------------------
1 | // See https://svelte.dev/docs/kit/types#app.d.ts
2 | // for information about these interfaces
3 | declare global {
4 | namespace App {
5 | // interface Error {}
6 | // interface Locals {}
7 | // interface PageData {}
8 | // interface PageState {}
9 | // interface Platform {}
10 | }
11 | }
12 |
13 | export {};
14 |
--------------------------------------------------------------------------------
/src/lib/components/ui/button/index.ts:
--------------------------------------------------------------------------------
1 | import Root, {
2 | type ButtonProps,
3 | type ButtonSize,
4 | type ButtonVariant,
5 | buttonVariants,
6 | } from "./button.svelte";
7 |
8 | export {
9 | Root,
10 | type ButtonProps as Props,
11 | //
12 | Root as Button,
13 | buttonVariants,
14 | type ButtonProps,
15 | type ButtonSize,
16 | type ButtonVariant,
17 | };
18 |
--------------------------------------------------------------------------------
/src/routes/+layout.svelte:
--------------------------------------------------------------------------------
1 |
7 |
8 |
9 |
10 |
11 | {@render children()}
12 |
13 |
--------------------------------------------------------------------------------
/drizzle.config.ts:
--------------------------------------------------------------------------------
1 | import { defineConfig } from 'drizzle-kit';
2 | if (!process.env.DATABASE_URL) throw new Error('DATABASE_URL is not set');
3 |
4 | export default defineConfig({
5 | schema: './src/lib/server/db/schema.ts',
6 |
7 | dbCredentials: {
8 | url: process.env.DATABASE_URL
9 | },
10 |
11 | verbose: true,
12 | strict: true,
13 | dialect: "postgresql"
14 | });
15 |
--------------------------------------------------------------------------------
/src/lib/types/drizzUsers.ts:
--------------------------------------------------------------------------------
1 | export interface UsersProfile {
2 | users: DrizzUser[];
3 | total: number;
4 | skip: number;
5 | limit: number;
6 | }
7 |
8 | export interface DrizzUser {
9 | id: number;
10 | firstName: string;
11 | lastName: string;
12 | email: string;
13 | company: string;
14 | status: 'active' | 'inactive' | 'sage' | 'god';
15 | }
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/src/lib/components/ui/hover-card/index.ts:
--------------------------------------------------------------------------------
1 | import { LinkPreview as HoverCardPrimitive } from "bits-ui";
2 |
3 | import Content from "./hover-card-content.svelte";
4 | const Root = HoverCardPrimitive.Root;
5 | const Trigger = HoverCardPrimitive.Trigger;
6 |
7 | export {
8 | Root,
9 | Content,
10 | Trigger,
11 | Root as HoverCard,
12 | Content as HoverCardContent,
13 | Trigger as HoverCardTrigger,
14 | };
15 |
--------------------------------------------------------------------------------
/src/lib/components/ui/pagination/pagination-item.svelte:
--------------------------------------------------------------------------------
1 |
11 |
12 |
13 | {@render children?.()}
14 |
15 |
--------------------------------------------------------------------------------
/src/lib/types/users.ts:
--------------------------------------------------------------------------------
1 | export interface UsersProfile {
2 | users: User[];
3 | total: number;
4 | skip: number;
5 | limit: number;
6 | }
7 |
8 | export interface User {
9 | id: number;
10 | firstName: string;
11 | lastName: string;
12 | email: string;
13 | company: Company;
14 | }
15 |
16 |
17 |
18 | export interface Company {
19 | department: string;
20 | name: string;
21 | title: string;
22 | }
23 |
24 |
--------------------------------------------------------------------------------
/components.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "https://next.shadcn-svelte.com/schema.json",
3 | "style": "new-york",
4 | "tailwind": {
5 | "config": "tailwind.config.ts",
6 | "css": "src\\app.css",
7 | "baseColor": "slate"
8 | },
9 | "aliases": {
10 | "components": "$lib/components",
11 | "utils": "$lib/utils",
12 | "ui": "$lib/components/ui",
13 | "hooks": "$lib/hooks"
14 | },
15 | "typescript": true,
16 | "registry": "https://next.shadcn-svelte.com/registry"
17 | }
18 |
--------------------------------------------------------------------------------
/src/lib/components/ui/select/select-group-heading.svelte:
--------------------------------------------------------------------------------
1 |
11 |
12 |
17 |
--------------------------------------------------------------------------------
/src/lib/components/ui/avatar/avatar-fallback.svelte:
--------------------------------------------------------------------------------
1 |
11 |
12 |
17 |
--------------------------------------------------------------------------------
/src/lib/components/ui/avatar/avatar-image.svelte:
--------------------------------------------------------------------------------
1 |
13 |
14 |
21 |
--------------------------------------------------------------------------------
/src/lib/components/ui/dropdown-menu/dropdown-menu-separator.svelte:
--------------------------------------------------------------------------------
1 |
11 |
12 |
17 |
--------------------------------------------------------------------------------
/src/lib/components/ui/select/select-separator.svelte:
--------------------------------------------------------------------------------
1 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/src/lib/components/ui/card/card-content.svelte:
--------------------------------------------------------------------------------
1 |
13 |
14 |
15 | {@render children?.()}
16 |
17 |
--------------------------------------------------------------------------------
/src/lib/components/ui/label/label.svelte:
--------------------------------------------------------------------------------
1 |
11 |
12 |
20 |
--------------------------------------------------------------------------------
/src/lib/components/ui/avatar/avatar.svelte:
--------------------------------------------------------------------------------
1 |
12 |
13 |
19 |
--------------------------------------------------------------------------------
/src/lib/components/ui/card/card-footer.svelte:
--------------------------------------------------------------------------------
1 |
13 |
14 |
15 | {@render children?.()}
16 |
17 |
--------------------------------------------------------------------------------
/src/lib/components/ui/card/card-header.svelte:
--------------------------------------------------------------------------------
1 |
13 |
14 |
15 | {@render children?.()}
16 |
17 |
--------------------------------------------------------------------------------
/src/lib/components/ui/table/table-header.svelte:
--------------------------------------------------------------------------------
1 |
13 |
14 |
15 | {@render children?.()}
16 |
17 |
--------------------------------------------------------------------------------
/src/lib/components/ui/card/card-description.svelte:
--------------------------------------------------------------------------------
1 |
13 |
14 |
15 | {@render children?.()}
16 |
17 |
--------------------------------------------------------------------------------
/src/lib/components/ui/table/table-body.svelte:
--------------------------------------------------------------------------------
1 |
13 |
14 |
15 | {@render children?.()}
16 |
17 |
--------------------------------------------------------------------------------
/src/lib/components/ui/table/table-footer.svelte:
--------------------------------------------------------------------------------
1 |
13 |
14 |
15 | {@render children?.()}
16 |
17 |
--------------------------------------------------------------------------------
/src/lib/server/db/schema.ts:
--------------------------------------------------------------------------------
1 | import { pgTable, serial, text, pgEnum } from 'drizzle-orm/pg-core';
2 | import { type InferSelectModel } from 'drizzle-orm'
3 |
4 | export let status = pgEnum('status', ['active', 'inactive', 'sage', 'god']);
5 | export const all_users = pgTable('all_users', {
6 | id: serial('id').primaryKey(),
7 | firstName: text('first_name'),
8 | lastName: text('last_name'),
9 | email: text('email'),
10 | company: text('company'),
11 | status: status()
12 | });
13 |
14 | export type DrizzUser = InferSelectModel;
15 |
--------------------------------------------------------------------------------
/src/lib/components/ui/table/table-caption.svelte:
--------------------------------------------------------------------------------
1 |
13 |
14 |
15 | {@render children?.()}
16 |
17 |
--------------------------------------------------------------------------------
/src/lib/components/ui/skeleton/skeleton.svelte:
--------------------------------------------------------------------------------
1 |
12 |
13 |
18 |
--------------------------------------------------------------------------------
/src/lib/components/ui/dropdown-menu/dropdown-menu-group-heading.svelte:
--------------------------------------------------------------------------------
1 |
14 |
15 |
20 |
--------------------------------------------------------------------------------
/src/lib/components/ui/card/card.svelte:
--------------------------------------------------------------------------------
1 |
13 |
14 |
19 | {@render children?.()}
20 |
21 |
--------------------------------------------------------------------------------
/src/lib/components/ui/card/index.ts:
--------------------------------------------------------------------------------
1 | import Root from "./card.svelte";
2 | import Content from "./card-content.svelte";
3 | import Description from "./card-description.svelte";
4 | import Footer from "./card-footer.svelte";
5 | import Header from "./card-header.svelte";
6 | import Title from "./card-title.svelte";
7 |
8 | export {
9 | Root,
10 | Content,
11 | Description,
12 | Footer,
13 | Header,
14 | Title,
15 | //
16 | Root as Card,
17 | Content as CardContent,
18 | Description as CardDescription,
19 | Footer as CardFooter,
20 | Header as CardHeader,
21 | Title as CardTitle,
22 | };
23 |
--------------------------------------------------------------------------------
/src/lib/components/ui/dropdown-menu/dropdown-menu-shortcut.svelte:
--------------------------------------------------------------------------------
1 |
13 |
14 |
19 | {@render children?.()}
20 |
21 |
--------------------------------------------------------------------------------
/src/lib/components/ui/dropdown-menu/dropdown-menu-sub-content.svelte:
--------------------------------------------------------------------------------
1 |
11 |
12 |
20 |
--------------------------------------------------------------------------------
/src/lib/components/ui/pagination/pagination-content.svelte:
--------------------------------------------------------------------------------
1 |
13 |
14 |
19 | {@render children?.()}
20 |
21 |
--------------------------------------------------------------------------------
/src/lib/components/ui/separator/separator.svelte:
--------------------------------------------------------------------------------
1 |
12 |
13 |
23 |
--------------------------------------------------------------------------------
/src/lib/components/ui/pagination/pagination.svelte:
--------------------------------------------------------------------------------
1 |
15 |
16 |
25 |
--------------------------------------------------------------------------------
/src/lib/components/ui/table/table-row.svelte:
--------------------------------------------------------------------------------
1 |
13 |
14 |
22 | {@render children?.()}
23 |
24 |
--------------------------------------------------------------------------------
/src/lib/components/ui/table/table.svelte:
--------------------------------------------------------------------------------
1 |
13 |
14 |
15 |
20 | {@render children?.()}
21 |
22 |
23 |
--------------------------------------------------------------------------------
/src/lib/components/ui/dropdown-menu/dropdown-menu-label.svelte:
--------------------------------------------------------------------------------
1 |
16 |
17 |
22 | {@render children?.()}
23 |
24 |
--------------------------------------------------------------------------------
/src/lib/components/ui/table/table-cell.svelte:
--------------------------------------------------------------------------------
1 |
13 |
14 | [role=checkbox]]:translate-y-[2px]",
18 | className
19 | )}
20 | {...restProps}
21 | >
22 | {@render children?.()}
23 |
24 |
--------------------------------------------------------------------------------
/src/lib/components/ui/table/table-head.svelte:
--------------------------------------------------------------------------------
1 |
13 |
14 | [role=checkbox]]:translate-y-[2px]",
18 | className
19 | )}
20 | {...restProps}
21 | >
22 | {@render children?.()}
23 |
24 |
--------------------------------------------------------------------------------
/src/lib/components/ui/card/card-title.svelte:
--------------------------------------------------------------------------------
1 |
16 |
17 |
24 | {@render children?.()}
25 |
26 |
--------------------------------------------------------------------------------
/src/lib/components/ui/select/select-scroll-up-button.svelte:
--------------------------------------------------------------------------------
1 |
12 |
13 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/src/lib/images/drizzle.svg:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
8 |
10 |
--------------------------------------------------------------------------------
/src/lib/components/ui/select/select-scroll-down-button.svelte:
--------------------------------------------------------------------------------
1 |
12 |
13 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/src/lib/components/ui/table/index.ts:
--------------------------------------------------------------------------------
1 | import Root from "./table.svelte";
2 | import Body from "./table-body.svelte";
3 | import Caption from "./table-caption.svelte";
4 | import Cell from "./table-cell.svelte";
5 | import Footer from "./table-footer.svelte";
6 | import Head from "./table-head.svelte";
7 | import Header from "./table-header.svelte";
8 | import Row from "./table-row.svelte";
9 |
10 | export {
11 | Root,
12 | Body,
13 | Caption,
14 | Cell,
15 | Footer,
16 | Head,
17 | Header,
18 | Row,
19 | //
20 | Root as Table,
21 | Body as TableBody,
22 | Caption as TableCaption,
23 | Cell as TableCell,
24 | Footer as TableFooter,
25 | Head as TableHead,
26 | Header as TableHeader,
27 | Row as TableRow,
28 | };
29 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "./.svelte-kit/tsconfig.json",
3 | "compilerOptions": {
4 | "allowJs": true,
5 | "checkJs": true,
6 | "esModuleInterop": true,
7 | "forceConsistentCasingInFileNames": true,
8 | "resolveJsonModule": true,
9 | "skipLibCheck": true,
10 | "sourceMap": true,
11 | "strict": true,
12 | "moduleResolution": "bundler"
13 | }
14 | // Path aliases are handled by https://svelte.dev/docs/kit/configuration#alias
15 | // except $lib which is handled by https://svelte.dev/docs/kit/configuration#files
16 | //
17 | // If you want to overwrite includes/excludes, make sure to copy over the relevant includes/excludes
18 | // from the referenced tsconfig.json - TypeScript does not merge them in
19 | }
20 |
--------------------------------------------------------------------------------
/src/lib/components/ui/pagination/pagination-ellipsis.svelte:
--------------------------------------------------------------------------------
1 |
13 |
14 |
20 |
21 | More pages
22 |
23 |
--------------------------------------------------------------------------------
/comp.md:
--------------------------------------------------------------------------------
1 | ## Inspiration
2 |
3 | - [Visit Shadcn Tasks Example](https://next.shadcn-svelte.com/examples/tasks)
4 |
5 | ## Components Needed to Build
6 |
7 | - Navbar from ui
8 | - Table
9 | - Input Search : [Origin UI](https://originui-svelte.pages.dev/inputs/inputs/input-26)
10 | - Pagination at bottom center : [Origin UI](https://originui-svelte.pages.dev/breadcrumbs-paginations/paginations/pagination-06)
11 | - Buttons
12 | - Github : [Origin UI](https://originui-svelte.pages.dev/buttons/buttons/button-41)
13 | - Dark Mode : [Origin UI](https://originui-svelte.pages.dev/checks-radios-switches/switches/switch-13)
14 |
15 | ## Features to be Includes
16 |
17 | - Pagination
18 | - Debounced Search - runed.dev
19 | - Sorting on columns
20 | - Filters on category
21 |
--------------------------------------------------------------------------------
/svelte.config.js:
--------------------------------------------------------------------------------
1 | import adapter from "@sveltejs/adapter-auto";
2 | import { vitePreprocess } from "@sveltejs/vite-plugin-svelte";
3 |
4 | /** @type {import('@sveltejs/kit').Config} */
5 | const config = {
6 | // Consult https://svelte.dev/docs/kit/integrations
7 | // for more information about preprocessors
8 | preprocess: vitePreprocess(),
9 |
10 | kit: {
11 | // adapter-auto only supports some environments, see https://svelte.dev/docs/kit/adapter-auto for a list.
12 | // If your environment is not supported, or you settled on a specific environment, switch out the adapter.
13 | // See https://svelte.dev/docs/kit/adapters for more information about adapters.
14 | adapter: adapter(),
15 | },
16 | };
17 |
18 | export default config;
19 |
--------------------------------------------------------------------------------
/src/lib/components/ui/pagination/index.ts:
--------------------------------------------------------------------------------
1 | import Root from "./pagination.svelte";
2 | import Content from "./pagination-content.svelte";
3 | import Item from "./pagination-item.svelte";
4 | import Link from "./pagination-link.svelte";
5 | import PrevButton from "./pagination-prev-button.svelte";
6 | import NextButton from "./pagination-next-button.svelte";
7 | import Ellipsis from "./pagination-ellipsis.svelte";
8 | export {
9 | Root,
10 | Content,
11 | Item,
12 | Link,
13 | PrevButton,
14 | NextButton,
15 | Ellipsis,
16 | //
17 | Root as Pagination,
18 | Content as PaginationContent,
19 | Item as PaginationItem,
20 | Link as PaginationLink,
21 | PrevButton as PaginationPrevButton,
22 | NextButton as PaginationNextButton,
23 | Ellipsis as PaginationEllipsis,
24 | };
25 |
--------------------------------------------------------------------------------
/src/lib/components/ui/sonner/sonner.svelte:
--------------------------------------------------------------------------------
1 |
7 |
8 |
21 |
--------------------------------------------------------------------------------
/src/routes/+page.svelte:
--------------------------------------------------------------------------------
1 |
12 |
13 |
14 |
Svelte Pagination Example
15 |
16 | pagination, sorting, filters, debounced search
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/src/lib/components/ui/hover-card/hover-card-content.svelte:
--------------------------------------------------------------------------------
1 |
16 |
17 |
18 |
28 |
29 |
--------------------------------------------------------------------------------
/src/lib/components/ui/dropdown-menu/dropdown-menu-item.svelte:
--------------------------------------------------------------------------------
1 |
14 |
15 | svg]:size-4 [&>svg]:shrink-0",
19 | inset && "pl-8",
20 | className
21 | )}
22 | {...restProps}
23 | />
24 |
--------------------------------------------------------------------------------
/src/lib/components/ui/input/input.svelte:
--------------------------------------------------------------------------------
1 |
13 |
14 |
23 |
--------------------------------------------------------------------------------
/src/lib/components/dashboard/filter-view/SearchFilterView.svelte:
--------------------------------------------------------------------------------
1 |
11 |
12 |
15 |
16 |
17 | {#if isMainPage}
18 |
19 | {:else}
20 |
21 | {/if}
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | # These are supported funding model platforms
2 |
3 | github: [SikandarJODD]
4 | patreon: # Replace with a single Patreon username
5 | open_collective: # Replace with a single Open Collective username
6 | ko_fi: # Replace with a single Ko-fi username
7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
9 | liberapay: # Replace with a single Liberapay username
10 | issuehunt: # Replace with a single IssueHunt username
11 | lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry
12 | polar: # Replace with a single Polar username
13 | buy_me_a_coffee: # Replace with a single Buy Me a Coffee username
14 | thanks_dev: # Replace with a single thanks.dev username
15 | custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']
16 |
--------------------------------------------------------------------------------
/src/lib/components/ui/select/select-trigger.svelte:
--------------------------------------------------------------------------------
1 |
13 |
14 | span]:line-clamp-1",
18 | className
19 | )}
20 | {...restProps}
21 | >
22 | {@render children?.()}
23 |
24 |
25 |
--------------------------------------------------------------------------------
/src/lib/components/ui/dropdown-menu/dropdown-menu-sub-trigger.svelte:
--------------------------------------------------------------------------------
1 |
16 |
17 |
26 | {@render children?.()}
27 |
28 |
29 |
--------------------------------------------------------------------------------
/src/lib/components/ui/pagination/pagination-next-button.svelte:
--------------------------------------------------------------------------------
1 |
16 |
17 | {#snippet Fallback()}
18 | Next
19 |
20 | {/snippet}
21 |
22 |
35 |
--------------------------------------------------------------------------------
/src/lib/components/ui/select/index.ts:
--------------------------------------------------------------------------------
1 | import { Select as SelectPrimitive } from "bits-ui";
2 |
3 | import GroupHeading from "./select-group-heading.svelte";
4 | import Item from "./select-item.svelte";
5 | import Content from "./select-content.svelte";
6 | import Trigger from "./select-trigger.svelte";
7 | import Separator from "./select-separator.svelte";
8 | import ScrollDownButton from "./select-scroll-down-button.svelte";
9 | import ScrollUpButton from "./select-scroll-up-button.svelte";
10 |
11 | const Root = SelectPrimitive.Root;
12 | const Group = SelectPrimitive.Group;
13 |
14 | export {
15 | Root,
16 | Item,
17 | Group,
18 | GroupHeading,
19 | Content,
20 | Trigger,
21 | Separator,
22 | ScrollDownButton,
23 | ScrollUpButton,
24 | //
25 | Root as Select,
26 | Item as SelectItem,
27 | Group as SelectGroup,
28 | GroupHeading as SelectGroupHeading,
29 | Content as SelectContent,
30 | Trigger as SelectTrigger,
31 | Separator as SelectSeparator,
32 | ScrollDownButton as SelectScrollDownButton,
33 | ScrollUpButton as SelectScrollUpButton,
34 | };
35 |
--------------------------------------------------------------------------------
/src/lib/components/ui/pagination/pagination-prev-button.svelte:
--------------------------------------------------------------------------------
1 |
16 |
17 | {#snippet Fallback()}
18 |
19 | Previous
20 | {/snippet}
21 |
22 |
35 |
--------------------------------------------------------------------------------
/src/lib/components/ui/pagination/pagination-link.svelte:
--------------------------------------------------------------------------------
1 |
27 |
28 | {#snippet Fallback()}
29 | {page.value}
30 | {/snippet}
31 |
32 |
46 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2025 Sikandar Bhide
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/src/lib/components/ui/dropdown-menu/dropdown-menu-radio-item.svelte:
--------------------------------------------------------------------------------
1 |
13 |
14 |
22 | {#snippet children({ checked })}
23 |
24 | {#if checked}
25 |
26 | {/if}
27 |
28 | {@render childrenProp?.({ checked })}
29 | {/snippet}
30 |
31 |
--------------------------------------------------------------------------------
/src/lib/images/supabase.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/src/lib/components/ui/dropdown-menu/dropdown-menu-content.svelte:
--------------------------------------------------------------------------------
1 |
15 |
16 |
17 |
27 |
28 |
--------------------------------------------------------------------------------
/src/routes/drizz/+page.svelte:
--------------------------------------------------------------------------------
1 |
23 |
24 |
25 |
Drizzle Dashboard
26 |
27 | pagination, sorting, filters, debounced search, caching
28 |
29 |
30 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/src/lib/components/ui/switch/switch.svelte:
--------------------------------------------------------------------------------
1 |
12 |
13 |
22 |
27 |
28 |
--------------------------------------------------------------------------------
/src/lib/components/ui/select/select-item.svelte:
--------------------------------------------------------------------------------
1 |
15 |
16 |
25 | {#snippet children({ selected, highlighted })}
26 |
27 | {#if selected}
28 |
29 | {/if}
30 |
31 | {#if childrenProp}
32 | {@render childrenProp({ selected, highlighted })}
33 | {:else}
34 | {label || value}
35 | {/if}
36 | {/snippet}
37 |
38 |
--------------------------------------------------------------------------------
/src/lib/components/ui/slider/slider.svelte:
--------------------------------------------------------------------------------
1 |
14 |
15 |
19 |
25 | {#snippet children({ thumbs })}
26 |
27 |
28 |
29 | {#each thumbs as thumb}
30 |
34 | {/each}
35 | {/snippet}
36 |
37 |
--------------------------------------------------------------------------------
/src/lib/components/ui/checkbox/checkbox.svelte:
--------------------------------------------------------------------------------
1 |
15 |
16 |
26 | {#snippet children({ checked, indeterminate })}
27 |
28 | {#if indeterminate}
29 |
30 | {:else}
31 |
32 | {/if}
33 |
34 | {/snippet}
35 |
36 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "pagination-management",
3 | "private": true,
4 | "version": "0.0.1",
5 | "type": "module",
6 | "scripts": {
7 | "dev": "vite dev",
8 | "build": "vite build",
9 | "preview": "vite preview",
10 | "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
11 | "check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch",
12 | "db:push": "drizzle-kit push",
13 | "db:migrate": "drizzle-kit migrate",
14 | "db:studio": "drizzle-kit studio"
15 | },
16 | "devDependencies": {
17 | "@sveltejs/adapter-auto": "^4.0.0",
18 | "@sveltejs/kit": "^2.0.0",
19 | "@sveltejs/vite-plugin-svelte": "^4.0.0",
20 | "@types/node": "^22.10.7",
21 | "@types/throttle-debounce": "^5.0.2",
22 | "autoprefixer": "^10.4.20",
23 | "bits-ui": "1.0.0-next.77",
24 | "clsx": "^2.1.1",
25 | "drizzle-kit": "^0.30.2",
26 | "lucide-svelte": "^0.471.0",
27 | "mode-watcher": "^0.5.0",
28 | "svelte": "^5.0.0",
29 | "svelte-check": "^4.0.0",
30 | "svelte-sonner": "^0.3.28",
31 | "tailwind-merge": "^2.6.0",
32 | "tailwind-variants": "^0.3.0",
33 | "tailwindcss": "^3.4.9",
34 | "tailwindcss-animate": "^1.0.7",
35 | "tsx": "^4.19.2",
36 | "typescript": "^5.0.0",
37 | "vite": "^5.4.11"
38 | },
39 | "dependencies": {
40 | "dotenv": "^16.4.7",
41 | "drizzle-orm": "^0.38.4",
42 | "postgres": "^3.4.5",
43 | "throttle-debounce": "^5.0.2"
44 | }
45 | }
--------------------------------------------------------------------------------
/src/lib/components/ui/dropdown-menu/dropdown-menu-checkbox-item.svelte:
--------------------------------------------------------------------------------
1 |
19 |
20 |
30 | {#snippet children({ checked, indeterminate })}
31 |
32 | {#if indeterminate}
33 |
34 | {:else}
35 |
36 | {/if}
37 |
38 | {@render childrenProp?.()}
39 | {/snippet}
40 |
41 |
--------------------------------------------------------------------------------
/src/routes/+page.server.ts:
--------------------------------------------------------------------------------
1 | // you can generate types for any api using thunder client
2 | import type { UsersProfile } from "$lib/types/users";
3 | import { error } from "@sveltejs/kit";
4 | import type { PageServerLoad } from "./$types";
5 |
6 | export const load: PageServerLoad = async ({ url, fetch }) => {
7 |
8 | // Filter : as api url is different for filter
9 | let filter = url.searchParams.get('filter') || '';
10 | let filter_value = url.searchParams.get('value') || '';
11 |
12 | // Limit and Skip
13 | let limit = Number(url.searchParams.get('limit')) || 10;
14 | let skip = Number(url.searchParams.get('skip')) || 0;
15 |
16 | // Search & Sort
17 | let searchQ = url.searchParams.get('q') || '';
18 | let sortOrder = url.searchParams.get('order') || 'asc';
19 | let sortBy = url.searchParams.get('sortBy') || '';
20 |
21 | // Fetch URL
22 | let fetch_url = `https://dummyjson.com/users/search?q=${searchQ}&limit=${limit}&skip=${skip}&sortBy=${sortBy}&order=${sortOrder}&select=id,firstName,lastName,email,company`;
23 |
24 |
25 | if (filter && filter_value) {
26 | // consider filter value = Sales Manager
27 | // convert it to Sales%20Manager
28 | filter_value = filter_value.replace(' ', '%20');
29 | fetch_url = `https://dummyjson.com/users/filter?key=${filter}&value=${filter_value}&limit=${limit}&skip=${skip}&select=id,firstName,lastName,email,company`;
30 | }
31 |
32 |
33 | // Now below response is streamed to the client
34 | let response = await fetch(fetch_url);
35 |
36 | return {
37 | users: await response.json()
38 | }
39 | };
--------------------------------------------------------------------------------
/src/lib/components/ui/select/select-content.svelte:
--------------------------------------------------------------------------------
1 |
17 |
18 |
19 |
28 |
29 |
34 | {@render children?.()}
35 |
36 |
37 |
38 |
39 |
--------------------------------------------------------------------------------
/src/lib/components/dashboard/filter-view/RowsPerPage.svelte:
--------------------------------------------------------------------------------
1 |
30 |
31 |
32 |
Rows per page
33 |
updateLimit(updated)}
38 | >
39 |
40 | {value}
41 |
42 |
43 |
44 | 20
45 | 30
46 | 40
47 | 50
48 |
49 |
50 |
51 |
--------------------------------------------------------------------------------
/src/app.css:
--------------------------------------------------------------------------------
1 | @tailwind base;
2 | @tailwind components;
3 | @tailwind utilities;
4 |
5 | @layer base {
6 | :root {
7 | --background: 0 0% 100%;
8 | --foreground: 240 10% 3.9%;
9 | --card: 0 0% 100%;
10 | --card-foreground: 240 10% 3.9%;
11 | --popover: 0 0% 100%;;
12 | --popover-foreground: 240 10% 3.9%;
13 | --primary: 240 5.9% 10%;
14 | --primary-foreground: 0 0% 98%;
15 | --secondary: 240 4.8% 95.9%;
16 | --secondary-foreground: 240 5.9% 10%;
17 | --muted: 240 4.8% 95.9%;
18 | --muted-foreground: 240 3.8% 46.1%;
19 | --accent: 240 4.8% 95.9%;
20 | --accent-foreground: 240 5.9% 10%;
21 | --destructive: 0 72.22% 50.59%;
22 | --destructive-foreground: 0 0% 98%;
23 | --border: 240 5.9% 90%;
24 | --input: 240 5.9% 90%;
25 | --ring: 240 5.9% 10%;
26 | --radius: 0.5rem;
27 | }
28 | .dark {
29 | --background: 240 10% 3.9%;
30 | --foreground: 0 0% 98%;
31 | --card: 240 10% 3.9%;
32 | --card-foreground: 0 0% 98%;
33 | --popover: 240 10% 3.9%;
34 | --popover-foreground: 0 0% 98%;
35 | --primary: 0 0% 98%;
36 | --primary-foreground: 240 5.9% 10%;
37 | --secondary: 240 3.7% 15.9%;
38 | --secondary-foreground: 0 0% 98%;
39 | --muted: 240 3.7% 15.9%;
40 | --muted-foreground: 240 5% 64.9%;
41 | --accent: 240 3.7% 15.9%;
42 | --accent-foreground: 0 0% 98%;
43 | --destructive: 0 62.8% 30.6%;
44 | --destructive-foreground: 0 0% 98%;
45 | --border: 240 3.7% 15.9%;
46 | --input: 240 3.7% 15.9%;
47 | --ring: 240 4.9% 83.9%;
48 | }
49 | }
50 |
51 | @layer base {
52 | * {
53 | @apply border-border;
54 | }
55 | body {
56 | @apply bg-background text-foreground;
57 | }
58 | }
--------------------------------------------------------------------------------
/src/lib/components/drizz/filter-status/FilterStatus.svelte:
--------------------------------------------------------------------------------
1 |
20 |
21 |
22 | Status
28 | {#if selected}
29 | {selected}
30 | {/if}
31 |
32 |
33 |
37 | Active
38 | Inactive
39 | Sage
40 | God
41 | None
42 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/src/app.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | Svelte Pagination Example
9 |
10 |
11 |
13 |
14 |
15 |
16 |
17 |
18 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 | %sveltekit.head%
29 |
30 |
31 |
32 | %sveltekit.body%
33 |
34 |
35 |
--------------------------------------------------------------------------------
/src/lib/components/ui/dropdown-menu/index.ts:
--------------------------------------------------------------------------------
1 | import { DropdownMenu as DropdownMenuPrimitive } from "bits-ui";
2 | import CheckboxItem from "./dropdown-menu-checkbox-item.svelte";
3 | import Content from "./dropdown-menu-content.svelte";
4 | import GroupHeading from "./dropdown-menu-group-heading.svelte";
5 | import Item from "./dropdown-menu-item.svelte";
6 | import Label from "./dropdown-menu-label.svelte";
7 | import RadioItem from "./dropdown-menu-radio-item.svelte";
8 | import Separator from "./dropdown-menu-separator.svelte";
9 | import Shortcut from "./dropdown-menu-shortcut.svelte";
10 | import SubContent from "./dropdown-menu-sub-content.svelte";
11 | import SubTrigger from "./dropdown-menu-sub-trigger.svelte";
12 |
13 | const Sub = DropdownMenuPrimitive.Sub;
14 | const Root = DropdownMenuPrimitive.Root;
15 | const Trigger = DropdownMenuPrimitive.Trigger;
16 | const Group = DropdownMenuPrimitive.Group;
17 | const RadioGroup = DropdownMenuPrimitive.RadioGroup;
18 |
19 | export {
20 | CheckboxItem,
21 | Content,
22 | Root as DropdownMenu,
23 | CheckboxItem as DropdownMenuCheckboxItem,
24 | Content as DropdownMenuContent,
25 | Group as DropdownMenuGroup,
26 | GroupHeading as DropdownMenuGroupHeading,
27 | Item as DropdownMenuItem,
28 | Label as DropdownMenuLabel,
29 | RadioGroup as DropdownMenuRadioGroup,
30 | RadioItem as DropdownMenuRadioItem,
31 | Separator as DropdownMenuSeparator,
32 | Shortcut as DropdownMenuShortcut,
33 | Sub as DropdownMenuSub,
34 | SubContent as DropdownMenuSubContent,
35 | SubTrigger as DropdownMenuSubTrigger,
36 | Trigger as DropdownMenuTrigger,
37 | Group,
38 | GroupHeading,
39 | Item,
40 | Label,
41 | RadioGroup,
42 | RadioItem,
43 | Root,
44 | Separator,
45 | Shortcut,
46 | Sub,
47 | SubContent,
48 | SubTrigger,
49 | Trigger,
50 | };
51 |
--------------------------------------------------------------------------------
/src/lib/images/svelte.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/routes/about/+page.svelte:
--------------------------------------------------------------------------------
1 |
24 |
25 |
26 |
Hello Everyone
27 |
28 | This project is all about pagination, sorting, filtering, debounced search,
29 | caching, and more.
30 |
31 |
32 |
33 | Motive :
34 | To Learn and teach all above concepts
35 |
36 |
37 | {#each all_imgs as item}
38 |
39 | {#if $mode === "dark"}
40 |
41 | {:else}
42 |
43 | {/if}
44 |
45 | {/each}
46 |
47 |
48 |
49 |
61 |
--------------------------------------------------------------------------------
/src/lib/components/ui/badge/badge.svelte:
--------------------------------------------------------------------------------
1 |
25 |
26 |
42 |
43 |
50 | {@render children?.()}
51 |
52 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Svelte Pagination Example
2 |
3 | 
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 | ## Features
14 |
15 | - Pagination
16 | - Debounce Search
17 | - Sorting
18 | - Filtering
19 | - Caching
20 |
21 | ## Demo
22 |
23 | 1. Simple : [Demo](https://sv-pagination.vercel.app)
24 |
25 | - Simple include all concepts on Dummy JSON API.
26 |
27 | 2. Advance : [Demo](https://sv-pagination.vercel.app/drizz)
28 | - Advance is build on top of Supabase + Drizzle ORM.
29 |
30 | ## Installation
31 |
32 | - Clone the repository
33 |
34 | ```bash
35 | git clone https://github.com/SikandarJODD/youva
36 | ```
37 |
38 | - Update your Database URL in `.env` file
39 |
40 | ```bash
41 | # Replace with your DB credentials! Supabase DB URL
42 | DATABASE_URL="postgres://user:password@host:port/db-name"
43 | ```
44 |
45 | - Install the dependencies
46 |
47 | ```bash
48 | pnpm install
49 | ```
50 |
51 | - Migrate Schema to DB and add some dummy data
52 |
53 | ```bash
54 | npx drizzle-kit migrate
55 | ```
56 |
57 | - Run the project
58 |
59 | ```bash
60 | pnpm dev
61 | ```
62 |
63 | #### [Checkout Usage & Learning](/usage.md)
64 |
65 | ### Components Used
66 |
67 | - [Shadcn Svelte](https://next.shadcn-svelte.com)
68 | - [Origin UI Svelte](https://originui-svelte.pages.dev)
69 |
--------------------------------------------------------------------------------
/src/lib/components/dashboard/table-view/TableView.svelte:
--------------------------------------------------------------------------------
1 |
14 |
15 |
16 |
17 |
18 |
19 |
21 |
22 |
25 |
28 |
29 | Company Title
30 |
31 |
32 |
33 | {#each users as user, i (i)}
34 |
35 | {user.id}
36 | {user.firstName}
37 | {user.lastName}
38 | {user.email}
39 | {user.company.title}
40 |
41 | {:else}
42 |
43 |
44 | No users found
45 |
46 |
47 | {/each}
48 |
49 |
50 |
51 |
--------------------------------------------------------------------------------
/drizzle/meta/0000_snapshot.json:
--------------------------------------------------------------------------------
1 | {
2 | "id": "87a75750-e273-4323-81b2-0a66decfb74f",
3 | "prevId": "00000000-0000-0000-0000-000000000000",
4 | "version": "7",
5 | "dialect": "postgresql",
6 | "tables": {
7 | "public.all_users": {
8 | "name": "all_users",
9 | "schema": "",
10 | "columns": {
11 | "id": {
12 | "name": "id",
13 | "type": "serial",
14 | "primaryKey": true,
15 | "notNull": true
16 | },
17 | "first_name": {
18 | "name": "first_name",
19 | "type": "text",
20 | "primaryKey": false,
21 | "notNull": false
22 | },
23 | "last_name": {
24 | "name": "last_name",
25 | "type": "text",
26 | "primaryKey": false,
27 | "notNull": false
28 | },
29 | "email": {
30 | "name": "email",
31 | "type": "text",
32 | "primaryKey": false,
33 | "notNull": false
34 | },
35 | "company": {
36 | "name": "company",
37 | "type": "text",
38 | "primaryKey": false,
39 | "notNull": false
40 | },
41 | "status": {
42 | "name": "status",
43 | "type": "status",
44 | "typeSchema": "public",
45 | "primaryKey": false,
46 | "notNull": false
47 | }
48 | },
49 | "indexes": {},
50 | "foreignKeys": {},
51 | "compositePrimaryKeys": {},
52 | "uniqueConstraints": {},
53 | "policies": {},
54 | "checkConstraints": {},
55 | "isRLSEnabled": false
56 | }
57 | },
58 | "enums": {
59 | "public.status": {
60 | "name": "status",
61 | "schema": "public",
62 | "values": [
63 | "active",
64 | "inactive",
65 | "sage",
66 | "god"
67 | ]
68 | }
69 | },
70 | "schemas": {},
71 | "sequences": {},
72 | "roles": {},
73 | "policies": {},
74 | "views": {},
75 | "_meta": {
76 | "columns": {},
77 | "schemas": {},
78 | "tables": {}
79 | }
80 | }
--------------------------------------------------------------------------------
/src/lib/components/dashboard/filter-view/FilterCompanyTitle.svelte:
--------------------------------------------------------------------------------
1 |
42 |
43 |
44 | {#each all_filters as filter}
45 | filter_users(filter.value)}
50 | >
51 | {filter.name}
53 | {/each}
54 | {#if is_filter_present}
55 | {
60 | let url = new URL(page.url);
61 | url.searchParams.delete("filter");
62 | url.searchParams.delete("value");
63 | url.searchParams.set("limit", "10");
64 | url.searchParams.set("skip", "0");
65 | goto(url.toString(), { replaceState: true });
66 | }}
67 | >
68 | Clear Filter
69 |
70 | {/if}
71 |
72 |
--------------------------------------------------------------------------------
/usage.md:
--------------------------------------------------------------------------------
1 | # Usage & Learning
2 |
3 | I am using Dummy JSON API to fetch data. You can replace it with your own API. Checkout Dummy JSON API [here](https://dummyjson.com/docs/users#users-all)
4 |
5 | - The Most important project lies in [`src/routes/+page.server.ts`](https://github.com/SikandarJODD/youva/blob/master/src/routes/%2Bpage.server.ts) file.
6 | - here you can query the data from the API and pass it to the `+page.svelte`.
7 | - The base of all features lies in `get`, `set` and `goto` functions.
8 |
9 | ### Pagination
10 |
11 | - we will be using `limit` & `skip` to paginate the data.
12 | - default `limit` is 10 and `skip` is 0.
13 | - when user clicks on the next button, we will increment the `skip` by 10 and fetch the next 10 records.
14 | - for specific page, we will calculate the `skip` value and fetch the records.
15 | - Checkout **[Pagination View Component](https://github.com/SikandarJODD/youva/blob/master/src/lib/components/dashboard/pagination-view/PaginationView.svelte)** for detail implementation.
16 |
17 | ### Debounce Search
18 |
19 | - we will be using `throttle-debounce` library to implement the debounce search.
20 | - when users inputs the value after `300ms` we will set the query value as `q=michael` and fetch the data.
21 | - Checkout [Search Input Component](https://github.com/SikandarJODD/youva/blob/master/src/lib/components/dashboard/filter-view/SearchInput.svelte) for detail implementation.
22 |
23 | ### Sorting
24 |
25 | - we will be using `sortBy` & `order` query to sort the data.
26 | - `sortBy` will be the key on which we want to sort the data for example id,firstName.
27 | - `order` will be the order of sorting `asc` or `desc`.
28 | - Checkout [Table View Component](https://github.com/SikandarJODD/youva/blob/master/src/lib/components/dashboard/table-view/TableView.svelte)
29 |
30 | ### Filtering
31 |
32 | - we will be using different [fetch url](https://dummyjson.com/docs/users#users-filter) to filter data based on the query.
33 | - here we are using `key` and `value` to filter the data.
34 | - for example `key`='company.title' and `value`='Sales Manager'
35 | - This will provide all the `users` who works in compnay with title `Sales Manager`.
36 | - Checkout [Filter Component](https://github.com/SikandarJODD/youva/blob/master/src/lib/components/dashboard/filter-view/FilterCompanyTitle.svelte) for detail implementation.
--------------------------------------------------------------------------------
/src/lib/components/dashboard/table-view/SortItem.svelte:
--------------------------------------------------------------------------------
1 |
35 |
36 |
37 |
38 |
39 |
44 | {name}
45 |
46 | {#if category === key}
47 | {#if orderBy === "asc"}
48 |
49 | {:else if orderBy === "desc"}
50 |
51 | {/if}
52 | {:else}
53 |
54 | {/if}
55 |
56 |
57 |
58 |
59 |
60 | Asc
61 |
62 |
63 |
64 | Desc
65 |
66 |
67 |
68 |
69 |
--------------------------------------------------------------------------------
/src/lib/images/logo-github-sq-light.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/src/lib/components/drizz/table-view/DrizzSortItem.svelte:
--------------------------------------------------------------------------------
1 |
36 |
37 |
38 |
39 |
40 |
45 | {name}
46 |
47 | {#if category === key}
48 | {#if orderBy === "asc"}
49 |
50 | {:else if orderBy === "desc"}
51 |
52 | {/if}
53 | {:else}
54 |
55 | {/if}
56 |
57 |
58 |
59 |
60 |
61 | Asc
62 |
63 |
64 |
65 | Desc
66 |
67 |
68 |
69 |
70 |
--------------------------------------------------------------------------------
/src/lib/images/logo-github-sq-dark.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/src/lib/components/ui/button/button.svelte:
--------------------------------------------------------------------------------
1 |
42 |
43 |
57 |
58 | {#if href}
59 |
65 | {@render children?.()}
66 |
67 | {:else}
68 |
74 | {@render children?.()}
75 |
76 | {/if}
77 |
--------------------------------------------------------------------------------
/src/lib/components/dashboard/pagination-view/PaginationView.svelte:
--------------------------------------------------------------------------------
1 |
50 |
51 |
52 | {#snippet children({ pages, currentPage })}
53 |
54 |
55 |
56 |
57 | {#each pages as page (page.key)}
58 | {#if page.type === "ellipsis"}
59 |
60 |
61 |
62 | {:else}
63 |
64 | goToIndexPage(page.value)}
66 | {page}
67 | isActive={currentPage === page.value}
68 | >
69 | {page.value}
70 |
71 |
72 | {/if}
73 | {/each}
74 |
75 |
76 |
77 |
78 | {/snippet}
79 |
80 |
--------------------------------------------------------------------------------
/src/routes/drizz/+page.server.ts:
--------------------------------------------------------------------------------
1 | import { db } from "$lib/server/db";
2 | import { all_users } from "$lib/server/db/schema";
3 | import { asc, desc, eq, ilike, or } from "drizzle-orm";
4 | import type { PageServerLoad } from "./$types";
5 |
6 | type Status = 'active' | 'inactive' | 'sage' | 'god';
7 | type SortBy = 'id' | 'firstName' | 'lastName' | 'email' | 'status';
8 |
9 | async function getTotalUsers() {
10 | return db.$count(all_users);
11 | }
12 |
13 | async function getTotalStatusUsers(status: Status) {
14 | return db.$count(all_users, eq(all_users.status, status));
15 | }
16 |
17 | async function getTotalSearchUsers(search: string) {
18 | return db.$count(all_users, eq(all_users.firstName, search));
19 | }
20 |
21 | async function getStatusUsers(limit: number, skip: number, status: Status) {
22 | return db.select().from(all_users).where(eq(all_users.status, status)).limit(limit).offset(skip);
23 | }
24 |
25 | async function getUsers(limit: number, skip: number, sortBy: SortBy, sortOrder: string) {
26 | if (sortOrder === 'asc') {
27 | return db.select().from(all_users).orderBy(asc(all_users[sortBy])).limit(limit).offset(skip);
28 | }
29 | else {
30 | return db.select().from(all_users).orderBy(desc(all_users[sortBy])).limit(limit).offset(skip);
31 | }
32 | }
33 |
34 | async function searchUsers(limit: number, skip: number, search: string) {
35 | return db.select().from(all_users).where(or(ilike(all_users.firstName, `%${search}%`), ilike(all_users.lastName, `%${search}%`))).limit(limit).offset(skip);
36 | }
37 |
38 |
39 |
40 |
41 | export const load: PageServerLoad = async ({ url, setHeaders }) => {
42 |
43 | // offset = skip
44 | let limit = Number(url.searchParams.get("limit")) || 10;
45 | let skip = Number(url.searchParams.get("skip")) || 0;
46 | let status = url.searchParams.get("status") || '';
47 | let search = url.searchParams.get("q") || '';
48 | let sortBy = url.searchParams.get("sortBy") || 'id';
49 | let sortOrder = url.searchParams.get("order") || 'asc';
50 |
51 | let res;
52 | let total_count = 0;
53 | if (status === 'active' || status === 'inactive' || status === 'sage' || status === 'god') {
54 | res = await getStatusUsers(limit, skip, status);
55 | total_count = await getTotalStatusUsers(status);
56 | }
57 | else if (search) {
58 | res = await searchUsers(limit, skip, search);
59 | total_count = await getTotalSearchUsers(search);
60 | }
61 | else {
62 | res = await getUsers(limit, skip, sortBy as SortBy, sortOrder);
63 | total_count = await getTotalUsers();
64 | }
65 |
66 | // Cache Data for 60 seconds checkout network tab in console
67 | // you can see new req may take 400-600ms but after that it will be 0-5ms
68 | setHeaders({
69 | 'cache-control': 'public, max-age=60',
70 | })
71 | return {
72 | users: res,
73 | count: total_count
74 | }
75 | };
--------------------------------------------------------------------------------
/src/lib/components/dashboard/filter-view/SearchInput.svelte:
--------------------------------------------------------------------------------
1 |
49 |
50 |
51 |
52 |
59 |
62 |
63 |
64 | {#if inputValue}
65 |
70 |
71 |
72 | {/if}
73 |
74 |
75 |
--------------------------------------------------------------------------------
/tailwind.config.ts:
--------------------------------------------------------------------------------
1 | import { fontFamily } from "tailwindcss/defaultTheme";
2 | import type { Config } from "tailwindcss";
3 | import tailwindcssAnimate from "tailwindcss-animate";
4 |
5 | const config: Config = {
6 | darkMode: ["class"],
7 | content: ["./src/**/*.{html,js,svelte,ts}"],
8 | safelist: ["dark"],
9 | theme: {
10 | container: {
11 | center: true,
12 | padding: "2rem",
13 | screens: {
14 | "2xl": "1400px"
15 | }
16 | },
17 | extend: {
18 | colors: {
19 | border: "hsl(var(--border) / )",
20 | input: "hsl(var(--input) / )",
21 | ring: "hsl(var(--ring) / )",
22 | background: "hsl(var(--background) / )",
23 | foreground: "hsl(var(--foreground) / )",
24 | primary: {
25 | DEFAULT: "hsl(var(--primary) / )",
26 | foreground: "hsl(var(--primary-foreground) / )"
27 | },
28 | secondary: {
29 | DEFAULT: "hsl(var(--secondary) / )",
30 | foreground: "hsl(var(--secondary-foreground) / )"
31 | },
32 | destructive: {
33 | DEFAULT: "hsl(var(--destructive) / )",
34 | foreground: "hsl(var(--destructive-foreground) / )"
35 | },
36 | muted: {
37 | DEFAULT: "hsl(var(--muted) / )",
38 | foreground: "hsl(var(--muted-foreground) / )"
39 | },
40 | accent: {
41 | DEFAULT: "hsl(var(--accent) / )",
42 | foreground: "hsl(var(--accent-foreground) / )"
43 | },
44 | popover: {
45 | DEFAULT: "hsl(var(--popover) / )",
46 | foreground: "hsl(var(--popover-foreground) / )"
47 | },
48 | card: {
49 | DEFAULT: "hsl(var(--card) / )",
50 | foreground: "hsl(var(--card-foreground) / )"
51 | },
52 | sidebar: {
53 | DEFAULT: "hsl(var(--sidebar-background))",
54 | foreground: "hsl(var(--sidebar-foreground))",
55 | primary: "hsl(var(--sidebar-primary))",
56 | "primary-foreground": "hsl(var(--sidebar-primary-foreground))",
57 | accent: "hsl(var(--sidebar-accent))",
58 | "accent-foreground": "hsl(var(--sidebar-accent-foreground))",
59 | border: "hsl(var(--sidebar-border))",
60 | ring: "hsl(var(--sidebar-ring))",
61 | },
62 | },
63 | borderRadius: {
64 | xl: "calc(var(--radius) + 4px)",
65 | lg: "var(--radius)",
66 | md: "calc(var(--radius) - 2px)",
67 | sm: "calc(var(--radius) - 4px)"
68 | },
69 | fontFamily: {
70 | sans: ['InterVariable', ...fontFamily.sans],
71 | "baloo": ['"Baloo 2"', ...fontFamily.sans],
72 | },
73 | keyframes: {
74 | "accordion-down": {
75 | from: { height: "0" },
76 | to: { height: "var(--bits-accordion-content-height)" },
77 | },
78 | "accordion-up": {
79 | from: { height: "var(--bits-accordion-content-height)" },
80 | to: { height: "0" },
81 | },
82 | "caret-blink": {
83 | "0%,70%,100%": { opacity: "1" },
84 | "20%,50%": { opacity: "0" },
85 | },
86 | },
87 | animation: {
88 | "accordion-down": "accordion-down 0.2s ease-out",
89 | "accordion-up": "accordion-up 0.2s ease-out",
90 | "caret-blink": "caret-blink 1.25s ease-out infinite",
91 | },
92 | },
93 | },
94 | plugins: [tailwindcssAnimate],
95 | };
96 |
97 | export default config;
98 |
--------------------------------------------------------------------------------
/src/lib/components/drizz/table-view/DrizzTableView.svelte:
--------------------------------------------------------------------------------
1 |
13 |
14 |
15 |
16 |
17 |
18 |
20 |
21 |
25 |
29 |
32 |
35 |
38 |
39 |
40 |
41 |
42 | {#each users as user, i (i)}
43 |
44 | {user.id}
45 | {user.firstName}
46 | {user.lastName}
47 | {user.email}
48 | {user.company}
49 |
50 | {#if user.status === "active"}
51 | {user.status}
55 | {:else if user.status === "inactive"}
56 | {user.status}
60 | {:else if user.status === "sage"}
61 | {user.status}
65 | {:else}
66 | {user.status}
70 | {/if}
71 |
72 |
73 | {:else}
74 |
75 |
76 | No users found
77 |
78 |
79 | {/each}
80 |
81 |
82 |
83 |
--------------------------------------------------------------------------------
/src/lib/images/supabase-logo-wordmarkdark.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/src/lib/images/supabase-logo-wordmarklight.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/src/lib/components/home/Sidebar.svelte:
--------------------------------------------------------------------------------
1 |
7 |
8 |
9 |
10 |
18 |
25 |
26 |
32 |
38 |
39 |
(isMobileMenu = false)}
43 | class="-ml-4 bg-transparent text-primary-foreground border-none"
44 | >
45 | Close sidebar
46 |
54 |
59 |
60 |
61 |
62 |
63 |
64 |
100 |
101 |
102 |
103 |
104 |
105 |
146 |
147 |
150 |
Filters
151 |
(isMobileMenu = true)}
156 | >
157 | Open sidebar
158 |
176 |
177 |
178 |
179 |
180 |
181 | {@render children()}
182 |
183 |
184 |
185 |
--------------------------------------------------------------------------------
/src/lib/components/home/Navbar.svelte:
--------------------------------------------------------------------------------
1 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
37 |
38 |
39 |
40 |
43 | {#each navs as nav}
44 | {nav.name}
46 | {#if nav.isNew}
47 | New
51 | {/if}
52 |
53 | {/each}
54 |
55 |
56 |
57 |
58 | {@render socials()}
59 |
60 |
61 |
62 | (isMobileMenu = !isMobileMenu)}
64 | size="icon"
65 | variant="secondary"
66 | >
67 | Open main menu
68 |
69 |
84 |
85 |
100 |
101 |
102 |
103 |
104 |
105 |
106 | {#if isMobileMenu}
107 |
123 | {/if}
124 |
125 |
126 | {#snippet ThemeToggle()}
127 |
128 |
129 | {#if $mode === "light"}
130 |
149 | {:else}
150 |
151 |
164 | {/if}
165 | Toggle theme
166 |
167 | {/snippet}
168 |
169 | {#snippet socials()}
170 |
171 |
172 |
185 |
188 |
190 |
191 |
192 |
208 | {@render ThemeToggle()}
209 |
210 | {/snippet}
211 |
--------------------------------------------------------------------------------