From 4384315b44cee2fe50cb3cee99051c8c0c817d9f Mon Sep 17 00:00:00 2001 From: Benson Wong Date: Wed, 28 Jan 2026 21:37:29 -0800 Subject: [PATCH] ui-svelte: add Svelte port of React UI (#487) Trying out svelte for the UI. The port was done by Claude Code on the iOS app w/ Opus 4.5. --- * ui: add Svelte port of React UI Port the React-based UI to Svelte 5 with the following changes: - Create new ui-svelte directory with complete Svelte 5 implementation - Use Svelte stores instead of React contexts for state management - Implement custom ResizablePanels component to replace react-resizable-panels - Port all pages: LogViewer, Models, Activity - Port all components: Header, ConnectionStatus, LogPanel, ModelsPanel, etc. - Use svelte-spa-router for client-side routing - Same build output directory (proxy/ui_dist) and base path (/ui/) - Tailwind CSS 4 with same theme configuration https://claude.ai/code/session_01F3xXLYsd62gePVSFv7aboP * ui-svelte: simplify state management - Remove redundant state syncing pattern in LogPanel and ModelsPanel - Use store values directly with $ syntax instead of manual subscriptions - Consolidate duplicate title sync logic in App.svelte - Use existing syncTitleToDocument() from theme.ts https://claude.ai/code/session_01F3xXLYsd62gePVSFv7aboP * ui-svelte: use idiomatic Svelte 5 patterns - Use $effect for document side effects (theme, title) instead of store subscriptions - Use class: directive for active nav links in Header - Remove SSR guards (unnecessary for client-only SPA) - Remove leaked subscription in syncThemeToDocument - Simplify theme.ts by removing sync functions https://claude.ai/code/session_01F3xXLYsd62gePVSFv7aboP * ui-svelte: fix build warnings and improve accessibility Fix Svelte build warnings and add proper accessibility support to interactive components. - add aria-labels to buttons for screen readers - implement keyboard navigation for resizable separator - suppress intentional state initialization warnings - update Makefile to use ui-svelte build directory - add peer:true to package-lock.json dependencies * ui-svelte: reorganize navigation and add log view toggle Make Models the default landing page and add view mode toggle to the Logs page with persistent state. - set Models as default route at / - move Logs to /logs route - reorder navigation: Models, Activity, Logs - add view toggle with three modes: Panels, Proxy only, Upstream only - fix horizontal overflow with width constraints --- Makefile | 4 +- ui-svelte/.gitignore | 1 + ui-svelte/index.html | 17 + ui-svelte/package-lock.json | 2127 +++++++++++++++++ ui-svelte/package.json | 25 + ui-svelte/public/apple-touch-icon.png | Bin 0 -> 6076 bytes ui-svelte/public/favicon-96x96.png | Bin 0 -> 2260 bytes ui-svelte/public/favicon.ico | Bin 0 -> 15086 bytes ui-svelte/public/favicon.svg | 17 + ui-svelte/public/site.webmanifest | 21 + ui-svelte/public/web-app-manifest-192x192.png | Bin 0 -> 6659 bytes ui-svelte/public/web-app-manifest-512x512.png | Bin 0 -> 28231 bytes ui-svelte/src/App.svelte | 46 + ui-svelte/src/assets/logo.png | Bin 0 -> 12157 bytes ui-svelte/src/assets/react.svg | 1 + .../src/components/ConnectionStatus.svelte | 24 + ui-svelte/src/components/Header.svelte | 90 + ui-svelte/src/components/LogPanel.svelte | 132 + ui-svelte/src/components/ModelsPanel.svelte | 208 ++ .../src/components/ResizablePanels.svelte | 152 ++ ui-svelte/src/components/StatsPanel.svelte | 147 ++ .../src/components/TokenHistogram.svelte | 129 + ui-svelte/src/components/Tooltip.svelte | 20 + ui-svelte/src/index.css | 176 ++ ui-svelte/src/lib/types.ts | 42 + ui-svelte/src/main.ts | 9 + ui-svelte/src/routes/Activity.svelte | 88 + ui-svelte/src/routes/LogViewer.svelte | 75 + ui-svelte/src/routes/Models.svelte | 26 + ui-svelte/src/stores/api.ts | 174 ++ ui-svelte/src/stores/persistent.ts | 31 + ui-svelte/src/stores/theme.ts | 53 + ui-svelte/svelte.config.js | 5 + ui-svelte/tsconfig.json | 20 + ui-svelte/vite.config.ts | 21 + 35 files changed, 3879 insertions(+), 2 deletions(-) create mode 100644 ui-svelte/.gitignore create mode 100644 ui-svelte/index.html create mode 100644 ui-svelte/package-lock.json create mode 100644 ui-svelte/package.json create mode 100644 ui-svelte/public/apple-touch-icon.png create mode 100644 ui-svelte/public/favicon-96x96.png create mode 100644 ui-svelte/public/favicon.ico create mode 100644 ui-svelte/public/favicon.svg create mode 100644 ui-svelte/public/site.webmanifest create mode 100644 ui-svelte/public/web-app-manifest-192x192.png create mode 100644 ui-svelte/public/web-app-manifest-512x512.png create mode 100644 ui-svelte/src/App.svelte create mode 100644 ui-svelte/src/assets/logo.png create mode 100644 ui-svelte/src/assets/react.svg create mode 100644 ui-svelte/src/components/ConnectionStatus.svelte create mode 100644 ui-svelte/src/components/Header.svelte create mode 100644 ui-svelte/src/components/LogPanel.svelte create mode 100644 ui-svelte/src/components/ModelsPanel.svelte create mode 100644 ui-svelte/src/components/ResizablePanels.svelte create mode 100644 ui-svelte/src/components/StatsPanel.svelte create mode 100644 ui-svelte/src/components/TokenHistogram.svelte create mode 100644 ui-svelte/src/components/Tooltip.svelte create mode 100644 ui-svelte/src/index.css create mode 100644 ui-svelte/src/lib/types.ts create mode 100644 ui-svelte/src/main.ts create mode 100644 ui-svelte/src/routes/Activity.svelte create mode 100644 ui-svelte/src/routes/LogViewer.svelte create mode 100644 ui-svelte/src/routes/Models.svelte create mode 100644 ui-svelte/src/stores/api.ts create mode 100644 ui-svelte/src/stores/persistent.ts create mode 100644 ui-svelte/src/stores/theme.ts create mode 100644 ui-svelte/svelte.config.js create mode 100644 ui-svelte/tsconfig.json create mode 100644 ui-svelte/vite.config.ts diff --git a/Makefile b/Makefile index 4d584433..f7d18586 100644 --- a/Makefile +++ b/Makefile @@ -36,11 +36,11 @@ test-all: proxy/ui_dist/placeholder.txt go test -race -count=1 ./proxy/... ui/node_modules: - cd ui && npm install + cd ui-svelte && npm install # build react UI ui: ui/node_modules - cd ui && npm run build + cd ui-svelte && npm run build # Build OSX binary mac: ui diff --git a/ui-svelte/.gitignore b/ui-svelte/.gitignore new file mode 100644 index 00000000..3c3629e6 --- /dev/null +++ b/ui-svelte/.gitignore @@ -0,0 +1 @@ +node_modules diff --git a/ui-svelte/index.html b/ui-svelte/index.html new file mode 100644 index 00000000..a1e0a95c --- /dev/null +++ b/ui-svelte/index.html @@ -0,0 +1,17 @@ + + + + + + + + + + + llama-swap + + +
+ + + diff --git a/ui-svelte/package-lock.json b/ui-svelte/package-lock.json new file mode 100644 index 00000000..93150075 --- /dev/null +++ b/ui-svelte/package-lock.json @@ -0,0 +1,2127 @@ +{ + "name": "ui-svelte", + "version": "0.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "ui-svelte", + "version": "0.0.0", + "dependencies": { + "svelte-spa-router": "^4.0.1" + }, + "devDependencies": { + "@sveltejs/vite-plugin-svelte": "^5.0.3", + "@tailwindcss/vite": "^4.1.8", + "@tsconfig/svelte": "^5.0.4", + "svelte": "^5.19.0", + "svelte-check": "^4.1.4", + "tailwindcss": "^4.1.8", + "typescript": "~5.8.3", + "vite": "^6.3.5" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.12.tgz", + "integrity": "sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.12.tgz", + "integrity": "sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.12.tgz", + "integrity": "sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.12.tgz", + "integrity": "sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.12.tgz", + "integrity": "sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.12.tgz", + "integrity": "sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.12.tgz", + "integrity": "sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.12.tgz", + "integrity": "sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.12.tgz", + "integrity": "sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.12.tgz", + "integrity": "sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.12.tgz", + "integrity": "sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.12.tgz", + "integrity": "sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.12.tgz", + "integrity": "sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.12.tgz", + "integrity": "sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.12.tgz", + "integrity": "sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.12.tgz", + "integrity": "sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.12.tgz", + "integrity": "sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.12.tgz", + "integrity": "sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.12.tgz", + "integrity": "sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.12.tgz", + "integrity": "sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.12.tgz", + "integrity": "sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.12.tgz", + "integrity": "sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.12.tgz", + "integrity": "sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.12.tgz", + "integrity": "sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.12.tgz", + "integrity": "sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.12.tgz", + "integrity": "sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.13", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", + "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/remapping": { + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", + "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "dev": true, + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.57.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.57.0.tgz", + "integrity": "sha512-tPgXB6cDTndIe1ah7u6amCI1T0SsnlOuKgg10Xh3uizJk4e5M1JGaUMk7J4ciuAUcFpbOiNhm2XIjP9ON0dUqA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.57.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.57.0.tgz", + "integrity": "sha512-sa4LyseLLXr1onr97StkU1Nb7fWcg6niokTwEVNOO7awaKaoRObQ54+V/hrF/BP1noMEaaAW6Fg2d/CfLiq3Mg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.57.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.57.0.tgz", + "integrity": "sha512-/NNIj9A7yLjKdmkx5dC2XQ9DmjIECpGpwHoGmA5E1AhU0fuICSqSWScPhN1yLCkEdkCwJIDu2xIeLPs60MNIVg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.57.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.57.0.tgz", + "integrity": "sha512-xoh8abqgPrPYPr7pTYipqnUi1V3em56JzE/HgDgitTqZBZ3yKCWI+7KUkceM6tNweyUKYru1UMi7FC060RyKwA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.57.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.57.0.tgz", + "integrity": "sha512-PCkMh7fNahWSbA0OTUQ2OpYHpjZZr0hPr8lId8twD7a7SeWrvT3xJVyza+dQwXSSq4yEQTMoXgNOfMCsn8584g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.57.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.57.0.tgz", + "integrity": "sha512-1j3stGx+qbhXql4OCDZhnK7b01s6rBKNybfsX+TNrEe9JNq4DLi1yGiR1xW+nL+FNVvI4D02PUnl6gJ/2y6WJA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.57.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.57.0.tgz", + "integrity": "sha512-eyrr5W08Ms9uM0mLcKfM/Uzx7hjhz2bcjv8P2uynfj0yU8GGPdz8iYrBPhiLOZqahoAMB8ZiolRZPbbU2MAi6Q==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.57.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.57.0.tgz", + "integrity": "sha512-Xds90ITXJCNyX9pDhqf85MKWUI4lqjiPAipJ8OLp8xqI2Ehk+TCVhF9rvOoN8xTbcafow3QOThkNnrM33uCFQA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.57.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.57.0.tgz", + "integrity": "sha512-Xws2KA4CLvZmXjy46SQaXSejuKPhwVdaNinldoYfqruZBaJHqVo6hnRa8SDo9z7PBW5x84SH64+izmldCgbezw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.57.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.57.0.tgz", + "integrity": "sha512-hrKXKbX5FdaRJj7lTMusmvKbhMJSGWJ+w++4KmjiDhpTgNlhYobMvKfDoIWecy4O60K6yA4SnztGuNTQF+Lplw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-gnu": { + "version": "4.57.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.57.0.tgz", + "integrity": "sha512-6A+nccfSDGKsPm00d3xKcrsBcbqzCTAukjwWK6rbuAnB2bHaL3r9720HBVZ/no7+FhZLz/U3GwwZZEh6tOSI8Q==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-musl": { + "version": "4.57.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.57.0.tgz", + "integrity": "sha512-4P1VyYUe6XAJtQH1Hh99THxr0GKMMwIXsRNOceLrJnaHTDgk1FTcTimDgneRJPvB3LqDQxUmroBclQ1S0cIJwQ==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-gnu": { + "version": "4.57.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.57.0.tgz", + "integrity": "sha512-8Vv6pLuIZCMcgXre6c3nOPhE0gjz1+nZP6T+hwWjr7sVH8k0jRkH+XnfjjOTglyMBdSKBPPz54/y1gToSKwrSQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-musl": { + "version": "4.57.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.57.0.tgz", + "integrity": "sha512-r1te1M0Sm2TBVD/RxBPC6RZVwNqUTwJTA7w+C/IW5v9Ssu6xmxWEi+iJQlpBhtUiT1raJ5b48pI8tBvEjEFnFA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.57.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.57.0.tgz", + "integrity": "sha512-say0uMU/RaPm3CDQLxUUTF2oNWL8ysvHkAjcCzV2znxBr23kFfaxocS9qJm+NdkRhF8wtdEEAJuYcLPhSPbjuQ==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-musl": { + "version": "4.57.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.57.0.tgz", + "integrity": "sha512-/MU7/HizQGsnBREtRpcSbSV1zfkoxSTR7wLsRmBPQ8FwUj5sykrP1MyJTvsxP5KBq9SyE6kH8UQQQwa0ASeoQQ==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.57.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.57.0.tgz", + "integrity": "sha512-Q9eh+gUGILIHEaJf66aF6a414jQbDnn29zeu0eX3dHMuysnhTvsUvZTCAyZ6tJhUjnvzBKE4FtuaYxutxRZpOg==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.57.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.57.0.tgz", + "integrity": "sha512-OR5p5yG5OKSxHReWmwvM0P+VTPMwoBS45PXTMYaskKQqybkS3Kmugq1W+YbNWArF8/s7jQScgzXUhArzEQ7x0A==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.57.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.57.0.tgz", + "integrity": "sha512-XeatKzo4lHDsVEbm1XDHZlhYZZSQYym6dg2X/Ko0kSFgio+KXLsxwJQprnR48GvdIKDOpqWqssC3iBCjoMcMpw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-openbsd-x64": { + "version": "4.57.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.57.0.tgz", + "integrity": "sha512-Lu71y78F5qOfYmubYLHPcJm74GZLU6UJ4THkf/a1K7Tz2ycwC2VUbsqbJAXaR6Bx70SRdlVrt2+n5l7F0agTUw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ] + }, + "node_modules/@rollup/rollup-openharmony-arm64": { + "version": "4.57.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.57.0.tgz", + "integrity": "sha512-v5xwKDWcu7qhAEcsUubiav7r+48Uk/ENWdr82MBZZRIm7zThSxCIVDfb3ZeRRq9yqk+oIzMdDo6fCcA5DHfMyA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.57.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.57.0.tgz", + "integrity": "sha512-XnaaaSMGSI6Wk8F4KK3QP7GfuuhjGchElsVerCplUuxRIzdvZ7hRBpLR0omCmw+kI2RFJB80nenhOoGXlJ5TfQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.57.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.57.0.tgz", + "integrity": "sha512-3K1lP+3BXY4t4VihLw5MEg6IZD3ojSYzqzBG571W3kNQe4G4CcFpSUQVgurYgib5d+YaCjeFow8QivWp8vuSvA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-gnu": { + "version": "4.57.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.57.0.tgz", + "integrity": "sha512-MDk610P/vJGc5L5ImE4k5s+GZT3en0KoK1MKPXCRgzmksAMk79j4h3k1IerxTNqwDLxsGxStEZVBqG0gIqZqoA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.57.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.57.0.tgz", + "integrity": "sha512-Zv7v6q6aV+VslnpwzqKAmrk5JdVkLUzok2208ZXGipjb+msxBr/fJPZyeEXiFgH7k62Ak0SLIfxQRZQvTuf7rQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@sveltejs/acorn-typescript": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@sveltejs/acorn-typescript/-/acorn-typescript-1.0.8.tgz", + "integrity": "sha512-esgN+54+q0NjB0Y/4BomT9samII7jGwNy/2a3wNZbT2A2RpmXsXwUt24LvLhx6jUq2gVk4cWEvcRO6MFQbOfNA==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "acorn": "^8.9.0" + } + }, + "node_modules/@sveltejs/vite-plugin-svelte": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/@sveltejs/vite-plugin-svelte/-/vite-plugin-svelte-5.1.1.tgz", + "integrity": "sha512-Y1Cs7hhTc+a5E9Va/xwKlAJoariQyHY+5zBgCZg4PFWNYQ1nMN9sjK1zhw1gK69DuqVP++sht/1GZg1aRwmAXQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@sveltejs/vite-plugin-svelte-inspector": "^4.0.1", + "debug": "^4.4.1", + "deepmerge": "^4.3.1", + "kleur": "^4.1.5", + "magic-string": "^0.30.17", + "vitefu": "^1.0.6" + }, + "engines": { + "node": "^18.0.0 || ^20.0.0 || >=22" + }, + "peerDependencies": { + "svelte": "^5.0.0", + "vite": "^6.0.0" + } + }, + "node_modules/@sveltejs/vite-plugin-svelte-inspector": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@sveltejs/vite-plugin-svelte-inspector/-/vite-plugin-svelte-inspector-4.0.1.tgz", + "integrity": "sha512-J/Nmb2Q2y7mck2hyCX4ckVHcR5tu2J+MtBEQqpDrrgELZ2uvraQcK/ioCV61AqkdXFgriksOKIceDcQmqnGhVw==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^4.3.7" + }, + "engines": { + "node": "^18.0.0 || ^20.0.0 || >=22" + }, + "peerDependencies": { + "@sveltejs/vite-plugin-svelte": "^5.0.0", + "svelte": "^5.0.0", + "vite": "^6.0.0" + } + }, + "node_modules/@tailwindcss/node": { + "version": "4.1.18", + "resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.1.18.tgz", + "integrity": "sha512-DoR7U1P7iYhw16qJ49fgXUlry1t4CpXeErJHnQ44JgTSKMaZUdf17cfn5mHchfJ4KRBZRFA/Coo+MUF5+gOaCQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/remapping": "^2.3.4", + "enhanced-resolve": "^5.18.3", + "jiti": "^2.6.1", + "lightningcss": "1.30.2", + "magic-string": "^0.30.21", + "source-map-js": "^1.2.1", + "tailwindcss": "4.1.18" + } + }, + "node_modules/@tailwindcss/oxide": { + "version": "4.1.18", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.1.18.tgz", + "integrity": "sha512-EgCR5tTS5bUSKQgzeMClT6iCY3ToqE1y+ZB0AKldj809QXk1Y+3jB0upOYZrn9aGIzPtUsP7sX4QQ4XtjBB95A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10" + }, + "optionalDependencies": { + "@tailwindcss/oxide-android-arm64": "4.1.18", + "@tailwindcss/oxide-darwin-arm64": "4.1.18", + "@tailwindcss/oxide-darwin-x64": "4.1.18", + "@tailwindcss/oxide-freebsd-x64": "4.1.18", + "@tailwindcss/oxide-linux-arm-gnueabihf": "4.1.18", + "@tailwindcss/oxide-linux-arm64-gnu": "4.1.18", + "@tailwindcss/oxide-linux-arm64-musl": "4.1.18", + "@tailwindcss/oxide-linux-x64-gnu": "4.1.18", + "@tailwindcss/oxide-linux-x64-musl": "4.1.18", + "@tailwindcss/oxide-wasm32-wasi": "4.1.18", + "@tailwindcss/oxide-win32-arm64-msvc": "4.1.18", + "@tailwindcss/oxide-win32-x64-msvc": "4.1.18" + } + }, + "node_modules/@tailwindcss/oxide-android-arm64": { + "version": "4.1.18", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.1.18.tgz", + "integrity": "sha512-dJHz7+Ugr9U/diKJA0W6N/6/cjI+ZTAoxPf9Iz9BFRF2GzEX8IvXxFIi/dZBloVJX/MZGvRuFA9rqwdiIEZQ0Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-darwin-arm64": { + "version": "4.1.18", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.1.18.tgz", + "integrity": "sha512-Gc2q4Qhs660bhjyBSKgq6BYvwDz4G+BuyJ5H1xfhmDR3D8HnHCmT/BSkvSL0vQLy/nkMLY20PQ2OoYMO15Jd0A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-darwin-x64": { + "version": "4.1.18", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.1.18.tgz", + "integrity": "sha512-FL5oxr2xQsFrc3X9o1fjHKBYBMD1QZNyc1Xzw/h5Qu4XnEBi3dZn96HcHm41c/euGV+GRiXFfh2hUCyKi/e+yw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-freebsd-x64": { + "version": "4.1.18", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.1.18.tgz", + "integrity": "sha512-Fj+RHgu5bDodmV1dM9yAxlfJwkkWvLiRjbhuO2LEtwtlYlBgiAT4x/j5wQr1tC3SANAgD+0YcmWVrj8R9trVMA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-linux-arm-gnueabihf": { + "version": "4.1.18", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.1.18.tgz", + "integrity": "sha512-Fp+Wzk/Ws4dZn+LV2Nqx3IilnhH51YZoRaYHQsVq3RQvEl+71VGKFpkfHrLM/Li+kt5c0DJe/bHXK1eHgDmdiA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-linux-arm64-gnu": { + "version": "4.1.18", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.1.18.tgz", + "integrity": "sha512-S0n3jboLysNbh55Vrt7pk9wgpyTTPD0fdQeh7wQfMqLPM/Hrxi+dVsLsPrycQjGKEQk85Kgbx+6+QnYNiHalnw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-linux-arm64-musl": { + "version": "4.1.18", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.1.18.tgz", + "integrity": "sha512-1px92582HkPQlaaCkdRcio71p8bc8i/ap5807tPRDK/uw953cauQBT8c5tVGkOwrHMfc2Yh6UuxaH4vtTjGvHg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-linux-x64-gnu": { + "version": "4.1.18", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.1.18.tgz", + "integrity": "sha512-v3gyT0ivkfBLoZGF9LyHmts0Isc8jHZyVcbzio6Wpzifg/+5ZJpDiRiUhDLkcr7f/r38SWNe7ucxmGW3j3Kb/g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-linux-x64-musl": { + "version": "4.1.18", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.1.18.tgz", + "integrity": "sha512-bhJ2y2OQNlcRwwgOAGMY0xTFStt4/wyU6pvI6LSuZpRgKQwxTec0/3Scu91O8ir7qCR3AuepQKLU/kX99FouqQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-wasm32-wasi": { + "version": "4.1.18", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-wasm32-wasi/-/oxide-wasm32-wasi-4.1.18.tgz", + "integrity": "sha512-LffYTvPjODiP6PT16oNeUQJzNVyJl1cjIebq/rWWBF+3eDst5JGEFSc5cWxyRCJ0Mxl+KyIkqRxk1XPEs9x8TA==", + "bundleDependencies": [ + "@napi-rs/wasm-runtime", + "@emnapi/core", + "@emnapi/runtime", + "@tybys/wasm-util", + "@emnapi/wasi-threads", + "tslib" + ], + "cpu": [ + "wasm32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/core": "^1.7.1", + "@emnapi/runtime": "^1.7.1", + "@emnapi/wasi-threads": "^1.1.0", + "@napi-rs/wasm-runtime": "^1.1.0", + "@tybys/wasm-util": "^0.10.1", + "tslib": "^2.4.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@tailwindcss/oxide-win32-arm64-msvc": { + "version": "4.1.18", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.1.18.tgz", + "integrity": "sha512-HjSA7mr9HmC8fu6bdsZvZ+dhjyGCLdotjVOgLA2vEqxEBZaQo9YTX4kwgEvPCpRh8o4uWc4J/wEoFzhEmjvPbA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-win32-x64-msvc": { + "version": "4.1.18", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.1.18.tgz", + "integrity": "sha512-bJWbyYpUlqamC8dpR7pfjA0I7vdF6t5VpUGMWRkXVE3AXgIZjYUYAK7II1GNaxR8J1SSrSrppRar8G++JekE3Q==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/vite": { + "version": "4.1.18", + "resolved": "https://registry.npmjs.org/@tailwindcss/vite/-/vite-4.1.18.tgz", + "integrity": "sha512-jVA+/UpKL1vRLg6Hkao5jldawNmRo7mQYrZtNHMIVpLfLhDml5nMRUo/8MwoX2vNXvnaXNNMedrMfMugAVX1nA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@tailwindcss/node": "4.1.18", + "@tailwindcss/oxide": "4.1.18", + "tailwindcss": "4.1.18" + }, + "peerDependencies": { + "vite": "^5.2.0 || ^6 || ^7" + } + }, + "node_modules/@tsconfig/svelte": { + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/@tsconfig/svelte/-/svelte-5.0.6.tgz", + "integrity": "sha512-yGxYL0I9eETH1/DR9qVJey4DAsCdeau4a9wYPKuXfEhm8lFO8wg+LLYJjIpAm6Fw7HSlhepPhYPDop75485yWQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/estree": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", + "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", + "dev": true, + "license": "MIT" + }, + "node_modules/acorn": { + "version": "8.15.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", + "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", + "dev": true, + "license": "MIT", + "peer": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/aria-query": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.2.tgz", + "integrity": "sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/axobject-query": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-4.1.0.tgz", + "integrity": "sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/chokidar": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", + "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", + "dev": true, + "license": "MIT", + "dependencies": { + "readdirp": "^4.0.1" + }, + "engines": { + "node": ">= 14.16.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/clsx": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", + "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/deepmerge": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", + "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/detect-libc": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", + "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=8" + } + }, + "node_modules/devalue": { + "version": "5.6.2", + "resolved": "https://registry.npmjs.org/devalue/-/devalue-5.6.2.tgz", + "integrity": "sha512-nPRkjWzzDQlsejL1WVifk5rvcFi/y1onBRxjaFMjZeR9mFpqu2gmAZ9xUB9/IEanEP/vBtGeGganC/GO1fmufg==", + "dev": true, + "license": "MIT" + }, + "node_modules/enhanced-resolve": { + "version": "5.18.4", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.18.4.tgz", + "integrity": "sha512-LgQMM4WXU3QI+SYgEc2liRgznaD5ojbmY3sb8LxyguVkIg5FxdpTkvk72te2R38/TGKxH634oLxXRGY6d7AP+Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.4", + "tapable": "^2.2.0" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/esbuild": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.12.tgz", + "integrity": "sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.25.12", + "@esbuild/android-arm": "0.25.12", + "@esbuild/android-arm64": "0.25.12", + "@esbuild/android-x64": "0.25.12", + "@esbuild/darwin-arm64": "0.25.12", + "@esbuild/darwin-x64": "0.25.12", + "@esbuild/freebsd-arm64": "0.25.12", + "@esbuild/freebsd-x64": "0.25.12", + "@esbuild/linux-arm": "0.25.12", + "@esbuild/linux-arm64": "0.25.12", + "@esbuild/linux-ia32": "0.25.12", + "@esbuild/linux-loong64": "0.25.12", + "@esbuild/linux-mips64el": "0.25.12", + "@esbuild/linux-ppc64": "0.25.12", + "@esbuild/linux-riscv64": "0.25.12", + "@esbuild/linux-s390x": "0.25.12", + "@esbuild/linux-x64": "0.25.12", + "@esbuild/netbsd-arm64": "0.25.12", + "@esbuild/netbsd-x64": "0.25.12", + "@esbuild/openbsd-arm64": "0.25.12", + "@esbuild/openbsd-x64": "0.25.12", + "@esbuild/openharmony-arm64": "0.25.12", + "@esbuild/sunos-x64": "0.25.12", + "@esbuild/win32-arm64": "0.25.12", + "@esbuild/win32-ia32": "0.25.12", + "@esbuild/win32-x64": "0.25.12" + } + }, + "node_modules/esm-env": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/esm-env/-/esm-env-1.2.2.tgz", + "integrity": "sha512-Epxrv+Nr/CaL4ZcFGPJIYLWFom+YeV1DqMLHJoEd9SYRxNbaFruBwfEX/kkHUJf55j2+TUbmDcmuilbP1TmXHA==", + "dev": true, + "license": "MIT" + }, + "node_modules/esrap": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/esrap/-/esrap-2.2.2.tgz", + "integrity": "sha512-zA6497ha+qKvoWIK+WM9NAh5ni17sKZKhbS5B3PoYbBvaYHZWoS33zmFybmyqpn07RLUxSmn+RCls2/XF+d0oQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.4.15" + } + }, + "node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/is-reference": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-reference/-/is-reference-3.0.3.tgz", + "integrity": "sha512-ixkJoqQvAP88E6wLydLGGqCJsrFUnqoH6HnaczB8XmDH1oaWU+xxdptvikTgaEhtZ53Ky6YXiBuUI2WXLMCwjw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.6" + } + }, + "node_modules/jiti": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.6.1.tgz", + "integrity": "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==", + "dev": true, + "license": "MIT", + "bin": { + "jiti": "lib/jiti-cli.mjs" + } + }, + "node_modules/kleur": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-4.1.5.tgz", + "integrity": "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/lightningcss": { + "version": "1.30.2", + "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.30.2.tgz", + "integrity": "sha512-utfs7Pr5uJyyvDETitgsaqSyjCb2qNRAtuqUeWIAKztsOYdcACf2KtARYXg2pSvhkt+9NfoaNY7fxjl6nuMjIQ==", + "dev": true, + "license": "MPL-2.0", + "dependencies": { + "detect-libc": "^2.0.3" + }, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "lightningcss-android-arm64": "1.30.2", + "lightningcss-darwin-arm64": "1.30.2", + "lightningcss-darwin-x64": "1.30.2", + "lightningcss-freebsd-x64": "1.30.2", + "lightningcss-linux-arm-gnueabihf": "1.30.2", + "lightningcss-linux-arm64-gnu": "1.30.2", + "lightningcss-linux-arm64-musl": "1.30.2", + "lightningcss-linux-x64-gnu": "1.30.2", + "lightningcss-linux-x64-musl": "1.30.2", + "lightningcss-win32-arm64-msvc": "1.30.2", + "lightningcss-win32-x64-msvc": "1.30.2" + } + }, + "node_modules/lightningcss-android-arm64": { + "version": "1.30.2", + "resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.30.2.tgz", + "integrity": "sha512-BH9sEdOCahSgmkVhBLeU7Hc9DWeZ1Eb6wNS6Da8igvUwAe0sqROHddIlvU06q3WyXVEOYDZ6ykBZQnjTbmo4+A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-arm64": { + "version": "1.30.2", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.30.2.tgz", + "integrity": "sha512-ylTcDJBN3Hp21TdhRT5zBOIi73P6/W0qwvlFEk22fkdXchtNTOU4Qc37SkzV+EKYxLouZ6M4LG9NfZ1qkhhBWA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-x64": { + "version": "1.30.2", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.30.2.tgz", + "integrity": "sha512-oBZgKchomuDYxr7ilwLcyms6BCyLn0z8J0+ZZmfpjwg9fRVZIR5/GMXd7r9RH94iDhld3UmSjBM6nXWM2TfZTQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-freebsd-x64": { + "version": "1.30.2", + "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.30.2.tgz", + "integrity": "sha512-c2bH6xTrf4BDpK8MoGG4Bd6zAMZDAXS569UxCAGcA7IKbHNMlhGQ89eRmvpIUGfKWNVdbhSbkQaWhEoMGmGslA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm-gnueabihf": { + "version": "1.30.2", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.30.2.tgz", + "integrity": "sha512-eVdpxh4wYcm0PofJIZVuYuLiqBIakQ9uFZmipf6LF/HRj5Bgm0eb3qL/mr1smyXIS1twwOxNWndd8z0E374hiA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-gnu": { + "version": "1.30.2", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.30.2.tgz", + "integrity": "sha512-UK65WJAbwIJbiBFXpxrbTNArtfuznvxAJw4Q2ZGlU8kPeDIWEX1dg3rn2veBVUylA2Ezg89ktszWbaQnxD/e3A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-musl": { + "version": "1.30.2", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.30.2.tgz", + "integrity": "sha512-5Vh9dGeblpTxWHpOx8iauV02popZDsCYMPIgiuw97OJ5uaDsL86cnqSFs5LZkG3ghHoX5isLgWzMs+eD1YzrnA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-gnu": { + "version": "1.30.2", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.30.2.tgz", + "integrity": "sha512-Cfd46gdmj1vQ+lR6VRTTadNHu6ALuw2pKR9lYq4FnhvgBc4zWY1EtZcAc6EffShbb1MFrIPfLDXD6Xprbnni4w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-musl": { + "version": "1.30.2", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.30.2.tgz", + "integrity": "sha512-XJaLUUFXb6/QG2lGIW6aIk6jKdtjtcffUT0NKvIqhSBY3hh9Ch+1LCeH80dR9q9LBjG3ewbDjnumefsLsP6aiA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-arm64-msvc": { + "version": "1.30.2", + "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.30.2.tgz", + "integrity": "sha512-FZn+vaj7zLv//D/192WFFVA0RgHawIcHqLX9xuWiQt7P0PtdFEVaxgF9rjM/IRYHQXNnk61/H/gb2Ei+kUQ4xQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-x64-msvc": { + "version": "1.30.2", + "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.30.2.tgz", + "integrity": "sha512-5g1yc73p+iAkid5phb4oVFMB45417DkRevRbt/El/gKXJk4jid+vPFF/AXbxn05Aky8PapwzZrdJShv5C0avjw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/locate-character": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-character/-/locate-character-3.0.0.tgz", + "integrity": "sha512-SW13ws7BjaeJ6p7Q6CO2nchbYEc3X3J6WrmTTDto7yMPqVSZTUyY5Tjbid+Ab8gLnATtygYtiDIJGQRRn2ZOiA==", + "dev": true, + "license": "MIT" + }, + "node_modules/magic-string": { + "version": "0.30.21", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", + "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.5" + } + }, + "node_modules/mri": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/mri/-/mri-1.2.0.tgz", + "integrity": "sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/nanoid": { + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", + "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true, + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/postcss": { + "version": "8.5.6", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", + "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.11", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/readdirp": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz", + "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 14.18.0" + }, + "funding": { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/regexparam": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/regexparam/-/regexparam-2.0.2.tgz", + "integrity": "sha512-A1PeDEYMrkLrfyOwv2jwihXbo9qxdGD3atBYQA9JJgreAx8/7rC6IUkWOw2NQlOxLp2wL0ifQbh1HuidDfYA6w==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/rollup": { + "version": "4.57.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.57.0.tgz", + "integrity": "sha512-e5lPJi/aui4TO1LpAXIRLySmwXSE8k3b9zoGfd42p67wzxog4WHjiZF3M2uheQih4DGyc25QEV4yRBbpueNiUA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "1.0.8" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.57.0", + "@rollup/rollup-android-arm64": "4.57.0", + "@rollup/rollup-darwin-arm64": "4.57.0", + "@rollup/rollup-darwin-x64": "4.57.0", + "@rollup/rollup-freebsd-arm64": "4.57.0", + "@rollup/rollup-freebsd-x64": "4.57.0", + "@rollup/rollup-linux-arm-gnueabihf": "4.57.0", + "@rollup/rollup-linux-arm-musleabihf": "4.57.0", + "@rollup/rollup-linux-arm64-gnu": "4.57.0", + "@rollup/rollup-linux-arm64-musl": "4.57.0", + "@rollup/rollup-linux-loong64-gnu": "4.57.0", + "@rollup/rollup-linux-loong64-musl": "4.57.0", + "@rollup/rollup-linux-ppc64-gnu": "4.57.0", + "@rollup/rollup-linux-ppc64-musl": "4.57.0", + "@rollup/rollup-linux-riscv64-gnu": "4.57.0", + "@rollup/rollup-linux-riscv64-musl": "4.57.0", + "@rollup/rollup-linux-s390x-gnu": "4.57.0", + "@rollup/rollup-linux-x64-gnu": "4.57.0", + "@rollup/rollup-linux-x64-musl": "4.57.0", + "@rollup/rollup-openbsd-x64": "4.57.0", + "@rollup/rollup-openharmony-arm64": "4.57.0", + "@rollup/rollup-win32-arm64-msvc": "4.57.0", + "@rollup/rollup-win32-ia32-msvc": "4.57.0", + "@rollup/rollup-win32-x64-gnu": "4.57.0", + "@rollup/rollup-win32-x64-msvc": "4.57.0", + "fsevents": "~2.3.2" + } + }, + "node_modules/sade": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/sade/-/sade-1.8.1.tgz", + "integrity": "sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A==", + "dev": true, + "license": "MIT", + "dependencies": { + "mri": "^1.1.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/svelte": { + "version": "5.48.5", + "resolved": "https://registry.npmjs.org/svelte/-/svelte-5.48.5.tgz", + "integrity": "sha512-NB3o70OxfmnE5UPyLr8uH3IV02Q43qJVAuWigYmsSOYsS0s/rHxP0TF81blG0onF/xkhNvZw4G8NfzIX+By5ZQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@jridgewell/remapping": "^2.3.4", + "@jridgewell/sourcemap-codec": "^1.5.0", + "@sveltejs/acorn-typescript": "^1.0.5", + "@types/estree": "^1.0.5", + "acorn": "^8.12.1", + "aria-query": "^5.3.1", + "axobject-query": "^4.1.0", + "clsx": "^2.1.1", + "devalue": "^5.6.2", + "esm-env": "^1.2.1", + "esrap": "^2.2.1", + "is-reference": "^3.0.3", + "locate-character": "^3.0.0", + "magic-string": "^0.30.11", + "zimmerframe": "^1.1.2" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/svelte-check": { + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/svelte-check/-/svelte-check-4.3.5.tgz", + "integrity": "sha512-e4VWZETyXaKGhpkxOXP+B/d0Fp/zKViZoJmneZWe/05Y2aqSKj3YN2nLfYPJBQ87WEiY4BQCQ9hWGu9mPT1a1Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.25", + "chokidar": "^4.0.1", + "fdir": "^6.2.0", + "picocolors": "^1.0.0", + "sade": "^1.7.4" + }, + "bin": { + "svelte-check": "bin/svelte-check" + }, + "engines": { + "node": ">= 18.0.0" + }, + "peerDependencies": { + "svelte": "^4.0.0 || ^5.0.0-next.0", + "typescript": ">=5.0.0" + } + }, + "node_modules/svelte-spa-router": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/svelte-spa-router/-/svelte-spa-router-4.0.1.tgz", + "integrity": "sha512-2JkmUQ2f9jRluijL58LtdQBIpynSbem2eBGp4zXdi7aDY1znbR6yjw0KsonD0aq2QLwf4Yx4tBJQjxIjgjXHKg==", + "license": "MIT", + "dependencies": { + "regexparam": "2.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ItalyPaleAle" + } + }, + "node_modules/tailwindcss": { + "version": "4.1.18", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.1.18.tgz", + "integrity": "sha512-4+Z+0yiYyEtUVCScyfHCxOYP06L5Ne+JiHhY2IjR2KWMIWhJOYZKLSGZaP5HkZ8+bY0cxfzwDE5uOmzFXyIwxw==", + "dev": true, + "license": "MIT" + }, + "node_modules/tapable": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.0.tgz", + "integrity": "sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/tinyglobby": { + "version": "0.2.15", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", + "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.3" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/typescript": { + "version": "5.8.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.3.tgz", + "integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==", + "dev": true, + "license": "Apache-2.0", + "peer": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/vite": { + "version": "6.4.1", + "resolved": "https://registry.npmjs.org/vite/-/vite-6.4.1.tgz", + "integrity": "sha512-+Oxm7q9hDoLMyJOYfUYBuHQo+dkAloi33apOPP56pzj+vsdJDzr+j1NISE5pyaAuKL4A3UD34qd0lx5+kfKp2g==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "esbuild": "^0.25.0", + "fdir": "^6.4.4", + "picomatch": "^4.0.2", + "postcss": "^8.5.3", + "rollup": "^4.34.9", + "tinyglobby": "^0.2.13" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^18.0.0 || ^20.0.0 || >=22.0.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", + "jiti": ">=1.21.0", + "less": "*", + "lightningcss": "^1.21.0", + "sass": "*", + "sass-embedded": "*", + "stylus": "*", + "sugarss": "*", + "terser": "^5.16.0", + "tsx": "^4.8.1", + "yaml": "^2.4.2" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "jiti": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } + } + }, + "node_modules/vitefu": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/vitefu/-/vitefu-1.1.1.tgz", + "integrity": "sha512-B/Fegf3i8zh0yFbpzZ21amWzHmuNlLlmJT6n7bu5e+pCHUKQIfXSYokrqOBGEMMe9UG2sostKQF9mml/vYaWJQ==", + "dev": true, + "license": "MIT", + "workspaces": [ + "tests/deps/*", + "tests/projects/*", + "tests/projects/workspace/packages/*" + ], + "peerDependencies": { + "vite": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0-beta.0" + }, + "peerDependenciesMeta": { + "vite": { + "optional": true + } + } + }, + "node_modules/zimmerframe": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/zimmerframe/-/zimmerframe-1.1.4.tgz", + "integrity": "sha512-B58NGBEoc8Y9MWWCQGl/gq9xBCe4IiKM0a2x7GZdQKOW5Exr8S1W24J6OgM1njK8xCRGvAJIL/MxXHf6SkmQKQ==", + "dev": true, + "license": "MIT" + } + } +} diff --git a/ui-svelte/package.json b/ui-svelte/package.json new file mode 100644 index 00000000..53296797 --- /dev/null +++ b/ui-svelte/package.json @@ -0,0 +1,25 @@ +{ + "name": "ui-svelte", + "private": true, + "version": "0.0.0", + "type": "module", + "scripts": { + "start": "vite", + "build": "vite build --emptyOutDir", + "preview": "vite preview", + "check": "svelte-check --tsconfig ./tsconfig.json" + }, + "devDependencies": { + "@sveltejs/vite-plugin-svelte": "^5.0.3", + "@tailwindcss/vite": "^4.1.8", + "@tsconfig/svelte": "^5.0.4", + "svelte": "^5.19.0", + "svelte-check": "^4.1.4", + "tailwindcss": "^4.1.8", + "typescript": "~5.8.3", + "vite": "^6.3.5" + }, + "dependencies": { + "svelte-spa-router": "^4.0.1" + } +} diff --git a/ui-svelte/public/apple-touch-icon.png b/ui-svelte/public/apple-touch-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..27b03b909fe3eadba4315d6091188bfc27dcd835 GIT binary patch literal 6076 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 literal 0 HcmV?d00001 diff --git a/ui-svelte/public/favicon.svg b/ui-svelte/public/favicon.svg new file mode 100644 index 00000000..80a63878 --- /dev/null +++ b/ui-svelte/public/favicon.svg @@ -0,0 +1,17 @@ + \ No newline at end of file diff --git a/ui-svelte/public/site.webmanifest b/ui-svelte/public/site.webmanifest new file mode 100644 index 00000000..42e9963a --- /dev/null +++ b/ui-svelte/public/site.webmanifest @@ -0,0 +1,21 @@ +{ + "name": "llama-swap", + "short_name": "llama-swap", + "icons": [ + { + "src": "/web-app-manifest-192x192.png", + "sizes": "192x192", + "type": "image/png", + "purpose": "maskable" + }, + { + "src": "/web-app-manifest-512x512.png", + "sizes": "512x512", + "type": "image/png", + "purpose": "maskable" + } + ], + "theme_color": "#ffffff", + "background_color": "#ffffff", + "display": "standalone" +} \ No newline at end of file diff --git a/ui-svelte/public/web-app-manifest-192x192.png b/ui-svelte/public/web-app-manifest-192x192.png new file mode 100644 index 0000000000000000000000000000000000000000..f2a1bcebd390bf5a220ee595520811a91471563c GIT binary patch literal 6659 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 F`#;tFASM6+ literal 0 HcmV?d00001 diff --git a/ui-svelte/public/web-app-manifest-512x512.png b/ui-svelte/public/web-app-manifest-512x512.png new file mode 100644 index 0000000000000000000000000000000000000000..7912d0b289575748e6d9ed4610c901f996c57f87 GIT binary patch literal 28231 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 + import { onMount } from "svelte"; + import Router from "svelte-spa-router"; + import Header from "./components/Header.svelte"; + import LogViewer from "./routes/LogViewer.svelte"; + import Models from "./routes/Models.svelte"; + import Activity from "./routes/Activity.svelte"; + import { enableAPIEvents } from "./stores/api"; + import { initScreenWidth, isDarkMode, appTitle, connectionState } from "./stores/theme"; + + const routes = { + "/": Models, + "/logs": LogViewer, + "/activity": Activity, + "*": Models, + }; + + // Sync theme to document attribute + $effect(() => { + document.documentElement.setAttribute("data-theme", $isDarkMode ? "dark" : "light"); + }); + + // Sync title to document + $effect(() => { + const icon = $connectionState === "connecting" ? "\u{1F7E1}" : $connectionState === "connected" ? "\u{1F7E2}" : "\u{1F534}"; + document.title = `${icon} ${$appTitle}`; + }); + + onMount(() => { + const cleanupScreenWidth = initScreenWidth(); + enableAPIEvents(true); + + return () => { + cleanupScreenWidth(); + enableAPIEvents(false); + }; + }); + + +
+
+ +
+ +
+
diff --git a/ui-svelte/src/assets/logo.png b/ui-svelte/src/assets/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..f842c0392b105bba1167b56395203607b6ed4a43 GIT binary patch literal 12157 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
diff --git a/ui-svelte/src/components/LogPanel.svelte b/ui-svelte/src/components/LogPanel.svelte new file mode 100644 index 00000000..573950ff --- /dev/null +++ b/ui-svelte/src/components/LogPanel.svelte @@ -0,0 +1,132 @@ + + +
+
+
+

{title}

+ +
+ + + +
+
+ + {#if $showFilterStore} +
+ + +
+ {/if} +
+
+
{filteredLogs}
+
+
diff --git a/ui-svelte/src/components/ModelsPanel.svelte b/ui-svelte/src/components/ModelsPanel.svelte new file mode 100644 index 00000000..b4115e47 --- /dev/null +++ b/ui-svelte/src/components/ModelsPanel.svelte @@ -0,0 +1,208 @@ + + +
+
+
+

Models

+ {#if $isNarrow} +
+ + {#if menuOpen} +
+ + + +
+ {/if} +
+ {/if} +
+ {#if !$isNarrow} +
+
+ + + +
+ +
+ {/if} +
+ +
+ + + + + + + + + + {#each filteredModels.regularModels as model (model.id)} + + + + + + {/each} + +
{$showIdorNameStore === "id" ? "Model ID" : "Name"}State
+ + {getModelDisplay(model)} + + {#if model.description} +

{model.description}

+ {/if} +
+ {#if model.state === "stopped"} + + {:else} + + {/if} + + {model.state} +
+ + {#if Object.keys(filteredModels.peerModelsByPeerId).length > 0} +

Peer Models

+ {#each Object.entries(filteredModels.peerModelsByPeerId).sort(([a], [b]) => a.localeCompare(b)) as [peerId, peerModels] (peerId)} +
+ + + + + + + + {#each peerModels as model (model.id)} + + + + {/each} + +
{peerId}
+ {model.id} +
+
+ {/each} + {/if} +
+
diff --git a/ui-svelte/src/components/ResizablePanels.svelte b/ui-svelte/src/components/ResizablePanels.svelte new file mode 100644 index 00000000..5d824ba4 --- /dev/null +++ b/ui-svelte/src/components/ResizablePanels.svelte @@ -0,0 +1,152 @@ + + +
+
+ {@render leftPanel()} +
+ + + + + +
+ {@render rightPanel()} +
+
diff --git a/ui-svelte/src/components/StatsPanel.svelte b/ui-svelte/src/components/StatsPanel.svelte new file mode 100644 index 00000000..2ef869a5 --- /dev/null +++ b/ui-svelte/src/components/StatsPanel.svelte @@ -0,0 +1,147 @@ + + +
+
+ + + + + + + + + + + + + + + + + + + + + +
Requests + Processed + + Generated + + Token Stats (tokens/sec) +
{stats.totalRequests} +
+ {nf.format(stats.totalInputTokens)} + tokens +
+
+
+ {nf.format(stats.totalOutputTokens)} + tokens +
+
+
+
+
+
P50
+
+ {stats.tokenStats.p50} +
+
+ +
+
P95
+
+ {stats.tokenStats.p95} +
+
+ +
+
P99
+
+ {stats.tokenStats.p99} +
+
+
+ {#if stats.histogramData} + + {/if} +
+
+
+
diff --git a/ui-svelte/src/components/TokenHistogram.svelte b/ui-svelte/src/components/TokenHistogram.svelte new file mode 100644 index 00000000..5523c571 --- /dev/null +++ b/ui-svelte/src/components/TokenHistogram.svelte @@ -0,0 +1,129 @@ + + +
+ + + + + + + + + {#each data.bins as count, i} + {@const barHeight = maxCount > 0 ? (count / maxCount) * chartHeight : 0} + {@const x = padding.left + i * barWidth} + {@const y = height - padding.bottom - barHeight} + {@const binStart = data.min + i * data.binSize} + {@const binEnd = binStart + data.binSize} + + + {`${binStart.toFixed(1)} - ${binEnd.toFixed(1)} tokens/sec\nCount: ${count}`} + + {/each} + + + + + + + + + + + {data.min.toFixed(1)} + + + + {data.max.toFixed(1)} + + + + + Tokens/Second Distribution + + +
diff --git a/ui-svelte/src/components/Tooltip.svelte b/ui-svelte/src/components/Tooltip.svelte new file mode 100644 index 00000000..97c76c96 --- /dev/null +++ b/ui-svelte/src/components/Tooltip.svelte @@ -0,0 +1,20 @@ + + +
+ +
+ {content} +
+
+
diff --git a/ui-svelte/src/index.css b/ui-svelte/src/index.css new file mode 100644 index 00000000..3e684bde --- /dev/null +++ b/ui-svelte/src/index.css @@ -0,0 +1,176 @@ +@import "tailwindcss"; +@custom-variant dark (&:where([data-theme=dark], [data-theme=dark] *)); + +@theme { + --color-background: rgba(252, 252, 249, 1); + --color-surface: rgba(255, 255, 253, 1); + + /* text colors */ + --color-txtmain: rgba(19, 52, 59, 1); + --color-txtsecondary: rgba(98, 108, 113, 1); + --color-navlink-active: rgba(245, 245, 245, 1); + + --color-primary: rgba(50, 184, 198, 1); + + --color-primary-hover: rgba(29, 116, 128, 1); + --color-primary-active: rgba(26, 104, 115, 1); + --color-secondary: rgba(94, 82, 64, 0.12); + --color-secondary-hover: rgba(94, 82, 64, 0.2); + --color-secondary-active: rgba(94, 82, 64, 0.25); + --color-border: rgba(94, 82, 64, 0.3); + --color-btn-primary-text: rgba(252, 252, 249, 1); + --color-card-border: rgba(94, 82, 64, 0.12); + --color-card-border-inner: rgba(94, 82, 64, 0.12); + --color-error: rgba(192, 21, 47, 1); + --color-success: rgba(33, 128, 141, 1); + --color-warning: rgb(244, 155, 0); + --color-info: rgba(98, 108, 113, 1); + --color-focus-ring: rgba(33, 128, 141, 0.4); + --color-select-caret: rgba(19, 52, 59, 0.8); + --color-btn-border: rgba(94, 82, 64, 0.7); +} + +@layer theme { + /* over ride theme for dark mode */ + [data-theme="dark"] { + --color-background: rgba(31, 33, 33, 1); + --color-surface: rgba(38, 40, 40, 1); + /* text colors */ + --color-txtmain: rgba(245, 245, 245, 1); + --color-txtsecondary: rgba(167, 169, 169, 0.7); + + --color-navlink-active: rgba(245, 245, 245, 1); + + --color-primary: rgba(33, 128, 141, 1); + --color-primary-hover: rgba(45, 166, 178, 1); + --color-primary-active: rgba(41, 150, 161, 1); + --color-secondary: rgba(119, 124, 124, 0.15); + --color-secondary-hover: rgba(119, 124, 124, 0.25); + --color-secondary-active: rgba(119, 124, 124, 0.3); + --color-border: rgba(119, 124, 124, 0.3); + --color-error: rgba(255, 84, 89, 1); + --color-success: rgba(50, 184, 198, 1); + --color-warning: rgb(244, 155, 0); + --color-info: rgba(167, 169, 169, 1); + --color-focus-ring: rgba(50, 184, 198, 0.4); + --color-btn-primary-text: rgba(19, 52, 59, 1); + --color-card-border: rgba(119, 124, 124, 0.2); + --color-card-border-inner: rgba(119, 124, 124, 0.15); + --shadow-inset-sm: inset 0 1px 0 rgba(255, 255, 255, 0.1), inset 0 -1px 0 rgba(0, 0, 0, 0.15); + --button-border-secondary: rgba(119, 124, 124, 0.2); + } +} + +@layer base { + body { + /* example of how colors using theme colors*/ + @apply bg-background text-txtmain; + } + + h1 { + @apply text-4xl text-txtmain font-bold pb-4; + } + h2 { + @apply text-3xl text-txtmain font-bold pb-4; + } + h3 { + @apply text-2xl text-txtmain font-bold pb-4; + } + h4 { + @apply text-xl text-txtmain font-bold pb-4; + } + h5 { + @apply text-lg text-txtmain font-bold pb-4; + } + h6 { + @apply text-base text-txtmain font-bold pb-4; + } +} + +/* define CSS classes here for specific types of components */ +@layer components { + .container { + @apply px-4; + } + + /* Tables */ + table th { + @apply p-2 font-semibold; + } + table td { + @apply p-2; + } + + /* Navigation Header */ + + .navlink { + @apply text-txtsecondary hover:bg-secondary hover:text-txtmain rounded-lg p-2; + } + .navlink.active { + @apply bg-primary text-navlink-active; + } + + /* Card component */ + .card { + @apply bg-surface rounded-lg border border-card-border shadow-sm overflow-hidden p-4; + } + + .card:hover { + @apply shadow-md; + } + + .card__body { + @apply p-4; + } + + .card__header, + .card__footer { + @apply p-4 border-b border-card-border-inner; + } + + /* Status Badges */ + .status { + @apply inline-block px-2 py-1 text-xs font-medium rounded-lg; + } + + .status--ready { + @apply bg-success/10 text-success; + } + + .status--starting, + .status--stopping { + @apply bg-warning/10 text-warning; + } + + .status--stopped { + @apply bg-error/10 text-error; + } + + /* Buttons */ + .btn { + @apply bg-surface py-2 px-4 text-sm rounded-md border transition-colors duration-200 border-btn-border; + } + + .btn:hover { + cursor: pointer; + } + + .btn--sm { + @apply px-2 py-0.5 text-xs; + } + + .btn:disabled { + @apply opacity-50 cursor-not-allowed; + } +} + +@layer utilities { + .ml-2 { + margin-left: 0.5rem; + } + + .my-8 { + margin-top: 2rem; + margin-bottom: 2rem; + } +} diff --git a/ui-svelte/src/lib/types.ts b/ui-svelte/src/lib/types.ts new file mode 100644 index 00000000..dc5d367f --- /dev/null +++ b/ui-svelte/src/lib/types.ts @@ -0,0 +1,42 @@ +export type ConnectionState = "connected" | "connecting" | "disconnected"; + +export type ModelStatus = "ready" | "starting" | "stopping" | "stopped" | "shutdown" | "unknown"; + +export interface Model { + id: string; + state: ModelStatus; + name: string; + description: string; + unlisted: boolean; + peerID: string; +} + +export interface Metrics { + id: number; + timestamp: string; + model: string; + cache_tokens: number; + input_tokens: number; + output_tokens: number; + prompt_per_second: number; + tokens_per_second: number; + duration_ms: number; +} + +export interface LogData { + source: "upstream" | "proxy"; + data: string; +} + +export interface APIEventEnvelope { + type: "modelStatus" | "logData" | "metrics"; + data: string; +} + +export interface VersionInfo { + build_date: string; + commit: string; + version: string; +} + +export type ScreenWidth = "xs" | "sm" | "md" | "lg" | "xl" | "2xl"; diff --git a/ui-svelte/src/main.ts b/ui-svelte/src/main.ts new file mode 100644 index 00000000..1272a949 --- /dev/null +++ b/ui-svelte/src/main.ts @@ -0,0 +1,9 @@ +import "./index.css"; +import App from "./App.svelte"; +import { mount } from "svelte"; + +const app = mount(App, { + target: document.getElementById("app")!, +}); + +export default app; diff --git a/ui-svelte/src/routes/Activity.svelte b/ui-svelte/src/routes/Activity.svelte new file mode 100644 index 00000000..338e85cf --- /dev/null +++ b/ui-svelte/src/routes/Activity.svelte @@ -0,0 +1,88 @@ + + +
+

Activity

+ + {#if $metrics.length === 0} +
+

No metrics data available

+
+ {:else} +
+ + + + + + + + + + + + + + + + {#each sortedMetrics as metric (metric.id)} + + + + + + + + + + + + {/each} + +
IDTimeModel + Cached + + Prompt + GeneratedPrompt ProcessingGeneration SpeedDuration
{metric.id + 1}{formatRelativeTime(metric.timestamp)}{metric.model}{metric.cache_tokens > 0 ? metric.cache_tokens.toLocaleString() : "-"}{metric.input_tokens.toLocaleString()}{metric.output_tokens.toLocaleString()}{formatSpeed(metric.prompt_per_second)}{formatSpeed(metric.tokens_per_second)}{formatDuration(metric.duration_ms)}
+
+ {/if} +
diff --git a/ui-svelte/src/routes/LogViewer.svelte b/ui-svelte/src/routes/LogViewer.svelte new file mode 100644 index 00000000..ff91ef42 --- /dev/null +++ b/ui-svelte/src/routes/LogViewer.svelte @@ -0,0 +1,75 @@ + + +
+
+ +
+ +
+ {#if $viewModeStore === "panels"} + + {#snippet leftPanel()} + + {/snippet} + {#snippet rightPanel()} + + {/snippet} + + {:else if $viewModeStore === "proxy"} + + {:else} + + {/if} +
+
diff --git a/ui-svelte/src/routes/Models.svelte b/ui-svelte/src/routes/Models.svelte new file mode 100644 index 00000000..96a08414 --- /dev/null +++ b/ui-svelte/src/routes/Models.svelte @@ -0,0 +1,26 @@ + + + + {#snippet leftPanel()} + + {/snippet} + {#snippet rightPanel()} +
+ {#if direction === "horizontal"} + + {/if} +
+ +
+
+ {/snippet} +
diff --git a/ui-svelte/src/stores/api.ts b/ui-svelte/src/stores/api.ts new file mode 100644 index 00000000..cbeef16f --- /dev/null +++ b/ui-svelte/src/stores/api.ts @@ -0,0 +1,174 @@ +import { writable } from "svelte/store"; +import type { Model, Metrics, VersionInfo, LogData, APIEventEnvelope } from "../lib/types"; +import { connectionState } from "./theme"; + +const LOG_LENGTH_LIMIT = 1024 * 100; /* 100KB of log data */ + +// Stores +export const models = writable([]); +export const proxyLogs = writable(""); +export const upstreamLogs = writable(""); +export const metrics = writable([]); +export const versionInfo = writable({ + build_date: "unknown", + commit: "unknown", + version: "unknown", +}); + +let apiEventSource: EventSource | null = null; + +function appendLog(newData: string, store: typeof proxyLogs | typeof upstreamLogs): void { + store.update((prev) => { + const updatedLog = prev + newData; + return updatedLog.length > LOG_LENGTH_LIMIT ? updatedLog.slice(-LOG_LENGTH_LIMIT) : updatedLog; + }); +} + +export function enableAPIEvents(enabled: boolean): void { + if (!enabled) { + apiEventSource?.close(); + apiEventSource = null; + metrics.set([]); + return; + } + + let retryCount = 0; + const initialDelay = 1000; // 1 second + + const connect = () => { + apiEventSource?.close(); + apiEventSource = new EventSource("/api/events"); + + connectionState.set("connecting"); + + apiEventSource.onopen = () => { + // Clear everything on connect to keep things in sync + proxyLogs.set(""); + upstreamLogs.set(""); + metrics.set([]); + models.set([]); + retryCount = 0; + connectionState.set("connected"); + }; + + apiEventSource.onmessage = (e: MessageEvent) => { + try { + const message = JSON.parse(e.data) as APIEventEnvelope; + switch (message.type) { + case "modelStatus": { + const newModels = JSON.parse(message.data) as Model[]; + // Sort models by name and id + newModels.sort((a, b) => { + return (a.name + a.id).localeCompare(b.name + b.id); + }); + models.set(newModels); + break; + } + + case "logData": { + const logData = JSON.parse(message.data) as LogData; + switch (logData.source) { + case "proxy": + appendLog(logData.data, proxyLogs); + break; + case "upstream": + appendLog(logData.data, upstreamLogs); + break; + } + break; + } + + case "metrics": { + const newMetrics = JSON.parse(message.data) as Metrics[]; + metrics.update((prevMetrics) => [...newMetrics, ...prevMetrics]); + break; + } + } + } catch (err) { + console.error(e.data, err); + } + }; + + apiEventSource.onerror = () => { + apiEventSource?.close(); + retryCount++; + const delay = Math.min(initialDelay * Math.pow(2, retryCount - 1), 5000); + connectionState.set("disconnected"); + setTimeout(connect, delay); + }; + }; + + connect(); +} + +// Fetch version info when connected +connectionState.subscribe(async (status) => { + if (status === "connected") { + try { + const response = await fetch("/api/version"); + if (!response.ok) { + throw new Error(`HTTP error! status: ${response.status}`); + } + const data: VersionInfo = await response.json(); + versionInfo.set(data); + } catch (error) { + console.error(error); + } + } +}); + +export async function listModels(): Promise { + try { + const response = await fetch("/api/models/"); + if (!response.ok) { + throw new Error(`HTTP error! status: ${response.status}`); + } + const data = await response.json(); + return data || []; + } catch (error) { + console.error("Failed to fetch models:", error); + return []; + } +} + +export async function unloadAllModels(): Promise { + try { + const response = await fetch(`/api/models/unload`, { + method: "POST", + }); + if (!response.ok) { + throw new Error(`Failed to unload models: ${response.status}`); + } + } catch (error) { + console.error("Failed to unload models:", error); + throw error; + } +} + +export async function unloadSingleModel(model: string): Promise { + try { + const response = await fetch(`/api/models/unload/${model}`, { + method: "POST", + }); + if (!response.ok) { + throw new Error(`Failed to unload model: ${response.status}`); + } + } catch (error) { + console.error("Failed to unload model", model, error); + throw error; + } +} + +export async function loadModel(model: string): Promise { + try { + const response = await fetch(`/upstream/${model}/`, { + method: "GET", + }); + if (!response.ok) { + throw new Error(`Failed to load model: ${response.status}`); + } + } catch (error) { + console.error("Failed to load model:", error); + throw error; + } +} diff --git a/ui-svelte/src/stores/persistent.ts b/ui-svelte/src/stores/persistent.ts new file mode 100644 index 00000000..134aeaa0 --- /dev/null +++ b/ui-svelte/src/stores/persistent.ts @@ -0,0 +1,31 @@ +import { writable, type Writable } from "svelte/store"; + +export function persistentStore(key: string, initialValue: T): Writable { + // Get initial value from localStorage or use default + let storedValue = initialValue; + if (typeof window !== "undefined") { + try { + const saved = localStorage.getItem(key); + if (saved !== null) { + storedValue = JSON.parse(saved); + } + } catch (e) { + console.error(`Error parsing stored value for ${key}`, e); + } + } + + const store = writable(storedValue); + + // Subscribe to changes and save to localStorage + store.subscribe((value) => { + if (typeof window !== "undefined") { + try { + localStorage.setItem(key, JSON.stringify(value)); + } catch (e) { + console.error(`Error saving value for ${key}`, e); + } + } + }); + + return store; +} diff --git a/ui-svelte/src/stores/theme.ts b/ui-svelte/src/stores/theme.ts new file mode 100644 index 00000000..7227125f --- /dev/null +++ b/ui-svelte/src/stores/theme.ts @@ -0,0 +1,53 @@ +import { writable, derived } from "svelte/store"; +import { persistentStore } from "./persistent"; +import type { ScreenWidth } from "../lib/types"; + +// Persistent stores +export const isDarkMode = persistentStore("theme", false); +export const appTitle = persistentStore("app-title", "llama-swap"); + +// Non-persistent stores +export const screenWidth = writable("md"); +export const connectionState = writable<"connected" | "connecting" | "disconnected">("disconnected"); + +// Derived store for narrow screens +export const isNarrow = derived(screenWidth, ($screenWidth) => { + return $screenWidth === "xs" || $screenWidth === "sm" || $screenWidth === "md"; +}); + +// Function to toggle theme +export function toggleTheme(): void { + isDarkMode.update((current) => !current); +} + +// Function to check and update screen width +export function checkScreenWidth(): void { + const innerWidth = window.innerWidth; + let newWidth: ScreenWidth; + + if (innerWidth < 640) { + newWidth = "xs"; + } else if (innerWidth < 768) { + newWidth = "sm"; + } else if (innerWidth < 1024) { + newWidth = "md"; + } else if (innerWidth < 1280) { + newWidth = "lg"; + } else if (innerWidth < 1536) { + newWidth = "xl"; + } else { + newWidth = "2xl"; + } + + screenWidth.set(newWidth); +} + +// Initialize screen width and set up resize listener +export function initScreenWidth(): () => void { + checkScreenWidth(); + window.addEventListener("resize", checkScreenWidth); + + return () => { + window.removeEventListener("resize", checkScreenWidth); + }; +} diff --git a/ui-svelte/svelte.config.js b/ui-svelte/svelte.config.js new file mode 100644 index 00000000..d0e64483 --- /dev/null +++ b/ui-svelte/svelte.config.js @@ -0,0 +1,5 @@ +import { vitePreprocess } from "@sveltejs/vite-plugin-svelte"; + +export default { + preprocess: vitePreprocess(), +}; diff --git a/ui-svelte/tsconfig.json b/ui-svelte/tsconfig.json new file mode 100644 index 00000000..80fb577b --- /dev/null +++ b/ui-svelte/tsconfig.json @@ -0,0 +1,20 @@ +{ + "extends": "@tsconfig/svelte/tsconfig.json", + "compilerOptions": { + "target": "ESNext", + "useDefineForClassFields": true, + "module": "ESNext", + "resolveJsonModule": true, + "allowJs": true, + "checkJs": true, + "isolatedModules": true, + "moduleDetection": "force", + "noEmit": true, + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noFallthroughCasesInSwitch": true, + "verbatimModuleSyntax": true + }, + "include": ["src/**/*.ts", "src/**/*.svelte"] +} diff --git a/ui-svelte/vite.config.ts b/ui-svelte/vite.config.ts new file mode 100644 index 00000000..f083a0d4 --- /dev/null +++ b/ui-svelte/vite.config.ts @@ -0,0 +1,21 @@ +import { defineConfig } from "vite"; +import { svelte } from "@sveltejs/vite-plugin-svelte"; +import tailwindcss from "@tailwindcss/vite"; + +// https://vite.dev/config/ +export default defineConfig({ + plugins: [svelte(), tailwindcss()], + base: "/ui/", + build: { + outDir: "../proxy/ui_dist", + assetsDir: "assets", + }, + server: { + proxy: { + "/api": "http://localhost:8080", // Proxy API calls to Go backend during development + "/logs": "http://localhost:8080", + "/upstream": "http://localhost:8080", + "/unload": "http://localhost:8080", + }, + }, +});
+ {#if $screenWidth !== "xs" && $screenWidth !== "sm"} +

+ {$appTitle} +

+ {/if} + +
+ + Models + + + Activity + + + Logs + + + + +