From a5918f418ffda0a84ee9a6e58d01a0e2cab07a86 Mon Sep 17 00:00:00 2001 From: flamboh Date: Fri, 21 Aug 2026 14:10:47 -0700 Subject: [PATCH 1/7] feat(web): add shadcn-svelte foundation with semantic theme tokens --- apps/web/components.json | 20 +++ apps/web/package.json | 9 +- apps/web/src/app.css | 118 +++++++++++++++++- .../lib/components/ui/button/button.svelte | 91 ++++++++++++++ .../web/src/lib/components/ui/button/index.ts | 17 +++ .../lib/components/ui/card/card-action.svelte | 23 ++++ .../components/ui/card/card-content.svelte | 20 +++ .../ui/card/card-description.svelte | 20 +++ .../lib/components/ui/card/card-footer.svelte | 23 ++++ .../lib/components/ui/card/card-header.svelte | 23 ++++ .../lib/components/ui/card/card-title.svelte | 20 +++ .../src/lib/components/ui/card/card.svelte | 25 ++++ apps/web/src/lib/components/ui/card/index.ts | 25 ++++ .../components/ui/checkbox/checkbox.svelte | 39 ++++++ .../src/lib/components/ui/checkbox/index.ts | 6 + .../web/src/lib/components/ui/select/index.ts | 37 ++++++ .../ui/select/select-content.svelte | 45 +++++++ .../ui/select/select-group-heading.svelte | 21 ++++ .../components/ui/select/select-group.svelte | 17 +++ .../components/ui/select/select-item.svelte | 40 ++++++ .../components/ui/select/select-label.svelte | 20 +++ .../components/ui/select/select-portal.svelte | 7 ++ .../select/select-scroll-down-button.svelte | 23 ++++ .../ui/select/select-scroll-up-button.svelte | 23 ++++ .../ui/select/select-separator.svelte | 18 +++ .../ui/select/select-trigger.svelte | 29 +++++ .../lib/components/ui/select/select.svelte | 11 ++ .../src/lib/components/ui/separator/index.ts | 7 ++ .../components/ui/separator/separator.svelte | 23 ++++ .../src/lib/components/ui/skeleton/index.ts | 7 ++ .../components/ui/skeleton/skeleton.svelte | 17 +++ apps/web/src/lib/components/ui/table/index.ts | 28 +++++ .../lib/components/ui/table/table-body.svelte | 20 +++ .../components/ui/table/table-caption.svelte | 20 +++ .../lib/components/ui/table/table-cell.svelte | 20 +++ .../components/ui/table/table-footer.svelte | 20 +++ .../lib/components/ui/table/table-head.svelte | 23 ++++ .../components/ui/table/table-header.svelte | 20 +++ .../lib/components/ui/table/table-row.svelte | 23 ++++ .../src/lib/components/ui/table/table.svelte | 22 ++++ apps/web/src/lib/components/ui/tabs/index.ts | 18 +++ .../components/ui/tabs/tabs-content.svelte | 17 +++ .../lib/components/ui/tabs/tabs-list.svelte | 40 ++++++ .../components/ui/tabs/tabs-trigger.svelte | 23 ++++ .../src/lib/components/ui/tabs/tabs.svelte | 19 +++ .../src/lib/components/ui/tooltip/index.ts | 19 +++ .../ui/tooltip/tooltip-content.svelte | 52 ++++++++ .../ui/tooltip/tooltip-portal.svelte | 7 ++ .../ui/tooltip/tooltip-provider.svelte | 7 ++ .../ui/tooltip/tooltip-trigger.svelte | 7 ++ .../lib/components/ui/tooltip/tooltip.svelte | 7 ++ apps/web/src/lib/utils.ts | 13 ++ bun.lock | 51 +++++++- 53 files changed, 1294 insertions(+), 6 deletions(-) create mode 100644 apps/web/components.json create mode 100644 apps/web/src/lib/components/ui/button/button.svelte create mode 100644 apps/web/src/lib/components/ui/button/index.ts create mode 100644 apps/web/src/lib/components/ui/card/card-action.svelte create mode 100644 apps/web/src/lib/components/ui/card/card-content.svelte create mode 100644 apps/web/src/lib/components/ui/card/card-description.svelte create mode 100644 apps/web/src/lib/components/ui/card/card-footer.svelte create mode 100644 apps/web/src/lib/components/ui/card/card-header.svelte create mode 100644 apps/web/src/lib/components/ui/card/card-title.svelte create mode 100644 apps/web/src/lib/components/ui/card/card.svelte create mode 100644 apps/web/src/lib/components/ui/card/index.ts create mode 100644 apps/web/src/lib/components/ui/checkbox/checkbox.svelte create mode 100644 apps/web/src/lib/components/ui/checkbox/index.ts create mode 100644 apps/web/src/lib/components/ui/select/index.ts create mode 100644 apps/web/src/lib/components/ui/select/select-content.svelte create mode 100644 apps/web/src/lib/components/ui/select/select-group-heading.svelte create mode 100644 apps/web/src/lib/components/ui/select/select-group.svelte create mode 100644 apps/web/src/lib/components/ui/select/select-item.svelte create mode 100644 apps/web/src/lib/components/ui/select/select-label.svelte create mode 100644 apps/web/src/lib/components/ui/select/select-portal.svelte create mode 100644 apps/web/src/lib/components/ui/select/select-scroll-down-button.svelte create mode 100644 apps/web/src/lib/components/ui/select/select-scroll-up-button.svelte create mode 100644 apps/web/src/lib/components/ui/select/select-separator.svelte create mode 100644 apps/web/src/lib/components/ui/select/select-trigger.svelte create mode 100644 apps/web/src/lib/components/ui/select/select.svelte create mode 100644 apps/web/src/lib/components/ui/separator/index.ts create mode 100644 apps/web/src/lib/components/ui/separator/separator.svelte create mode 100644 apps/web/src/lib/components/ui/skeleton/index.ts create mode 100644 apps/web/src/lib/components/ui/skeleton/skeleton.svelte create mode 100644 apps/web/src/lib/components/ui/table/index.ts create mode 100644 apps/web/src/lib/components/ui/table/table-body.svelte create mode 100644 apps/web/src/lib/components/ui/table/table-caption.svelte create mode 100644 apps/web/src/lib/components/ui/table/table-cell.svelte create mode 100644 apps/web/src/lib/components/ui/table/table-footer.svelte create mode 100644 apps/web/src/lib/components/ui/table/table-head.svelte create mode 100644 apps/web/src/lib/components/ui/table/table-header.svelte create mode 100644 apps/web/src/lib/components/ui/table/table-row.svelte create mode 100644 apps/web/src/lib/components/ui/table/table.svelte create mode 100644 apps/web/src/lib/components/ui/tabs/index.ts create mode 100644 apps/web/src/lib/components/ui/tabs/tabs-content.svelte create mode 100644 apps/web/src/lib/components/ui/tabs/tabs-list.svelte create mode 100644 apps/web/src/lib/components/ui/tabs/tabs-trigger.svelte create mode 100644 apps/web/src/lib/components/ui/tabs/tabs.svelte create mode 100644 apps/web/src/lib/components/ui/tooltip/index.ts create mode 100644 apps/web/src/lib/components/ui/tooltip/tooltip-content.svelte create mode 100644 apps/web/src/lib/components/ui/tooltip/tooltip-portal.svelte create mode 100644 apps/web/src/lib/components/ui/tooltip/tooltip-provider.svelte create mode 100644 apps/web/src/lib/components/ui/tooltip/tooltip-trigger.svelte create mode 100644 apps/web/src/lib/components/ui/tooltip/tooltip.svelte create mode 100644 apps/web/src/lib/utils.ts diff --git a/apps/web/components.json b/apps/web/components.json new file mode 100644 index 00000000..44fad997 --- /dev/null +++ b/apps/web/components.json @@ -0,0 +1,20 @@ +{ + "$schema": "https://shadcn-svelte.com/schema.json", + "tailwind": { + "css": "src/app.css", + "baseColor": "neutral" + }, + "aliases": { + "components": "$lib/components", + "utils": "$lib/utils", + "ui": "$lib/components/ui", + "hooks": "$lib/hooks", + "lib": "$lib" + }, + "typescript": true, + "registry": "https://shadcn-svelte.com/registry", + "style": "vega", + "iconLibrary": "lucide", + "menuColor": "default", + "menuAccent": "subtle" +} diff --git a/apps/web/package.json b/apps/web/package.json index 7eb112cd..20db95d3 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -31,6 +31,7 @@ "@cloudflare/workers-types": "^4.20260511.1", "@eslint/compat": "^1.2.5", "@eslint/js": "^9.18.0", + "@internationalized/date": "^3.12.0", "@playwright/test": "1.52.0", "@sveltejs/adapter-cloudflare": "^7.2.8", "@sveltejs/kit": "^2.16.0", @@ -38,6 +39,8 @@ "@tailwindcss/vite": "^4.0.0", "@types/better-sqlite3": "^7.6.13", "@types/node": "^22.15.17", + "bits-ui": "^2.16.3", + "clsx": "^2.1.1", "eslint": "^9.18.0", "eslint-config-prettier": "^10.0.1", "eslint-plugin-svelte": "^3.0.0", @@ -45,9 +48,13 @@ "prettier": "^3.8.1", "prettier-plugin-svelte": "^3.5.1", "prettier-plugin-tailwindcss": "^0.7.2", + "shadcn-svelte": "^1.5.0", "svelte": "^5.0.0", "svelte-check": "^4.0.0", + "tailwind-merge": "^3.6.0", + "tailwind-variants": "^3.3.1", "tailwindcss": "^4.0.0", + "tw-animate-css": "^1.4.0", "typescript": "^5.0.0", "typescript-eslint": "^8.20.0", "vite": "^6.2.6", @@ -55,7 +62,7 @@ "wrangler": "^4.90.0" }, "dependencies": { - "@lucide/svelte": "^0.511.0", + "@lucide/svelte": "^1.33.0", "better-sqlite3": "^12.6.2", "chart.js": "^4.4.9", "chartjs-plugin-annotation": "^3.1.0", diff --git a/apps/web/src/app.css b/apps/web/src/app.css index 6191ce8f..3877c4ec 100644 --- a/apps/web/src/app.css +++ b/apps/web/src/app.css @@ -1,17 +1,56 @@ @import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap'); @import 'tailwindcss'; +@import 'tw-animate-css'; +@import 'shadcn-svelte/tailwind.css'; @custom-variant dark (&:where(.dark, .dark *)); @theme { --font-body: 'Inter', sans-serif; - --color-cisco-blue: #009edc; - --color-dark-bg: #0a0a0a; --color-dark-surface: #111111; --color-dark-subtle: #1a1a1a; --color-dark-border: #2d2d2d; + --font-sans: 'Inter', sans-serif; + --color-sidebar-ring: var(--sidebar-ring); + --color-sidebar-border: var(--sidebar-border); + --color-sidebar-accent-foreground: var(--sidebar-accent-foreground); + --color-sidebar-accent: var(--sidebar-accent); + --color-sidebar-primary-foreground: var(--sidebar-primary-foreground); + --color-sidebar-primary: var(--sidebar-primary); + --color-sidebar-foreground: var(--sidebar-foreground); + --color-sidebar: var(--sidebar); + --color-chart-5: var(--chart-5); + --color-chart-4: var(--chart-4); + --color-chart-3: var(--chart-3); + --color-chart-2: var(--chart-2); + --color-chart-1: var(--chart-1); + --color-ring: var(--ring); + --color-input: var(--input); + --color-border: var(--border); + --color-destructive: var(--destructive); + --color-accent-foreground: var(--accent-foreground); + --color-accent: var(--accent); + --color-muted-foreground: var(--muted-foreground); + --color-muted: var(--muted); + --color-secondary-foreground: var(--secondary-foreground); + --color-secondary: var(--secondary); + --color-primary-foreground: var(--primary-foreground); + --color-primary: var(--primary); + --color-popover-foreground: var(--popover-foreground); + --color-popover: var(--popover); + --color-card-foreground: var(--card-foreground); + --color-card: var(--card); + --color-foreground: var(--foreground); + --color-background: var(--background); + --radius-sm: calc(var(--radius) * 0.6); + --radius-md: calc(var(--radius) * 0.8); + --radius-lg: var(--radius); + --radius-xl: calc(var(--radius) * 1.4); + --radius-2xl: calc(var(--radius) * 1.8); + --radius-3xl: calc(var(--radius) * 2.2); + --radius-4xl: calc(var(--radius) * 2.6); } :root { @@ -21,6 +60,38 @@ --chart-tooltip-bg: rgba(17, 24, 39, 0.9); --chart-tooltip-text-color: #f9fafb; --chart-tooltip-border-color: rgba(107, 114, 128, 0.7); + --background: #ffffff; + --foreground: #111827; + --card: #ffffff; + --card-foreground: #111827; + --popover: #ffffff; + --popover-foreground: #111827; + --primary: #2563eb; + --primary-foreground: #ffffff; + --secondary: oklch(0.97 0 0); + --secondary-foreground: oklch(0.205 0 0); + --muted: #f3f4f6; + --muted-foreground: #6b7280; + --accent: #f3f4f6; + --accent-foreground: #111827; + --destructive: #dc2626; + --border: #e5e7eb; + --input: #e5e7eb; + --ring: #2563eb; + --chart-1: oklch(0.87 0 0); + --chart-2: oklch(0.556 0 0); + --chart-3: oklch(0.439 0 0); + --chart-4: oklch(0.371 0 0); + --chart-5: oklch(0.269 0 0); + --radius: 0.625rem; + --sidebar: oklch(0.985 0 0); + --sidebar-foreground: oklch(0.145 0 0); + --sidebar-primary: oklch(0.205 0 0); + --sidebar-primary-foreground: oklch(0.985 0 0); + --sidebar-accent: oklch(0.97 0 0); + --sidebar-accent-foreground: oklch(0.205 0 0); + --sidebar-border: oklch(0.922 0 0); + --sidebar-ring: oklch(0.708 0 0); } .dark { @@ -30,6 +101,37 @@ --chart-tooltip-bg: rgba(3, 7, 18, 0.92); --chart-tooltip-text-color: #f3f4f6; --chart-tooltip-border-color: rgba(75, 85, 99, 0.85); + --background: #0a0a0a; + --foreground: #fafafa; + --card: #111111; + --card-foreground: #fafafa; + --popover: #111111; + --popover-foreground: #fafafa; + --primary: #2563eb; + --primary-foreground: #ffffff; + --secondary: #1a1a1a; + --secondary-foreground: oklch(0.985 0 0); + --muted: #1a1a1a; + --muted-foreground: #a3a3a3; + --accent: #1a1a1a; + --accent-foreground: #fafafa; + --destructive: #dc2626; + --border: #2d2d2d; + --input: #2d2d2d; + --ring: #2563eb; + --chart-1: oklch(0.87 0 0); + --chart-2: oklch(0.556 0 0); + --chart-3: oklch(0.439 0 0); + --chart-4: oklch(0.371 0 0); + --chart-5: oklch(0.269 0 0); + --sidebar: oklch(0.205 0 0); + --sidebar-foreground: oklch(0.985 0 0); + --sidebar-primary: oklch(0.488 0.243 264.376); + --sidebar-primary-foreground: oklch(0.985 0 0); + --sidebar-accent: oklch(0.269 0 0); + --sidebar-accent-foreground: oklch(0.985 0 0); + --sidebar-border: oklch(1 0 0 / 10%); + --sidebar-ring: oklch(0.556 0 0); } html { @@ -45,3 +147,15 @@ body { .app-shell__main { scrollbar-gutter: stable; } + +@layer base { + * { + @apply border-border outline-ring/50; + } + body { + @apply bg-background text-foreground; + } + html { + @apply font-sans; + } +} diff --git a/apps/web/src/lib/components/ui/button/button.svelte b/apps/web/src/lib/components/ui/button/button.svelte new file mode 100644 index 00000000..611b8929 --- /dev/null +++ b/apps/web/src/lib/components/ui/button/button.svelte @@ -0,0 +1,91 @@ + + + + +{#if href} + + + {@render children?.()} + + +{:else} + +{/if} diff --git a/apps/web/src/lib/components/ui/button/index.ts b/apps/web/src/lib/components/ui/button/index.ts new file mode 100644 index 00000000..5414d9d3 --- /dev/null +++ b/apps/web/src/lib/components/ui/button/index.ts @@ -0,0 +1,17 @@ +import Root, { + type ButtonProps, + type ButtonSize, + type ButtonVariant, + buttonVariants +} from './button.svelte'; + +export { + Root, + type ButtonProps as Props, + // + Root as Button, + buttonVariants, + type ButtonProps, + type ButtonSize, + type ButtonVariant +}; diff --git a/apps/web/src/lib/components/ui/card/card-action.svelte b/apps/web/src/lib/components/ui/card/card-action.svelte new file mode 100644 index 00000000..bc79c73d --- /dev/null +++ b/apps/web/src/lib/components/ui/card/card-action.svelte @@ -0,0 +1,23 @@ + + +
+ {@render children?.()} +
diff --git a/apps/web/src/lib/components/ui/card/card-content.svelte b/apps/web/src/lib/components/ui/card/card-content.svelte new file mode 100644 index 00000000..4d887798 --- /dev/null +++ b/apps/web/src/lib/components/ui/card/card-content.svelte @@ -0,0 +1,20 @@ + + +
+ {@render children?.()} +
diff --git a/apps/web/src/lib/components/ui/card/card-description.svelte b/apps/web/src/lib/components/ui/card/card-description.svelte new file mode 100644 index 00000000..58c0904c --- /dev/null +++ b/apps/web/src/lib/components/ui/card/card-description.svelte @@ -0,0 +1,20 @@ + + +

+ {@render children?.()} +

diff --git a/apps/web/src/lib/components/ui/card/card-footer.svelte b/apps/web/src/lib/components/ui/card/card-footer.svelte new file mode 100644 index 00000000..253e7f23 --- /dev/null +++ b/apps/web/src/lib/components/ui/card/card-footer.svelte @@ -0,0 +1,23 @@ + + +
+ {@render children?.()} +
diff --git a/apps/web/src/lib/components/ui/card/card-header.svelte b/apps/web/src/lib/components/ui/card/card-header.svelte new file mode 100644 index 00000000..b2f5f4df --- /dev/null +++ b/apps/web/src/lib/components/ui/card/card-header.svelte @@ -0,0 +1,23 @@ + + +
+ {@render children?.()} +
diff --git a/apps/web/src/lib/components/ui/card/card-title.svelte b/apps/web/src/lib/components/ui/card/card-title.svelte new file mode 100644 index 00000000..cc49a4d1 --- /dev/null +++ b/apps/web/src/lib/components/ui/card/card-title.svelte @@ -0,0 +1,20 @@ + + +
+ {@render children?.()} +
diff --git a/apps/web/src/lib/components/ui/card/card.svelte b/apps/web/src/lib/components/ui/card/card.svelte new file mode 100644 index 00000000..54f3f751 --- /dev/null +++ b/apps/web/src/lib/components/ui/card/card.svelte @@ -0,0 +1,25 @@ + + +
img:first-child]:pt-0 data-[size=sm]:[--card-spacing:--spacing(4)] *:[img:first-child]:rounded-t-xl *:[img:last-child]:rounded-b-xl', + className + )} + {...restProps} +> + {@render children?.()} +
diff --git a/apps/web/src/lib/components/ui/card/index.ts b/apps/web/src/lib/components/ui/card/index.ts new file mode 100644 index 00000000..6a3ae41f --- /dev/null +++ b/apps/web/src/lib/components/ui/card/index.ts @@ -0,0 +1,25 @@ +import Action from './card-action.svelte'; +import Content from './card-content.svelte'; +import Description from './card-description.svelte'; +import Footer from './card-footer.svelte'; +import Header from './card-header.svelte'; +import Title from './card-title.svelte'; +import Root from './card.svelte'; + +export { + Root, + Content, + Description, + Footer, + Header, + Title, + Action, + // + Root as Card, + Content as CardContent, + Description as CardDescription, + Footer as CardFooter, + Header as CardHeader, + Title as CardTitle, + Action as CardAction +}; diff --git a/apps/web/src/lib/components/ui/checkbox/checkbox.svelte b/apps/web/src/lib/components/ui/checkbox/checkbox.svelte new file mode 100644 index 00000000..56a5447b --- /dev/null +++ b/apps/web/src/lib/components/ui/checkbox/checkbox.svelte @@ -0,0 +1,39 @@ + + + + {#snippet children({ checked, indeterminate })} +
+ {#if checked} + + {:else if indeterminate} + + {/if} +
+ {/snippet} +
diff --git a/apps/web/src/lib/components/ui/checkbox/index.ts b/apps/web/src/lib/components/ui/checkbox/index.ts new file mode 100644 index 00000000..5c276719 --- /dev/null +++ b/apps/web/src/lib/components/ui/checkbox/index.ts @@ -0,0 +1,6 @@ +import Root from './checkbox.svelte'; +export { + Root, + // + Root as Checkbox +}; diff --git a/apps/web/src/lib/components/ui/select/index.ts b/apps/web/src/lib/components/ui/select/index.ts new file mode 100644 index 00000000..23ba7ded --- /dev/null +++ b/apps/web/src/lib/components/ui/select/index.ts @@ -0,0 +1,37 @@ +import Content from './select-content.svelte'; +import GroupHeading from './select-group-heading.svelte'; +import Group from './select-group.svelte'; +import Item from './select-item.svelte'; +import Label from './select-label.svelte'; +import Portal from './select-portal.svelte'; +import ScrollDownButton from './select-scroll-down-button.svelte'; +import ScrollUpButton from './select-scroll-up-button.svelte'; +import Separator from './select-separator.svelte'; +import Trigger from './select-trigger.svelte'; +import Root from './select.svelte'; + +export { + Root, + Group, + Label, + Item, + Content, + Trigger, + Separator, + ScrollDownButton, + ScrollUpButton, + GroupHeading, + Portal, + // + Root as Select, + Group as SelectGroup, + Label as SelectLabel, + Item as SelectItem, + Content as SelectContent, + Trigger as SelectTrigger, + Separator as SelectSeparator, + ScrollDownButton as SelectScrollDownButton, + ScrollUpButton as SelectScrollUpButton, + GroupHeading as SelectGroupHeading, + Portal as SelectPortal +}; diff --git a/apps/web/src/lib/components/ui/select/select-content.svelte b/apps/web/src/lib/components/ui/select/select-content.svelte new file mode 100644 index 00000000..c63791ca --- /dev/null +++ b/apps/web/src/lib/components/ui/select/select-content.svelte @@ -0,0 +1,45 @@ + + + + + + + {@render children?.()} + + + + diff --git a/apps/web/src/lib/components/ui/select/select-group-heading.svelte b/apps/web/src/lib/components/ui/select/select-group-heading.svelte new file mode 100644 index 00000000..3ff70030 --- /dev/null +++ b/apps/web/src/lib/components/ui/select/select-group-heading.svelte @@ -0,0 +1,21 @@ + + + + {@render children?.()} + diff --git a/apps/web/src/lib/components/ui/select/select-group.svelte b/apps/web/src/lib/components/ui/select/select-group.svelte new file mode 100644 index 00000000..553f7e70 --- /dev/null +++ b/apps/web/src/lib/components/ui/select/select-group.svelte @@ -0,0 +1,17 @@ + + + diff --git a/apps/web/src/lib/components/ui/select/select-item.svelte b/apps/web/src/lib/components/ui/select/select-item.svelte new file mode 100644 index 00000000..f9f9f946 --- /dev/null +++ b/apps/web/src/lib/components/ui/select/select-item.svelte @@ -0,0 +1,40 @@ + + + + {#snippet children({ selected, highlighted })} + + {#if selected} + + {/if} + + + {#if childrenProp} + {@render childrenProp({ selected, highlighted })} + {:else} + {label || value} + {/if} + + {/snippet} + diff --git a/apps/web/src/lib/components/ui/select/select-label.svelte b/apps/web/src/lib/components/ui/select/select-label.svelte new file mode 100644 index 00000000..6c76ced6 --- /dev/null +++ b/apps/web/src/lib/components/ui/select/select-label.svelte @@ -0,0 +1,20 @@ + + +
+ {@render children?.()} +
diff --git a/apps/web/src/lib/components/ui/select/select-portal.svelte b/apps/web/src/lib/components/ui/select/select-portal.svelte new file mode 100644 index 00000000..59c4b78e --- /dev/null +++ b/apps/web/src/lib/components/ui/select/select-portal.svelte @@ -0,0 +1,7 @@ + + + diff --git a/apps/web/src/lib/components/ui/select/select-scroll-down-button.svelte b/apps/web/src/lib/components/ui/select/select-scroll-down-button.svelte new file mode 100644 index 00000000..7edad9a9 --- /dev/null +++ b/apps/web/src/lib/components/ui/select/select-scroll-down-button.svelte @@ -0,0 +1,23 @@ + + + + + diff --git a/apps/web/src/lib/components/ui/select/select-scroll-up-button.svelte b/apps/web/src/lib/components/ui/select/select-scroll-up-button.svelte new file mode 100644 index 00000000..324fb795 --- /dev/null +++ b/apps/web/src/lib/components/ui/select/select-scroll-up-button.svelte @@ -0,0 +1,23 @@ + + + + + diff --git a/apps/web/src/lib/components/ui/select/select-separator.svelte b/apps/web/src/lib/components/ui/select/select-separator.svelte new file mode 100644 index 00000000..c508e26a --- /dev/null +++ b/apps/web/src/lib/components/ui/select/select-separator.svelte @@ -0,0 +1,18 @@ + + + diff --git a/apps/web/src/lib/components/ui/select/select-trigger.svelte b/apps/web/src/lib/components/ui/select/select-trigger.svelte new file mode 100644 index 00000000..28fb7c1a --- /dev/null +++ b/apps/web/src/lib/components/ui/select/select-trigger.svelte @@ -0,0 +1,29 @@ + + + + {@render children?.()} + + diff --git a/apps/web/src/lib/components/ui/select/select.svelte b/apps/web/src/lib/components/ui/select/select.svelte new file mode 100644 index 00000000..b9bf9ba5 --- /dev/null +++ b/apps/web/src/lib/components/ui/select/select.svelte @@ -0,0 +1,11 @@ + + + diff --git a/apps/web/src/lib/components/ui/separator/index.ts b/apps/web/src/lib/components/ui/separator/index.ts new file mode 100644 index 00000000..768efac9 --- /dev/null +++ b/apps/web/src/lib/components/ui/separator/index.ts @@ -0,0 +1,7 @@ +import Root from './separator.svelte'; + +export { + Root, + // + Root as Separator +}; diff --git a/apps/web/src/lib/components/ui/separator/separator.svelte b/apps/web/src/lib/components/ui/separator/separator.svelte new file mode 100644 index 00000000..37da5e55 --- /dev/null +++ b/apps/web/src/lib/components/ui/separator/separator.svelte @@ -0,0 +1,23 @@ + + + diff --git a/apps/web/src/lib/components/ui/skeleton/index.ts b/apps/web/src/lib/components/ui/skeleton/index.ts new file mode 100644 index 00000000..3120ce12 --- /dev/null +++ b/apps/web/src/lib/components/ui/skeleton/index.ts @@ -0,0 +1,7 @@ +import Root from './skeleton.svelte'; + +export { + Root, + // + Root as Skeleton +}; diff --git a/apps/web/src/lib/components/ui/skeleton/skeleton.svelte b/apps/web/src/lib/components/ui/skeleton/skeleton.svelte new file mode 100644 index 00000000..3a28b0c2 --- /dev/null +++ b/apps/web/src/lib/components/ui/skeleton/skeleton.svelte @@ -0,0 +1,17 @@ + + +
diff --git a/apps/web/src/lib/components/ui/table/index.ts b/apps/web/src/lib/components/ui/table/index.ts new file mode 100644 index 00000000..553b6b44 --- /dev/null +++ b/apps/web/src/lib/components/ui/table/index.ts @@ -0,0 +1,28 @@ +import Body from './table-body.svelte'; +import Caption from './table-caption.svelte'; +import Cell from './table-cell.svelte'; +import Footer from './table-footer.svelte'; +import Head from './table-head.svelte'; +import Header from './table-header.svelte'; +import Row from './table-row.svelte'; +import Root from './table.svelte'; + +export { + Root, + Body, + Caption, + Cell, + Footer, + Head, + Header, + Row, + // + Root as Table, + Body as TableBody, + Caption as TableCaption, + Cell as TableCell, + Footer as TableFooter, + Head as TableHead, + Header as TableHeader, + Row as TableRow +}; diff --git a/apps/web/src/lib/components/ui/table/table-body.svelte b/apps/web/src/lib/components/ui/table/table-body.svelte new file mode 100644 index 00000000..cf720f47 --- /dev/null +++ b/apps/web/src/lib/components/ui/table/table-body.svelte @@ -0,0 +1,20 @@ + + + + {@render children?.()} + diff --git a/apps/web/src/lib/components/ui/table/table-caption.svelte b/apps/web/src/lib/components/ui/table/table-caption.svelte new file mode 100644 index 00000000..61ac4153 --- /dev/null +++ b/apps/web/src/lib/components/ui/table/table-caption.svelte @@ -0,0 +1,20 @@ + + + + {@render children?.()} + diff --git a/apps/web/src/lib/components/ui/table/table-cell.svelte b/apps/web/src/lib/components/ui/table/table-cell.svelte new file mode 100644 index 00000000..1fb325bb --- /dev/null +++ b/apps/web/src/lib/components/ui/table/table-cell.svelte @@ -0,0 +1,20 @@ + + + + {@render children?.()} + diff --git a/apps/web/src/lib/components/ui/table/table-footer.svelte b/apps/web/src/lib/components/ui/table/table-footer.svelte new file mode 100644 index 00000000..53a9eb45 --- /dev/null +++ b/apps/web/src/lib/components/ui/table/table-footer.svelte @@ -0,0 +1,20 @@ + + +tr]:last:border-b-0', className)} + {...restProps} +> + {@render children?.()} + diff --git a/apps/web/src/lib/components/ui/table/table-head.svelte b/apps/web/src/lib/components/ui/table/table-head.svelte new file mode 100644 index 00000000..1ef7f1d9 --- /dev/null +++ b/apps/web/src/lib/components/ui/table/table-head.svelte @@ -0,0 +1,23 @@ + + + + {@render children?.()} + diff --git a/apps/web/src/lib/components/ui/table/table-header.svelte b/apps/web/src/lib/components/ui/table/table-header.svelte new file mode 100644 index 00000000..615b5d8e --- /dev/null +++ b/apps/web/src/lib/components/ui/table/table-header.svelte @@ -0,0 +1,20 @@ + + + + {@render children?.()} + diff --git a/apps/web/src/lib/components/ui/table/table-row.svelte b/apps/web/src/lib/components/ui/table/table-row.svelte new file mode 100644 index 00000000..d0d5fed1 --- /dev/null +++ b/apps/web/src/lib/components/ui/table/table-row.svelte @@ -0,0 +1,23 @@ + + + + {@render children?.()} + diff --git a/apps/web/src/lib/components/ui/table/table.svelte b/apps/web/src/lib/components/ui/table/table.svelte new file mode 100644 index 00000000..a5acd8f2 --- /dev/null +++ b/apps/web/src/lib/components/ui/table/table.svelte @@ -0,0 +1,22 @@ + + +
+ + {@render children?.()} +
+
diff --git a/apps/web/src/lib/components/ui/tabs/index.ts b/apps/web/src/lib/components/ui/tabs/index.ts new file mode 100644 index 00000000..c5a15a0b --- /dev/null +++ b/apps/web/src/lib/components/ui/tabs/index.ts @@ -0,0 +1,18 @@ +import Content from './tabs-content.svelte'; +import Trigger from './tabs-trigger.svelte'; +import Root from './tabs.svelte'; +import List, { tabsListVariants, type TabsListVariant } from './tabs-list.svelte'; + +export { + Root, + Content, + List, + Trigger, + tabsListVariants, + type TabsListVariant, + // + Root as Tabs, + Content as TabsContent, + List as TabsList, + Trigger as TabsTrigger +}; diff --git a/apps/web/src/lib/components/ui/tabs/tabs-content.svelte b/apps/web/src/lib/components/ui/tabs/tabs-content.svelte new file mode 100644 index 00000000..2f30880d --- /dev/null +++ b/apps/web/src/lib/components/ui/tabs/tabs-content.svelte @@ -0,0 +1,17 @@ + + + diff --git a/apps/web/src/lib/components/ui/tabs/tabs-list.svelte b/apps/web/src/lib/components/ui/tabs/tabs-list.svelte new file mode 100644 index 00000000..b98149d7 --- /dev/null +++ b/apps/web/src/lib/components/ui/tabs/tabs-list.svelte @@ -0,0 +1,40 @@ + + + + + diff --git a/apps/web/src/lib/components/ui/tabs/tabs-trigger.svelte b/apps/web/src/lib/components/ui/tabs/tabs-trigger.svelte new file mode 100644 index 00000000..dabe8df4 --- /dev/null +++ b/apps/web/src/lib/components/ui/tabs/tabs-trigger.svelte @@ -0,0 +1,23 @@ + + + diff --git a/apps/web/src/lib/components/ui/tabs/tabs.svelte b/apps/web/src/lib/components/ui/tabs/tabs.svelte new file mode 100644 index 00000000..9a9b0ce9 --- /dev/null +++ b/apps/web/src/lib/components/ui/tabs/tabs.svelte @@ -0,0 +1,19 @@ + + + diff --git a/apps/web/src/lib/components/ui/tooltip/index.ts b/apps/web/src/lib/components/ui/tooltip/index.ts new file mode 100644 index 00000000..b98d5771 --- /dev/null +++ b/apps/web/src/lib/components/ui/tooltip/index.ts @@ -0,0 +1,19 @@ +import Content from './tooltip-content.svelte'; +import Portal from './tooltip-portal.svelte'; +import Provider from './tooltip-provider.svelte'; +import Trigger from './tooltip-trigger.svelte'; +import Root from './tooltip.svelte'; + +export { + Root, + Trigger, + Content, + Provider, + Portal, + // + Root as Tooltip, + Content as TooltipContent, + Trigger as TooltipTrigger, + Provider as TooltipProvider, + Portal as TooltipPortal +}; diff --git a/apps/web/src/lib/components/ui/tooltip/tooltip-content.svelte b/apps/web/src/lib/components/ui/tooltip/tooltip-content.svelte new file mode 100644 index 00000000..9e5d0774 --- /dev/null +++ b/apps/web/src/lib/components/ui/tooltip/tooltip-content.svelte @@ -0,0 +1,52 @@ + + + + + {@render children?.()} + + {#snippet child({ props })} +
+ {/snippet} +
+
+
diff --git a/apps/web/src/lib/components/ui/tooltip/tooltip-portal.svelte b/apps/web/src/lib/components/ui/tooltip/tooltip-portal.svelte new file mode 100644 index 00000000..7d328f01 --- /dev/null +++ b/apps/web/src/lib/components/ui/tooltip/tooltip-portal.svelte @@ -0,0 +1,7 @@ + + + diff --git a/apps/web/src/lib/components/ui/tooltip/tooltip-provider.svelte b/apps/web/src/lib/components/ui/tooltip/tooltip-provider.svelte new file mode 100644 index 00000000..fde5bb28 --- /dev/null +++ b/apps/web/src/lib/components/ui/tooltip/tooltip-provider.svelte @@ -0,0 +1,7 @@ + + + diff --git a/apps/web/src/lib/components/ui/tooltip/tooltip-trigger.svelte b/apps/web/src/lib/components/ui/tooltip/tooltip-trigger.svelte new file mode 100644 index 00000000..0f041627 --- /dev/null +++ b/apps/web/src/lib/components/ui/tooltip/tooltip-trigger.svelte @@ -0,0 +1,7 @@ + + + diff --git a/apps/web/src/lib/components/ui/tooltip/tooltip.svelte b/apps/web/src/lib/components/ui/tooltip/tooltip.svelte new file mode 100644 index 00000000..16eeb706 --- /dev/null +++ b/apps/web/src/lib/components/ui/tooltip/tooltip.svelte @@ -0,0 +1,7 @@ + + + diff --git a/apps/web/src/lib/utils.ts b/apps/web/src/lib/utils.ts new file mode 100644 index 00000000..f92bfcbb --- /dev/null +++ b/apps/web/src/lib/utils.ts @@ -0,0 +1,13 @@ +import { clsx, type ClassValue } from 'clsx'; +import { twMerge } from 'tailwind-merge'; + +export function cn(...inputs: ClassValue[]) { + return twMerge(clsx(inputs)); +} + +// eslint-disable-next-line @typescript-eslint/no-explicit-any +export type WithoutChild = T extends { child?: any } ? Omit : T; +// eslint-disable-next-line @typescript-eslint/no-explicit-any +export type WithoutChildren = T extends { children?: any } ? Omit : T; +export type WithoutChildrenOrChild = WithoutChildren>; +export type WithElementRef = T & { ref?: U | null }; diff --git a/bun.lock b/bun.lock index d257fb6b..7d37ac74 100644 --- a/bun.lock +++ b/bun.lock @@ -31,7 +31,7 @@ "name": "@atlantis/web", "version": "0.0.1", "dependencies": { - "@lucide/svelte": "^0.511.0", + "@lucide/svelte": "^1.33.0", "better-sqlite3": "^12.6.2", "chart.js": "^4.4.9", "chartjs-plugin-annotation": "^3.1.0", @@ -43,6 +43,7 @@ "@cloudflare/workers-types": "^4.20260511.1", "@eslint/compat": "^1.2.5", "@eslint/js": "^9.18.0", + "@internationalized/date": "^3.12.0", "@playwright/test": "1.52.0", "@sveltejs/adapter-cloudflare": "^7.2.8", "@sveltejs/kit": "^2.16.0", @@ -50,6 +51,8 @@ "@tailwindcss/vite": "^4.0.0", "@types/better-sqlite3": "^7.6.13", "@types/node": "^22.15.17", + "bits-ui": "^2.16.3", + "clsx": "^2.1.1", "eslint": "^9.18.0", "eslint-config-prettier": "^10.0.1", "eslint-plugin-svelte": "^3.0.0", @@ -57,9 +60,13 @@ "prettier": "^3.8.1", "prettier-plugin-svelte": "^3.5.1", "prettier-plugin-tailwindcss": "^0.7.2", + "shadcn-svelte": "^1.5.0", "svelte": "^5.0.0", "svelte-check": "^4.0.0", + "tailwind-merge": "^3.6.0", + "tailwind-variants": "^3.3.1", "tailwindcss": "^4.0.0", + "tw-animate-css": "^1.4.0", "typescript": "^5.0.0", "typescript-eslint": "^8.20.0", "vite": "^6.2.6", @@ -197,6 +204,12 @@ "@eslint/plugin-kit": ["@eslint/plugin-kit@0.6.1", "", { "dependencies": { "@eslint/core": "^1.1.1", "levn": "^0.4.1" } }, "sha512-iH1B076HoAshH1mLpHMgwdGeTs0CYwL0SPMkGuSebZrwBp16v415e9NZXg2jtrqPVQjf6IANe2Vtlr5KswtcZQ=="], + "@floating-ui/core": ["@floating-ui/core@1.8.0", "", { "dependencies": { "@floating-ui/utils": "^0.2.12" } }, "sha512-0CIZ5itps/8x7BG8dEIhs53BvCUH2PCoogtakwRTut+Arm58sJooJ0AuZhLw2HJYIR5cMLNPBSS728sPho2khQ=="], + + "@floating-ui/dom": ["@floating-ui/dom@1.8.0", "", { "dependencies": { "@floating-ui/core": "^1.8.0", "@floating-ui/utils": "^0.2.12" } }, "sha512-yXSrzeHZBTZadLOlfyhCkJHNeLJnHRnRInwdZ40L7ZiaAtrBwoYlsDrX3v5zB1Utk7CLfzcOVnVVWoXEky7Ceg=="], + + "@floating-ui/utils": ["@floating-ui/utils@0.2.12", "", {}, "sha512-HpCo8tmWzLVad5s2d19EhAz5zqrrQ6s69qd6moPMQvkOuSwDT1YgRfWSVuc4ennqrgv3OHppiOGMQ7oC13yIww=="], + "@gar/promisify": ["@gar/promisify@1.1.3", "", {}, "sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw=="], "@humanfs/core": ["@humanfs/core@0.19.1", "", {}, "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA=="], @@ -257,6 +270,8 @@ "@img/sharp-win32-x64": ["@img/sharp-win32-x64@0.34.5", "", { "os": "win32", "cpu": "x64" }, "sha512-+29YMsqY2/9eFEiW93eqWnuLcWcufowXewwSNIT6UwZdUUCrM3oFjMWH/Z6/TMmb4hlFenmfAVbpWeup2jryCw=="], + "@internationalized/date": ["@internationalized/date@3.12.3", "", { "dependencies": { "@swc/helpers": "^0.5.0" } }, "sha512-fuLX+3ZKLsxI73y8b01EG/WjHb6gE6weCqlfawPO27kBWGMh9G1yH6Csv1uU7/cac9H2GHmOMt6CjmuQ1aia4Q=="], + "@jridgewell/gen-mapping": ["@jridgewell/gen-mapping@0.3.13", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.0", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA=="], "@jridgewell/remapping": ["@jridgewell/remapping@2.3.5", "", { "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ=="], @@ -269,7 +284,7 @@ "@kurkle/color": ["@kurkle/color@0.3.4", "", {}, "sha512-M5UknZPHRu3DEDWoipU6sE8PdkZ6Z/S+v4dD+Ke8IaNlpdSQah50lz1KtcFBa2vsdOnwbbnxJwVM4wty6udA5w=="], - "@lucide/svelte": ["@lucide/svelte@0.511.0", "", { "peerDependencies": { "svelte": "^5" } }, "sha512-aLCSPMUJmHlCuLXzXENXa4Z1NV2mN1iAZAFKk4bEbey+/MdsNlu+/DqwVkgW3Yvj6p8y8Vn5xZ2v9CLmPlA6Vw=="], + "@lucide/svelte": ["@lucide/svelte@1.33.0", "", { "peerDependencies": { "svelte": "^5" } }, "sha512-b+osTYG2V4dge5Lr7tnaTaahhy/4vH7Xb8zcqVjmctjwgkpXS0NNOJPkGzHHZoxtw/OO+2YAU28omeMfYCaawg=="], "@nodelib/fs.scandir": ["@nodelib/fs.scandir@2.1.5", "", { "dependencies": { "@nodelib/fs.stat": "2.0.5", "run-parallel": "^1.1.9" } }, "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g=="], @@ -379,6 +394,8 @@ "@sveltejs/vite-plugin-svelte-inspector": ["@sveltejs/vite-plugin-svelte-inspector@4.0.1", "", { "dependencies": { "debug": "^4.3.7" }, "peerDependencies": { "@sveltejs/vite-plugin-svelte": "^5.0.0", "svelte": "^5.0.0", "vite": "^6.0.0" } }, "sha512-J/Nmb2Q2y7mck2hyCX4ckVHcR5tu2J+MtBEQqpDrrgELZ2uvraQcK/ioCV61AqkdXFgriksOKIceDcQmqnGhVw=="], + "@swc/helpers": ["@swc/helpers@0.5.23", "", { "dependencies": { "tslib": "^2.8.0" } }, "sha512-5lSsMOTXURePglDfvuAQUqkGek9Hg2kksOYay2m0+XR++b2NWYL/4sWyuvVBIs8oKnJaxkdi9whaL/sqN13afw=="], + "@tailwindcss/node": ["@tailwindcss/node@4.2.2", "", { "dependencies": { "@jridgewell/remapping": "^2.3.5", "enhanced-resolve": "^5.19.0", "jiti": "^2.6.1", "lightningcss": "1.32.0", "magic-string": "^0.30.21", "source-map-js": "^1.2.1", "tailwindcss": "4.2.2" } }, "sha512-pXS+wJ2gZpVXqFaUEjojq7jzMpTGf8rU6ipJz5ovJV6PUGmlJ+jvIwGrzdHdQ80Sg+wmQxUFuoW1UAAwHNEdFA=="], "@tailwindcss/oxide": ["@tailwindcss/oxide@4.2.2", "", { "optionalDependencies": { "@tailwindcss/oxide-android-arm64": "4.2.2", "@tailwindcss/oxide-darwin-arm64": "4.2.2", "@tailwindcss/oxide-darwin-x64": "4.2.2", "@tailwindcss/oxide-freebsd-x64": "4.2.2", "@tailwindcss/oxide-linux-arm-gnueabihf": "4.2.2", "@tailwindcss/oxide-linux-arm64-gnu": "4.2.2", "@tailwindcss/oxide-linux-arm64-musl": "4.2.2", "@tailwindcss/oxide-linux-x64-gnu": "4.2.2", "@tailwindcss/oxide-linux-x64-musl": "4.2.2", "@tailwindcss/oxide-wasm32-wasi": "4.2.2", "@tailwindcss/oxide-win32-arm64-msvc": "4.2.2", "@tailwindcss/oxide-win32-x64-msvc": "4.2.2" } }, "sha512-qEUA07+E5kehxYp9BVMpq9E8vnJuBHfJEC0vPC5e7iL/hw7HR61aDKoVoKzrG+QKp56vhNZe4qwkRmMC0zDLvg=="], @@ -531,6 +548,8 @@ "bindings": ["bindings@1.5.0", "", { "dependencies": { "file-uri-to-path": "1.0.0" } }, "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ=="], + "bits-ui": ["bits-ui@2.19.0", "", { "dependencies": { "@floating-ui/core": "^1.7.1", "@floating-ui/dom": "^1.7.1", "esm-env": "^1.1.2", "runed": "^0.35.1", "svelte-toolbelt": "^0.10.6", "tabbable": "^6.2.0" }, "peerDependencies": { "@internationalized/date": "^3.8.1", "svelte": "^5.33.0" } }, "sha512-dHDm5Jw2NZJgLRvHAwPeuR4BnZij+AqTIq33OqVfo+qiMXontoC/yIvGT5TZaviv7OuBdJ2QUy2JPQ2yKBvF6w=="], + "bl": ["bl@4.1.0", "", { "dependencies": { "buffer": "^5.5.0", "inherits": "^2.0.4", "readable-stream": "^3.4.0" } }, "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w=="], "blake3-wasm": ["blake3-wasm@2.1.5", "", {}, "sha512-F1+K8EbfOZE49dtoPtmxUQrpXaBIl3ICvasLh+nJta0xkz+9kF/7uet9fLnwKqhDrmj6g+6K3Tw9yQPUg2ka5g=="], @@ -591,7 +610,7 @@ "comma-separated-tokens": ["comma-separated-tokens@2.0.3", "", {}, "sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg=="], - "commander": ["commander@11.1.0", "", {}, "sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ=="], + "commander": ["commander@14.0.3", "", {}, "sha512-H+y0Jo/T1RZ9qPP4Eh1pkcQcLRglraJaSLoyOtHxu6AapkjWVCy2Sit1QQ4x3Dng8qDlSsZEet7g5Pq06MvTgw=="], "common-ancestor-path": ["common-ancestor-path@2.0.0", "", {}, "sha512-dnN3ibLeoRf2HNC+OlCiNc5d2zxbLJXOtiZUudNFSXZrNSydxcCsSpRzXwfu7BBWCIfHPw+xTayeBvJCP/D8Ng=="], @@ -849,6 +868,8 @@ "ini": ["ini@1.3.8", "", {}, "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew=="], + "inline-style-parser": ["inline-style-parser@0.2.7", "", {}, "sha512-Nb2ctOyNR8DqQoR0OwRG95uNWIC0C1lCgf5Naz5H6Ji72KZ8OcFZLz2P5sNgwlyoJ8Yif11oMuYs5pBQa86csA=="], + "ip-address": ["ip-address@10.1.0", "", {}, "sha512-XXADHxXmvT9+CRxhXg56LJovE+bmWnEWB78LB83VZTprKTmaC5QfruXocxzTZ2Kl0DNwKuBdlIhjL8LeY8Sf8Q=="], "iron-webcrypto": ["iron-webcrypto@1.2.1", "", {}, "sha512-feOM6FaSr6rEABp/eDfVseKyTMDt+KGpeB35SkVn9Tyn0CqvVsY3EwI0v5i8nMHyJnzCIQf7nsy3p41TPkJZhg=="], @@ -1263,6 +1284,8 @@ "set-cookie-parser": ["set-cookie-parser@3.1.0", "", {}, "sha512-kjnC1DXBHcxaOaOXBHBeRtltsDG2nUiUni+jP92M9gYdW12rsmx92UsfpH7o5tDRs7I1ZZPSQJQGv3UaRfCiuw=="], + "shadcn-svelte": ["shadcn-svelte@1.5.0", "", { "dependencies": { "commander": "^14.0.0", "node-fetch-native": "^1.6.4", "postcss": "^8.5.10", "tailwind-merge": "^3.6.0" }, "peerDependencies": { "svelte": "^5.0.0" }, "bin": { "shadcn-svelte": "dist/index.mjs" } }, "sha512-fcxTeUwEIvELkL/h0Vg2i/9Sf6exAmLG5u3GXc0aN8CA+3fNffKQnfrTdMgkjUEmx9XP619I+wcJOvlr5aDWYQ=="], + "sharp": ["sharp@0.34.5", "", { "dependencies": { "@img/colour": "^1.0.0", "detect-libc": "^2.1.2", "semver": "^7.7.3" }, "optionalDependencies": { "@img/sharp-darwin-arm64": "0.34.5", "@img/sharp-darwin-x64": "0.34.5", "@img/sharp-libvips-darwin-arm64": "1.2.4", "@img/sharp-libvips-darwin-x64": "1.2.4", "@img/sharp-libvips-linux-arm": "1.2.4", "@img/sharp-libvips-linux-arm64": "1.2.4", "@img/sharp-libvips-linux-ppc64": "1.2.4", "@img/sharp-libvips-linux-riscv64": "1.2.4", "@img/sharp-libvips-linux-s390x": "1.2.4", "@img/sharp-libvips-linux-x64": "1.2.4", "@img/sharp-libvips-linuxmusl-arm64": "1.2.4", "@img/sharp-libvips-linuxmusl-x64": "1.2.4", "@img/sharp-linux-arm": "0.34.5", "@img/sharp-linux-arm64": "0.34.5", "@img/sharp-linux-ppc64": "0.34.5", "@img/sharp-linux-riscv64": "0.34.5", "@img/sharp-linux-s390x": "0.34.5", "@img/sharp-linux-x64": "0.34.5", "@img/sharp-linuxmusl-arm64": "0.34.5", "@img/sharp-linuxmusl-x64": "0.34.5", "@img/sharp-wasm32": "0.34.5", "@img/sharp-win32-arm64": "0.34.5", "@img/sharp-win32-ia32": "0.34.5", "@img/sharp-win32-x64": "0.34.5" } }, "sha512-Ou9I5Ft9WNcCbXrU9cMgPBcCK8LiwLqcbywW3t4oDV37n1pzpuNLsYiAV8eODnjbtQlSDwZ2cUEeQz4E54Hltg=="], "shebang-command": ["shebang-command@2.0.0", "", { "dependencies": { "shebang-regex": "^3.0.0" } }, "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA=="], @@ -1325,6 +1348,8 @@ "strip-literal": ["strip-literal@3.1.0", "", { "dependencies": { "js-tokens": "^9.0.1" } }, "sha512-8r3mkIM/2+PpjHoOtiAW8Rg3jJLHaV7xPwG+YRGrv6FP0wwk/toTpATxWYOW0BKdWwl82VT2tFYi5DlROa0Mxg=="], + "style-to-object": ["style-to-object@1.0.14", "", { "dependencies": { "inline-style-parser": "0.2.7" } }, "sha512-LIN7rULI0jBscWQYaSswptyderlarFkjQ+t79nzty8tcIAceVomEVlLzH5VP4Cmsv6MtKhs7qaAiwlcp+Mgaxw=="], + "suf-log": ["suf-log@2.5.3", "", { "dependencies": { "s.color": "0.0.15" } }, "sha512-KvC8OPjzdNOe+xQ4XWJV2whQA0aM1kGVczMQ8+dStAO6KfEB140JEVQ9dE76ONZ0/Ylf67ni4tILPJB41U0eow=="], "supports-color": ["supports-color@8.1.1", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q=="], @@ -1335,10 +1360,18 @@ "svelte-eslint-parser": ["svelte-eslint-parser@1.6.0", "", { "dependencies": { "eslint-scope": "^8.2.0", "eslint-visitor-keys": "^4.0.0", "espree": "^10.0.0", "postcss": "^8.4.49", "postcss-scss": "^4.0.9", "postcss-selector-parser": "^7.0.0", "semver": "^7.7.2" }, "peerDependencies": { "svelte": "^3.37.0 || ^4.0.0 || ^5.0.0" }, "optionalPeers": ["svelte"] }, "sha512-qoB1ehychT6OxEtQAqc/guSqLS20SlA53Uijl7x375s8nlUT0lb9ol/gzraEEatQwsyPTJo87s2CmKL9Xab+Uw=="], + "svelte-toolbelt": ["svelte-toolbelt@0.10.6", "", { "dependencies": { "clsx": "^2.1.1", "runed": "^0.35.1", "style-to-object": "^1.0.8" }, "peerDependencies": { "svelte": "^5.30.2" } }, "sha512-YWuX+RE+CnWYx09yseAe4ZVMM7e7GRFZM6OYWpBKOb++s+SQ8RBIMMe+Bs/CznBMc0QPLjr+vDBxTAkozXsFXQ=="], + "svgo": ["svgo@4.0.1", "", { "dependencies": { "commander": "^11.1.0", "css-select": "^5.1.0", "css-tree": "^3.0.1", "css-what": "^6.1.0", "csso": "^5.0.5", "picocolors": "^1.1.1", "sax": "^1.5.0" }, "bin": "./bin/svgo.js" }, "sha512-XDpWUOPC6FEibaLzjfe0ucaV0YrOjYotGJO1WpF0Zd+n6ZGEQUsSugaoLq9QkEZtAfQIxT42UChcssDVPP3+/w=="], "synckit": ["synckit@0.11.12", "", { "dependencies": { "@pkgr/core": "^0.2.9" } }, "sha512-Bh7QjT8/SuKUIfObSXNHNSK6WHo6J1tHCqJsuaFDP7gP0fkzSfTxI8y85JrppZ0h8l0maIgc2tfuZQ6/t3GtnQ=="], + "tabbable": ["tabbable@6.5.0", "", {}, "sha512-wieBHXygIm7OyQOu5hQlkk62/WyCFYGlWg7L6/ZCUZwx0o398Zkn4pVmMyfYhfMG8kGrj/Krt8eIk6UKC6VzwA=="], + + "tailwind-merge": ["tailwind-merge@3.6.0", "", {}, "sha512-uxL7qAVQriqRQPAyK3pj66VqskWqoZ37PW94jwOTwNfq/z9oyu1V+eqrZqtR2+fCiXdYOZe/Modt8GtvqNzu+w=="], + + "tailwind-variants": ["tailwind-variants@3.3.1", "", { "peerDependencies": { "tailwind-merge": ">=3.0.0", "tailwindcss": "*" }, "optionalPeers": ["tailwind-merge", "tailwindcss"] }, "sha512-4pAvwUtM4HKBiRZftncAbpn6V9Hhwoa5Fl7O2u5zbp7Z5Cvu+/o/6+176WY3WCEES209543quG8zFIcXCsc5Jw=="], + "tailwindcss": ["tailwindcss@4.2.2", "", {}, "sha512-KWBIxs1Xb6NoLdMVqhbhgwZf2PGBpPEiwOqgI4pFIYbNTfBXiKYyWoTsXgBQ9WFg/OlhnvHaY+AEpW7wSmFo2Q=="], "tapable": ["tapable@2.3.2", "", {}, "sha512-1MOpMXuhGzGL5TTCZFItxCc0AARf1EZFQkGqMm7ERKj8+Hgr5oLvJOVFcC+lRmR8hCe2S3jC4T5D7Vg/d7/fhA=="], @@ -1385,6 +1418,8 @@ "tunnel-agent": ["tunnel-agent@0.6.0", "", { "dependencies": { "safe-buffer": "^5.0.1" } }, "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w=="], + "tw-animate-css": ["tw-animate-css@1.4.0", "", {}, "sha512-7bziOlRqH0hJx80h/3mbicLW7o8qLsH5+RaLR2t+OHM3D0JlWGODQKQ4cxbK7WlvmUxpcj6Kgu6EKqjrGFe3QQ=="], + "type-check": ["type-check@0.4.0", "", { "dependencies": { "prelude-ls": "^1.2.1" } }, "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew=="], "typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="], @@ -1553,6 +1588,8 @@ "astro-eslint-parser/espree": ["espree@10.4.0", "", { "dependencies": { "acorn": "^8.15.0", "acorn-jsx": "^5.3.2", "eslint-visitor-keys": "^4.2.1" } }, "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ=="], + "bits-ui/runed": ["runed@0.35.1", "", { "dependencies": { "dequal": "^2.0.3", "esm-env": "^1.0.0", "lz-string": "^1.5.0" }, "peerDependencies": { "@sveltejs/kit": "^2.21.0", "svelte": "^5.7.0" }, "optionalPeers": ["@sveltejs/kit"] }, "sha512-2F4Q/FZzbeJTFdIS/PuOoPRSm92sA2LhzTnv6FXhCoENb3huf5+fDuNOg1LNvGOouy3u/225qxmuJvcV3IZK5Q=="], + "cacache/chownr": ["chownr@2.0.0", "", {}, "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ=="], "cacache/lru-cache": ["lru-cache@6.0.0", "", { "dependencies": { "yallist": "^4.0.0" } }, "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA=="], @@ -1599,6 +1636,8 @@ "rc/strip-json-comments": ["strip-json-comments@2.0.1", "", {}, "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ=="], + "shadcn-svelte/postcss": ["postcss@8.5.26", "", { "dependencies": { "nanoid": "^3.3.17", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, "sha512-u82N74LFzG8ca+dD8puPnplTXoGH4fTPpVGuIbt36G3qvNlkvfD0lEAZSxaly3KX8TS/L1A1gsCEmvKmBcVbkQ=="], + "sitemap/@types/node": ["@types/node@24.12.0", "", { "dependencies": { "undici-types": "~7.16.0" } }, "sha512-GYDxsZi3ChgmckRT9HPU0WEhKLP08ev/Yfcq2AstjrDASOYCSXeyjDsHg4v5t4jOj7cyDX3vmprafKlWIG9MXQ=="], "ssri/minipass": ["minipass@3.3.6", "", { "dependencies": { "yallist": "^4.0.0" } }, "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw=="], @@ -1611,6 +1650,10 @@ "svelte-eslint-parser/espree": ["espree@10.4.0", "", { "dependencies": { "acorn": "^8.15.0", "acorn-jsx": "^5.3.2", "eslint-visitor-keys": "^4.2.1" } }, "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ=="], + "svelte-toolbelt/runed": ["runed@0.35.1", "", { "dependencies": { "dequal": "^2.0.3", "esm-env": "^1.0.0", "lz-string": "^1.5.0" }, "peerDependencies": { "@sveltejs/kit": "^2.21.0", "svelte": "^5.7.0" }, "optionalPeers": ["@sveltejs/kit"] }, "sha512-2F4Q/FZzbeJTFdIS/PuOoPRSm92sA2LhzTnv6FXhCoENb3huf5+fDuNOg1LNvGOouy3u/225qxmuJvcV3IZK5Q=="], + + "svgo/commander": ["commander@11.1.0", "", {}, "sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ=="], + "tar/chownr": ["chownr@2.0.0", "", {}, "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ=="], "tsx/esbuild": ["esbuild@0.27.7", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.27.7", "@esbuild/android-arm": "0.27.7", "@esbuild/android-arm64": "0.27.7", "@esbuild/android-x64": "0.27.7", "@esbuild/darwin-arm64": "0.27.7", "@esbuild/darwin-x64": "0.27.7", "@esbuild/freebsd-arm64": "0.27.7", "@esbuild/freebsd-x64": "0.27.7", "@esbuild/linux-arm": "0.27.7", "@esbuild/linux-arm64": "0.27.7", "@esbuild/linux-ia32": "0.27.7", "@esbuild/linux-loong64": "0.27.7", "@esbuild/linux-mips64el": "0.27.7", "@esbuild/linux-ppc64": "0.27.7", "@esbuild/linux-riscv64": "0.27.7", "@esbuild/linux-s390x": "0.27.7", "@esbuild/linux-x64": "0.27.7", "@esbuild/netbsd-arm64": "0.27.7", "@esbuild/netbsd-x64": "0.27.7", "@esbuild/openbsd-arm64": "0.27.7", "@esbuild/openbsd-x64": "0.27.7", "@esbuild/openharmony-arm64": "0.27.7", "@esbuild/sunos-x64": "0.27.7", "@esbuild/win32-arm64": "0.27.7", "@esbuild/win32-ia32": "0.27.7", "@esbuild/win32-x64": "0.27.7" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-IxpibTjyVnmrIQo5aqNpCgoACA/dTKLTlhMHihVHhdkxKyPO1uBBthumT0rdHmcsk9uMonIWS0m4FljWzILh3w=="], @@ -1763,6 +1806,8 @@ "p-locate/p-limit/yocto-queue": ["yocto-queue@0.1.0", "", {}, "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q=="], + "shadcn-svelte/postcss/nanoid": ["nanoid@3.3.18", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-DTg4MJbGMWkfi6VZFdNt2/caMbQy4Ou+Op/hJQvGEWcnVfoA1QA+xzRKAzw9jD6+GVOOeYr/mIcuDSdug6F6+w=="], + "sitemap/@types/node/undici-types": ["undici-types@7.16.0", "", {}, "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw=="], "tsx/esbuild/@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.27.7", "", { "os": "aix", "cpu": "ppc64" }, "sha512-EKX3Qwmhz1eMdEJokhALr0YiD0lhQNwDqkPYyPhiSwKrh7/4KRjQc04sZ8db+5DVVnZ1LmbNDI1uAMPEUBnQPg=="], From 4e2c98f547bcf1a09648afa2f0e24f5604e4897e Mon Sep 17 00:00:00 2001 From: flamboh Date: Fri, 21 Aug 2026 14:55:41 -0700 Subject: [PATCH 2/7] refactor(web): adopt shadcn primitives and semantic tokens across dashboard --- .../components/common/SegmentedControl.svelte | 95 ++++++ .../components/datasets/DatasetTabs.svelte | 31 +- .../components/filters/DateRangeFilter.svelte | 6 +- .../components/filters/MetricSelector.svelte | 104 ++----- .../components/filters/PrimaryFilters.svelte | 139 ++++----- .../components/filters/RouterFilter.svelte | 21 +- .../netflow/DatasetDashboardPage.svelte | 4 +- .../netflow/NetflowDashboard.svelte | 33 +- .../netflow/NetflowFileAnalysisPane.svelte | 34 +-- .../netflow/NetflowFileHeader.svelte | 23 +- .../netflow/NetflowFileLoadingSkeleton.svelte | 77 ++--- .../netflow/NetflowFileMessageCard.svelte | 29 +- .../NetflowFileRouterAnalysisSection.svelte | 2 +- .../netflow/NetflowFileRouterCard.svelte | 19 +- .../netflow/NetflowFileRouterSummary.svelte | 23 +- apps/web/src/routes/+error.svelte | 34 +-- apps/web/src/routes/+layout.svelte | 30 +- apps/web/src/routes/+page.svelte | 60 ++-- .../datasets/[dataset]/alerts/+page.svelte | 281 ++++++++---------- .../web/src/routes/netflow/files/+page.svelte | 115 ++++--- 20 files changed, 559 insertions(+), 601 deletions(-) create mode 100644 apps/web/src/lib/components/common/SegmentedControl.svelte diff --git a/apps/web/src/lib/components/common/SegmentedControl.svelte b/apps/web/src/lib/components/common/SegmentedControl.svelte new file mode 100644 index 00000000..3147084f --- /dev/null +++ b/apps/web/src/lib/components/common/SegmentedControl.svelte @@ -0,0 +1,95 @@ + + + + +
+ {#each options as option (option.value)} + {#if option.disabledReason} + + + {#snippet child({ props })} + + {/snippet} + + {option.disabledReason} + + {:else} + + {/if} + {/each} +
diff --git a/apps/web/src/lib/components/datasets/DatasetTabs.svelte b/apps/web/src/lib/components/datasets/DatasetTabs.svelte index 4c84d4ef..b7bcfd80 100644 --- a/apps/web/src/lib/components/datasets/DatasetTabs.svelte +++ b/apps/web/src/lib/components/datasets/DatasetTabs.svelte @@ -1,30 +1,31 @@ -