├── .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 | 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 | 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 | 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 | logo 41 | {:else} 42 | logo 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 | ![Main_Page](/static/img_icon.png) 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 | 53 | {/each} 54 | {#if is_filter_present} 55 | 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 | 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 | 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 | 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 | 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 | 103 | 104 | 105 | 146 | 147 |
    150 |
    Filters
    151 | 177 |
    178 | 179 |
    180 |
    181 | {@render children()} 182 |
    183 |
    184 |
    185 | -------------------------------------------------------------------------------- /src/lib/components/home/Navbar.svelte: -------------------------------------------------------------------------------- 1 | 16 | 17 | 125 | 126 | {#snippet ThemeToggle()} 127 | 167 | {/snippet} 168 | 169 | {#snippet socials()} 170 |
    171 | 172 | 190 | 191 | 192 | 208 | {@render ThemeToggle()} 209 |
    210 | {/snippet} 211 | --------------------------------------------------------------------------------