- packages/ui (@executor/ui): shared UI package with shadcn components - 56 components installed (button, card, dialog, sidebar, etc.) - lib/utils.ts with cn() helper - globals.css with light/dark theme (oklch colors, auto detection) - DM Sans + Instrument Serif + JetBrains Mono fonts - components.json in both packages/ui and apps/web for CLI support - Tailwind v4 with @source directives for cross-package class scanning - Fixed source namespace detection (use last tag, filter by 'openapi' presence) - apps/web imports globals.css from @executor/ui/globals.css
Unified · Split
| @@ -0,0 +1,20 @@ | |||
| 1 | { | ||
| 2 | "$schema": "https://ui.shadcn.com/schema.json", | ||
| 3 | "style": "new-york", | ||
| 4 | "rsc": false, | ||
| 5 | "tsx": true, | ||
| 6 | "tailwind": { | ||
| 7 | "config": "", | ||
| 8 | "css": "../../packages/ui/src/styles/globals.css", | ||
| 9 | "baseColor": "neutral", | ||
| 10 | "cssVariables": true | ||
| 11 | }, | ||
| 12 | "iconLibrary": "lucide", | ||
| 13 | "aliases": { | ||
| 14 | "components": "@/components", | ||
| 15 | "hooks": "@/hooks", | ||
| 16 | "lib": "@/lib", | ||
| 17 | "utils": "@executor/ui/lib/utils", | ||
| 18 | "ui": "@executor/ui/components" | ||
| 19 | } | ||
| 20 | } | ||
| @@ -5,6 +5,7 @@ · 4 unmodified lines | |||
| 5 | "type": "module", | 5 | "type": "module", |
| 6 | "dependencies": { | 6 | "dependencies": { |
| 7 | "@executor/plugin-openapi": "workspace:*", | 7 | "@executor/plugin-openapi": "workspace:*", |
| 8 | "@executor/ui": "workspace:*", | ||
| 8 | "tailwindcss": "^4.1.10", | 9 | "tailwindcss": "^4.1.10", |
| 9 | "@executor/react": "workspace:*", | 10 | "@executor/react": "workspace:*", |
| 10 | "@executor/server": "workspace:*", | 11 | "@executor/server": "workspace:*", |
| @@ -1,6 +1,6 @@ | |||
| 1 | import React from "react"; | 1 | import React from "react"; |
| 2 | import { createRoot } from "react-dom/client"; | 2 | import { createRoot } from "react-dom/client"; |
| 3 | import "./styles.css"; | 3 | import "@executor/ui/globals.css"; |
| 4 | import { App } from "./App"; | 4 | import { App } from "./App"; |
| 5 | 5 | ||
| 6 | const root = createRoot(document.getElementById("root")!); | 6 | const root = createRoot(document.getElementById("root")!); |
| @@ -22,10 +22,10 @@ export function SourcesPage() { · 21 unmodified lines | |||
| 22 | if (tools._tag !== "Success") return []; | 22 | if (tools._tag !== "Success") return []; |
| 23 | const namespaces = new Map<string, number>(); | 23 | const namespaces = new Map<string, number>(); |
| 24 | for (const tool of tools.value) { | 24 | for (const tool of tools.value) { |
| 25 | const ns = tool.tags.find( | 25 | if (!tool.tags.includes("openapi")) continue; |
| 26 | (t) => t !== "openapi" && !sourcePlugins.some((p) => p.key === t), | 26 | // Namespace is the last tag (after op tags and "openapi") |
| 27 | ); | 27 | const ns = tool.tags[tool.tags.length - 1]; |
| 28 | if (ns) { | 28 | if (ns && ns !== "openapi") { |
| 29 | namespaces.set(ns, (namespaces.get(ns) ?? 0) + 1); | 29 | namespaces.set(ns, (namespaces.get(ns) ?? 0) + 1); |
| 30 | } | 30 | } |
| 31 | } | 31 | } |
| @@ -34,8 +34,9 @@ function SourceList() { · 33 unmodified lines | |||
| 34 | if (tools._tag !== "Success") return []; | 34 | if (tools._tag !== "Success") return []; |
| 35 | const namespaces = new Map<string, number>(); | 35 | const namespaces = new Map<string, number>(); |
| 36 | for (const tool of tools.value) { | 36 | for (const tool of tools.value) { |
| 37 | const ns = tool.tags.find((t) => t !== "openapi"); | 37 | if (!tool.tags.includes("openapi")) continue; |
| 38 | if (ns && ns !== tool.tags[0]) { | 38 | const ns = tool.tags[tool.tags.length - 1]; |
| 39 | if (ns && ns !== "openapi") { | ||
| 39 | namespaces.set(ns, (namespaces.get(ns) ?? 0) + 1); | 40 | namespaces.set(ns, (namespaces.get(ns) ?? 0) + 1); |
| 40 | } | 41 | } |
| 41 | } | 42 | } |
| @@ -34,6 +34,7 @@ · 33 unmodified lines | |||
| 34 | "@executor/plugin-openapi": "workspace:*", | 34 | "@executor/plugin-openapi": "workspace:*", |
| 35 | "@executor/react": "workspace:*", | 35 | "@executor/react": "workspace:*", |
| 36 | "@executor/server": "workspace:*", | 36 | "@executor/server": "workspace:*", |
| 37 | "@executor/ui": "workspace:*", | ||
| 37 | "@tanstack/react-router": "^1.168.10", | 38 | "@tanstack/react-router": "^1.168.10", |
| 38 | "react": "^19.1.0", | 39 | "react": "^19.1.0", |
| 39 | "react-dom": "^19.1.0", | 40 | "react-dom": "^19.1.0", |
| @@ -190,6 +191,37 @@ · 150 unmodified lines | |||
| 190 | "react", | 191 | "react", |
| 191 | ], | 192 | ], |
| 192 | }, | 193 | }, |
| 194 | "packages/ui": { | ||
| 195 | "name": "@executor/ui", | ||
| 196 | "version": "0.0.0", | ||
| 197 | "dependencies": { | ||
| 198 | "@base-ui/react": "^1.3.0", | ||
| 199 | "@hookform/resolvers": "^5.2.2", | ||
| 200 | "class-variance-authority": "^0.7.1", | ||
| 201 | "clsx": "^2.1.1", | ||
| 202 | "cmdk": "^1.1.1", | ||
| 203 | "date-fns": "^4.1.0", | ||
| 204 | "embla-carousel-react": "^8.6.0", | ||
| 205 | "input-otp": "^1.4.2", | ||
| 206 | "lucide-react": "^1.7.0", | ||
| 207 | "next-themes": "^0.4.6", | ||
| 208 | "radix-ui": "^1.4.3", | ||
| 209 | "react": "^19.1.0", | ||
| 210 | "react-day-picker": "^9.14.0", | ||
| 211 | "react-hook-form": "^7.72.0", | ||
| 212 | "react-resizable-panels": "^4", | ||
| 213 | "recharts": "3.8.0", | ||
| 214 | "sonner": "^2.0.7", | ||
| 215 | "tailwind-merge": "^3.3.0", | ||
| 216 | "vaul": "^1.1.2", | ||
| 217 | "zod": "^4.3.6", | ||
| 218 | }, | ||
| 219 | "devDependencies": { | ||
| 220 | "@types/react": "^19.1.0", | ||
| 221 | "tailwindcss": "^4.1.10", | ||
| 222 | "typescript": "^5.9.3", | ||
| 223 | }, | ||
| 224 | }, | ||
| 193 | }, | 225 | }, |
| 194 | "catalog": { | 226 | "catalog": { |
| 195 | "@effect/cluster": "^0.58.0", | 227 | "@effect/cluster": "^0.58.0", |
| @@ -243,12 +275,20 @@ · 47 unmodified lines | |||
| 243 | 275 | ||
| 244 | "@babel/plugin-transform-react-jsx-source": ["@babel/plugin-transform-react-jsx-source@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-zbwoTsBruTeKB9hSq73ha66iFeJHuaFkUbwvqElnygoNbj/jHRsSeokowZFN3CZ64IvEqcmmkVe89OPXc7ldAw=="], | 276 | "@babel/plugin-transform-react-jsx-source": ["@babel/plugin-transform-react-jsx-source@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-zbwoTsBruTeKB9hSq73ha66iFeJHuaFkUbwvqElnygoNbj/jHRsSeokowZFN3CZ64IvEqcmmkVe89OPXc7ldAw=="], |
| 245 | 277 | ||
| 278 | "@babel/runtime": ["@babel/runtime@7.29.2", "", {}, "sha512-JiDShH45zKHWyGe4ZNVRrCjBz8Nh9TMmZG1kh4QTK8hCBTWBi8Da+i7s1fJw7/lYpM4ccepSNfqzZ/QvABBi5g=="], | ||
| 279 | |||
| 246 | "@babel/template": ["@babel/template@7.28.6", "", { "dependencies": { "@babel/code-frame": "^7.28.6", "@babel/parser": "^7.28.6", "@babel/types": "^7.28.6" } }, "sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ=="], | 280 | "@babel/template": ["@babel/template@7.28.6", "", { "dependencies": { "@babel/code-frame": "^7.28.6", "@babel/parser": "^7.28.6", "@babel/types": "^7.28.6" } }, "sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ=="], |
| 247 | 281 | ||
| 248 | "@babel/traverse": ["@babel/traverse@7.29.0", "", { "dependencies": { "@babel/code-frame": "^7.29.0", "@babel/generator": "^7.29.0", "@babel/helper-globals": "^7.28.0", "@babel/parser": "^7.29.0", "@babel/template": "^7.28.6", "@babel/types": "^7.29.0", "debug": "^4.3.1" } }, "sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA=="], | 282 | "@babel/traverse": ["@babel/traverse@7.29.0", "", { "dependencies": { "@babel/code-frame": "^7.29.0", "@babel/generator": "^7.29.0", "@babel/helper-globals": "^7.28.0", "@babel/parser": "^7.29.0", "@babel/template": "^7.28.6", "@babel/types": "^7.29.0", "debug": "^4.3.1" } }, "sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA=="], |
| 249 | 283 | ||
| 250 | "@babel/types": ["@babel/types@7.29.0", "", { "dependencies": { "@babel/helper-string-parser": "^7.27.1", "@babel/helper-validator-identifier": "^7.28.5" } }, "sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A=="], | 284 | "@babel/types": ["@babel/types@7.29.0", "", { "dependencies": { "@babel/helper-string-parser": "^7.27.1", "@babel/helper-validator-identifier": "^7.28.5" } }, "sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A=="], |
| 251 | 285 | ||
| 286 | "@base-ui/react": ["@base-ui/react@1.3.0", "", { "dependencies": { "@babel/runtime": "^7.28.6", "@base-ui/utils": "0.2.6", "@floating-ui/react-dom": "^2.1.8", "@floating-ui/utils": "^0.2.11", "tabbable": "^6.4.0", "use-sync-external-store": "^1.6.0" }, "peerDependencies": { "@types/react": "^17 || ^18 || ^19", "react": "^17 || ^18 || ^19", "react-dom": "^17 || ^18 || ^19" }, "optionalPeers": ["@types/react"] }, "sha512-FwpKqZbPz14AITp1CVgf4AjhKPe1OeeVKSBMdgD10zbFlj3QSWelmtCMLi2+/PFZZcIm3l87G7rwtCZJwHyXWA=="], | ||
| 287 | |||
| 288 | "@base-ui/utils": ["@base-ui/utils@0.2.6", "", { "dependencies": { "@babel/runtime": "^7.28.6", "@floating-ui/utils": "^0.2.11", "reselect": "^5.1.1", "use-sync-external-store": "^1.6.0" }, "peerDependencies": { "@types/react": "^17 || ^18 || ^19", "react": "^17 || ^18 || ^19", "react-dom": "^17 || ^18 || ^19" }, "optionalPeers": ["@types/react"] }, "sha512-yQ+qeuqohwhsNpoYDqqXaLllYAkPCP4vYdDrVo8FQXaAPfHWm1pG/Vm+jmGTA5JFS0BAIjookyapuJFY8F9PIw=="], | ||
| 289 | |||
| 290 | "@date-fns/tz": ["@date-fns/tz@1.4.1", "", {}, "sha512-P5LUNhtbj6YfI3iJjw5EL9eUAG6OitD0W3fWQcpQjDRc/QIsL0tRNuO1PcDvPccWL1fSTXXdE1ds+l95DV/OFA=="], | ||
| 291 | |||
| 252 | "@effect-atom/atom": ["@effect-atom/atom@0.5.3", "", { "peerDependencies": { "@effect/experimental": "^0.58.0", "@effect/platform": "^0.94.2", "@effect/rpc": "^0.73.0", "effect": "^3.19.15" } }, "sha512-TRZv/i+YT3TtnN0oFORJqXdxSs1fc7lrJlH+1xZvDFyjC9hgoVnrcKbeZsDFmr6r0wYRqVo7U3IftxiQNjpNZA=="], | 292 | "@effect-atom/atom": ["@effect-atom/atom@0.5.3", "", { "peerDependencies": { "@effect/experimental": "^0.58.0", "@effect/platform": "^0.94.2", "@effect/rpc": "^0.73.0", "effect": "^3.19.15" } }, "sha512-TRZv/i+YT3TtnN0oFORJqXdxSs1fc7lrJlH+1xZvDFyjC9hgoVnrcKbeZsDFmr6r0wYRqVo7U3IftxiQNjpNZA=="], |
| 253 | 293 | ||
| 254 | "@effect-atom/atom-react": ["@effect-atom/atom-react@0.5.0", "", { "dependencies": { "@effect-atom/atom": "^0.5.0" }, "peerDependencies": { "effect": "^3.19", "react": ">=18 <20", "scheduler": "*" } }, "sha512-aFfjWi4rEJCqfM12Oi36/EKaDm/W6n4/N6yM5vL0t/QozKhJhK05rQL/GY4XMxlH2eqkQ4ih8jBQa3Yyp0Fiqw=="], | 294 | "@effect-atom/atom-react": ["@effect-atom/atom-react@0.5.0", "", { "dependencies": { "@effect-atom/atom": "^0.5.0" }, "peerDependencies": { "effect": "^3.19", "react": ">=18 <20", "scheduler": "*" } }, "sha512-aFfjWi4rEJCqfM12Oi36/EKaDm/W6n4/N6yM5vL0t/QozKhJhK05rQL/GY4XMxlH2eqkQ4ih8jBQa3Yyp0Fiqw=="], |
| @@ -343,8 +383,20 @@ · 88 unmodified lines | |||
| 343 | 383 | ||
| 344 | "@executor/server": ["@executor/server@workspace:apps/server"], | 384 | "@executor/server": ["@executor/server@workspace:apps/server"], |
| 345 | 385 | ||
| 386 | "@executor/ui": ["@executor/ui@workspace:packages/ui"], | ||
| 387 | |||
| 346 | "@executor/web": ["@executor/web@workspace:apps/web"], | 388 | "@executor/web": ["@executor/web@workspace:apps/web"], |
| 347 | 389 | ||
| 390 | "@floating-ui/core": ["@floating-ui/core@1.7.5", "", { "dependencies": { "@floating-ui/utils": "^0.2.11" } }, "sha512-1Ih4WTWyw0+lKyFMcBHGbb5U5FtuHJuujoyyr5zTaWS5EYMeT6Jb2AuDeftsCsEuchO+mM2ij5+q9crhydzLhQ=="], | ||
| 391 | |||
| 392 | "@floating-ui/dom": ["@floating-ui/dom@1.7.6", "", { "dependencies": { "@floating-ui/core": "^1.7.5", "@floating-ui/utils": "^0.2.11" } }, "sha512-9gZSAI5XM36880PPMm//9dfiEngYoC6Am2izES1FF406YFsjvyBMmeJ2g4SAju3xWwtuynNRFL2s9hgxpLI5SQ=="], | ||
| 393 | |||
| 394 | "@floating-ui/react-dom": ["@floating-ui/react-dom@2.1.8", "", { "dependencies": { "@floating-ui/dom": "^1.7.6" }, "peerDependencies": { "react": ">=16.8.0", "react-dom": ">=16.8.0" } }, "sha512-cC52bHwM/n/CxS87FH0yWdngEZrjdtLW/qVruo68qg+prK7ZQ4YGdut2GyDVpoGeAYe/h899rVeOVm6Oi40k2A=="], | ||
| 395 | |||
| 396 | "@floating-ui/utils": ["@floating-ui/utils@0.2.11", "", {}, "sha512-RiB/yIh78pcIxl6lLMG0CgBXAZ2Y0eVHqMPYugu+9U0AeT6YBeiJpf7lbdJNIugFP5SIjwNRgo4DhR1Qxi26Gg=="], | ||
| 397 | |||
| 398 | "@hookform/resolvers": ["@hookform/resolvers@5.2.2", "", { "dependencies": { "@standard-schema/utils": "^0.3.0" }, "peerDependencies": { "react-hook-form": "^7.55.0" } }, "sha512-A/IxlMLShx3KjV/HeTcTfaMxdwy690+L/ZADoeaTltLx+CVuzkeVIPuybK3jrRfw7YZnmdKsVVHAlEPIAEUNlA=="], | ||
| 399 | |||
| 348 | "@jitl/quickjs-ffi-types": ["@jitl/quickjs-ffi-types@0.31.0", "", {}, "sha512-1yrgvXlmXH2oNj3eFTrkwacGJbmM0crwipA3ohCrjv52gBeDaD7PsTvFYinlAnqU8iPME3LGP437yk05a2oejw=="], | 400 | "@jitl/quickjs-ffi-types": ["@jitl/quickjs-ffi-types@0.31.0", "", {}, "sha512-1yrgvXlmXH2oNj3eFTrkwacGJbmM0crwipA3ohCrjv52gBeDaD7PsTvFYinlAnqU8iPME3LGP437yk05a2oejw=="], |
| 349 | 401 | ||
| 350 | "@jitl/quickjs-wasmfile-debug-asyncify": ["@jitl/quickjs-wasmfile-debug-asyncify@0.31.0", "", { "dependencies": { "@jitl/quickjs-ffi-types": "0.31.0" } }, "sha512-YkdzQdr1uaftFhgEnTRjTTZHk2SFZdpWO7XhOmRVbi6CEVsH9g5oNF8Ta1q3OuSJHRwwT8YsuR1YzEiEIJEk6w=="], | 402 | "@jitl/quickjs-wasmfile-debug-asyncify": ["@jitl/quickjs-wasmfile-debug-asyncify@0.31.0", "", { "dependencies": { "@jitl/quickjs-ffi-types": "0.31.0" } }, "sha512-YkdzQdr1uaftFhgEnTRjTTZHk2SFZdpWO7XhOmRVbi6CEVsH9g5oNF8Ta1q3OuSJHRwwT8YsuR1YzEiEIJEk6w=="], |
| @@ -469,6 +521,128 @@ · 118 unmodified lines | |||
| 469 | 521 | ||
| 470 | "@parcel/watcher-win32-x64": ["@parcel/watcher-win32-x64@2.5.6", "", { "os": "win32", "cpu": "x64" }, "sha512-hbQlYcCq5dlAX9Qx+kFb0FHue6vbjlf0FrNzSKdYK2APUf7tGfGxQCk2ihEREmbR6ZMc0MVAD5RIX/41gpUzTw=="], | 522 | "@parcel/watcher-win32-x64": ["@parcel/watcher-win32-x64@2.5.6", "", { "os": "win32", "cpu": "x64" }, "sha512-hbQlYcCq5dlAX9Qx+kFb0FHue6vbjlf0FrNzSKdYK2APUf7tGfGxQCk2ihEREmbR6ZMc0MVAD5RIX/41gpUzTw=="], |
| 471 | 523 | ||
| 524 | "@radix-ui/number": ["@radix-ui/number@1.1.1", "", {}, "sha512-MkKCwxlXTgz6CFoJx3pCwn07GKp36+aZyu/u2Ln2VrA5DcdyCZkASEDBTd8x5whTQQL5CiYf4prXKLcgQdv29g=="], | ||
| 525 | |||
| 526 | "@radix-ui/primitive": ["@radix-ui/primitive@1.1.3", "", {}, "sha512-JTF99U/6XIjCBo0wqkU5sK10glYe27MRRsfwoiq5zzOEZLHU3A3KCMa5X/azekYRCJ0HlwI0crAXS/5dEHTzDg=="], | ||
| 527 | |||
| 528 | "@radix-ui/react-accessible-icon": ["@radix-ui/react-accessible-icon@1.1.7", "", { "dependencies": { "@radix-ui/react-visually-hidden": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-XM+E4WXl0OqUJFovy6GjmxxFyx9opfCAIUku4dlKRd5YEPqt4kALOkQOp0Of6reHuUkJuiPBEc5k0o4z4lTC8A=="], | ||
| 529 | |||
| 530 | "@radix-ui/react-accordion": ["@radix-ui/react-accordion@1.2.12", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-collapsible": "1.1.12", "@radix-ui/react-collection": "1.1.7", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-controllable-state": "1.2.2" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-T4nygeh9YE9dLRPhAHSeOZi7HBXo+0kYIPJXayZfvWOWA0+n3dESrZbjfDPUABkUNym6Hd+f2IR113To8D2GPA=="], | ||
| 531 | |||
| 532 | "@radix-ui/react-alert-dialog": ["@radix-ui/react-alert-dialog@1.1.15", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-dialog": "1.1.15", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-slot": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-oTVLkEw5GpdRe29BqJ0LSDFWI3qu0vR1M0mUkOQWDIUnY/QIkLpgDMWuKxP94c2NAC2LGcgVhG1ImF3jkZ5wXw=="], | ||
| 533 | |||
| 534 | "@radix-ui/react-arrow": ["@radix-ui/react-arrow@1.1.7", "", { "dependencies": { "@radix-ui/react-primitive": "2.1.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-F+M1tLhO+mlQaOWspE8Wstg+z6PwxwRd8oQ8IXceWz92kfAmalTRf0EjrouQeo7QssEPfCn05B4Ihs1K9WQ/7w=="], | ||
| 535 | |||
| 536 | "@radix-ui/react-aspect-ratio": ["@radix-ui/react-aspect-ratio@1.1.7", "", { "dependencies": { "@radix-ui/react-primitive": "2.1.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-Yq6lvO9HQyPwev1onK1daHCHqXVLzPhSVjmsNjCa2Zcxy2f7uJD2itDtxknv6FzAKCwD1qQkeVDmX/cev13n/g=="], | ||
| 537 | |||
| 538 | "@radix-ui/react-avatar": ["@radix-ui/react-avatar@1.1.10", "", { "dependencies": { "@radix-ui/react-context": "1.1.2", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-callback-ref": "1.1.1", "@radix-ui/react-use-is-hydrated": "0.1.0", "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-V8piFfWapM5OmNCXTzVQY+E1rDa53zY+MQ4Y7356v4fFz6vqCyUtIz2rUD44ZEdwg78/jKmMJHj07+C/Z/rcog=="], | ||
| 539 | |||
| 540 | "@radix-ui/react-checkbox": ["@radix-ui/react-checkbox@1.3.3", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-presence": "1.1.5", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-controllable-state": "1.2.2", "@radix-ui/react-use-previous": "1.1.1", "@radix-ui/react-use-size": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-wBbpv+NQftHDdG86Qc0pIyXk5IR3tM8Vd0nWLKDcX8nNn4nXFOFwsKuqw2okA/1D/mpaAkmuyndrPJTYDNZtFw=="], | ||
| 541 | |||
| 542 | "@radix-ui/react-collapsible": ["@radix-ui/react-collapsible@1.1.12", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-presence": "1.1.5", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-controllable-state": "1.2.2", "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-Uu+mSh4agx2ib1uIGPP4/CKNULyajb3p92LsVXmH2EHVMTfZWpll88XJ0j4W0z3f8NK1eYl1+Mf/szHPmcHzyA=="], | ||
| 543 | |||
| 544 | "@radix-ui/react-collection": ["@radix-ui/react-collection@1.1.7", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-slot": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-Fh9rGN0MoI4ZFUNyfFVNU4y9LUz93u9/0K+yLgA2bwRojxM8JU1DyvvMBabnZPBgMWREAJvU2jjVzq+LrFUglw=="], | ||
| 545 | |||
| 546 | "@radix-ui/react-compose-refs": ["@radix-ui/react-compose-refs@1.1.2", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg=="], | ||
| 547 | |||
| 548 | "@radix-ui/react-context": ["@radix-ui/react-context@1.1.2", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-jCi/QKUM2r1Ju5a3J64TH2A5SpKAgh0LpknyqdQ4m6DCV0xJ2HG1xARRwNGPQfi1SLdLWZ1OJz6F4OMBBNiGJA=="], | ||
| 549 | |||
| 550 | "@radix-ui/react-context-menu": ["@radix-ui/react-context-menu@2.2.16", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-menu": "2.1.16", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-callback-ref": "1.1.1", "@radix-ui/react-use-controllable-state": "1.2.2" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-O8morBEW+HsVG28gYDZPTrT9UUovQUlJue5YO836tiTJhuIWBm/zQHc7j388sHWtdH/xUZurK9olD2+pcqx5ww=="], | ||
| 551 | |||
| 552 | "@radix-ui/react-dialog": ["@radix-ui/react-dialog@1.1.15", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-dismissable-layer": "1.1.11", "@radix-ui/react-focus-guards": "1.1.3", "@radix-ui/react-focus-scope": "1.1.7", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-portal": "1.1.9", "@radix-ui/react-presence": "1.1.5", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-slot": "1.2.3", "@radix-ui/react-use-controllable-state": "1.2.2", "aria-hidden": "^1.2.4", "react-remove-scroll": "^2.6.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-TCglVRtzlffRNxRMEyR36DGBLJpeusFcgMVD9PZEzAKnUs1lKCgX5u9BmC2Yg+LL9MgZDugFFs1Vl+Jp4t/PGw=="], | ||
| 553 | |||
| 554 | "@radix-ui/react-direction": ["@radix-ui/react-direction@1.1.1", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-1UEWRX6jnOA2y4H5WczZ44gOOjTEmlqv1uNW4GAJEO5+bauCBhv8snY65Iw5/VOS/ghKN9gr2KjnLKxrsvoMVw=="], | ||
| 555 | |||
| 556 | "@radix-ui/react-dismissable-layer": ["@radix-ui/react-dismissable-layer@1.1.11", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-callback-ref": "1.1.1", "@radix-ui/react-use-escape-keydown": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-Nqcp+t5cTB8BinFkZgXiMJniQH0PsUt2k51FUhbdfeKvc4ACcG2uQniY/8+h1Yv6Kza4Q7lD7PQV0z0oicE0Mg=="], | ||
| 557 | |||
| 558 | "@radix-ui/react-dropdown-menu": ["@radix-ui/react-dropdown-menu@2.1.16", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-menu": "2.1.16", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-controllable-state": "1.2.2" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-1PLGQEynI/3OX/ftV54COn+3Sud/Mn8vALg2rWnBLnRaGtJDduNW/22XjlGgPdpcIbiQxjKtb7BkcjP00nqfJw=="], | ||
| 559 | |||
| 560 | "@radix-ui/react-focus-guards": ["@radix-ui/react-focus-guards@1.1.3", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-0rFg/Rj2Q62NCm62jZw0QX7a3sz6QCQU0LpZdNrJX8byRGaGVTqbrW9jAoIAHyMQqsNpeZ81YgSizOt5WXq0Pw=="], | ||
| 561 | |||
| 562 | "@radix-ui/react-focus-scope": ["@radix-ui/react-focus-scope@1.1.7", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-callback-ref": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-t2ODlkXBQyn7jkl6TNaw/MtVEVvIGelJDCG41Okq/KwUsJBwQ4XVZsHAVUkK4mBv3ewiAS3PGuUWuY2BoK4ZUw=="], | ||
| 563 | |||
| 564 | "@radix-ui/react-form": ["@radix-ui/react-form@0.1.8", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-label": "2.1.7", "@radix-ui/react-primitive": "2.1.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-QM70k4Zwjttifr5a4sZFts9fn8FzHYvQ5PiB19O2HsYibaHSVt9fH9rzB0XZo/YcM+b7t/p7lYCT/F5eOeF5yQ=="], | ||
| 565 | |||
| 566 | "@radix-ui/react-hover-card": ["@radix-ui/react-hover-card@1.1.15", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-dismissable-layer": "1.1.11", "@radix-ui/react-popper": "1.2.8", "@radix-ui/react-portal": "1.1.9", "@radix-ui/react-presence": "1.1.5", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-controllable-state": "1.2.2" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-qgTkjNT1CfKMoP0rcasmlH2r1DAiYicWsDsufxl940sT2wHNEWWv6FMWIQXWhVdmC1d/HYfbhQx60KYyAtKxjg=="], | ||
| 567 | |||
| 568 | "@radix-ui/react-id": ["@radix-ui/react-id@1.1.1", "", { "dependencies": { "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-kGkGegYIdQsOb4XjsfM97rXsiHaBwco+hFI66oO4s9LU+PLAC5oJ7khdOVFxkhsmlbpUqDAvXw11CluXP+jkHg=="], | ||
| 569 | |||
| 570 | "@radix-ui/react-label": ["@radix-ui/react-label@2.1.7", "", { "dependencies": { "@radix-ui/react-primitive": "2.1.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-YT1GqPSL8kJn20djelMX7/cTRp/Y9w5IZHvfxQTVHrOqa2yMl7i/UfMqKRU5V7mEyKTrUVgJXhNQPVCG8PBLoQ=="], | ||
| 571 | |||
| 572 | "@radix-ui/react-menu": ["@radix-ui/react-menu@2.1.16", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-collection": "1.1.7", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-dismissable-layer": "1.1.11", "@radix-ui/react-focus-guards": "1.1.3", "@radix-ui/react-focus-scope": "1.1.7", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-popper": "1.2.8", "@radix-ui/react-portal": "1.1.9", "@radix-ui/react-presence": "1.1.5", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-roving-focus": "1.1.11", "@radix-ui/react-slot": "1.2.3", "@radix-ui/react-use-callback-ref": "1.1.1", "aria-hidden": "^1.2.4", "react-remove-scroll": "^2.6.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-72F2T+PLlphrqLcAotYPp0uJMr5SjP5SL01wfEspJbru5Zs5vQaSHb4VB3ZMJPimgHHCHG7gMOeOB9H3Hdmtxg=="], | ||
| 573 | |||
| 574 | "@radix-ui/react-menubar": ["@radix-ui/react-menubar@1.1.16", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-collection": "1.1.7", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-menu": "2.1.16", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-roving-focus": "1.1.11", "@radix-ui/react-use-controllable-state": "1.2.2" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-EB1FktTz5xRRi2Er974AUQZWg2yVBb1yjip38/lgwtCVRd3a+maUoGHN/xs9Yv8SY8QwbSEb+YrxGadVWbEutA=="], | ||
| 575 | |||
| 576 | "@radix-ui/react-navigation-menu": ["@radix-ui/react-navigation-menu@1.2.14", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-collection": "1.1.7", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-dismissable-layer": "1.1.11", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-presence": "1.1.5", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-callback-ref": "1.1.1", "@radix-ui/react-use-controllable-state": "1.2.2", "@radix-ui/react-use-layout-effect": "1.1.1", "@radix-ui/react-use-previous": "1.1.1", "@radix-ui/react-visually-hidden": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-YB9mTFQvCOAQMHU+C/jVl96WmuWeltyUEpRJJky51huhds5W2FQr1J8D/16sQlf0ozxkPK8uF3niQMdUwZPv5w=="], | ||
| 577 | |||
| 578 | "@radix-ui/react-one-time-password-field": ["@radix-ui/react-one-time-password-field@0.1.8", "", { "dependencies": { "@radix-ui/number": "1.1.1", "@radix-ui/primitive": "1.1.3", "@radix-ui/react-collection": "1.1.7", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-roving-focus": "1.1.11", "@radix-ui/react-use-controllable-state": "1.2.2", "@radix-ui/react-use-effect-event": "0.0.2", "@radix-ui/react-use-is-hydrated": "0.1.0", "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-ycS4rbwURavDPVjCb5iS3aG4lURFDILi6sKI/WITUMZ13gMmn/xGjpLoqBAalhJaDk8I3UbCM5GzKHrnzwHbvg=="], | ||
| 579 | |||
| 580 | "@radix-ui/react-password-toggle-field": ["@radix-ui/react-password-toggle-field@0.1.3", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-controllable-state": "1.2.2", "@radix-ui/react-use-effect-event": "0.0.2", "@radix-ui/react-use-is-hydrated": "0.1.0" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-/UuCrDBWravcaMix4TdT+qlNdVwOM1Nck9kWx/vafXsdfj1ChfhOdfi3cy9SGBpWgTXwYCuboT/oYpJy3clqfw=="], | ||
| 581 | |||
| 582 | "@radix-ui/react-popover": ["@radix-ui/react-popover@1.1.15", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-dismissable-layer": "1.1.11", "@radix-ui/react-focus-guards": "1.1.3", "@radix-ui/react-focus-scope": "1.1.7", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-popper": "1.2.8", "@radix-ui/react-portal": "1.1.9", "@radix-ui/react-presence": "1.1.5", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-slot": "1.2.3", "@radix-ui/react-use-controllable-state": "1.2.2", "aria-hidden": "^1.2.4", "react-remove-scroll": "^2.6.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-kr0X2+6Yy/vJzLYJUPCZEc8SfQcf+1COFoAqauJm74umQhta9M7lNJHP7QQS3vkvcGLQUbWpMzwrXYwrYztHKA=="], | ||
| 583 | |||
| 584 | "@radix-ui/react-popper": ["@radix-ui/react-popper@1.2.8", "", { "dependencies": { "@floating-ui/react-dom": "^2.0.0", "@radix-ui/react-arrow": "1.1.7", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-callback-ref": "1.1.1", "@radix-ui/react-use-layout-effect": "1.1.1", "@radix-ui/react-use-rect": "1.1.1", "@radix-ui/react-use-size": "1.1.1", "@radix-ui/rect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-0NJQ4LFFUuWkE7Oxf0htBKS6zLkkjBH+hM1uk7Ng705ReR8m/uelduy1DBo0PyBXPKVnBA6YBlU94MBGXrSBCw=="], | ||
| 585 | |||
| 586 | "@radix-ui/react-portal": ["@radix-ui/react-portal@1.1.9", "", { "dependencies": { "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-bpIxvq03if6UNwXZ+HTK71JLh4APvnXntDc6XOX8UVq4XQOVl7lwok0AvIl+b8zgCw3fSaVTZMpAPPagXbKmHQ=="], | ||
| 587 | |||
| 588 | "@radix-ui/react-presence": ["@radix-ui/react-presence@1.1.5", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-/jfEwNDdQVBCNvjkGit4h6pMOzq8bHkopq458dPt2lMjx+eBQUohZNG9A7DtO/O5ukSbxuaNGXMjHicgwy6rQQ=="], | ||
| 589 | |||
| 590 | "@radix-ui/react-primitive": ["@radix-ui/react-primitive@2.1.3", "", { "dependencies": { "@radix-ui/react-slot": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ=="], | ||
| 591 | |||
| 592 | "@radix-ui/react-progress": ["@radix-ui/react-progress@1.1.7", "", { "dependencies": { "@radix-ui/react-context": "1.1.2", "@radix-ui/react-primitive": "2.1.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-vPdg/tF6YC/ynuBIJlk1mm7Le0VgW6ub6J2UWnTQ7/D23KXcPI1qy+0vBkgKgd38RCMJavBXpB83HPNFMTb0Fg=="], | ||
| 593 | |||
| 594 | "@radix-ui/react-radio-group": ["@radix-ui/react-radio-group@1.3.8", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-presence": "1.1.5", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-roving-focus": "1.1.11", "@radix-ui/react-use-controllable-state": "1.2.2", "@radix-ui/react-use-previous": "1.1.1", "@radix-ui/react-use-size": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-VBKYIYImA5zsxACdisNQ3BjCBfmbGH3kQlnFVqlWU4tXwjy7cGX8ta80BcrO+WJXIn5iBylEH3K6ZTlee//lgQ=="], | ||
| 595 | |||
| 596 | "@radix-ui/react-roving-focus": ["@radix-ui/react-roving-focus@1.1.11", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-collection": "1.1.7", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-callback-ref": "1.1.1", "@radix-ui/react-use-controllable-state": "1.2.2" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-7A6S9jSgm/S+7MdtNDSb+IU859vQqJ/QAtcYQcfFC6W8RS4IxIZDldLR0xqCFZ6DCyrQLjLPsxtTNch5jVA4lA=="], | ||
| 597 | |||
| 598 | "@radix-ui/react-scroll-area": ["@radix-ui/react-scroll-area@1.2.10", "", { "dependencies": { "@radix-ui/number": "1.1.1", "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-presence": "1.1.5", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-callback-ref": "1.1.1", "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-tAXIa1g3sM5CGpVT0uIbUx/U3Gs5N8T52IICuCtObaos1S8fzsrPXG5WObkQN3S6NVl6wKgPhAIiBGbWnvc97A=="], | ||
| 599 | |||
| 600 | "@radix-ui/react-select": ["@radix-ui/react-select@2.2.6", "", { "dependencies": { "@radix-ui/number": "1.1.1", "@radix-ui/primitive": "1.1.3", "@radix-ui/react-collection": "1.1.7", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-dismissable-layer": "1.1.11", "@radix-ui/react-focus-guards": "1.1.3", "@radix-ui/react-focus-scope": "1.1.7", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-popper": "1.2.8", "@radix-ui/react-portal": "1.1.9", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-slot": "1.2.3", "@radix-ui/react-use-callback-ref": "1.1.1", "@radix-ui/react-use-controllable-state": "1.2.2", "@radix-ui/react-use-layout-effect": "1.1.1", "@radix-ui/react-use-previous": "1.1.1", "@radix-ui/react-visually-hidden": "1.2.3", "aria-hidden": "^1.2.4", "react-remove-scroll": "^2.6.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-I30RydO+bnn2PQztvo25tswPH+wFBjehVGtmagkU78yMdwTwVf12wnAOF+AeP8S2N8xD+5UPbGhkUfPyvT+mwQ=="], | ||
| 601 | |||
| 602 | "@radix-ui/react-separator": ["@radix-ui/react-separator@1.1.7", "", { "dependencies": { "@radix-ui/react-primitive": "2.1.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-0HEb8R9E8A+jZjvmFCy/J4xhbXy3TV+9XSnGJ3KvTtjlIUy/YQ/p6UYZvi7YbeoeXdyU9+Y3scizK6hkY37baA=="], | ||
| 603 | |||
| 604 | "@radix-ui/react-slider": ["@radix-ui/react-slider@1.3.6", "", { "dependencies": { "@radix-ui/number": "1.1.1", "@radix-ui/primitive": "1.1.3", "@radix-ui/react-collection": "1.1.7", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-controllable-state": "1.2.2", "@radix-ui/react-use-layout-effect": "1.1.1", "@radix-ui/react-use-previous": "1.1.1", "@radix-ui/react-use-size": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-JPYb1GuM1bxfjMRlNLE+BcmBC8onfCi60Blk7OBqi2MLTFdS+8401U4uFjnwkOr49BLmXxLC6JHkvAsx5OJvHw=="], | ||
| 605 | |||
| 606 | "@radix-ui/react-slot": ["@radix-ui/react-slot@1.2.3", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A=="], | ||
| 607 | |||
| 608 | "@radix-ui/react-switch": ["@radix-ui/react-switch@1.2.6", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-controllable-state": "1.2.2", "@radix-ui/react-use-previous": "1.1.1", "@radix-ui/react-use-size": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-bByzr1+ep1zk4VubeEVViV592vu2lHE2BZY5OnzehZqOOgogN80+mNtCqPkhn2gklJqOpxWgPoYTSnhBCqpOXQ=="], | ||
| 609 | |||
| 610 | "@radix-ui/react-tabs": ["@radix-ui/react-tabs@1.1.13", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-presence": "1.1.5", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-roving-focus": "1.1.11", "@radix-ui/react-use-controllable-state": "1.2.2" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-7xdcatg7/U+7+Udyoj2zodtI9H/IIopqo+YOIcZOq1nJwXWBZ9p8xiu5llXlekDbZkca79a/fozEYQXIA4sW6A=="], | ||
| 611 | |||
| 612 | "@radix-ui/react-toast": ["@radix-ui/react-toast@1.2.15", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-collection": "1.1.7", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-dismissable-layer": "1.1.11", "@radix-ui/react-portal": "1.1.9", "@radix-ui/react-presence": "1.1.5", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-callback-ref": "1.1.1", "@radix-ui/react-use-controllable-state": "1.2.2", "@radix-ui/react-use-layout-effect": "1.1.1", "@radix-ui/react-visually-hidden": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-3OSz3TacUWy4WtOXV38DggwxoqJK4+eDkNMl5Z/MJZaoUPaP4/9lf81xXMe1I2ReTAptverZUpbPY4wWwWyL5g=="], | ||
| 613 | |||
| 614 | "@radix-ui/react-toggle": ["@radix-ui/react-toggle@1.1.10", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-controllable-state": "1.2.2" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-lS1odchhFTeZv3xwHH31YPObmJn8gOg7Lq12inrr0+BH/l3Tsq32VfjqH1oh80ARM3mlkfMic15n0kg4sD1poQ=="], | ||
| 615 | |||
| 616 | "@radix-ui/react-toggle-group": ["@radix-ui/react-toggle-group@1.1.11", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-roving-focus": "1.1.11", "@radix-ui/react-toggle": "1.1.10", "@radix-ui/react-use-controllable-state": "1.2.2" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-5umnS0T8JQzQT6HbPyO7Hh9dgd82NmS36DQr+X/YJ9ctFNCiiQd6IJAYYZ33LUwm8M+taCz5t2ui29fHZc4Y6Q=="], | ||
| 617 | |||
| 618 | "@radix-ui/react-toolbar": ["@radix-ui/react-toolbar@1.1.11", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-roving-focus": "1.1.11", "@radix-ui/react-separator": "1.1.7", "@radix-ui/react-toggle-group": "1.1.11" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-4ol06/1bLoFu1nwUqzdD4Y5RZ9oDdKeiHIsntug54Hcr1pgaHiPqHFEaXI1IFP/EsOfROQZ8Mig9VTIRza6Tjg=="], | ||
| 619 | |||
| 620 | "@radix-ui/react-tooltip": ["@radix-ui/react-tooltip@1.2.8", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-dismissable-layer": "1.1.11", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-popper": "1.2.8", "@radix-ui/react-portal": "1.1.9", "@radix-ui/react-presence": "1.1.5", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-slot": "1.2.3", "@radix-ui/react-use-controllable-state": "1.2.2", "@radix-ui/react-visually-hidden": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-tY7sVt1yL9ozIxvmbtN5qtmH2krXcBCfjEiCgKGLqunJHvgvZG2Pcl2oQ3kbcZARb1BGEHdkLzcYGO8ynVlieg=="], | ||
| 621 | |||
| 622 | "@radix-ui/react-use-callback-ref": ["@radix-ui/react-use-callback-ref@1.1.1", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-FkBMwD+qbGQeMu1cOHnuGB6x4yzPjho8ap5WtbEJ26umhgqVXbhekKUQO+hZEL1vU92a3wHwdp0HAcqAUF5iDg=="], | ||
| 623 | |||
| 624 | "@radix-ui/react-use-controllable-state": ["@radix-ui/react-use-controllable-state@1.2.2", "", { "dependencies": { "@radix-ui/react-use-effect-event": "0.0.2", "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-BjasUjixPFdS+NKkypcyyN5Pmg83Olst0+c6vGov0diwTEo6mgdqVR6hxcEgFuh4QrAs7Rc+9KuGJ9TVCj0Zzg=="], | ||
| 625 | |||
| 626 | "@radix-ui/react-use-effect-event": ["@radix-ui/react-use-effect-event@0.0.2", "", { "dependencies": { "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-Qp8WbZOBe+blgpuUT+lw2xheLP8q0oatc9UpmiemEICxGvFLYmHm9QowVZGHtJlGbS6A6yJ3iViad/2cVjnOiA=="], | ||
| 627 | |||
| 628 | "@radix-ui/react-use-escape-keydown": ["@radix-ui/react-use-escape-keydown@1.1.1", "", { "dependencies": { "@radix-ui/react-use-callback-ref": "1.1.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-Il0+boE7w/XebUHyBjroE+DbByORGR9KKmITzbR7MyQ4akpORYP/ZmbhAr0DG7RmmBqoOnZdy2QlvajJ2QA59g=="], | ||
| 629 | |||
| 630 | "@radix-ui/react-use-is-hydrated": ["@radix-ui/react-use-is-hydrated@0.1.0", "", { "dependencies": { "use-sync-external-store": "^1.5.0" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-U+UORVEq+cTnRIaostJv9AGdV3G6Y+zbVd+12e18jQ5A3c0xL03IhnHuiU4UV69wolOQp5GfR58NW/EgdQhwOA=="], | ||
| 631 | |||
| 632 | "@radix-ui/react-use-layout-effect": ["@radix-ui/react-use-layout-effect@1.1.1", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ=="], | ||
| 633 | |||
| 634 | "@radix-ui/react-use-previous": ["@radix-ui/react-use-previous@1.1.1", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-2dHfToCj/pzca2Ck724OZ5L0EVrr3eHRNsG/b3xQJLA2hZpVCS99bLAX+hm1IHXDEnzU6by5z/5MIY794/a8NQ=="], | ||
| 635 | |||
| 636 | "@radix-ui/react-use-rect": ["@radix-ui/react-use-rect@1.1.1", "", { "dependencies": { "@radix-ui/rect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-QTYuDesS0VtuHNNvMh+CjlKJ4LJickCMUAqjlE3+j8w+RlRpwyX3apEQKGFzbZGdo7XNG1tXa+bQqIE7HIXT2w=="], | ||
| 637 | |||
| 638 | "@radix-ui/react-use-size": ["@radix-ui/react-use-size@1.1.1", "", { "dependencies": { "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-ewrXRDTAqAXlkl6t/fkXWNAhFX9I+CkKlw6zjEwk86RSPKwZr3xpBRso655aqYafwtnbpHLj6toFzmd6xdVptQ=="], | ||
| 639 | |||
| 640 | "@radix-ui/react-visually-hidden": ["@radix-ui/react-visually-hidden@1.2.3", "", { "dependencies": { "@radix-ui/react-primitive": "2.1.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-pzJq12tEaaIhqjbzpCuv/OypJY/BPavOofm+dbab+MHLajy277+1lLm6JFcGgF5eskJ6mquGirhXY2GD/8u8Ug=="], | ||
| 641 | |||
| 642 | "@radix-ui/rect": ["@radix-ui/rect@1.1.1", "", {}, "sha512-HPwpGIzkl28mWyZqG52jiqDJ12waP11Pa1lGoiyUkIEuMLBP0oeK/C89esbXrxsky5we7dfd8U58nm0SgAWpVw=="], | ||
| 643 | |||
| 644 | "@reduxjs/toolkit": ["@reduxjs/toolkit@2.11.2", "", { "dependencies": { "@standard-schema/spec": "^1.0.0", "@standard-schema/utils": "^0.3.0", "immer": "^11.0.0", "redux": "^5.0.1", "redux-thunk": "^3.1.0", "reselect": "^5.1.0" }, "peerDependencies": { "react": "^16.9.0 || ^17.0.0 || ^18 || ^19", "react-redux": "^7.2.1 || ^8.1.3 || ^9.0.0" }, "optionalPeers": ["react", "react-redux"] }, "sha512-Kd6kAHTA6/nUpp8mySPqj3en3dm0tdMIgbttnQ1xFMVpufoj+ADi8pXLBsd4xzTRHQa7t/Jv8W5UnCuW4kuWMQ=="], | ||
| 645 | |||
| 472 | "@rolldown/pluginutils": ["@rolldown/pluginutils@1.0.0-beta.27", "", {}, "sha512-+d0F4MKMCbeVUJwG96uQ4SgAznZNSq93I3V+9NHA4OpvqG8mRCpGdKmK8l/dl02h2CCDHwW2FqilnTyDcAnqjA=="], | 646 | "@rolldown/pluginutils": ["@rolldown/pluginutils@1.0.0-beta.27", "", {}, "sha512-+d0F4MKMCbeVUJwG96uQ4SgAznZNSq93I3V+9NHA4OpvqG8mRCpGdKmK8l/dl02h2CCDHwW2FqilnTyDcAnqjA=="], |
| 473 | 647 | ||
| 474 | "@rollup/rollup-android-arm-eabi": ["@rollup/rollup-android-arm-eabi@4.60.1", "", { "os": "android", "cpu": "arm" }, "sha512-d6FinEBLdIiK+1uACUttJKfgZREXrF0Qc2SmLII7W2AD8FfiZ9Wjd+rD/iRuf5s5dWrr1GgwXCvPqOuDquOowA=="], | 648 | "@rollup/rollup-android-arm-eabi": ["@rollup/rollup-android-arm-eabi@4.60.1", "", { "os": "android", "cpu": "arm" }, "sha512-d6FinEBLdIiK+1uACUttJKfgZREXrF0Qc2SmLII7W2AD8FfiZ9Wjd+rD/iRuf5s5dWrr1GgwXCvPqOuDquOowA=="], |
| @@ -523,6 +697,10 @@ · 48 unmodified lines | |||
| 523 | 697 | ||
| 524 | "@standard-schema/spec": ["@standard-schema/spec@1.1.0", "", {}, "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w=="], | 698 | "@standard-schema/spec": ["@standard-schema/spec@1.1.0", "", {}, "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w=="], |
| 525 | 699 | ||
| 700 | "@standard-schema/utils": ["@standard-schema/utils@0.3.0", "", {}, "sha512-e7Mew686owMaPJVNNLs55PUvgz371nKgwsc4vxE49zsODpJEnxgxRo2y/OKrqueavXgZNMDVj3DdHFlaSAeU8g=="], | ||
| 701 | |||
| 702 | "@tabby_ai/hijri-converter": ["@tabby_ai/hijri-converter@1.0.5", "", {}, "sha512-r5bClKrcIusDoo049dSL8CawnHR6mRdDwhlQuIgZRNty68q0x8k3Lf1BtPAMxRf/GgnHBnIO4ujd3+GQdLWzxQ=="], | ||
| 703 | |||
| 526 | "@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=="], | 704 | "@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=="], |
| 527 | 705 | ||
| 528 | "@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=="], | 706 | "@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=="], |
| @@ -585,6 +763,24 @@ · 56 unmodified lines | |||
| 585 | 763 | ||
| 586 | "@types/chai": ["@types/chai@5.2.3", "", { "dependencies": { "@types/deep-eql": "*", "assertion-error": "^2.0.1" } }, "sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA=="], | 764 | "@types/chai": ["@types/chai@5.2.3", "", { "dependencies": { "@types/deep-eql": "*", "assertion-error": "^2.0.1" } }, "sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA=="], |
| 587 | 765 | ||
| 766 | "@types/d3-array": ["@types/d3-array@3.2.2", "", {}, "sha512-hOLWVbm7uRza0BYXpIIW5pxfrKe0W+D5lrFiAEYR+pb6w3N2SwSMaJbXdUfSEv+dT4MfHBLtn5js0LAWaO6otw=="], | ||
| 767 | |||
| 768 | "@types/d3-color": ["@types/d3-color@3.1.3", "", {}, "sha512-iO90scth9WAbmgv7ogoq57O9YpKmFBbmoEoCHDB2xMBY0+/KVrqAaCDyCE16dUspeOvIxFFRI+0sEtqDqy2b4A=="], | ||
| 769 | |||
| 770 | "@types/d3-ease": ["@types/d3-ease@3.0.2", "", {}, "sha512-NcV1JjO5oDzoK26oMzbILE6HW7uVXOHLQvHshBUW4UMdZGfiY6v5BeQwh9a9tCzv+CeefZQHJt5SRgK154RtiA=="], | ||
| 771 | |||
| 772 | "@types/d3-interpolate": ["@types/d3-interpolate@3.0.4", "", { "dependencies": { "@types/d3-color": "*" } }, "sha512-mgLPETlrpVV1YRJIglr4Ez47g7Yxjl1lj7YKsiMCb27VJH9W8NVM6Bb9d8kkpG/uAQS5AmbA48q2IAolKKo1MA=="], | ||
| 773 | |||
| 774 | "@types/d3-path": ["@types/d3-path@3.1.1", "", {}, "sha512-VMZBYyQvbGmWyWVea0EHs/BwLgxc+MKi1zLDCONksozI4YJMcTt8ZEuIR4Sb1MMTE8MMW49v0IwI5+b7RmfWlg=="], | ||
| 775 | |||
| 776 | "@types/d3-scale": ["@types/d3-scale@4.0.9", "", { "dependencies": { "@types/d3-time": "*" } }, "sha512-dLmtwB8zkAeO/juAMfnV+sItKjlsw2lKdZVVy6LRr0cBmegxSABiLEpGVmSJJ8O08i4+sGR6qQtb6WtuwJdvVw=="], | ||
| 777 | |||
| 778 | "@types/d3-shape": ["@types/d3-shape@3.1.8", "", { "dependencies": { "@types/d3-path": "*" } }, "sha512-lae0iWfcDeR7qt7rA88BNiqdvPS5pFVPpo5OfjElwNaT2yyekbM0C9vK+yqBqEmHr6lDkRnYNoTBYlAgJa7a4w=="], | ||
| 779 | |||
| 780 | "@types/d3-time": ["@types/d3-time@3.0.4", "", {}, "sha512-yuzZug1nkAAaBlBBikKZTgzCeA+k1uy4ZFwWANOfKw5z5LRhV0gNA7gNkKm7HoK+HRN0wX3EkxGk0fpbWhmB7g=="], | ||
| 781 | |||
| 782 | "@types/d3-timer": ["@types/d3-timer@3.0.2", "", {}, "sha512-Ps3T8E8dZDam6fUyNiMkekK3XUsaUEik+idO9/YjPtfj2qruF8tFBXS7XhtE4iIXBLxhmLjP3SXpLhVf21I9Lw=="], | ||
| 783 | |||
| 588 | "@types/deep-eql": ["@types/deep-eql@4.0.2", "", {}, "sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw=="], | 784 | "@types/deep-eql": ["@types/deep-eql@4.0.2", "", {}, "sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw=="], |
| 589 | 785 | ||
| 590 | "@types/estree": ["@types/estree@1.0.8", "", {}, "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w=="], | 786 | "@types/estree": ["@types/estree@1.0.8", "", {}, "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w=="], |
| @@ -597,6 +793,8 @@ · 6 unmodified lines | |||
| 597 | 793 | ||
| 598 | "@types/react-dom": ["@types/react-dom@19.2.3", "", { "peerDependencies": { "@types/react": "^19.2.0" } }, "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ=="], | 794 | "@types/react-dom": ["@types/react-dom@19.2.3", "", { "peerDependencies": { "@types/react": "^19.2.0" } }, "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ=="], |
| 599 | 795 | ||
| 796 | "@types/use-sync-external-store": ["@types/use-sync-external-store@0.0.6", "", {}, "sha512-zFDAD+tlpf2r4asuHEj0XH6pY6i0g5NeAHPn+15wk3BV6JA69eERFXC1gyGThDkVa1zCyKr5jox1+2LbV/AMLg=="], | ||
| 797 | |||
| 600 | "@vitejs/plugin-react": ["@vitejs/plugin-react@4.7.0", "", { "dependencies": { "@babel/core": "^7.28.0", "@babel/plugin-transform-react-jsx-self": "^7.27.1", "@babel/plugin-transform-react-jsx-source": "^7.27.1", "@rolldown/pluginutils": "1.0.0-beta.27", "@types/babel__core": "^7.20.5", "react-refresh": "^0.17.0" }, "peerDependencies": { "vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0" } }, "sha512-gUu9hwfWvvEDBBmgtAowQCojwZmJ5mcLn3aufeCsitijs3+f2NsrPtlAWIR6OPiqljl96GVCUbLe0HyqIpVaoA=="], | 798 | "@vitejs/plugin-react": ["@vitejs/plugin-react@4.7.0", "", { "dependencies": { "@babel/core": "^7.28.0", "@babel/plugin-transform-react-jsx-self": "^7.27.1", "@babel/plugin-transform-react-jsx-source": "^7.27.1", "@rolldown/pluginutils": "1.0.0-beta.27", "@types/babel__core": "^7.20.5", "react-refresh": "^0.17.0" }, "peerDependencies": { "vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0" } }, "sha512-gUu9hwfWvvEDBBmgtAowQCojwZmJ5mcLn3aufeCsitijs3+f2NsrPtlAWIR6OPiqljl96GVCUbLe0HyqIpVaoA=="], |
| 601 | 799 | ||
| 602 | "@vitest/expect": ["@vitest/expect@3.2.4", "", { "dependencies": { "@types/chai": "^5.2.2", "@vitest/spy": "3.2.4", "@vitest/utils": "3.2.4", "chai": "^5.2.0", "tinyrainbow": "^2.0.0" } }, "sha512-Io0yyORnB6sikFlt8QW5K7slY4OjqNX9jmJQ02QDda8lyM6B5oNgVWoSoKPac8/kgnCUzuHQKrSLtu/uOqqrig=="], | 800 | "@vitest/expect": ["@vitest/expect@3.2.4", "", { "dependencies": { "@types/chai": "^5.2.2", "@vitest/spy": "3.2.4", "@vitest/utils": "3.2.4", "chai": "^5.2.0", "tinyrainbow": "^2.0.0" } }, "sha512-Io0yyORnB6sikFlt8QW5K7slY4OjqNX9jmJQ02QDda8lyM6B5oNgVWoSoKPac8/kgnCUzuHQKrSLtu/uOqqrig=="], |
| @@ -621,6 +819,8 @@ · 18 unmodified lines | |||
| 621 | 819 | ||
| 622 | "argparse": ["argparse@2.0.1", "", {}, "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q=="], | 820 | "argparse": ["argparse@2.0.1", "", {}, "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q=="], |
| 623 | 821 | ||
| 822 | "aria-hidden": ["aria-hidden@1.2.6", "", { "dependencies": { "tslib": "^2.0.0" } }, "sha512-ik3ZgC9dY/lYVVM++OISsaYDeg1tb0VtP5uL3ouh1koGOaUMDPpbFIei4JkFimWUFPn90sbMNMXQAIVOlnYKJA=="], | ||
| 823 | |||
| 624 | "assertion-error": ["assertion-error@2.0.1", "", {}, "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA=="], | 824 | "assertion-error": ["assertion-error@2.0.1", "", {}, "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA=="], |
| 625 | 825 | ||
| 626 | "baseline-browser-mapping": ["baseline-browser-mapping@2.10.13", "", { "bin": { "baseline-browser-mapping": "dist/cli.cjs" } }, "sha512-BL2sTuHOdy0YT1lYieUxTw/QMtPBC3pmlJC6xk8BBYVv6vcw3SGdKemQ+Xsx9ik2F/lYDO9tqsFQH1r9PFuHKw=="], | 826 | "baseline-browser-mapping": ["baseline-browser-mapping@2.10.13", "", { "bin": { "baseline-browser-mapping": "dist/cli.cjs" } }, "sha512-BL2sTuHOdy0YT1lYieUxTw/QMtPBC3pmlJC6xk8BBYVv6vcw3SGdKemQ+Xsx9ik2F/lYDO9tqsFQH1r9PFuHKw=="], |
| @@ -639,32 +839,78 @@ · 12 unmodified lines | |||
| 639 | 839 | ||
| 640 | "check-error": ["check-error@2.1.3", "", {}, "sha512-PAJdDJusoxnwm1VwW07VWwUN1sl7smmC3OKggvndJFadxxDRyFJBX/ggnu/KE4kQAB7a3Dp8f/YXC1FlUprWmA=="], | 840 | "check-error": ["check-error@2.1.3", "", {}, "sha512-PAJdDJusoxnwm1VwW07VWwUN1sl7smmC3OKggvndJFadxxDRyFJBX/ggnu/KE4kQAB7a3Dp8f/YXC1FlUprWmA=="], |
| 641 | 841 | ||
| 842 | "class-variance-authority": ["class-variance-authority@0.7.1", "", { "dependencies": { "clsx": "^2.1.1" } }, "sha512-Ka+9Trutv7G8M6WT6SeiRWz792K5qEqIGEGzXKhAE6xOWAY6pPH8U+9IY3oCMv6kqTmLsv7Xh/2w2RigkePMsg=="], | ||
| 843 | |||
| 844 | "clsx": ["clsx@2.1.1", "", {}, "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA=="], | ||
| 845 | |||
| 846 | "cmdk": ["cmdk@1.1.1", "", { "dependencies": { "@radix-ui/react-compose-refs": "^1.1.1", "@radix-ui/react-dialog": "^1.1.6", "@radix-ui/react-id": "^1.1.0", "@radix-ui/react-primitive": "^2.0.2" }, "peerDependencies": { "react": "^18 || ^19 || ^19.0.0-rc", "react-dom": "^18 || ^19 || ^19.0.0-rc" } }, "sha512-Vsv7kFaXm+ptHDMZ7izaRsP70GgrW9NBNGswt9OZaVBLlE0SNpDq8eu/VGXyF9r7M0azK3Wy7OlYXsuyYLFzHg=="], | ||
| 847 | |||
| 642 | "convert-source-map": ["convert-source-map@2.0.0", "", {}, "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg=="], | 848 | "convert-source-map": ["convert-source-map@2.0.0", "", {}, "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg=="], |
| 643 | 849 | ||
| 644 | "cookie-es": ["cookie-es@2.0.0", "", {}, "sha512-RAj4E421UYRgqokKUmotqAwuplYw15qtdXfY+hGzgCJ/MBjCVZcSoHK/kH9kocfjRjcDME7IiDWR/1WX1TM2Pg=="], | 850 | "cookie-es": ["cookie-es@2.0.0", "", {}, "sha512-RAj4E421UYRgqokKUmotqAwuplYw15qtdXfY+hGzgCJ/MBjCVZcSoHK/kH9kocfjRjcDME7IiDWR/1WX1TM2Pg=="], |
| 645 | 851 | ||
| 646 | "csstype": ["csstype@3.2.3", "", {}, "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ=="], | 852 | "csstype": ["csstype@3.2.3", "", {}, "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ=="], |
| 647 | 853 | ||
| 854 | "d3-array": ["d3-array@3.2.4", "", { "dependencies": { "internmap": "1 - 2" } }, "sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg=="], | ||
| 855 | |||
| 856 | "d3-color": ["d3-color@3.1.0", "", {}, "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA=="], | ||
| 857 | |||
| 858 | "d3-ease": ["d3-ease@3.0.1", "", {}, "sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w=="], | ||
| 859 | |||
| 860 | "d3-format": ["d3-format@3.1.2", "", {}, "sha512-AJDdYOdnyRDV5b6ArilzCPPwc1ejkHcoyFarqlPqT7zRYjhavcT3uSrqcMvsgh2CgoPbK3RCwyHaVyxYcP2Arg=="], | ||
| 861 | |||
| 862 | "d3-interpolate": ["d3-interpolate@3.0.1", "", { "dependencies": { "d3-color": "1 - 3" } }, "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g=="], | ||
| 863 | |||
| 864 | "d3-path": ["d3-path@3.1.0", "", {}, "sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ=="], | ||
| 865 | |||
| 866 | "d3-scale": ["d3-scale@4.0.2", "", { "dependencies": { "d3-array": "2.10.0 - 3", "d3-format": "1 - 3", "d3-interpolate": "1.2.0 - 3", "d3-time": "2.1.1 - 3", "d3-time-format": "2 - 4" } }, "sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ=="], | ||
| 867 | |||
| 868 | "d3-shape": ["d3-shape@3.2.0", "", { "dependencies": { "d3-path": "^3.1.0" } }, "sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA=="], | ||
| 869 | |||
| 870 | "d3-time": ["d3-time@3.1.0", "", { "dependencies": { "d3-array": "2 - 3" } }, "sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q=="], | ||
| 871 | |||
| 872 | "d3-time-format": ["d3-time-format@4.1.0", "", { "dependencies": { "d3-time": "1 - 3" } }, "sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg=="], | ||
| 873 | |||
| 874 | "d3-timer": ["d3-timer@3.0.1", "", {}, "sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA=="], | ||
| 875 | |||
| 876 | "date-fns": ["date-fns@4.1.0", "", {}, "sha512-Ukq0owbQXxa/U3EGtsdVBkR1w7KOQ5gIBqdH2hkvknzZPYvBxb/aa6E8L7tmjFtkwZBu3UXBbjIgPo/Ez4xaNg=="], | ||
| 877 | |||
| 878 | "date-fns-jalali": ["date-fns-jalali@4.1.0-0", "", {}, "sha512-hTIP/z+t+qKwBDcmmsnmjWTduxCg+5KfdqWQvb2X/8C9+knYY6epN/pfxdDuyVlSVeFz0sM5eEfwIUQ70U4ckg=="], | ||
| 879 | |||
| 648 | "debug": ["debug@4.4.3", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="], | 880 | "debug": ["debug@4.4.3", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="], |
| 649 | 881 | ||
| 882 | "decimal.js-light": ["decimal.js-light@2.5.1", "", {}, "sha512-qIMFpTMZmny+MMIitAB6D7iVPEorVw6YQRWkvarTkT4tBeSLLiHzcwj6q0MmYSFCiVpiqPJTJEYIrpcPzVEIvg=="], | ||
| 883 | |||
| 650 | "deep-eql": ["deep-eql@5.0.2", "", {}, "sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q=="], | 884 | "deep-eql": ["deep-eql@5.0.2", "", {}, "sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q=="], |
| 651 | 885 | ||
| 652 | "detect-libc": ["detect-libc@2.1.2", "", {}, "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ=="], | 886 | "detect-libc": ["detect-libc@2.1.2", "", {}, "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ=="], |
| 653 | 887 | ||
| 888 | "detect-node-es": ["detect-node-es@1.1.0", "", {}, "sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ=="], | ||
| 889 | |||
| 654 | "effect": ["effect@3.21.0", "", { "dependencies": { "@standard-schema/spec": "^1.0.0", "fast-check": "^3.23.1" } }, "sha512-PPN80qRokCd1f015IANNhrwOnLO7GrrMQfk4/lnZRE/8j7UPWrNNjPV0uBrZutI/nHzernbW+J0hdqQysHiSnQ=="], | 890 | "effect": ["effect@3.21.0", "", { "dependencies": { "@standard-schema/spec": "^1.0.0", "fast-check": "^3.23.1" } }, "sha512-PPN80qRokCd1f015IANNhrwOnLO7GrrMQfk4/lnZRE/8j7UPWrNNjPV0uBrZutI/nHzernbW+J0hdqQysHiSnQ=="], |
| 655 | 891 | ||
| 656 | "electron-to-chromium": ["electron-to-chromium@1.5.330", "", {}, "sha512-jFNydB5kFtYUobh4IkWUnXeyDbjf/r9gcUEXe1xcrcUxIGfTdzPXA+ld6zBRbwvgIGVzDll/LTIiDztEtckSnA=="], | 892 | "electron-to-chromium": ["electron-to-chromium@1.5.330", "", {}, "sha512-jFNydB5kFtYUobh4IkWUnXeyDbjf/r9gcUEXe1xcrcUxIGfTdzPXA+ld6zBRbwvgIGVzDll/LTIiDztEtckSnA=="], |
| 657 | 893 | ||
| 894 | "embla-carousel": ["embla-carousel@8.6.0", "", {}, "sha512-SjWyZBHJPbqxHOzckOfo8lHisEaJWmwd23XppYFYVh10bU66/Pn5tkVkbkCMZVdbUE5eTCI2nD8OyIP4Z+uwkA=="], | ||
| 895 | |||
| 896 | "embla-carousel-react": ["embla-carousel-react@8.6.0", "", { "dependencies": { "embla-carousel": "8.6.0", "embla-carousel-reactive-utils": "8.6.0" }, "peerDependencies": { "react": "^16.8.0 || ^17.0.1 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" } }, "sha512-0/PjqU7geVmo6F734pmPqpyHqiM99olvyecY7zdweCw+6tKEXnrE90pBiBbMMU8s5tICemzpQ3hi5EpxzGW+JA=="], | ||
| 897 | |||
| 898 | "embla-carousel-reactive-utils": ["embla-carousel-reactive-utils@8.6.0", "", { "peerDependencies": { "embla-carousel": "8.6.0" } }, "sha512-fMVUDUEx0/uIEDM0Mz3dHznDhfX+znCCDCeIophYb1QGVM7YThSWX+wz11zlYwWFOr74b4QLGg0hrGPJeG2s4A=="], | ||
| 899 | |||
| 658 | "enhanced-resolve": ["enhanced-resolve@5.20.1", "", { "dependencies": { "graceful-fs": "^4.2.4", "tapable": "^2.3.0" } }, "sha512-Qohcme7V1inbAfvjItgw0EaxVX5q2rdVEZHRBrEQdRZTssLDGsL8Lwrznl8oQ/6kuTJONLaDcGjkNP247XEhcA=="], | 900 | "enhanced-resolve": ["enhanced-resolve@5.20.1", "", { "dependencies": { "graceful-fs": "^4.2.4", "tapable": "^2.3.0" } }, "sha512-Qohcme7V1inbAfvjItgw0EaxVX5q2rdVEZHRBrEQdRZTssLDGsL8Lwrznl8oQ/6kuTJONLaDcGjkNP247XEhcA=="], |
| 659 | 901 | ||
| 660 | "es-module-lexer": ["es-module-lexer@1.7.0", "", {}, "sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA=="], | 902 | "es-module-lexer": ["es-module-lexer@1.7.0", "", {}, "sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA=="], |
| 661 | 903 | ||
| 904 | "es-toolkit": ["es-toolkit@1.45.1", "", {}, "sha512-/jhoOj/Fx+A+IIyDNOvO3TItGmlMKhtX8ISAHKE90c4b/k1tqaqEZ+uUqfpU8DMnW5cgNJv606zS55jGvza0Xw=="], | ||
| 905 | |||
| 662 | "esbuild": ["esbuild@0.25.12", "", { "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" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg=="], | 906 | "esbuild": ["esbuild@0.25.12", "", { "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" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg=="], |
| 663 | 907 | ||
| 664 | "escalade": ["escalade@3.2.0", "", {}, "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA=="], | 908 | "escalade": ["escalade@3.2.0", "", {}, "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA=="], |
| 665 | 909 | ||
| 666 | "estree-walker": ["estree-walker@3.0.3", "", { "dependencies": { "@types/estree": "^1.0.0" } }, "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g=="], | 910 | "estree-walker": ["estree-walker@3.0.3", "", { "dependencies": { "@types/estree": "^1.0.0" } }, "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g=="], |
| 667 | 911 | ||
| 912 | "eventemitter3": ["eventemitter3@5.0.4", "", {}, "sha512-mlsTRyGaPBjPedk6Bvw+aqbsXDtoAyAzm5MO7JgU+yVRyMQ5O8bD4Kcci7BS85f93veegeCPkL8R4GLClnjLFw=="], | ||
| 913 | |||
| 668 | "expect-type": ["expect-type@1.3.0", "", {}, "sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA=="], | 914 | "expect-type": ["expect-type@1.3.0", "", {}, "sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA=="], |
| 669 | 915 | ||
| 670 | "fast-check": ["fast-check@3.23.2", "", { "dependencies": { "pure-rand": "^6.1.0" } }, "sha512-h5+1OzzfCC3Ef7VbtKdcv7zsstUQwUDlYpUTvjeUsJAssPgLn7QzbboPtL5ro04Mq0rPOsMzl7q5hIbRs2wD1A=="], | 916 | "fast-check": ["fast-check@3.23.2", "", { "dependencies": { "pure-rand": "^6.1.0" } }, "sha512-h5+1OzzfCC3Ef7VbtKdcv7zsstUQwUDlYpUTvjeUsJAssPgLn7QzbboPtL5ro04Mq0rPOsMzl7q5hIbRs2wD1A=="], |
| @@ -681,8 +927,16 @@ · 10 unmodified lines | |||
| 681 | 927 | ||
| 682 | "gensync": ["gensync@1.0.0-beta.2", "", {}, "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg=="], | 928 | "gensync": ["gensync@1.0.0-beta.2", "", {}, "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg=="], |
| 683 | 929 | ||
| 930 | "get-nonce": ["get-nonce@1.0.1", "", {}, "sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q=="], | ||
| 931 | |||
| 684 | "graceful-fs": ["graceful-fs@4.2.11", "", {}, "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ=="], | 932 | "graceful-fs": ["graceful-fs@4.2.11", "", {}, "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ=="], |
| 685 | 933 | ||
| 934 | "immer": ["immer@10.2.0", "", {}, "sha512-d/+XTN3zfODyjr89gM3mPq1WNX2B8pYsu7eORitdwyA2sBubnTl3laYlBk4sXY5FUa5qTZGBDPJICVbvqzjlbw=="], | ||
| 935 | |||
| 936 | "input-otp": ["input-otp@1.4.2", "", { "peerDependencies": { "react": "^16.8 || ^17.0 || ^18.0 || ^19.0.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0.0 || ^19.0.0-rc" } }, "sha512-l3jWwYNvrEa6NTCt7BECfCm48GvwuZzkoeG3gBL2w4CHeOXW3eKFmf9UNYkNfYc3mxMrthMnxjIE07MT0zLBQA=="], | ||
| 937 | |||
| 938 | "internmap": ["internmap@2.0.3", "", {}, "sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg=="], | ||
| 939 | |||
| 686 | "is-extglob": ["is-extglob@2.1.1", "", {}, "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ=="], | 940 | "is-extglob": ["is-extglob@2.1.1", "", {}, "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ=="], |
| 687 | 941 | ||
| 688 | "is-glob": ["is-glob@4.0.3", "", { "dependencies": { "is-extglob": "^2.1.1" } }, "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg=="], | 942 | "is-glob": ["is-glob@4.0.3", "", { "dependencies": { "is-extglob": "^2.1.1" } }, "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg=="], |
| @@ -731,6 +985,8 @@ · 42 unmodified lines | |||
| 731 | 985 | ||
| 732 | "lru-cache": ["lru-cache@5.1.1", "", { "dependencies": { "yallist": "^3.0.2" } }, "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w=="], | 986 | "lru-cache": ["lru-cache@5.1.1", "", { "dependencies": { "yallist": "^3.0.2" } }, "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w=="], |
| 733 | 987 | ||
| 988 | "lucide-react": ["lucide-react@1.7.0", "", { "peerDependencies": { "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-yI7BeItCLZJTXikmK4KNUGCKoGzSvbKlfCvw44bU4fXAL6v3gYS4uHD1jzsLkfwODYwI6Drw5Tu9Z5ulDe0TSg=="], | ||
| 989 | |||
| 734 | "magic-string": ["magic-string@0.30.21", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.5" } }, "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ=="], | 990 | "magic-string": ["magic-string@0.30.21", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.5" } }, "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ=="], |
| 735 | 991 | ||
| 736 | "mime": ["mime@3.0.0", "", { "bin": { "mime": "cli.js" } }, "sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A=="], | 992 | "mime": ["mime@3.0.0", "", { "bin": { "mime": "cli.js" } }, "sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A=="], |
| @@ -745,6 +1001,8 @@ · 8 unmodified lines | |||
| 745 | 1001 | ||
| 746 | "nanoid": ["nanoid@3.3.11", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w=="], | 1002 | "nanoid": ["nanoid@3.3.11", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w=="], |
| 747 | 1003 | ||
| 1004 | "next-themes": ["next-themes@0.4.6", "", { "peerDependencies": { "react": "^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc", "react-dom": "^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc" } }, "sha512-pZvgD5L0IEvX5/9GWyHMf3m8BKiVQwsCMHfoFosXtXBMnaS0ZnIJ9ST4b4NqLVKDEm8QBxoNNGNaBv2JNF6XNA=="], | ||
| 1005 | |||
| 748 | "node-addon-api": ["node-addon-api@7.1.1", "", {}, "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ=="], | 1006 | "node-addon-api": ["node-addon-api@7.1.1", "", {}, "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ=="], |
| 749 | 1007 | ||
| 750 | "node-gyp-build-optional-packages": ["node-gyp-build-optional-packages@5.2.2", "", { "dependencies": { "detect-libc": "^2.0.1" }, "bin": { "node-gyp-build-optional-packages": "bin.js", "node-gyp-build-optional-packages-optional": "optional.js", "node-gyp-build-optional-packages-test": "build-test.js" } }, "sha512-s+w+rBWnpTMwSFbaE0UXsRlg7hU4FjekKU4eyAih5T8nJuNZT1nNsskXpxmeqSK9UzkBl6UgRlnKc8hz8IEqOw=="], | 1008 | "node-gyp-build-optional-packages": ["node-gyp-build-optional-packages@5.2.2", "", { "dependencies": { "detect-libc": "^2.0.1" }, "bin": { "node-gyp-build-optional-packages": "bin.js", "node-gyp-build-optional-packages-optional": "optional.js", "node-gyp-build-optional-packages-test": "build-test.js" } }, "sha512-s+w+rBWnpTMwSFbaE0UXsRlg7hU4FjekKU4eyAih5T8nJuNZT1nNsskXpxmeqSK9UzkBl6UgRlnKc8hz8IEqOw=="], |
| @@ -771,14 +1029,40 @@ · 20 unmodified lines | |||
| 771 | 1029 | ||
| 772 | "quickjs-emscripten-core": ["quickjs-emscripten-core@0.31.0", "", { "dependencies": { "@jitl/quickjs-ffi-types": "0.31.0" } }, "sha512-oQz8p0SiKDBc1TC7ZBK2fr0GoSHZKA0jZIeXxsnCyCs4y32FStzCW4d1h6E1sE0uHDMbGITbk2zhNaytaoJwXQ=="], | 1030 | "quickjs-emscripten-core": ["quickjs-emscripten-core@0.31.0", "", { "dependencies": { "@jitl/quickjs-ffi-types": "0.31.0" } }, "sha512-oQz8p0SiKDBc1TC7ZBK2fr0GoSHZKA0jZIeXxsnCyCs4y32FStzCW4d1h6E1sE0uHDMbGITbk2zhNaytaoJwXQ=="], |
| 773 | 1031 | ||
| 1032 | "radix-ui": ["radix-ui@1.4.3", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-accessible-icon": "1.1.7", "@radix-ui/react-accordion": "1.2.12", "@radix-ui/react-alert-dialog": "1.1.15", "@radix-ui/react-arrow": "1.1.7", "@radix-ui/react-aspect-ratio": "1.1.7", "@radix-ui/react-avatar": "1.1.10", "@radix-ui/react-checkbox": "1.3.3", "@radix-ui/react-collapsible": "1.1.12", "@radix-ui/react-collection": "1.1.7", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-context-menu": "2.2.16", "@radix-ui/react-dialog": "1.1.15", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-dismissable-layer": "1.1.11", "@radix-ui/react-dropdown-menu": "2.1.16", "@radix-ui/react-focus-guards": "1.1.3", "@radix-ui/react-focus-scope": "1.1.7", "@radix-ui/react-form": "0.1.8", "@radix-ui/react-hover-card": "1.1.15", "@radix-ui/react-label": "2.1.7", "@radix-ui/react-menu": "2.1.16", "@radix-ui/react-menubar": "1.1.16", "@radix-ui/react-navigation-menu": "1.2.14", "@radix-ui/react-one-time-password-field": "0.1.8", "@radix-ui/react-password-toggle-field": "0.1.3", "@radix-ui/react-popover": "1.1.15", "@radix-ui/react-popper": "1.2.8", "@radix-ui/react-portal": "1.1.9", "@radix-ui/react-presence": "1.1.5", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-progress": "1.1.7", "@radix-ui/react-radio-group": "1.3.8", "@radix-ui/react-roving-focus": "1.1.11", "@radix-ui/react-scroll-area": "1.2.10", "@radix-ui/react-select": "2.2.6", "@radix-ui/react-separator": "1.1.7", "@radix-ui/react-slider": "1.3.6", "@radix-ui/react-slot": "1.2.3", "@radix-ui/react-switch": "1.2.6", "@radix-ui/react-tabs": "1.1.13", "@radix-ui/react-toast": "1.2.15", "@radix-ui/react-toggle": "1.1.10", "@radix-ui/react-toggle-group": "1.1.11", "@radix-ui/react-toolbar": "1.1.11", "@radix-ui/react-tooltip": "1.2.8", "@radix-ui/react-use-callback-ref": "1.1.1", "@radix-ui/react-use-controllable-state": "1.2.2", "@radix-ui/react-use-effect-event": "0.0.2", "@radix-ui/react-use-escape-keydown": "1.1.1", "@radix-ui/react-use-is-hydrated": "0.1.0", "@radix-ui/react-use-layout-effect": "1.1.1", "@radix-ui/react-use-size": "1.1.1", "@radix-ui/react-visually-hidden": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-aWizCQiyeAenIdUbqEpXgRA1ya65P13NKn/W8rWkcN0OPkRDxdBVLWnIEDsS2RpwCK2nobI7oMUSmexzTDyAmA=="], | ||
| 1033 | |||
| 774 | "react": ["react@19.2.4", "", {}, "sha512-9nfp2hYpCwOjAN+8TZFGhtWEwgvWHXqESH8qT89AT/lWklpLON22Lc8pEtnpsZz7VmawabSU0gCjnj8aC0euHQ=="], | 1034 | "react": ["react@19.2.4", "", {}, "sha512-9nfp2hYpCwOjAN+8TZFGhtWEwgvWHXqESH8qT89AT/lWklpLON22Lc8pEtnpsZz7VmawabSU0gCjnj8aC0euHQ=="], |
| 775 | 1035 | ||
| 1036 | "react-day-picker": ["react-day-picker@9.14.0", "", { "dependencies": { "@date-fns/tz": "^1.4.1", "@tabby_ai/hijri-converter": "1.0.5", "date-fns": "^4.1.0", "date-fns-jalali": "4.1.0-0" }, "peerDependencies": { "react": ">=16.8.0" } }, "sha512-tBaoDWjPwe0M5pGrum4H0SR6Lyk+BO9oHnp9JbKpGKW2mlraNPgP9BMfsg5pWpwrssARmeqk7YBl2oXutZTaHA=="], | ||
| 1037 | |||
| 776 | "react-dom": ["react-dom@19.2.4", "", { "dependencies": { "scheduler": "^0.27.0" }, "peerDependencies": { "react": "^19.2.4" } }, "sha512-AXJdLo8kgMbimY95O2aKQqsz2iWi9jMgKJhRBAxECE4IFxfcazB2LmzloIoibJI3C12IlY20+KFaLv+71bUJeQ=="], | 1038 | "react-dom": ["react-dom@19.2.4", "", { "dependencies": { "scheduler": "^0.27.0" }, "peerDependencies": { "react": "^19.2.4" } }, "sha512-AXJdLo8kgMbimY95O2aKQqsz2iWi9jMgKJhRBAxECE4IFxfcazB2LmzloIoibJI3C12IlY20+KFaLv+71bUJeQ=="], |
| 777 | 1039 | ||
| 1040 | "react-hook-form": ["react-hook-form@7.72.0", "", { "peerDependencies": { "react": "^16.8.0 || ^17 || ^18 || ^19" } }, "sha512-V4v6jubaf6JAurEaVnT9aUPKFbNtDgohj5CIgVGyPHvT9wRx5OZHVjz31GsxnPNI278XMu+ruFz+wGOscHaLKw=="], | ||
| 1041 | |||
| 1042 | "react-is": ["react-is@19.2.4", "", {}, "sha512-W+EWGn2v0ApPKgKKCy/7s7WHXkboGcsrXE+2joLyVxkbyVQfO3MUEaUQDHoSmb8TFFrSKYa9mw64WZHNHSDzYA=="], | ||
| 1043 | |||
| 1044 | "react-redux": ["react-redux@9.2.0", "", { "dependencies": { "@types/use-sync-external-store": "^0.0.6", "use-sync-external-store": "^1.4.0" }, "peerDependencies": { "@types/react": "^18.2.25 || ^19", "react": "^18.0 || ^19", "redux": "^5.0.0" }, "optionalPeers": ["@types/react", "redux"] }, "sha512-ROY9fvHhwOD9ySfrF0wmvu//bKCQ6AeZZq1nJNtbDC+kk5DuSuNX/n6YWYF/SYy7bSba4D4FSz8DJeKY/S/r+g=="], | ||
| 1045 | |||
| 778 | "react-refresh": ["react-refresh@0.17.0", "", {}, "sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ=="], | 1046 | "react-refresh": ["react-refresh@0.17.0", "", {}, "sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ=="], |
| 779 | 1047 | ||
| 1048 | "react-remove-scroll": ["react-remove-scroll@2.7.2", "", { "dependencies": { "react-remove-scroll-bar": "^2.3.7", "react-style-singleton": "^2.2.3", "tslib": "^2.1.0", "use-callback-ref": "^1.3.3", "use-sidecar": "^1.1.3" }, "peerDependencies": { "@types/react": "*", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-Iqb9NjCCTt6Hf+vOdNIZGdTiH1QSqr27H/Ek9sv/a97gfueI/5h1s3yRi1nngzMUaOOToin5dI1dXKdXiF+u0Q=="], | ||
| 1049 | |||
| 1050 | "react-remove-scroll-bar": ["react-remove-scroll-bar@2.3.8", "", { "dependencies": { "react-style-singleton": "^2.2.2", "tslib": "^2.0.0" }, "peerDependencies": { "@types/react": "*", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" }, "optionalPeers": ["@types/react"] }, "sha512-9r+yi9+mgU33AKcj6IbT9oRCO78WriSj6t/cF8DWBZJ9aOGPOTEDvdUDz1FwKim7QXWwmHqtdHnRJfhAxEG46Q=="], | ||
| 1051 | |||
| 1052 | "react-resizable-panels": ["react-resizable-panels@4.8.0", "", { "peerDependencies": { "react": "^18.0.0 || ^19.0.0", "react-dom": "^18.0.0 || ^19.0.0" } }, "sha512-2uEABkewb3ky/ZgIlAUxWa1W/LjsK494fdV1QsXxst7CDRHCzo7h22tWWu3NNaBjmiuriOCt3CvhipnaYcpoIw=="], | ||
| 1053 | |||
| 1054 | "react-style-singleton": ["react-style-singleton@2.2.3", "", { "dependencies": { "get-nonce": "^1.0.0", "tslib": "^2.0.0" }, "peerDependencies": { "@types/react": "*", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-b6jSvxvVnyptAiLjbkWLE/lOnR4lfTtDAl+eUC7RZy+QQWc6wRzIV2CE6xBuMmDxc2qIihtDCZD5NPOFl7fRBQ=="], | ||
| 1055 | |||
| 1056 | "recharts": ["recharts@3.8.0", "", { "dependencies": { "@reduxjs/toolkit": "^1.9.0 || 2.x.x", "clsx": "^2.1.1", "decimal.js-light": "^2.5.1", "es-toolkit": "^1.39.3", "eventemitter3": "^5.0.1", "immer": "^10.1.1", "react-redux": "8.x.x || 9.x.x", "reselect": "5.1.1", "tiny-invariant": "^1.3.3", "use-sync-external-store": "^1.2.2", "victory-vendor": "^37.0.2" }, "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react-dom": "^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react-is": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-Z/m38DX3L73ExO4Tpc9/iZWHmHnlzWG4njQbxsF5aSjwqmHNDDIm0rdEBArkwsBvR8U6EirlEHiQNYWCVh9sGQ=="], | ||
| 1057 | |||
| 1058 | "redux": ["redux@5.0.1", "", {}, "sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w=="], | ||
| 1059 | |||
| 1060 | "redux-thunk": ["redux-thunk@3.1.0", "", { "peerDependencies": { "redux": "^5.0.0" } }, "sha512-NW2r5T6ksUKXCabzhL9z+h206HQw/NJkcLm1GPImRQ8IzfXwRGqjVhKJGauHirT0DAuyy6hjdnMZaRoAcy0Klw=="], | ||
| 1061 | |||
| 780 | "require-from-string": ["require-from-string@2.0.2", "", {}, "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw=="], | 1062 | "require-from-string": ["require-from-string@2.0.2", "", {}, "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw=="], |
| 781 | 1063 | ||
| 1064 | "reselect": ["reselect@5.1.1", "", {}, "sha512-K/BG6eIky/SBpzfHZv/dd+9JBFiS4SWV7FIujVyJRux6e45+73RaUHXLmIR1f7WOMaQ0U1km6qwklRQxpJJY0w=="], | ||
| 1065 | |||
| 782 | "rollup": ["rollup@4.60.1", "", { "dependencies": { "@types/estree": "1.0.8" }, "optionalDependencies": { "@rollup/rollup-android-arm-eabi": "4.60.1", "@rollup/rollup-android-arm64": "4.60.1", "@rollup/rollup-darwin-arm64": "4.60.1", "@rollup/rollup-darwin-x64": "4.60.1", "@rollup/rollup-freebsd-arm64": "4.60.1", "@rollup/rollup-freebsd-x64": "4.60.1", "@rollup/rollup-linux-arm-gnueabihf": "4.60.1", "@rollup/rollup-linux-arm-musleabihf": "4.60.1", "@rollup/rollup-linux-arm64-gnu": "4.60.1", "@rollup/rollup-linux-arm64-musl": "4.60.1", "@rollup/rollup-linux-loong64-gnu": "4.60.1", "@rollup/rollup-linux-loong64-musl": "4.60.1", "@rollup/rollup-linux-ppc64-gnu": "4.60.1", "@rollup/rollup-linux-ppc64-musl": "4.60.1", "@rollup/rollup-linux-riscv64-gnu": "4.60.1", "@rollup/rollup-linux-riscv64-musl": "4.60.1", "@rollup/rollup-linux-s390x-gnu": "4.60.1", "@rollup/rollup-linux-x64-gnu": "4.60.1", "@rollup/rollup-linux-x64-musl": "4.60.1", "@rollup/rollup-openbsd-x64": "4.60.1", "@rollup/rollup-openharmony-arm64": "4.60.1", "@rollup/rollup-win32-arm64-msvc": "4.60.1", "@rollup/rollup-win32-ia32-msvc": "4.60.1", "@rollup/rollup-win32-x64-gnu": "4.60.1", "@rollup/rollup-win32-x64-msvc": "4.60.1", "fsevents": "~2.3.2" }, "bin": { "rollup": "dist/bin/rollup" } }, "sha512-VmtB2rFU/GroZ4oL8+ZqXgSA38O6GR8KSIvWmEFv63pQ0G6KaBH9s07PO8XTXP4vI+3UJUEypOfjkGfmSBBR0w=="], | 1066 | "rollup": ["rollup@4.60.1", "", { "dependencies": { "@types/estree": "1.0.8" }, "optionalDependencies": { "@rollup/rollup-android-arm-eabi": "4.60.1", "@rollup/rollup-android-arm64": "4.60.1", "@rollup/rollup-darwin-arm64": "4.60.1", "@rollup/rollup-darwin-x64": "4.60.1", "@rollup/rollup-freebsd-arm64": "4.60.1", "@rollup/rollup-freebsd-x64": "4.60.1", "@rollup/rollup-linux-arm-gnueabihf": "4.60.1", "@rollup/rollup-linux-arm-musleabihf": "4.60.1", "@rollup/rollup-linux-arm64-gnu": "4.60.1", "@rollup/rollup-linux-arm64-musl": "4.60.1", "@rollup/rollup-linux-loong64-gnu": "4.60.1", "@rollup/rollup-linux-loong64-musl": "4.60.1", "@rollup/rollup-linux-ppc64-gnu": "4.60.1", "@rollup/rollup-linux-ppc64-musl": "4.60.1", "@rollup/rollup-linux-riscv64-gnu": "4.60.1", "@rollup/rollup-linux-riscv64-musl": "4.60.1", "@rollup/rollup-linux-s390x-gnu": "4.60.1", "@rollup/rollup-linux-x64-gnu": "4.60.1", "@rollup/rollup-linux-x64-musl": "4.60.1", "@rollup/rollup-openbsd-x64": "4.60.1", "@rollup/rollup-openharmony-arm64": "4.60.1", "@rollup/rollup-win32-arm64-msvc": "4.60.1", "@rollup/rollup-win32-ia32-msvc": "4.60.1", "@rollup/rollup-win32-x64-gnu": "4.60.1", "@rollup/rollup-win32-x64-msvc": "4.60.1", "fsevents": "~2.3.2" }, "bin": { "rollup": "dist/bin/rollup" } }, "sha512-VmtB2rFU/GroZ4oL8+ZqXgSA38O6GR8KSIvWmEFv63pQ0G6KaBH9s07PO8XTXP4vI+3UJUEypOfjkGfmSBBR0w=="], |
| 783 | 1067 | ||
| 784 | "scheduler": ["scheduler@0.27.0", "", {}, "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q=="], | 1068 | "scheduler": ["scheduler@0.27.0", "", {}, "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q=="], |
| @@ -791,6 +1075,8 @@ · 6 unmodified lines | |||
| 791 | 1075 | ||
| 792 | "siginfo": ["siginfo@2.0.0", "", {}, "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g=="], | 1076 | "siginfo": ["siginfo@2.0.0", "", {}, "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g=="], |
| 793 | 1077 | ||
| 1078 | "sonner": ["sonner@2.0.7", "", { "peerDependencies": { "react": "^18.0.0 || ^19.0.0 || ^19.0.0-rc", "react-dom": "^18.0.0 || ^19.0.0 || ^19.0.0-rc" } }, "sha512-W6ZN4p58k8aDKA4XPcx2hpIQXBRAgyiWVkYhT7CvK6D3iAu7xjvVyhQHg2/iaKJZ1XVJ4r7XuwGL+WGEK37i9w=="], | ||
| 1079 | |||
| 794 | "source-map-js": ["source-map-js@1.2.1", "", {}, "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA=="], | 1080 | "source-map-js": ["source-map-js@1.2.1", "", {}, "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA=="], |
| 795 | 1081 | ||
| 796 | "stackback": ["stackback@0.0.2", "", {}, "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw=="], | 1082 | "stackback": ["stackback@0.0.2", "", {}, "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw=="], |
| @@ -799,10 +1085,16 @@ · 2 unmodified lines | |||
| 799 | 1085 | ||
| 800 | "strip-literal": ["strip-literal@3.1.0", "", { "dependencies": { "js-tokens": "^9.0.1" } }, "sha512-8r3mkIM/2+PpjHoOtiAW8Rg3jJLHaV7xPwG+YRGrv6FP0wwk/toTpATxWYOW0BKdWwl82VT2tFYi5DlROa0Mxg=="], | 1086 | "strip-literal": ["strip-literal@3.1.0", "", { "dependencies": { "js-tokens": "^9.0.1" } }, "sha512-8r3mkIM/2+PpjHoOtiAW8Rg3jJLHaV7xPwG+YRGrv6FP0wwk/toTpATxWYOW0BKdWwl82VT2tFYi5DlROa0Mxg=="], |
| 801 | 1087 | ||
| 1088 | "tabbable": ["tabbable@6.4.0", "", {}, "sha512-05PUHKSNE8ou2dwIxTngl4EzcnsCDZGJ/iCLtDflR/SHB/ny14rXc+qU5P4mG9JkusiV7EivzY9Mhm55AzAvCg=="], | ||
| 1089 | |||
| 1090 | "tailwind-merge": ["tailwind-merge@3.5.0", "", {}, "sha512-I8K9wewnVDkL1NTGoqWmVEIlUcB9gFriAEkXkfCjX5ib8ezGxtR3xD7iZIxrfArjEsH7F1CHD4RFUtxefdqV/A=="], | ||
| 1091 | |||
| 802 | "tailwindcss": ["tailwindcss@4.2.2", "", {}, "sha512-KWBIxs1Xb6NoLdMVqhbhgwZf2PGBpPEiwOqgI4pFIYbNTfBXiKYyWoTsXgBQ9WFg/OlhnvHaY+AEpW7wSmFo2Q=="], | 1092 | "tailwindcss": ["tailwindcss@4.2.2", "", {}, "sha512-KWBIxs1Xb6NoLdMVqhbhgwZf2PGBpPEiwOqgI4pFIYbNTfBXiKYyWoTsXgBQ9WFg/OlhnvHaY+AEpW7wSmFo2Q=="], |
| 803 | 1093 | ||
| 804 | "tapable": ["tapable@2.3.2", "", {}, "sha512-1MOpMXuhGzGL5TTCZFItxCc0AARf1EZFQkGqMm7ERKj8+Hgr5oLvJOVFcC+lRmR8hCe2S3jC4T5D7Vg/d7/fhA=="], | 1094 | "tapable": ["tapable@2.3.2", "", {}, "sha512-1MOpMXuhGzGL5TTCZFItxCc0AARf1EZFQkGqMm7ERKj8+Hgr5oLvJOVFcC+lRmR8hCe2S3jC4T5D7Vg/d7/fhA=="], |
| 805 | 1095 | ||
| 1096 | "tiny-invariant": ["tiny-invariant@1.3.3", "", {}, "sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg=="], | ||
| 1097 | |||
| 806 | "tinybench": ["tinybench@2.9.0", "", {}, "sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg=="], | 1098 | "tinybench": ["tinybench@2.9.0", "", {}, "sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg=="], |
| 807 | 1099 | ||
| 808 | "tinyexec": ["tinyexec@0.3.2", "", {}, "sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA=="], | 1100 | "tinyexec": ["tinyexec@0.3.2", "", {}, "sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA=="], |
| @@ -815,6 +1107,8 @@ · 6 unmodified lines | |||
| 815 | 1107 | ||
| 816 | "tinyspy": ["tinyspy@4.0.4", "", {}, "sha512-azl+t0z7pw/z958Gy9svOTuzqIk6xq+NSheJzn5MMWtWTFywIacg2wUlzKFGtt3cthx0r2SxMK0yzJOR0IES7Q=="], | 1108 | "tinyspy": ["tinyspy@4.0.4", "", {}, "sha512-azl+t0z7pw/z958Gy9svOTuzqIk6xq+NSheJzn5MMWtWTFywIacg2wUlzKFGtt3cthx0r2SxMK0yzJOR0IES7Q=="], |
| 817 | 1109 | ||
| 1110 | "tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="], | ||
| 1111 | |||
| 818 | "turbo": ["turbo@2.9.2", "", { "optionalDependencies": { "@turbo/darwin-64": "2.9.2", "@turbo/darwin-arm64": "2.9.2", "@turbo/linux-64": "2.9.2", "@turbo/linux-arm64": "2.9.2", "@turbo/windows-64": "2.9.2", "@turbo/windows-arm64": "2.9.2" }, "bin": { "turbo": "bin/turbo" } }, "sha512-DUUWysctg/vax8W05UJcyrHm4LvxtX0umAT4bZB5lab4inNXTbwoYSFpdgqzBxON23j8ls3xGxvx0kwQz6Q8wQ=="], | 1112 | "turbo": ["turbo@2.9.2", "", { "optionalDependencies": { "@turbo/darwin-64": "2.9.2", "@turbo/darwin-arm64": "2.9.2", "@turbo/linux-64": "2.9.2", "@turbo/linux-arm64": "2.9.2", "@turbo/windows-64": "2.9.2", "@turbo/windows-arm64": "2.9.2" }, "bin": { "turbo": "bin/turbo" } }, "sha512-DUUWysctg/vax8W05UJcyrHm4LvxtX0umAT4bZB5lab4inNXTbwoYSFpdgqzBxON23j8ls3xGxvx0kwQz6Q8wQ=="], |
| 819 | 1113 | ||
| 820 | "typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="], | 1114 | "typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="], |
| @@ -825,10 +1119,18 @@ · 4 unmodified lines | |||
| 825 | 1119 | ||
| 826 | "update-browserslist-db": ["update-browserslist-db@1.2.3", "", { "dependencies": { "escalade": "^3.2.0", "picocolors": "^1.1.1" }, "peerDependencies": { "browserslist": ">= 4.21.0" }, "bin": { "update-browserslist-db": "cli.js" } }, "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w=="], | 1120 | "update-browserslist-db": ["update-browserslist-db@1.2.3", "", { "dependencies": { "escalade": "^3.2.0", "picocolors": "^1.1.1" }, "peerDependencies": { "browserslist": ">= 4.21.0" }, "bin": { "update-browserslist-db": "cli.js" } }, "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w=="], |
| 827 | 1121 | ||
| 1122 | "use-callback-ref": ["use-callback-ref@1.3.3", "", { "dependencies": { "tslib": "^2.0.0" }, "peerDependencies": { "@types/react": "*", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-jQL3lRnocaFtu3V00JToYz/4QkNWswxijDaCVNZRiRTO3HQDLsdu1ZtmIUvV4yPp+rvWm5j0y0TG/S61cuijTg=="], | ||
| 1123 | |||
| 1124 | "use-sidecar": ["use-sidecar@1.1.3", "", { "dependencies": { "detect-node-es": "^1.1.0", "tslib": "^2.0.0" }, "peerDependencies": { "@types/react": "*", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-Fedw0aZvkhynoPYlA5WXrMCAMm+nSWdZt6lzJQ7Ok8S6Q+VsHmHpRWndVRJ8Be0ZbkfPc5LRYH+5XrzXcEeLRQ=="], | ||
| 1125 | |||
| 828 | "use-sync-external-store": ["use-sync-external-store@1.6.0", "", { "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w=="], | 1126 | "use-sync-external-store": ["use-sync-external-store@1.6.0", "", { "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w=="], |
| 829 | 1127 | ||
| 830 | "uuid": ["uuid@11.1.0", "", { "bin": { "uuid": "dist/esm/bin/uuid" } }, "sha512-0/A9rDy9P7cJ+8w1c9WD9V//9Wj15Ce2MPz8Ri6032usz+NfePxx5AcN3bN+r6ZL6jEo066/yNYB3tn4pQEx+A=="], | 1128 | "uuid": ["uuid@11.1.0", "", { "bin": { "uuid": "dist/esm/bin/uuid" } }, "sha512-0/A9rDy9P7cJ+8w1c9WD9V//9Wj15Ce2MPz8Ri6032usz+NfePxx5AcN3bN+r6ZL6jEo066/yNYB3tn4pQEx+A=="], |
| 831 | 1129 | ||
| 1130 | "vaul": ["vaul@1.1.2", "", { "dependencies": { "@radix-ui/react-dialog": "^1.1.1" }, "peerDependencies": { "react": "^16.8 || ^17.0 || ^18.0 || ^19.0.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0.0 || ^19.0.0-rc" } }, "sha512-ZFkClGpWyI2WUQjdLJ/BaGuV6AVQiJ3uELGk3OYtP+B6yCO7Cmn9vPFXVJkRaGkOJu3m8bQMgtyzNHixULceQA=="], | ||
| 1131 | |||
| 1132 | "victory-vendor": ["victory-vendor@37.3.6", "", { "dependencies": { "@types/d3-array": "^3.0.3", "@types/d3-ease": "^3.0.0", "@types/d3-interpolate": "^3.0.1", "@types/d3-scale": "^4.0.2", "@types/d3-shape": "^3.1.0", "@types/d3-time": "^3.0.0", "@types/d3-timer": "^3.0.0", "d3-array": "^3.1.6", "d3-ease": "^3.0.1", "d3-interpolate": "^3.0.1", "d3-scale": "^4.0.2", "d3-shape": "^3.1.0", "d3-time": "^3.0.0", "d3-timer": "^3.0.1" } }, "sha512-SbPDPdDBYp+5MJHhBCAyI7wKM3d5ivekigc2Dk2s7pgbZ9wIgIBYGVw4zGHBml/qTFbexrofXW6Gu4noGxrOwQ=="], | ||
| 1133 | |||
| 832 | "vite": ["vite@6.4.1", "", { "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" }, "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" }, "optionalPeers": ["@types/node", "jiti", "less", "lightningcss", "sass", "sass-embedded", "stylus", "sugarss", "terser", "tsx", "yaml"], "bin": { "vite": "bin/vite.js" } }, "sha512-+Oxm7q9hDoLMyJOYfUYBuHQo+dkAloi33apOPP56pzj+vsdJDzr+j1NISE5pyaAuKL4A3UD34qd0lx5+kfKp2g=="], | 1134 | "vite": ["vite@6.4.1", "", { "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" }, "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" }, "optionalPeers": ["@types/node", "jiti", "less", "lightningcss", "sass", "sass-embedded", "stylus", "sugarss", "terser", "tsx", "yaml"], "bin": { "vite": "bin/vite.js" } }, "sha512-+Oxm7q9hDoLMyJOYfUYBuHQo+dkAloi33apOPP56pzj+vsdJDzr+j1NISE5pyaAuKL4A3UD34qd0lx5+kfKp2g=="], |
| 833 | 1135 | ||
| 834 | "vite-node": ["vite-node@3.2.4", "", { "dependencies": { "cac": "^6.7.14", "debug": "^4.4.1", "es-module-lexer": "^1.7.0", "pathe": "^2.0.3", "vite": "^5.0.0 || ^6.0.0 || ^7.0.0-0" }, "bin": { "vite-node": "vite-node.mjs" } }, "sha512-EbKSKh+bh1E1IFxeO0pg1n4dvoOTt0UDiXMd/qn++r98+jPO1xtJilvXldeuQ8giIB5IkpjCgMleHMNEsGH6pg=="], | 1136 | "vite-node": ["vite-node@3.2.4", "", { "dependencies": { "cac": "^6.7.14", "debug": "^4.4.1", "es-module-lexer": "^1.7.0", "pathe": "^2.0.3", "vite": "^5.0.0 || ^6.0.0 || ^7.0.0-0" }, "bin": { "vite-node": "vite-node.mjs" } }, "sha512-EbKSKh+bh1E1IFxeO0pg1n4dvoOTt0UDiXMd/qn++r98+jPO1xtJilvXldeuQ8giIB5IkpjCgMleHMNEsGH6pg=="], |
| @@ -843,10 +1145,14 @@ · 8 unmodified lines | |||
| 843 | 1145 | ||
| 844 | "yaml": ["yaml@2.8.3", "", { "bin": { "yaml": "bin.mjs" } }, "sha512-AvbaCLOO2Otw/lW5bmh9d/WEdcDFdQp2Z2ZUH3pX9U2ihyUY0nvLv7J6TrWowklRGPYbB/IuIMfYgxaCPg5Bpg=="], | 1146 | "yaml": ["yaml@2.8.3", "", { "bin": { "yaml": "bin.mjs" } }, "sha512-AvbaCLOO2Otw/lW5bmh9d/WEdcDFdQp2Z2ZUH3pX9U2ihyUY0nvLv7J6TrWowklRGPYbB/IuIMfYgxaCPg5Bpg=="], |
| 845 | 1147 | ||
| 1148 | "zod": ["zod@4.3.6", "", {}, "sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg=="], | ||
| 1149 | |||
| 846 | "@babel/code-frame/js-tokens": ["js-tokens@4.0.0", "", {}, "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="], | 1150 | "@babel/code-frame/js-tokens": ["js-tokens@4.0.0", "", {}, "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="], |
| 847 | 1151 | ||
| 848 | "@executor/sdk/typescript": ["typescript@6.0.2", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-bGdAIrZ0wiGDo5l8c++HWtbaNCWTS4UTv7RaTH/ThVIgjkveJt83m74bBHMJkuCbslY8ixgLBVZJIOiQlQTjfQ=="], | 1152 | "@executor/sdk/typescript": ["typescript@6.0.2", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-bGdAIrZ0wiGDo5l8c++HWtbaNCWTS4UTv7RaTH/ThVIgjkveJt83m74bBHMJkuCbslY8ixgLBVZJIOiQlQTjfQ=="], |
| 849 | 1153 | ||
| 1154 | "@reduxjs/toolkit/immer": ["immer@11.1.4", "", {}, "sha512-XREFCPo6ksxVzP4E0ekD5aMdf8WMwmdNaz6vuvxgI40UaEiu6q3p8X52aU6GdyvLY3XXX/8R7JOTXStz/nBbRw=="], | ||
| 1155 | |||
| 850 | "@tailwindcss/oxide-wasm32-wasi/@emnapi/core": ["@emnapi/core@1.9.1", "", { "dependencies": { "@emnapi/wasi-threads": "1.2.0", "tslib": "^2.4.0" }, "bundled": true }, "sha512-mukuNALVsoix/w1BJwFzwXBN/dHeejQtuVzcDsfOEsdpCumXb/E9j8w11h5S54tT1xhifGfbbSm/ICrObRb3KA=="], | 1156 | "@tailwindcss/oxide-wasm32-wasi/@emnapi/core": ["@emnapi/core@1.9.1", "", { "dependencies": { "@emnapi/wasi-threads": "1.2.0", "tslib": "^2.4.0" }, "bundled": true }, "sha512-mukuNALVsoix/w1BJwFzwXBN/dHeejQtuVzcDsfOEsdpCumXb/E9j8w11h5S54tT1xhifGfbbSm/ICrObRb3KA=="], |
| 851 | 1157 | ||
| 852 | "@tailwindcss/oxide-wasm32-wasi/@emnapi/runtime": ["@emnapi/runtime@1.9.1", "", { "dependencies": { "tslib": "^2.4.0" }, "bundled": true }, "sha512-VYi5+ZVLhpgK4hQ0TAjiQiZ6ol0oe4mBx7mVv7IflsiEp0OWoVsp/+f9Vc1hOhE0TtkORVrI1GvzyreqpgWtkA=="], | 1158 | "@tailwindcss/oxide-wasm32-wasi/@emnapi/runtime": ["@emnapi/runtime@1.9.1", "", { "dependencies": { "tslib": "^2.4.0" }, "bundled": true }, "sha512-VYi5+ZVLhpgK4hQ0TAjiQiZ6ol0oe4mBx7mVv7IflsiEp0OWoVsp/+f9Vc1hOhE0TtkORVrI1GvzyreqpgWtkA=="], |
| @@ -5,6 +5,7 @@ · 4 unmodified lines | |||
| 5 | "packageManager": "bun@1.2.22", | 5 | "packageManager": "bun@1.2.22", |
| 6 | "workspaces": [ | 6 | "workspaces": [ |
| 7 | "packages/*/*", | 7 | "packages/*/*", |
| 8 | "packages/ui", | ||
| 8 | "apps/*" | 9 | "apps/*" |
| 9 | ], | 10 | ], |
| 10 | "catalog": { | 11 | "catalog": { |
| @@ -0,0 +1,20 @@ | |||
| 1 | { | ||
| 2 | "$schema": "https://ui.shadcn.com/schema.json", | ||
| 3 | "style": "new-york", | ||
| 4 | "rsc": false, | ||
| 5 | "tsx": true, | ||
| 6 | "tailwind": { | ||
| 7 | "config": "", | ||
| 8 | "css": "src/styles/globals.css", | ||
| 9 | "baseColor": "neutral", | ||
| 10 | "cssVariables": true | ||
| 11 | }, | ||
| 12 | "iconLibrary": "lucide", | ||
| 13 | "aliases": { | ||
| 14 | "components": "@executor/ui/components", | ||
| 15 | "utils": "@executor/ui/lib/utils", | ||
| 16 | "hooks": "@executor/ui/hooks", | ||
| 17 | "lib": "@executor/ui/lib", | ||
| 18 | "ui": "@executor/ui/components" | ||
| 19 | } | ||
| 20 | } | ||
| @@ -0,0 +1,42 @@ | |||
| 1 | { | ||
| 2 | "name": "@executor/ui", | ||
| 3 | "version": "0.0.0", | ||
| 4 | "private": true, | ||
| 5 | "type": "module", | ||
| 6 | "exports": { | ||
| 7 | "./components/*": "./src/components/*.tsx", | ||
| 8 | "./hooks/*": "./src/hooks/*.ts", | ||
| 9 | "./lib/*": "./src/lib/*.ts", | ||
| 10 | "./globals.css": "./src/styles/globals.css" | ||
| 11 | }, | ||
| 12 | "dependencies": { | ||
| 13 | "@base-ui/react": "^1.3.0", | ||
| 14 | "@hookform/resolvers": "^5.2.2", | ||
| 15 | "class-variance-authority": "^0.7.1", | ||
| 16 | "clsx": "^2.1.1", | ||
| 17 | "cmdk": "^1.1.1", | ||
| 18 | "date-fns": "^4.1.0", | ||
| 19 | "embla-carousel-react": "^8.6.0", | ||
| 20 | "input-otp": "^1.4.2", | ||
| 21 | "lucide-react": "^1.7.0", | ||
| 22 | "next-themes": "^0.4.6", | ||
| 23 | "radix-ui": "^1.4.3", | ||
| 24 | "react": "^19.1.0", | ||
| 25 | "react-day-picker": "^9.14.0", | ||
| 26 | "react-hook-form": "^7.72.0", | ||
| 27 | "react-resizable-panels": "^4", | ||
| 28 | "recharts": "3.8.0", | ||
| 29 | "sonner": "^2.0.7", | ||
| 30 | "tailwind-merge": "^3.3.0", | ||
| 31 | "vaul": "^1.1.2", | ||
| 32 | "zod": "^4.3.6" | ||
| 33 | }, | ||
| 34 | "devDependencies": { | ||
| 35 | "@types/react": "^19.1.0", | ||
| 36 | "typescript": "^5.9.3", | ||
| 37 | "tailwindcss": "^4.1.10" | ||
| 38 | }, | ||
| 39 | "scripts": { | ||
| 40 | "typecheck": "tsc --noEmit" | ||
| 41 | } | ||
| 42 | } | ||
| @@ -0,0 +1,64 @@ | |||
| 1 | import * as React from "react" | ||
| 2 | import { ChevronDownIcon } from "lucide-react" | ||
| 3 | import { Accordion as AccordionPrimitive } from "radix-ui" | ||
| 4 | |||
| 5 | import { cn } from "@executor/ui/lib/utils" | ||
| 6 | |||
| 7 | function Accordion({ | ||
| 8 | ...props | ||
| 9 | }: React.ComponentProps<typeof AccordionPrimitive.Root>) { | ||
| 10 | return <AccordionPrimitive.Root data-slot="accordion" {...props} /> | ||
| 11 | } | ||
| 12 | |||
| 13 | function AccordionItem({ | ||
| 14 | className, | ||
| 15 | ...props | ||
| 16 | }: React.ComponentProps<typeof AccordionPrimitive.Item>) { | ||
| 17 | return ( | ||
| 18 | <AccordionPrimitive.Item | ||
| 19 | data-slot="accordion-item" | ||
| 20 | className={cn("border-b last:border-b-0", className)} | ||
| 21 | {...props} | ||
| 22 | /> | ||
| 23 | ) | ||
| 24 | } | ||
| 25 | |||
| 26 | function AccordionTrigger({ | ||
| 27 | className, | ||
| 28 | children, | ||
| 29 | ...props | ||
| 30 | }: React.ComponentProps<typeof AccordionPrimitive.Trigger>) { | ||
| 31 | return ( | ||
| 32 | <AccordionPrimitive.Header className="flex"> | ||
| 33 | <AccordionPrimitive.Trigger | ||
| 34 | data-slot="accordion-trigger" | ||
| 35 | className={cn( | ||
| 36 | "flex flex-1 items-start justify-between gap-4 rounded-md py-4 text-left text-sm font-medium transition-all outline-none hover:underline focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 disabled:pointer-events-none disabled:opacity-50 [&[data-state=open]>svg]:rotate-180", | ||
| 37 | className | ||
| 38 | )} | ||
| 39 | {...props} | ||
| 40 | > | ||
| 41 | {children} | ||
| 42 | <ChevronDownIcon className="pointer-events-none size-4 shrink-0 translate-y-0.5 text-muted-foreground transition-transform duration-200" /> | ||
| 43 | </AccordionPrimitive.Trigger> | ||
| 44 | </AccordionPrimitive.Header> | ||
| 45 | ) | ||
| 46 | } | ||
| 47 | |||
| 48 | function AccordionContent({ | ||
| 49 | className, | ||
| 50 | children, | ||
| 51 | ...props | ||
| 52 | }: React.ComponentProps<typeof AccordionPrimitive.Content>) { | ||
| 53 | return ( | ||
| 54 | <AccordionPrimitive.Content | ||
| 55 | data-slot="accordion-content" | ||
| 56 | className="overflow-hidden text-sm data-[state=closed]:animate-accordion-up data-[state=open]:animate-accordion-down" | ||
| 57 | {...props} | ||
| 58 | > | ||
| 59 | <div className={cn("pt-0 pb-4", className)}>{children}</div> | ||
| 60 | </AccordionPrimitive.Content> | ||
| 61 | ) | ||
| 62 | } | ||
| 63 | |||
| 64 | export { Accordion, AccordionItem, AccordionTrigger, AccordionContent } | ||
| @@ -0,0 +1,196 @@ | |||
| 1 | "use client" | ||
| 2 | |||
| 3 | import * as React from "react" | ||
| 4 | import { AlertDialog as AlertDialogPrimitive } from "radix-ui" | ||
| 5 | |||
| 6 | import { cn } from "@executor/ui/lib/utils" | ||
| 7 | import { Button } from "@executor/ui/components/button" | ||
| 8 | |||
| 9 | function AlertDialog({ | ||
| 10 | ...props | ||
| 11 | }: React.ComponentProps<typeof AlertDialogPrimitive.Root>) { | ||
| 12 | return <AlertDialogPrimitive.Root data-slot="alert-dialog" {...props} /> | ||
| 13 | } | ||
| 14 | |||
| 15 | function AlertDialogTrigger({ | ||
| 16 | ...props | ||
| 17 | }: React.ComponentProps<typeof AlertDialogPrimitive.Trigger>) { | ||
| 18 | return ( | ||
| 19 | <AlertDialogPrimitive.Trigger data-slot="alert-dialog-trigger" {...props} /> | ||
| 20 | ) | ||
| 21 | } | ||
| 22 | |||
| 23 | function AlertDialogPortal({ | ||
| 24 | ...props | ||
| 25 | }: React.ComponentProps<typeof AlertDialogPrimitive.Portal>) { | ||
| 26 | return ( | ||
| 27 | <AlertDialogPrimitive.Portal data-slot="alert-dialog-portal" {...props} /> | ||
| 28 | ) | ||
| 29 | } | ||
| 30 | |||
| 31 | function AlertDialogOverlay({ | ||
| 32 | className, | ||
| 33 | ...props | ||
| 34 | }: React.ComponentProps<typeof AlertDialogPrimitive.Overlay>) { | ||
| 35 | return ( | ||
| 36 | <AlertDialogPrimitive.Overlay | ||
| 37 | data-slot="alert-dialog-overlay" | ||
| 38 | className={cn( | ||
| 39 | "fixed inset-0 z-50 bg-black/50 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:animate-in data-[state=open]:fade-in-0", | ||
| 40 | className | ||
| 41 | )} | ||
| 42 | {...props} | ||
| 43 | /> | ||
| 44 | ) | ||
| 45 | } | ||
| 46 | |||
| 47 | function AlertDialogContent({ | ||
| 48 | className, | ||
| 49 | size = "default", | ||
| 50 | ...props | ||
| 51 | }: React.ComponentProps<typeof AlertDialogPrimitive.Content> & { | ||
| 52 | size?: "default" | "sm" | ||
| 53 | }) { | ||
| 54 | return ( | ||
| 55 | <AlertDialogPortal> | ||
| 56 | <AlertDialogOverlay /> | ||
| 57 | <AlertDialogPrimitive.Content | ||
| 58 | data-slot="alert-dialog-content" | ||
| 59 | data-size={size} | ||
| 60 | className={cn( | ||
| 61 | "group/alert-dialog-content fixed top-[50%] left-[50%] z-50 grid w-full max-w-[calc(100%-2rem)] translate-x-[-50%] translate-y-[-50%] gap-4 rounded-lg border bg-background p-6 shadow-lg duration-200 data-[size=sm]:max-w-xs data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95 data-[size=default]:sm:max-w-lg", | ||
| 62 | className | ||
| 63 | )} | ||
| 64 | {...props} | ||
| 65 | /> | ||
| 66 | </AlertDialogPortal> | ||
| 67 | ) | ||
| 68 | } | ||
| 69 | |||
| 70 | function AlertDialogHeader({ | ||
| 71 | className, | ||
| 72 | ...props | ||
| 73 | }: React.ComponentProps<"div">) { | ||
| 74 | return ( | ||
| 75 | <div | ||
| 76 | data-slot="alert-dialog-header" | ||
| 77 | className={cn( | ||
| 78 | "grid grid-rows-[auto_1fr] place-items-center gap-1.5 text-center has-data-[slot=alert-dialog-media]:grid-rows-[auto_auto_1fr] has-data-[slot=alert-dialog-media]:gap-x-6 sm:group-data-[size=default]/alert-dialog-content:place-items-start sm:group-data-[size=default]/alert-dialog-content:text-left sm:group-data-[size=default]/alert-dialog-content:has-data-[slot=alert-dialog-media]:grid-rows-[auto_1fr]", | ||
| 79 | className | ||
| 80 | )} | ||
| 81 | {...props} | ||
| 82 | /> | ||
| 83 | ) | ||
| 84 | } | ||
| 85 | |||
| 86 | function AlertDialogFooter({ | ||
| 87 | className, | ||
| 88 | ...props | ||
| 89 | }: React.ComponentProps<"div">) { | ||
| 90 | return ( | ||
| 91 | <div | ||
| 92 | data-slot="alert-dialog-footer" | ||
| 93 | className={cn( | ||
| 94 | "flex flex-col-reverse gap-2 group-data-[size=sm]/alert-dialog-content:grid group-data-[size=sm]/alert-dialog-content:grid-cols-2 sm:flex-row sm:justify-end", | ||
| 95 | className | ||
| 96 | )} | ||
| 97 | {...props} | ||
| 98 | /> | ||
| 99 | ) | ||
| 100 | } | ||
| 101 | |||
| 102 | function AlertDialogTitle({ | ||
| 103 | className, | ||
| 104 | ...props | ||
| 105 | }: React.ComponentProps<typeof AlertDialogPrimitive.Title>) { | ||
| 106 | return ( | ||
| 107 | <AlertDialogPrimitive.Title | ||
| 108 | data-slot="alert-dialog-title" | ||
| 109 | className={cn( | ||
| 110 | "text-lg font-semibold sm:group-data-[size=default]/alert-dialog-content:group-has-data-[slot=alert-dialog-media]/alert-dialog-content:col-start-2", | ||
| 111 | className | ||
| 112 | )} | ||
| 113 | {...props} | ||
| 114 | /> | ||
| 115 | ) | ||
| 116 | } | ||
| 117 | |||
| 118 | function AlertDialogDescription({ | ||
| 119 | className, | ||
| 120 | ...props | ||
| 121 | }: React.ComponentProps<typeof AlertDialogPrimitive.Description>) { | ||
| 122 | return ( | ||
| 123 | <AlertDialogPrimitive.Description | ||
| 124 | data-slot="alert-dialog-description" | ||
| 125 | className={cn("text-sm text-muted-foreground", className)} | ||
| 126 | {...props} | ||
| 127 | /> | ||
| 128 | ) | ||
| 129 | } | ||
| 130 | |||
| 131 | function AlertDialogMedia({ | ||
| 132 | className, | ||
| 133 | ...props | ||
| 134 | }: React.ComponentProps<"div">) { | ||
| 135 | return ( | ||
| 136 | <div | ||
| 137 | data-slot="alert-dialog-media" | ||
| 138 | className={cn( | ||
| 139 | "mb-2 inline-flex size-16 items-center justify-center rounded-md bg-muted sm:group-data-[size=default]/alert-dialog-content:row-span-2 *:[svg:not([class*='size-'])]:size-8", | ||
| 140 | className | ||
| 141 | )} | ||
| 142 | {...props} | ||
| 143 | /> | ||
| 144 | ) | ||
| 145 | } | ||
| 146 | |||
| 147 | function AlertDialogAction({ | ||
| 148 | className, | ||
| 149 | variant = "default", | ||
| 150 | size = "default", | ||
| 151 | ...props | ||
| 152 | }: React.ComponentProps<typeof AlertDialogPrimitive.Action> & | ||
| 153 | Pick<React.ComponentProps<typeof Button>, "variant" | "size">) { | ||
| 154 | return ( | ||
| 155 | <Button variant={variant} size={size} asChild> | ||
| 156 | <AlertDialogPrimitive.Action | ||
| 157 | data-slot="alert-dialog-action" | ||
| 158 | className={cn(className)} | ||
| 159 | {...props} | ||
| 160 | /> | ||
| 161 | </Button> | ||
| 162 | ) | ||
| 163 | } | ||
| 164 | |||
| 165 | function AlertDialogCancel({ | ||
| 166 | className, | ||
| 167 | variant = "outline", | ||
| 168 | size = "default", | ||
| 169 | ...props | ||
| 170 | }: React.ComponentProps<typeof AlertDialogPrimitive.Cancel> & | ||
| 171 | Pick<React.ComponentProps<typeof Button>, "variant" | "size">) { | ||
| 172 | return ( | ||
| 173 | <Button variant={variant} size={size} asChild> | ||
| 174 | <AlertDialogPrimitive.Cancel | ||
| 175 | data-slot="alert-dialog-cancel" | ||
| 176 | className={cn(className)} | ||
| 177 | {...props} | ||
| 178 | /> | ||
| 179 | </Button> | ||
| 180 | ) | ||
| 181 | } | ||
| 182 | |||
| 183 | export { | ||
| 184 | AlertDialog, | ||
| 185 | AlertDialogAction, | ||
| 186 | AlertDialogCancel, | ||
| 187 | AlertDialogContent, | ||
| 188 | AlertDialogDescription, | ||
| 189 | AlertDialogFooter, | ||
| 190 | AlertDialogHeader, | ||
| 191 | AlertDialogMedia, | ||
| 192 | AlertDialogOverlay, | ||
| 193 | AlertDialogPortal, | ||
| 194 | AlertDialogTitle, | ||
| 195 | AlertDialogTrigger, | ||
| 196 | } | ||
| @@ -0,0 +1,66 @@ | |||
| 1 | import * as React from "react" | ||
| 2 | import { cva, type VariantProps } from "class-variance-authority" | ||
| 3 | |||
| 4 | import { cn } from "@executor/ui/lib/utils" | ||
| 5 | |||
| 6 | const alertVariants = cva( | ||
| 7 | "relative grid w-full grid-cols-[0_1fr] items-start gap-y-0.5 rounded-lg border px-4 py-3 text-sm has-[>svg]:grid-cols-[calc(var(--spacing)*4)_1fr] has-[>svg]:gap-x-3 [&>svg]:size-4 [&>svg]:translate-y-0.5 [&>svg]:text-current", | ||
| 8 | { | ||
| 9 | variants: { | ||
| 10 | variant: { | ||
| 11 | default: "bg-card text-card-foreground", | ||
| 12 | destructive: | ||
| 13 | "bg-card text-destructive *:data-[slot=alert-description]:text-destructive/90 [&>svg]:text-current", | ||
| 14 | }, | ||
| 15 | }, | ||
| 16 | defaultVariants: { | ||
| 17 | variant: "default", | ||
| 18 | }, | ||
| 19 | } | ||
| 20 | ) | ||
| 21 | |||
| 22 | function Alert({ | ||
| 23 | className, | ||
| 24 | variant, | ||
| 25 | ...props | ||
| 26 | }: React.ComponentProps<"div"> & VariantProps<typeof alertVariants>) { | ||
| 27 | return ( | ||
| 28 | <div | ||
| 29 | data-slot="alert" | ||
| 30 | role="alert" | ||
| 31 | className={cn(alertVariants({ variant }), className)} | ||
| 32 | {...props} | ||
| 33 | /> | ||
| 34 | ) | ||
| 35 | } | ||
| 36 | |||
| 37 | function AlertTitle({ className, ...props }: React.ComponentProps<"div">) { | ||
| 38 | return ( | ||
| 39 | <div | ||
| 40 | data-slot="alert-title" | ||
| 41 | className={cn( | ||
| 42 | "col-start-2 line-clamp-1 min-h-4 font-medium tracking-tight", | ||
| 43 | className | ||
| 44 | )} | ||
| 45 | {...props} | ||
| 46 | /> | ||
| 47 | ) | ||
| 48 | } | ||
| 49 | |||
| 50 | function AlertDescription({ | ||
| 51 | className, | ||
| 52 | ...props | ||
| 53 | }: React.ComponentProps<"div">) { | ||
| 54 | return ( | ||
| 55 | <div | ||
| 56 | data-slot="alert-description" | ||
| 57 | className={cn( | ||
| 58 | "col-start-2 grid justify-items-start gap-1 text-sm text-muted-foreground [&_p]:leading-relaxed", | ||
| 59 | className | ||
| 60 | )} | ||
| 61 | {...props} | ||
| 62 | /> | ||
| 63 | ) | ||
| 64 | } | ||
| 65 | |||
| 66 | export { Alert, AlertTitle, AlertDescription } | ||
| @@ -0,0 +1,11 @@ | |||
| 1 | "use client" | ||
| 2 | |||
| 3 | import { AspectRatio as AspectRatioPrimitive } from "radix-ui" | ||
| 4 | |||
| 5 | function AspectRatio({ | ||
| 6 | ...props | ||
| 7 | }: React.ComponentProps<typeof AspectRatioPrimitive.Root>) { | ||
| 8 | return <AspectRatioPrimitive.Root data-slot="aspect-ratio" {...props} /> | ||
| 9 | } | ||
| 10 | |||
| 11 | export { AspectRatio } | ||
| @@ -0,0 +1,107 @@ | |||
| 1 | import * as React from "react" | ||
| 2 | import { Avatar as AvatarPrimitive } from "radix-ui" | ||
| 3 | |||
| 4 | import { cn } from "@executor/ui/lib/utils" | ||
| 5 | |||
| 6 | function Avatar({ | ||
| 7 | className, | ||
| 8 | size = "default", | ||
| 9 | ...props | ||
| 10 | }: React.ComponentProps<typeof AvatarPrimitive.Root> & { | ||
| 11 | size?: "default" | "sm" | "lg" | ||
| 12 | }) { | ||
| 13 | return ( | ||
| 14 | <AvatarPrimitive.Root | ||
| 15 | data-slot="avatar" | ||
| 16 | data-size={size} | ||
| 17 | className={cn( | ||
| 18 | "group/avatar relative flex size-8 shrink-0 overflow-hidden rounded-full select-none data-[size=lg]:size-10 data-[size=sm]:size-6", | ||
| 19 | className | ||
| 20 | )} | ||
| 21 | {...props} | ||
| 22 | /> | ||
| 23 | ) | ||
| 24 | } | ||
| 25 | |||
| 26 | function AvatarImage({ | ||
| 27 | className, | ||
| 28 | ...props | ||
| 29 | }: React.ComponentProps<typeof AvatarPrimitive.Image>) { | ||
| 30 | return ( | ||
| 31 | <AvatarPrimitive.Image | ||
| 32 | data-slot="avatar-image" | ||
| 33 | className={cn("aspect-square size-full", className)} | ||
| 34 | {...props} | ||
| 35 | /> | ||
| 36 | ) | ||
| 37 | } | ||
| 38 | |||
| 39 | function AvatarFallback({ | ||
| 40 | className, | ||
| 41 | ...props | ||
| 42 | }: React.ComponentProps<typeof AvatarPrimitive.Fallback>) { | ||
| 43 | return ( | ||
| 44 | <AvatarPrimitive.Fallback | ||
| 45 | data-slot="avatar-fallback" | ||
| 46 | className={cn( | ||
| 47 | "flex size-full items-center justify-center rounded-full bg-muted text-sm text-muted-foreground group-data-[size=sm]/avatar:text-xs", | ||
| 48 | className | ||
| 49 | )} | ||
| 50 | {...props} | ||
| 51 | /> | ||
| 52 | ) | ||
| 53 | } | ||
| 54 | |||
| 55 | function AvatarBadge({ className, ...props }: React.ComponentProps<"span">) { | ||
| 56 | return ( | ||
| 57 | <span | ||
| 58 | data-slot="avatar-badge" | ||
| 59 | className={cn( | ||
| 60 | "absolute right-0 bottom-0 z-10 inline-flex items-center justify-center rounded-full bg-primary text-primary-foreground ring-2 ring-background select-none", | ||
| 61 | "group-data-[size=sm]/avatar:size-2 group-data-[size=sm]/avatar:[&>svg]:hidden", | ||
| 62 | "group-data-[size=default]/avatar:size-2.5 group-data-[size=default]/avatar:[&>svg]:size-2", | ||
| 63 | "group-data-[size=lg]/avatar:size-3 group-data-[size=lg]/avatar:[&>svg]:size-2", | ||
| 64 | className | ||
| 65 | )} | ||
| 66 | {...props} | ||
| 67 | /> | ||
| 68 | ) | ||
| 69 | } | ||
| 70 | |||
| 71 | function AvatarGroup({ className, ...props }: React.ComponentProps<"div">) { | ||
| 72 | return ( | ||
| 73 | <div | ||
| 74 | data-slot="avatar-group" | ||
| 75 | className={cn( | ||
| 76 | "group/avatar-group flex -space-x-2 *:data-[slot=avatar]:ring-2 *:data-[slot=avatar]:ring-background", | ||
| 77 | className | ||
| 78 | )} | ||
| 79 | {...props} | ||
| 80 | /> | ||
| 81 | ) | ||
| 82 | } | ||
| 83 | |||
| 84 | function AvatarGroupCount({ | ||
| 85 | className, | ||
| 86 | ...props | ||
| 87 | }: React.ComponentProps<"div">) { | ||
| 88 | return ( | ||
| 89 | <div | ||
| 90 | data-slot="avatar-group-count" | ||
| 91 | className={cn( | ||
| 92 | "relative flex size-8 shrink-0 items-center justify-center rounded-full bg-muted text-sm text-muted-foreground ring-2 ring-background group-has-data-[size=lg]/avatar-group:size-10 group-has-data-[size=sm]/avatar-group:size-6 [&>svg]:size-4 group-has-data-[size=lg]/avatar-group:[&>svg]:size-5 group-has-data-[size=sm]/avatar-group:[&>svg]:size-3", | ||
| 93 | className | ||
| 94 | )} | ||
| 95 | {...props} | ||
| 96 | /> | ||
| 97 | ) | ||
| 98 | } | ||
| 99 | |||
| 100 | export { | ||
| 101 | Avatar, | ||
| 102 | AvatarImage, | ||
| 103 | AvatarFallback, | ||
| 104 | AvatarBadge, | ||
| 105 | AvatarGroup, | ||
| 106 | AvatarGroupCount, | ||
| 107 | } | ||
| @@ -0,0 +1,48 @@ | |||
| 1 | import * as React from "react" | ||
| 2 | import { cva, type VariantProps } from "class-variance-authority" | ||
| 3 | import { Slot } from "radix-ui" | ||
| 4 | |||
| 5 | import { cn } from "@executor/ui/lib/utils" | ||
| 6 | |||
| 7 | const badgeVariants = cva( | ||
| 8 | "inline-flex w-fit shrink-0 items-center justify-center gap-1 overflow-hidden rounded-full border border-transparent px-2 py-0.5 text-xs font-medium whitespace-nowrap transition-[color,box-shadow] focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 aria-invalid:border-destructive aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 [&>svg]:pointer-events-none [&>svg]:size-3", | ||
| 9 | { | ||
| 10 | variants: { | ||
| 11 | variant: { | ||
| 12 | default: "bg-primary text-primary-foreground [a&]:hover:bg-primary/90", | ||
| 13 | secondary: | ||
| 14 | "bg-secondary text-secondary-foreground [a&]:hover:bg-secondary/90", | ||
| 15 | destructive: | ||
| 16 | "bg-destructive text-white focus-visible:ring-destructive/20 dark:bg-destructive/60 dark:focus-visible:ring-destructive/40 [a&]:hover:bg-destructive/90", | ||
| 17 | outline: | ||
| 18 | "border-border text-foreground [a&]:hover:bg-accent [a&]:hover:text-accent-foreground", | ||
| 19 | ghost: "[a&]:hover:bg-accent [a&]:hover:text-accent-foreground", | ||
| 20 | link: "text-primary underline-offset-4 [a&]:hover:underline", | ||
| 21 | }, | ||
| 22 | }, | ||
| 23 | defaultVariants: { | ||
| 24 | variant: "default", | ||
| 25 | }, | ||
| 26 | } | ||
| 27 | ) | ||
| 28 | |||
| 29 | function Badge({ | ||
| 30 | className, | ||
| 31 | variant = "default", | ||
| 32 | asChild = false, | ||
| 33 | ...props | ||
| 34 | }: React.ComponentProps<"span"> & | ||
| 35 | VariantProps<typeof badgeVariants> & { asChild?: boolean }) { | ||
| 36 | const Comp = asChild ? Slot.Root : "span" | ||
| 37 | |||
| 38 | return ( | ||
| 39 | <Comp | ||
| 40 | data-slot="badge" | ||
| 41 | data-variant={variant} | ||
| 42 | className={cn(badgeVariants({ variant }), className)} | ||
| 43 | {...props} | ||
| 44 | /> | ||
| 45 | ) | ||
| 46 | } | ||
| 47 | |||
| 48 | export { Badge, badgeVariants } | ||
| @@ -0,0 +1,109 @@ | |||
| 1 | import * as React from "react" | ||
| 2 | import { ChevronRight, MoreHorizontal } from "lucide-react" | ||
| 3 | import { Slot } from "radix-ui" | ||
| 4 | |||
| 5 | import { cn } from "@executor/ui/lib/utils" | ||
| 6 | |||
| 7 | function Breadcrumb({ ...props }: React.ComponentProps<"nav">) { | ||
| 8 | return <nav aria-label="breadcrumb" data-slot="breadcrumb" {...props} /> | ||
| 9 | } | ||
| 10 | |||
| 11 | function BreadcrumbList({ className, ...props }: React.ComponentProps<"ol">) { | ||
| 12 | return ( | ||
| 13 | <ol | ||
| 14 | data-slot="breadcrumb-list" | ||
| 15 | className={cn( | ||
| 16 | "flex flex-wrap items-center gap-1.5 text-sm break-words text-muted-foreground sm:gap-2.5", | ||
| 17 | className | ||
| 18 | )} | ||
| 19 | {...props} | ||
| 20 | /> | ||
| 21 | ) | ||
| 22 | } | ||
| 23 | |||
| 24 | function BreadcrumbItem({ className, ...props }: React.ComponentProps<"li">) { | ||
| 25 | return ( | ||
| 26 | <li | ||
| 27 | data-slot="breadcrumb-item" | ||
| 28 | className={cn("inline-flex items-center gap-1.5", className)} | ||
| 29 | {...props} | ||
| 30 | /> | ||
| 31 | ) | ||
| 32 | } | ||
| 33 | |||
| 34 | function BreadcrumbLink({ | ||
| 35 | asChild, | ||
| 36 | className, | ||
| 37 | ...props | ||
| 38 | }: React.ComponentProps<"a"> & { | ||
| 39 | asChild?: boolean | ||
| 40 | }) { | ||
| 41 | const Comp = asChild ? Slot.Root : "a" | ||
| 42 | |||
| 43 | return ( | ||
| 44 | <Comp | ||
| 45 | data-slot="breadcrumb-link" | ||
| 46 | className={cn("transition-colors hover:text-foreground", className)} | ||
| 47 | {...props} | ||
| 48 | /> | ||
| 49 | ) | ||
| 50 | } | ||
| 51 | |||
| 52 | function BreadcrumbPage({ className, ...props }: React.ComponentProps<"span">) { | ||
| 53 | return ( | ||
| 54 | <span | ||
| 55 | data-slot="breadcrumb-page" | ||
| 56 | role="link" | ||
| 57 | aria-disabled="true" | ||
| 58 | aria-current="page" | ||
| 59 | className={cn("font-normal text-foreground", className)} | ||
| 60 | {...props} | ||
| 61 | /> | ||
| 62 | ) | ||
| 63 | } | ||
| 64 | |||
| 65 | function BreadcrumbSeparator({ | ||
| 66 | children, | ||
| 67 | className, | ||
| 68 | ...props | ||
| 69 | }: React.ComponentProps<"li">) { | ||
| 70 | return ( | ||
| 71 | <li | ||
| 72 | data-slot="breadcrumb-separator" | ||
| 73 | role="presentation" | ||
| 74 | aria-hidden="true" | ||
| 75 | className={cn("[&>svg]:size-3.5", className)} | ||
| 76 | {...props} | ||
| 77 | > | ||
| 78 | {children ?? <ChevronRight />} | ||
| 79 | </li> | ||
| 80 | ) | ||
| 81 | } | ||
| 82 | |||
| 83 | function BreadcrumbEllipsis({ | ||
| 84 | className, | ||
| 85 | ...props | ||
| 86 | }: React.ComponentProps<"span">) { | ||
| 87 | return ( | ||
| 88 | <span | ||
| 89 | data-slot="breadcrumb-ellipsis" | ||
| 90 | role="presentation" | ||
| 91 | aria-hidden="true" | ||
| 92 | className={cn("flex size-9 items-center justify-center", className)} | ||
| 93 | {...props} | ||
| 94 | > | ||
| 95 | <MoreHorizontal className="size-4" /> | ||
| 96 | <span className="sr-only">More</span> | ||
| 97 | </span> | ||
| 98 | ) | ||
| 99 | } | ||
| 100 | |||
| 101 | export { | ||
| 102 | Breadcrumb, | ||
| 103 | BreadcrumbList, | ||
| 104 | BreadcrumbItem, | ||
| 105 | BreadcrumbLink, | ||
| 106 | BreadcrumbPage, | ||
| 107 | BreadcrumbSeparator, | ||
| 108 | BreadcrumbEllipsis, | ||
| 109 | } | ||
| @@ -0,0 +1,83 @@ | |||
| 1 | import { cva, type VariantProps } from "class-variance-authority" | ||
| 2 | import { Slot } from "radix-ui" | ||
| 3 | |||
| 4 | import { cn } from "@executor/ui/lib/utils" | ||
| 5 | import { Separator } from "@executor/ui/components/separator" | ||
| 6 | |||
| 7 | const buttonGroupVariants = cva( | ||
| 8 | "flex w-fit items-stretch has-[>[data-slot=button-group]]:gap-2 [&>*]:focus-visible:relative [&>*]:focus-visible:z-10 has-[select[aria-hidden=true]:last-child]:[&>[data-slot=select-trigger]:last-of-type]:rounded-r-md [&>[data-slot=select-trigger]:not([class*='w-'])]:w-fit [&>input]:flex-1", | ||
| 9 | { | ||
| 10 | variants: { | ||
| 11 | orientation: { | ||
| 12 | horizontal: | ||
| 13 | "[&>*:not(:first-child)]:rounded-l-none [&>*:not(:first-child)]:border-l-0 [&>*:not(:last-child)]:rounded-r-none", | ||
| 14 | vertical: | ||
| 15 | "flex-col [&>*:not(:first-child)]:rounded-t-none [&>*:not(:first-child)]:border-t-0 [&>*:not(:last-child)]:rounded-b-none", | ||
| 16 | }, | ||
| 17 | }, | ||
| 18 | defaultVariants: { | ||
| 19 | orientation: "horizontal", | ||
| 20 | }, | ||
| 21 | } | ||
| 22 | ) | ||
| 23 | |||
| 24 | function ButtonGroup({ | ||
| 25 | className, | ||
| 26 | orientation, | ||
| 27 | ...props | ||
| 28 | }: React.ComponentProps<"div"> & VariantProps<typeof buttonGroupVariants>) { | ||
| 29 | return ( | ||
| 30 | <div | ||
| 31 | role="group" | ||
| 32 | data-slot="button-group" | ||
| 33 | data-orientation={orientation} | ||
| 34 | className={cn(buttonGroupVariants({ orientation }), className)} | ||
| 35 | {...props} | ||
| 36 | /> | ||
| 37 | ) | ||
| 38 | } | ||
| 39 | |||
| 40 | function ButtonGroupText({ | ||
| 41 | className, | ||
| 42 | asChild = false, | ||
| 43 | ...props | ||
| 44 | }: React.ComponentProps<"div"> & { | ||
| 45 | asChild?: boolean | ||
| 46 | }) { | ||
| 47 | const Comp = asChild ? Slot.Root : "div" | ||
| 48 | |||
| 49 | return ( | ||
| 50 | <Comp | ||
| 51 | className={cn( | ||
| 52 | "flex items-center gap-2 rounded-md border bg-muted px-4 text-sm font-medium shadow-xs [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4", | ||
| 53 | className | ||
| 54 | )} | ||
| 55 | {...props} | ||
| 56 | /> | ||
| 57 | ) | ||
| 58 | } | ||
| 59 | |||
| 60 | function ButtonGroupSeparator({ | ||
| 61 | className, | ||
| 62 | orientation = "vertical", | ||
| 63 | ...props | ||
| 64 | }: React.ComponentProps<typeof Separator>) { | ||
| 65 | return ( | ||
| 66 | <Separator | ||
| 67 | data-slot="button-group-separator" | ||
| 68 | orientation={orientation} | ||
| 69 | className={cn( | ||
| 70 | "relative m-0! self-stretch bg-input data-[orientation=vertical]:h-auto", | ||
| 71 | className | ||
| 72 | )} | ||
| 73 | {...props} | ||
| 74 | /> | ||
| 75 | ) | ||
| 76 | } | ||
| 77 | |||
| 78 | export { | ||
| 79 | ButtonGroup, | ||
| 80 | ButtonGroupSeparator, | ||
| 81 | ButtonGroupText, | ||
| 82 | buttonGroupVariants, | ||
| 83 | } | ||
| @@ -0,0 +1,64 @@ | |||
| 1 | import * as React from "react" | ||
| 2 | import { cva, type VariantProps } from "class-variance-authority" | ||
| 3 | import { Slot } from "radix-ui" | ||
| 4 | |||
| 5 | import { cn } from "@executor/ui/lib/utils" | ||
| 6 | |||
| 7 | const buttonVariants = cva( | ||
| 8 | "inline-flex shrink-0 items-center justify-center gap-2 rounded-md text-sm font-medium whitespace-nowrap transition-all outline-none focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 disabled:pointer-events-none disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4", | ||
| 9 | { | ||
| 10 | variants: { | ||
| 11 | variant: { | ||
| 12 | default: "bg-primary text-primary-foreground hover:bg-primary/90", | ||
| 13 | destructive: | ||
| 14 | "bg-destructive text-white hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:bg-destructive/60 dark:focus-visible:ring-destructive/40", | ||
| 15 | outline: | ||
| 16 | "border bg-background shadow-xs hover:bg-accent hover:text-accent-foreground dark:border-input dark:bg-input/30 dark:hover:bg-input/50", | ||
| 17 | secondary: | ||
| 18 | "bg-secondary text-secondary-foreground hover:bg-secondary/80", | ||
| 19 | ghost: | ||
| 20 | "hover:bg-accent hover:text-accent-foreground dark:hover:bg-accent/50", | ||
| 21 | link: "text-primary underline-offset-4 hover:underline", | ||
| 22 | }, | ||
| 23 | size: { | ||
| 24 | default: "h-9 px-4 py-2 has-[>svg]:px-3", | ||
| 25 | xs: "h-6 gap-1 rounded-md px-2 text-xs has-[>svg]:px-1.5 [&_svg:not([class*='size-'])]:size-3", | ||
| 26 | sm: "h-8 gap-1.5 rounded-md px-3 has-[>svg]:px-2.5", | ||
| 27 | lg: "h-10 rounded-md px-6 has-[>svg]:px-4", | ||
| 28 | icon: "size-9", | ||
| 29 | "icon-xs": "size-6 rounded-md [&_svg:not([class*='size-'])]:size-3", | ||
| 30 | "icon-sm": "size-8", | ||
| 31 | "icon-lg": "size-10", | ||
| 32 | }, | ||
| 33 | }, | ||
| 34 | defaultVariants: { | ||
| 35 | variant: "default", | ||
| 36 | size: "default", | ||
| 37 | }, | ||
| 38 | } | ||
| 39 | ) | ||
| 40 | |||
| 41 | function Button({ | ||
| 42 | className, | ||
| 43 | variant = "default", | ||
| 44 | size = "default", | ||
| 45 | asChild = false, | ||
| 46 | ...props | ||
| 47 | }: React.ComponentProps<"button"> & | ||
| 48 | VariantProps<typeof buttonVariants> & { | ||
| 49 | asChild?: boolean | ||
| 50 | }) { | ||
| 51 | const Comp = asChild ? Slot.Root : "button" | ||
| 52 | |||
| 53 | return ( | ||
| 54 | <Comp | ||
| 55 | data-slot="button" | ||
| 56 | data-variant={variant} | ||
| 57 | data-size={size} | ||
| 58 | className={cn(buttonVariants({ variant, size, className }))} | ||
| 59 | {...props} | ||
| 60 | /> | ||
| 61 | ) | ||
| 62 | } | ||
| 63 | |||
| 64 | export { Button, buttonVariants } | ||
| @@ -0,0 +1,218 @@ | |||
| 1 | import * as React from "react" | ||
| 2 | import { | ||
| 3 | ChevronDownIcon, | ||
| 4 | ChevronLeftIcon, | ||
| 5 | ChevronRightIcon, | ||
| 6 | } from "lucide-react" | ||
| 7 | import { | ||
| 8 | DayPicker, | ||
| 9 | getDefaultClassNames, | ||
| 10 | type DayButton, | ||
| 11 | } from "react-day-picker" | ||
| 12 | |||
| 13 | import { cn } from "@executor/ui/lib/utils" | ||
| 14 | import { Button, buttonVariants } from "@executor/ui/components/button" | ||
| 15 | |||
| 16 | function Calendar({ | ||
| 17 | className, | ||
| 18 | classNames, | ||
| 19 | showOutsideDays = true, | ||
| 20 | captionLayout = "label", | ||
| 21 | buttonVariant = "ghost", | ||
| 22 | formatters, | ||
| 23 | components, | ||
| 24 | ...props | ||
| 25 | }: React.ComponentProps<typeof DayPicker> & { | ||
| 26 | buttonVariant?: React.ComponentProps<typeof Button>["variant"] | ||
| 27 | }) { | ||
| 28 | const defaultClassNames = getDefaultClassNames() | ||
| 29 | |||
| 30 | return ( | ||
| 31 | <DayPicker | ||
| 32 | showOutsideDays={showOutsideDays} | ||
| 33 | className={cn( | ||
| 34 | "group/calendar bg-background p-3 [--cell-size:--spacing(8)] [[data-slot=card-content]_&]:bg-transparent [[data-slot=popover-content]_&]:bg-transparent", | ||
| 35 | String.raw`rtl:**:[.rdp-button\_next>svg]:rotate-180`, | ||
| 36 | String.raw`rtl:**:[.rdp-button\_previous>svg]:rotate-180`, | ||
| 37 | className | ||
| 38 | )} | ||
| 39 | captionLayout={captionLayout} | ||
| 40 | formatters={{ | ||
| 41 | formatMonthDropdown: (date) => | ||
| 42 | date.toLocaleString("default", { month: "short" }), | ||
| 43 | ...formatters, | ||
| 44 | }} | ||
| 45 | classNames={{ | ||
| 46 | root: cn("w-fit", defaultClassNames.root), | ||
| 47 | months: cn( | ||
| 48 | "relative flex flex-col gap-4 md:flex-row", | ||
| 49 | defaultClassNames.months | ||
| 50 | ), | ||
| 51 | month: cn("flex w-full flex-col gap-4", defaultClassNames.month), | ||
| 52 | nav: cn( | ||
| 53 | "absolute inset-x-0 top-0 flex w-full items-center justify-between gap-1", | ||
| 54 | defaultClassNames.nav | ||
| 55 | ), | ||
| 56 | button_previous: cn( | ||
| 57 | buttonVariants({ variant: buttonVariant }), | ||
| 58 | "size-(--cell-size) p-0 select-none aria-disabled:opacity-50", | ||
| 59 | defaultClassNames.button_previous | ||
| 60 | ), | ||
| 61 | button_next: cn( | ||
| 62 | buttonVariants({ variant: buttonVariant }), | ||
| 63 | "size-(--cell-size) p-0 select-none aria-disabled:opacity-50", | ||
| 64 | defaultClassNames.button_next | ||
| 65 | ), | ||
| 66 | month_caption: cn( | ||
| 67 | "flex h-(--cell-size) w-full items-center justify-center px-(--cell-size)", | ||
| 68 | defaultClassNames.month_caption | ||
| 69 | ), | ||
| 70 | dropdowns: cn( | ||
| 71 | "flex h-(--cell-size) w-full items-center justify-center gap-1.5 text-sm font-medium", | ||
| 72 | defaultClassNames.dropdowns | ||
| 73 | ), | ||
| 74 | dropdown_root: cn( | ||
| 75 | "relative rounded-md border border-input shadow-xs has-focus:border-ring has-focus:ring-[3px] has-focus:ring-ring/50", | ||
| 76 | defaultClassNames.dropdown_root | ||
| 77 | ), | ||
| 78 | dropdown: cn( | ||
| 79 | "absolute inset-0 bg-popover opacity-0", | ||
| 80 | defaultClassNames.dropdown | ||
| 81 | ), | ||
| 82 | caption_label: cn( | ||
| 83 | "font-medium select-none", | ||
| 84 | captionLayout === "label" | ||
| 85 | ? "text-sm" | ||
| 86 | : "flex h-8 items-center gap-1 rounded-md pr-1 pl-2 text-sm [&>svg]:size-3.5 [&>svg]:text-muted-foreground", | ||
| 87 | defaultClassNames.caption_label | ||
| 88 | ), | ||
| 89 | table: "w-full border-collapse", | ||
| 90 | weekdays: cn("flex", defaultClassNames.weekdays), | ||
| 91 | weekday: cn( | ||
| 92 | "flex-1 rounded-md text-[0.8rem] font-normal text-muted-foreground select-none", | ||
| 93 | defaultClassNames.weekday | ||
| 94 | ), | ||
| 95 | week: cn("mt-2 flex w-full", defaultClassNames.week), | ||
| 96 | week_number_header: cn( | ||
| 97 | "w-(--cell-size) select-none", | ||
| 98 | defaultClassNames.week_number_header | ||
| 99 | ), | ||
| 100 | week_number: cn( | ||
| 101 | "text-[0.8rem] text-muted-foreground select-none", | ||
| 102 | defaultClassNames.week_number | ||
| 103 | ), | ||
| 104 | day: cn( | ||
| 105 | "group/day relative aspect-square h-full w-full p-0 text-center select-none [&:last-child[data-selected=true]_button]:rounded-r-md", | ||
| 106 | props.showWeekNumber | ||
| 107 | ? "[&:nth-child(2)[data-selected=true]_button]:rounded-l-md" | ||
| 108 | : "[&:first-child[data-selected=true]_button]:rounded-l-md", | ||
| 109 | defaultClassNames.day | ||
| 110 | ), | ||
| 111 | range_start: cn( | ||
| 112 | "rounded-l-md bg-accent", | ||
| 113 | defaultClassNames.range_start | ||
| 114 | ), | ||
| 115 | range_middle: cn("rounded-none", defaultClassNames.range_middle), | ||
| 116 | range_end: cn("rounded-r-md bg-accent", defaultClassNames.range_end), | ||
| 117 | today: cn( | ||
| 118 | "rounded-md bg-accent text-accent-foreground data-[selected=true]:rounded-none", | ||
| 119 | defaultClassNames.today | ||
| 120 | ), | ||
| 121 | outside: cn( | ||
| 122 | "text-muted-foreground aria-selected:text-muted-foreground", | ||
| 123 | defaultClassNames.outside | ||
| 124 | ), | ||
| 125 | disabled: cn( | ||
| 126 | "text-muted-foreground opacity-50", | ||
| 127 | defaultClassNames.disabled | ||
| 128 | ), | ||
| 129 | hidden: cn("invisible", defaultClassNames.hidden), | ||
| 130 | ...classNames, | ||
| 131 | }} | ||
| 132 | components={{ | ||
| 133 | Root: ({ className, rootRef, ...props }) => { | ||
| 134 | return ( | ||
| 135 | <div | ||
| 136 | data-slot="calendar" | ||
| 137 | ref={rootRef} | ||
| 138 | className={cn(className)} | ||
| 139 | {...props} | ||
| 140 | /> | ||
| 141 | ) | ||
| 142 | }, | ||
| 143 | Chevron: ({ className, orientation, ...props }) => { | ||
| 144 | if (orientation === "left") { | ||
| 145 | return ( | ||
| 146 | <ChevronLeftIcon className={cn("size-4", className)} {...props} /> | ||
| 147 | ) | ||
| 148 | } | ||
| 149 | |||
| 150 | if (orientation === "right") { | ||
| 151 | return ( | ||
| 152 | <ChevronRightIcon | ||
| 153 | className={cn("size-4", className)} | ||
| 154 | {...props} | ||
| 155 | /> | ||
| 156 | ) | ||
| 157 | } | ||
| 158 | |||
| 159 | return ( | ||
| 160 | <ChevronDownIcon className={cn("size-4", className)} {...props} /> | ||
| 161 | ) | ||
| 162 | }, | ||
| 163 | DayButton: CalendarDayButton, | ||
| 164 | WeekNumber: ({ children, ...props }) => { | ||
| 165 | return ( | ||
| 166 | <td {...props}> | ||
| 167 | <div className="flex size-(--cell-size) items-center justify-center text-center"> | ||
| 168 | {children} | ||
| 169 | </div> | ||
| 170 | </td> | ||
| 171 | ) | ||
| 172 | }, | ||
| 173 | ...components, | ||
| 174 | }} | ||
| 175 | {...props} | ||
| 176 | /> | ||
| 177 | ) | ||
| 178 | } | ||
| 179 | |||
| 180 | function CalendarDayButton({ | ||
| 181 | className, | ||
| 182 | day, | ||
| 183 | modifiers, | ||
| 184 | ...props | ||
| 185 | }: React.ComponentProps<typeof DayButton>) { | ||
| 186 | const defaultClassNames = getDefaultClassNames() | ||
| 187 | |||
| 188 | const ref = React.useRef<HTMLButtonElement>(null) | ||
| 189 | React.useEffect(() => { | ||
| 190 | if (modifiers.focused) ref.current?.focus() | ||
| 191 | }, [modifiers.focused]) | ||
| 192 | |||
| 193 | return ( | ||
| 194 | <Button | ||
| 195 | ref={ref} | ||
| 196 | variant="ghost" | ||
| 197 | size="icon" | ||
| 198 | data-day={day.date.toLocaleDateString()} | ||
| 199 | data-selected-single={ | ||
| 200 | modifiers.selected && | ||
| 201 | !modifiers.range_start && | ||
| 202 | !modifiers.range_end && | ||
| 203 | !modifiers.range_middle | ||
| 204 | } | ||
| 205 | data-range-start={modifiers.range_start} | ||
| 206 | data-range-end={modifiers.range_end} | ||
| 207 | data-range-middle={modifiers.range_middle} | ||
| 208 | className={cn( | ||
| 209 | "flex aspect-square size-auto w-full min-w-(--cell-size) flex-col gap-1 leading-none font-normal group-data-[focused=true]/day:relative group-data-[focused=true]/day:z-10 group-data-[focused=true]/day:border-ring group-data-[focused=true]/day:ring-[3px] group-data-[focused=true]/day:ring-ring/50 data-[range-end=true]:rounded-md data-[range-end=true]:rounded-r-md data-[range-end=true]:bg-primary data-[range-end=true]:text-primary-foreground data-[range-middle=true]:rounded-none data-[range-middle=true]:bg-accent data-[range-middle=true]:text-accent-foreground data-[range-start=true]:rounded-md data-[range-start=true]:rounded-l-md data-[range-start=true]:bg-primary data-[range-start=true]:text-primary-foreground data-[selected-single=true]:bg-primary data-[selected-single=true]:text-primary-foreground dark:hover:text-accent-foreground [&>span]:text-xs [&>span]:opacity-70", | ||
| 210 | defaultClassNames.day, | ||
| 211 | className | ||
| 212 | )} | ||
| 213 | {...props} | ||
| 214 | /> | ||
| 215 | ) | ||
| 216 | } | ||
| 217 | |||
| 218 | export { Calendar, CalendarDayButton } | ||
| @@ -0,0 +1,92 @@ | |||
| 1 | import * as React from "react" | ||
| 2 | |||
| 3 | import { cn } from "@executor/ui/lib/utils" | ||
| 4 | |||
| 5 | function Card({ className, ...props }: React.ComponentProps<"div">) { | ||
| 6 | return ( | ||
| 7 | <div | ||
| 8 | data-slot="card" | ||
| 9 | className={cn( | ||
| 10 | "flex flex-col gap-6 rounded-xl border bg-card py-6 text-card-foreground shadow-sm", | ||
| 11 | className | ||
| 12 | )} | ||
| 13 | {...props} | ||
| 14 | /> | ||
| 15 | ) | ||
| 16 | } | ||
| 17 | |||
| 18 | function CardHeader({ className, ...props }: React.ComponentProps<"div">) { | ||
| 19 | return ( | ||
| 20 | <div | ||
| 21 | data-slot="card-header" | ||
| 22 | className={cn( | ||
| 23 | "@container/card-header grid auto-rows-min grid-rows-[auto_auto] items-start gap-2 px-6 has-data-[slot=card-action]:grid-cols-[1fr_auto] [.border-b]:pb-6", | ||
| 24 | className | ||
| 25 | )} | ||
| 26 | {...props} | ||
| 27 | /> | ||
| 28 | ) | ||
| 29 | } | ||
| 30 | |||
| 31 | function CardTitle({ className, ...props }: React.ComponentProps<"div">) { | ||
| 32 | return ( | ||
| 33 | <div | ||
| 34 | data-slot="card-title" | ||
| 35 | className={cn("leading-none font-semibold", className)} | ||
| 36 | {...props} | ||
| 37 | /> | ||
| 38 | ) | ||
| 39 | } | ||
| 40 | |||
| 41 | function CardDescription({ className, ...props }: React.ComponentProps<"div">) { | ||
| 42 | return ( | ||
| 43 | <div | ||
| 44 | data-slot="card-description" | ||
| 45 | className={cn("text-sm text-muted-foreground", className)} | ||
| 46 | {...props} | ||
| 47 | /> | ||
| 48 | ) | ||
| 49 | } | ||
| 50 | |||
| 51 | function CardAction({ className, ...props }: React.ComponentProps<"div">) { | ||
| 52 | return ( | ||
| 53 | <div | ||
| 54 | data-slot="card-action" | ||
| 55 | className={cn( | ||
| 56 | "col-start-2 row-span-2 row-start-1 self-start justify-self-end", | ||
| 57 | className | ||
| 58 | )} | ||
| 59 | {...props} | ||
| 60 | /> | ||
| 61 | ) | ||
| 62 | } | ||
| 63 | |||
| 64 | function CardContent({ className, ...props }: React.ComponentProps<"div">) { | ||
| 65 | return ( | ||
| 66 | <div | ||
| 67 | data-slot="card-content" | ||
| 68 | className={cn("px-6", className)} | ||
| 69 | {...props} | ||
| 70 | /> | ||
| 71 | ) | ||
| 72 | } | ||
| 73 | |||
| 74 | function CardFooter({ className, ...props }: React.ComponentProps<"div">) { | ||
| 75 | return ( | ||
| 76 | <div | ||
| 77 | data-slot="card-footer" | ||
| 78 | className={cn("flex items-center px-6 [.border-t]:pt-6", className)} | ||
| 79 | {...props} | ||
| 80 | /> | ||
| 81 | ) | ||
| 82 | } | ||
| 83 | |||
| 84 | export { | ||
| 85 | Card, | ||
| 86 | CardHeader, | ||
| 87 | CardFooter, | ||
| 88 | CardTitle, | ||
| 89 | CardAction, | ||
| 90 | CardDescription, | ||
| 91 | CardContent, | ||
| 92 | } | ||
| @@ -0,0 +1,241 @@ | |||
| 1 | "use client" | ||
| 2 | |||
| 3 | import * as React from "react" | ||
| 4 | import useEmblaCarousel, { | ||
| 5 | type UseEmblaCarouselType, | ||
| 6 | } from "embla-carousel-react" | ||
| 7 | import { ArrowLeft, ArrowRight } from "lucide-react" | ||
| 8 | |||
| 9 | import { cn } from "@executor/ui/lib/utils" | ||
| 10 | import { Button } from "@executor/ui/components/button" | ||
| 11 | |||
| 12 | type CarouselApi = UseEmblaCarouselType[1] | ||
| 13 | type UseCarouselParameters = Parameters<typeof useEmblaCarousel> | ||
| 14 | type CarouselOptions = UseCarouselParameters[0] | ||
| 15 | type CarouselPlugin = UseCarouselParameters[1] | ||
| 16 | |||
| 17 | type CarouselProps = { | ||
| 18 | opts?: CarouselOptions | ||
| 19 | plugins?: CarouselPlugin | ||
| 20 | orientation?: "horizontal" | "vertical" | ||
| 21 | setApi?: (api: CarouselApi) => void | ||
| 22 | } | ||
| 23 | |||
| 24 | type CarouselContextProps = { | ||
| 25 | carouselRef: ReturnType<typeof useEmblaCarousel>[0] | ||
| 26 | api: ReturnType<typeof useEmblaCarousel>[1] | ||
| 27 | scrollPrev: () => void | ||
| 28 | scrollNext: () => void | ||
| 29 | canScrollPrev: boolean | ||
| 30 | canScrollNext: boolean | ||
| 31 | } & CarouselProps | ||
| 32 | |||
| 33 | const CarouselContext = React.createContext<CarouselContextProps | null>(null) | ||
| 34 | |||
| 35 | function useCarousel() { | ||
| 36 | const context = React.useContext(CarouselContext) | ||
| 37 | |||
| 38 | if (!context) { | ||
| 39 | throw new Error("useCarousel must be used within a <Carousel />") | ||
| 40 | } | ||
| 41 | |||
| 42 | return context | ||
| 43 | } | ||
| 44 | |||
| 45 | function Carousel({ | ||
| 46 | orientation = "horizontal", | ||
| 47 | opts, | ||
| 48 | setApi, | ||
| 49 | plugins, | ||
| 50 | className, | ||
| 51 | children, | ||
| 52 | ...props | ||
| 53 | }: React.ComponentProps<"div"> & CarouselProps) { | ||
| 54 | const [carouselRef, api] = useEmblaCarousel( | ||
| 55 | { | ||
| 56 | ...opts, | ||
| 57 | axis: orientation === "horizontal" ? "x" : "y", | ||
| 58 | }, | ||
| 59 | plugins | ||
| 60 | ) | ||
| 61 | const [canScrollPrev, setCanScrollPrev] = React.useState(false) | ||
| 62 | const [canScrollNext, setCanScrollNext] = React.useState(false) | ||
| 63 | |||
| 64 | const onSelect = React.useCallback((api: CarouselApi) => { | ||
| 65 | if (!api) return | ||
| 66 | setCanScrollPrev(api.canScrollPrev()) | ||
| 67 | setCanScrollNext(api.canScrollNext()) | ||
| 68 | }, []) | ||
| 69 | |||
| 70 | const scrollPrev = React.useCallback(() => { | ||
| 71 | api?.scrollPrev() | ||
| 72 | }, [api]) | ||
| 73 | |||
| 74 | const scrollNext = React.useCallback(() => { | ||
| 75 | api?.scrollNext() | ||
| 76 | }, [api]) | ||
| 77 | |||
| 78 | const handleKeyDown = React.useCallback( | ||
| 79 | (event: React.KeyboardEvent<HTMLDivElement>) => { | ||
| 80 | if (event.key === "ArrowLeft") { | ||
| 81 | event.preventDefault() | ||
| 82 | scrollPrev() | ||
| 83 | } else if (event.key === "ArrowRight") { | ||
| 84 | event.preventDefault() | ||
| 85 | scrollNext() | ||
| 86 | } | ||
| 87 | }, | ||
| 88 | [scrollPrev, scrollNext] | ||
| 89 | ) | ||
| 90 | |||
| 91 | React.useEffect(() => { | ||
| 92 | if (!api || !setApi) return | ||
| 93 | setApi(api) | ||
| 94 | }, [api, setApi]) | ||
| 95 | |||
| 96 | React.useEffect(() => { | ||
| 97 | if (!api) return | ||
| 98 | onSelect(api) | ||
| 99 | api.on("reInit", onSelect) | ||
| 100 | api.on("select", onSelect) | ||
| 101 | |||
| 102 | return () => { | ||
| 103 | api?.off("select", onSelect) | ||
| 104 | } | ||
| 105 | }, [api, onSelect]) | ||
| 106 | |||
| 107 | return ( | ||
| 108 | <CarouselContext.Provider | ||
| 109 | value={{ | ||
| 110 | carouselRef, | ||
| 111 | api: api, | ||
| 112 | opts, | ||
| 113 | orientation: | ||
| 114 | orientation || (opts?.axis === "y" ? "vertical" : "horizontal"), | ||
| 115 | scrollPrev, | ||
| 116 | scrollNext, | ||
| 117 | canScrollPrev, | ||
| 118 | canScrollNext, | ||
| 119 | }} | ||
| 120 | > | ||
| 121 | <div | ||
| 122 | onKeyDownCapture={handleKeyDown} | ||
| 123 | className={cn("relative", className)} | ||
| 124 | role="region" | ||
| 125 | aria-roledescription="carousel" | ||
| 126 | data-slot="carousel" | ||
| 127 | {...props} | ||
| 128 | > | ||
| 129 | {children} | ||
| 130 | </div> | ||
| 131 | </CarouselContext.Provider> | ||
| 132 | ) | ||
| 133 | } | ||
| 134 | |||
| 135 | function CarouselContent({ className, ...props }: React.ComponentProps<"div">) { | ||
| 136 | const { carouselRef, orientation } = useCarousel() | ||
| 137 | |||
| 138 | return ( | ||
| 139 | <div | ||
| 140 | ref={carouselRef} | ||
| 141 | className="overflow-hidden" | ||
| 142 | data-slot="carousel-content" | ||
| 143 | > | ||
| 144 | <div | ||
| 145 | className={cn( | ||
| 146 | "flex", | ||
| 147 | orientation === "horizontal" ? "-ml-4" : "-mt-4 flex-col", | ||
| 148 | className | ||
| 149 | )} | ||
| 150 | {...props} | ||
| 151 | /> | ||
| 152 | </div> | ||
| 153 | ) | ||
| 154 | } | ||
| 155 | |||
| 156 | function CarouselItem({ className, ...props }: React.ComponentProps<"div">) { | ||
| 157 | const { orientation } = useCarousel() | ||
| 158 | |||
| 159 | return ( | ||
| 160 | <div | ||
| 161 | role="group" | ||
| 162 | aria-roledescription="slide" | ||
| 163 | data-slot="carousel-item" | ||
| 164 | className={cn( | ||
| 165 | "min-w-0 shrink-0 grow-0 basis-full", | ||
| 166 | orientation === "horizontal" ? "pl-4" : "pt-4", | ||
| 167 | className | ||
| 168 | )} | ||
| 169 | {...props} | ||
| 170 | /> | ||
| 171 | ) | ||
| 172 | } | ||
| 173 | |||
| 174 | function CarouselPrevious({ | ||
| 175 | className, | ||
| 176 | variant = "outline", | ||
| 177 | size = "icon", | ||
| 178 | ...props | ||
| 179 | }: React.ComponentProps<typeof Button>) { | ||
| 180 | const { orientation, scrollPrev, canScrollPrev } = useCarousel() | ||
| 181 | |||
| 182 | return ( | ||
| 183 | <Button | ||
| 184 | data-slot="carousel-previous" | ||
| 185 | variant={variant} | ||
| 186 | size={size} | ||
| 187 | className={cn( | ||
| 188 | "absolute size-8 rounded-full", | ||
| 189 | orientation === "horizontal" | ||
| 190 | ? "top-1/2 -left-12 -translate-y-1/2" | ||
| 191 | : "-top-12 left-1/2 -translate-x-1/2 rotate-90", | ||
| 192 | className | ||
| 193 | )} | ||
| 194 | disabled={!canScrollPrev} | ||
| 195 | onClick={scrollPrev} | ||
| 196 | {...props} | ||
| 197 | > | ||
| 198 | <ArrowLeft /> | ||
| 199 | <span className="sr-only">Previous slide</span> | ||
| 200 | </Button> | ||
| 201 | ) | ||
| 202 | } | ||
| 203 | |||
| 204 | function CarouselNext({ | ||
| 205 | className, | ||
| 206 | variant = "outline", | ||
| 207 | size = "icon", | ||
| 208 | ...props | ||
| 209 | }: React.ComponentProps<typeof Button>) { | ||
| 210 | const { orientation, scrollNext, canScrollNext } = useCarousel() | ||
| 211 | |||
| 212 | return ( | ||
| 213 | <Button | ||
| 214 | data-slot="carousel-next" | ||
| 215 | variant={variant} | ||
| 216 | size={size} | ||
| 217 | className={cn( | ||
| 218 | "absolute size-8 rounded-full", | ||
| 219 | orientation === "horizontal" | ||
| 220 | ? "top-1/2 -right-12 -translate-y-1/2" | ||
| 221 | : "-bottom-12 left-1/2 -translate-x-1/2 rotate-90", | ||
| 222 | className | ||
| 223 | )} | ||
| 224 | disabled={!canScrollNext} | ||
| 225 | onClick={scrollNext} | ||
| 226 | {...props} | ||
| 227 | > | ||
| 228 | <ArrowRight /> | ||
| 229 | <span className="sr-only">Next slide</span> | ||
| 230 | </Button> | ||
| 231 | ) | ||
| 232 | } | ||
| 233 | |||
| 234 | export { | ||
| 235 | type CarouselApi, | ||
| 236 | Carousel, | ||
| 237 | CarouselContent, | ||
| 238 | CarouselItem, | ||
| 239 | CarouselPrevious, | ||
| 240 | CarouselNext, | ||
| 241 | } | ||
| @@ -0,0 +1,372 @@ | |||
| 1 | import * as React from "react" | ||
| 2 | import * as RechartsPrimitive from "recharts" | ||
| 3 | import type { TooltipValueType } from "recharts" | ||
| 4 | |||
| 5 | import { cn } from "@executor/ui/lib/utils" | ||
| 6 | |||
| 7 | // Format: { THEME_NAME: CSS_SELECTOR } | ||
| 8 | const THEMES = { light: "", dark: ".dark" } as const | ||
| 9 | |||
| 10 | const INITIAL_DIMENSION = { width: 320, height: 200 } as const | ||
| 11 | type TooltipNameType = number | string | ||
| 12 | |||
| 13 | export type ChartConfig = Record< | ||
| 14 | string, | ||
| 15 | { | ||
| 16 | label?: React.ReactNode | ||
| 17 | icon?: React.ComponentType | ||
| 18 | } & ( | ||
| 19 | | { color?: string; theme?: never } | ||
| 20 | | { color?: never; theme: Record<keyof typeof THEMES, string> } | ||
| 21 | ) | ||
| 22 | > | ||
| 23 | |||
| 24 | type ChartContextProps = { | ||
| 25 | config: ChartConfig | ||
| 26 | } | ||
| 27 | |||
| 28 | const ChartContext = React.createContext<ChartContextProps | null>(null) | ||
| 29 | |||
| 30 | function useChart() { | ||
| 31 | const context = React.useContext(ChartContext) | ||
| 32 | |||
| 33 | if (!context) { | ||
| 34 | throw new Error("useChart must be used within a <ChartContainer />") | ||
| 35 | } | ||
| 36 | |||
| 37 | return context | ||
| 38 | } | ||
| 39 | |||
| 40 | function ChartContainer({ | ||
| 41 | id, | ||
| 42 | className, | ||
| 43 | children, | ||
| 44 | config, | ||
| 45 | initialDimension = INITIAL_DIMENSION, | ||
| 46 | ...props | ||
| 47 | }: React.ComponentProps<"div"> & { | ||
| 48 | config: ChartConfig | ||
| 49 | children: React.ComponentProps< | ||
| 50 | typeof RechartsPrimitive.ResponsiveContainer | ||
| 51 | >["children"] | ||
| 52 | initialDimension?: { | ||
| 53 | width: number | ||
| 54 | height: number | ||
| 55 | } | ||
| 56 | }) { | ||
| 57 | const uniqueId = React.useId() | ||
| 58 | const chartId = `chart-${id ?? uniqueId.replace(/:/g, "")}` | ||
| 59 | |||
| 60 | return ( | ||
| 61 | <ChartContext.Provider value={{ config }}> | ||
| 62 | <div | ||
| 63 | data-slot="chart" | ||
| 64 | data-chart={chartId} | ||
| 65 | className={cn( | ||
| 66 | "flex aspect-video justify-center text-xs [&_.recharts-cartesian-axis-tick_text]:fill-muted-foreground [&_.recharts-cartesian-grid_line[stroke='#ccc']]:stroke-border/50 [&_.recharts-curve.recharts-tooltip-cursor]:stroke-border [&_.recharts-dot[stroke='#fff']]:stroke-transparent [&_.recharts-layer]:outline-hidden [&_.recharts-polar-grid_[stroke='#ccc']]:stroke-border [&_.recharts-radial-bar-background-sector]:fill-muted [&_.recharts-rectangle.recharts-tooltip-cursor]:fill-muted [&_.recharts-reference-line_[stroke='#ccc']]:stroke-border [&_.recharts-sector]:outline-hidden [&_.recharts-sector[stroke='#fff']]:stroke-transparent [&_.recharts-surface]:outline-hidden", | ||
| 67 | className | ||
| 68 | )} | ||
| 69 | {...props} | ||
| 70 | > | ||
| 71 | <ChartStyle id={chartId} config={config} /> | ||
| 72 | <RechartsPrimitive.ResponsiveContainer | ||
| 73 | initialDimension={initialDimension} | ||
| 74 | > | ||
| 75 | {children} | ||
| 76 | </RechartsPrimitive.ResponsiveContainer> | ||
| 77 | </div> | ||
| 78 | </ChartContext.Provider> | ||
| 79 | ) | ||
| 80 | } | ||
| 81 | |||
| 82 | const ChartStyle = ({ id, config }: { id: string; config: ChartConfig }) => { | ||
| 83 | const colorConfig = Object.entries(config).filter( | ||
| 84 | ([, config]) => config.theme ?? config.color | ||
| 85 | ) | ||
| 86 | |||
| 87 | if (!colorConfig.length) { | ||
| 88 | return null | ||
| 89 | } | ||
| 90 | |||
| 91 | return ( | ||
| 92 | <style | ||
| 93 | dangerouslySetInnerHTML={{ | ||
| 94 | __html: Object.entries(THEMES) | ||
| 95 | .map( | ||
| 96 | ([theme, prefix]) => ` | ||
| 97 | ${prefix} [data-chart=${id}] { | ||
| 98 | ${colorConfig | ||
| 99 | .map(([key, itemConfig]) => { | ||
| 100 | const color = | ||
| 101 | itemConfig.theme?.[theme as keyof typeof itemConfig.theme] ?? | ||
| 102 | itemConfig.color | ||
| 103 | return color ? ` --color-${key}: ${color};` : null | ||
| 104 | }) | ||
| 105 | .join("\n")} | ||
| 106 | } | ||
| 107 | ` | ||
| 108 | ) | ||
| 109 | .join("\n"), | ||
| 110 | }} | ||
| 111 | /> | ||
| 112 | ) | ||
| 113 | } | ||
| 114 | |||
| 115 | const ChartTooltip = RechartsPrimitive.Tooltip | ||
| 116 | |||
| 117 | function ChartTooltipContent({ | ||
| 118 | active, | ||
| 119 | payload, | ||
| 120 | className, | ||
| 121 | indicator = "dot", | ||
| 122 | hideLabel = false, | ||
| 123 | hideIndicator = false, | ||
| 124 | label, | ||
| 125 | labelFormatter, | ||
| 126 | labelClassName, | ||
| 127 | formatter, | ||
| 128 | color, | ||
| 129 | nameKey, | ||
| 130 | labelKey, | ||
| 131 | }: React.ComponentProps<typeof RechartsPrimitive.Tooltip> & | ||
| 132 | React.ComponentProps<"div"> & { | ||
| 133 | hideLabel?: boolean | ||
| 134 | hideIndicator?: boolean | ||
| 135 | indicator?: "line" | "dot" | "dashed" | ||
| 136 | nameKey?: string | ||
| 137 | labelKey?: string | ||
| 138 | } & Omit< | ||
| 139 | RechartsPrimitive.DefaultTooltipContentProps< | ||
| 140 | TooltipValueType, | ||
| 141 | TooltipNameType | ||
| 142 | >, | ||
| 143 | "accessibilityLayer" | ||
| 144 | >) { | ||
| 145 | const { config } = useChart() | ||
| 146 | |||
| 147 | const tooltipLabel = React.useMemo(() => { | ||
| 148 | if (hideLabel || !payload?.length) { | ||
| 149 | return null | ||
| 150 | } | ||
| 151 | |||
| 152 | const [item] = payload | ||
| 153 | const key = `${labelKey ?? item?.dataKey ?? item?.name ?? "value"}` | ||
| 154 | const itemConfig = getPayloadConfigFromPayload(config, item, key) | ||
| 155 | const value = | ||
| 156 | !labelKey && typeof label === "string" | ||
| 157 | ? (config[label]?.label ?? label) | ||
| 158 | : itemConfig?.label | ||
| 159 | |||
| 160 | if (labelFormatter) { | ||
| 161 | return ( | ||
| 162 | <div className={cn("font-medium", labelClassName)}> | ||
| 163 | {labelFormatter(value, payload)} | ||
| 164 | </div> | ||
| 165 | ) | ||
| 166 | } | ||
| 167 | |||
| 168 | if (!value) { | ||
| 169 | return null | ||
| 170 | } | ||
| 171 | |||
| 172 | return <div className={cn("font-medium", labelClassName)}>{value}</div> | ||
| 173 | }, [ | ||
| 174 | label, | ||
| 175 | labelFormatter, | ||
| 176 | payload, | ||
| 177 | hideLabel, | ||
| 178 | labelClassName, | ||
| 179 | config, | ||
| 180 | labelKey, | ||
| 181 | ]) | ||
| 182 | |||
| 183 | if (!active || !payload?.length) { | ||
| 184 | return null | ||
| 185 | } | ||
| 186 | |||
| 187 | const nestLabel = payload.length === 1 && indicator !== "dot" | ||
| 188 | |||
| 189 | return ( | ||
| 190 | <div | ||
| 191 | className={cn( | ||
| 192 | "grid min-w-[8rem] items-start gap-1.5 rounded-lg border border-border/50 bg-background px-2.5 py-1.5 text-xs shadow-xl", | ||
| 193 | className | ||
| 194 | )} | ||
| 195 | > | ||
| 196 | {!nestLabel ? tooltipLabel : null} | ||
| 197 | <div className="grid gap-1.5"> | ||
| 198 | {payload | ||
| 199 | .filter((item) => item.type !== "none") | ||
| 200 | .map((item, index) => { | ||
| 201 | const key = `${nameKey ?? item.name ?? item.dataKey ?? "value"}` | ||
| 202 | const itemConfig = getPayloadConfigFromPayload(config, item, key) | ||
| 203 | const indicatorColor = color ?? item.payload?.fill ?? item.color | ||
| 204 | |||
| 205 | return ( | ||
| 206 | <div | ||
| 207 | key={index} | ||
| 208 | className={cn( | ||
| 209 | "flex w-full flex-wrap items-stretch gap-2 [&>svg]:h-2.5 [&>svg]:w-2.5 [&>svg]:text-muted-foreground", | ||
| 210 | indicator === "dot" && "items-center" | ||
| 211 | )} | ||
| 212 | > | ||
| 213 | {formatter && item?.value !== undefined && item.name ? ( | ||
| 214 | formatter(item.value, item.name, item, index, item.payload) | ||
| 215 | ) : ( | ||
| 216 | <> | ||
| 217 | {itemConfig?.icon ? ( | ||
| 218 | <itemConfig.icon /> | ||
| 219 | ) : ( | ||
| 220 | !hideIndicator && ( | ||
| 221 | <div | ||
| 222 | className={cn( | ||
| 223 | "shrink-0 rounded-[2px] border-(--color-border) bg-(--color-bg)", | ||
| 224 | { | ||
| 225 | "h-2.5 w-2.5": indicator === "dot", | ||
| 226 | "w-1": indicator === "line", | ||
| 227 | "w-0 border-[1.5px] border-dashed bg-transparent": | ||
| 228 | indicator === "dashed", | ||
| 229 | "my-0.5": nestLabel && indicator === "dashed", | ||
| 230 | } | ||
| 231 | )} | ||
| 232 | style={ | ||
| 233 | { | ||
| 234 | "--color-bg": indicatorColor, | ||
| 235 | "--color-border": indicatorColor, | ||
| 236 | } as React.CSSProperties | ||
| 237 | } | ||
| 238 | /> | ||
| 239 | ) | ||
| 240 | )} | ||
| 241 | <div | ||
| 242 | className={cn( | ||
| 243 | "flex flex-1 justify-between leading-none", | ||
| 244 | nestLabel ? "items-end" : "items-center" | ||
| 245 | )} | ||
| 246 | > | ||
| 247 | <div className="grid gap-1.5"> | ||
| 248 | {nestLabel ? tooltipLabel : null} | ||
| 249 | <span className="text-muted-foreground"> | ||
| 250 | {itemConfig?.label ?? item.name} | ||
| 251 | </span> | ||
| 252 | </div> | ||
| 253 | {item.value != null && ( | ||
| 254 | <span className="font-mono font-medium text-foreground tabular-nums"> | ||
| 255 | {typeof item.value === "number" | ||
| 256 | ? item.value.toLocaleString() | ||
| 257 | : String(item.value)} | ||
| 258 | </span> | ||
| 259 | )} | ||
| 260 | </div> | ||
| 261 | </> | ||
| 262 | )} | ||
| 263 | </div> | ||
| 264 | ) | ||
| 265 | })} | ||
| 266 | </div> | ||
| 267 | </div> | ||
| 268 | ) | ||
| 269 | } | ||
| 270 | |||
| 271 | const ChartLegend = RechartsPrimitive.Legend | ||
| 272 | |||
| 273 | function ChartLegendContent({ | ||
| 274 | className, | ||
| 275 | hideIcon = false, | ||
| 276 | payload, | ||
| 277 | verticalAlign = "bottom", | ||
| 278 | nameKey, | ||
| 279 | }: React.ComponentProps<"div"> & { | ||
| 280 | hideIcon?: boolean | ||
| 281 | nameKey?: string | ||
| 282 | } & RechartsPrimitive.DefaultLegendContentProps) { | ||
| 283 | const { config } = useChart() | ||
| 284 | |||
| 285 | if (!payload?.length) { | ||
| 286 | return null | ||
| 287 | } | ||
| 288 | |||
| 289 | return ( | ||
| 290 | <div | ||
| 291 | className={cn( | ||
| 292 | "flex items-center justify-center gap-4", | ||
| 293 | verticalAlign === "top" ? "pb-3" : "pt-3", | ||
| 294 | className | ||
| 295 | )} | ||
| 296 | > | ||
| 297 | {payload | ||
| 298 | .filter((item) => item.type !== "none") | ||
| 299 | .map((item, index) => { | ||
| 300 | const key = `${nameKey ?? item.dataKey ?? "value"}` | ||
| 301 | const itemConfig = getPayloadConfigFromPayload(config, item, key) | ||
| 302 | |||
| 303 | return ( | ||
| 304 | <div | ||
| 305 | key={index} | ||
| 306 | className={cn( | ||
| 307 | "flex items-center gap-1.5 [&>svg]:h-3 [&>svg]:w-3 [&>svg]:text-muted-foreground" | ||
| 308 | )} | ||
| 309 | > | ||
| 310 | {itemConfig?.icon && !hideIcon ? ( | ||
| 311 | <itemConfig.icon /> | ||
| 312 | ) : ( | ||
| 313 | <div | ||
| 314 | className="h-2 w-2 shrink-0 rounded-[2px]" | ||
| 315 | style={{ | ||
| 316 | backgroundColor: item.color, | ||
| 317 | }} | ||
| 318 | /> | ||
| 319 | )} | ||
| 320 | {itemConfig?.label} | ||
| 321 | </div> | ||
| 322 | ) | ||
| 323 | })} | ||
| 324 | </div> | ||
| 325 | ) | ||
| 326 | } | ||
| 327 | |||
| 328 | // Helper to extract item config from a payload. | ||
| 329 | function getPayloadConfigFromPayload( | ||
| 330 | config: ChartConfig, | ||
| 331 | payload: unknown, | ||
| 332 | key: string | ||
| 333 | ) { | ||
| 334 | if (typeof payload !== "object" || payload === null) { | ||
| 335 | return undefined | ||
| 336 | } | ||
| 337 | |||
| 338 | const payloadPayload = | ||
| 339 | "payload" in payload && | ||
| 340 | typeof payload.payload === "object" && | ||
| 341 | payload.payload !== null | ||
| 342 | ? payload.payload | ||
| 343 | : undefined | ||
| 344 | |||
| 345 | let configLabelKey: string = key | ||
| 346 | |||
| 347 | if ( | ||
| 348 | key in payload && | ||
| 349 | typeof payload[key as keyof typeof payload] === "string" | ||
| 350 | ) { | ||
| 351 | configLabelKey = payload[key as keyof typeof payload] as string | ||
| 352 | } else if ( | ||
| 353 | payloadPayload && | ||
| 354 | key in payloadPayload && | ||
| 355 | typeof payloadPayload[key as keyof typeof payloadPayload] === "string" | ||
| 356 | ) { | ||
| 357 | configLabelKey = payloadPayload[ | ||
| 358 | key as keyof typeof payloadPayload | ||
| 359 | ] as string | ||
| 360 | } | ||
| 361 | |||
| 362 | return configLabelKey in config ? config[configLabelKey] : config[key] | ||
| 363 | } | ||
| 364 | |||
| 365 | export { | ||
| 366 | ChartContainer, | ||
| 367 | ChartTooltip, | ||
| 368 | ChartTooltipContent, | ||
| 369 | ChartLegend, | ||
| 370 | ChartLegendContent, | ||
| 371 | ChartStyle, | ||
| 372 | } | ||
| @@ -0,0 +1,32 @@ | |||
| 1 | "use client" | ||
| 2 | |||
| 3 | import * as React from "react" | ||
| 4 | import { CheckIcon } from "lucide-react" | ||
| 5 | import { Checkbox as CheckboxPrimitive } from "radix-ui" | ||
| 6 | |||
| 7 | import { cn } from "@executor/ui/lib/utils" | ||
| 8 | |||
| 9 | function Checkbox({ | ||
| 10 | className, | ||
| 11 | ...props | ||
| 12 | }: React.ComponentProps<typeof CheckboxPrimitive.Root>) { | ||
| 13 | return ( | ||
| 14 | <CheckboxPrimitive.Root | ||
| 15 | data-slot="checkbox" | ||
| 16 | className={cn( | ||
| 17 | "peer size-4 shrink-0 rounded-[4px] border border-input shadow-xs transition-shadow outline-none focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 disabled:cursor-not-allowed disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-destructive/20 data-[state=checked]:border-primary data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground dark:bg-input/30 dark:aria-invalid:ring-destructive/40 dark:data-[state=checked]:bg-primary", | ||
| 18 | className | ||
| 19 | )} | ||
| 20 | {...props} | ||
| 21 | > | ||
| 22 | <CheckboxPrimitive.Indicator | ||
| 23 | data-slot="checkbox-indicator" | ||
| 24 | className="grid place-content-center text-current transition-none" | ||
| 25 | > | ||
| 26 | <CheckIcon className="size-3.5" /> | ||
| 27 | </CheckboxPrimitive.Indicator> | ||
| 28 | </CheckboxPrimitive.Root> | ||
| 29 | ) | ||
| 30 | } | ||
| 31 | |||
| 32 | export { Checkbox } | ||
| @@ -0,0 +1,31 @@ | |||
| 1 | import { Collapsible as CollapsiblePrimitive } from "radix-ui" | ||
| 2 | |||
| 3 | function Collapsible({ | ||
| 4 | ...props | ||
| 5 | }: React.ComponentProps<typeof CollapsiblePrimitive.Root>) { | ||
| 6 | return <CollapsiblePrimitive.Root data-slot="collapsible" {...props} /> | ||
| 7 | } | ||
| 8 | |||
| 9 | function CollapsibleTrigger({ | ||
| 10 | ...props | ||
| 11 | }: React.ComponentProps<typeof CollapsiblePrimitive.CollapsibleTrigger>) { | ||
| 12 | return ( | ||
| 13 | <CollapsiblePrimitive.CollapsibleTrigger | ||
| 14 | data-slot="collapsible-trigger" | ||
| 15 | {...props} | ||
| 16 | /> | ||
| 17 | ) | ||
| 18 | } | ||
| 19 | |||
| 20 | function CollapsibleContent({ | ||
| 21 | ...props | ||
| 22 | }: React.ComponentProps<typeof CollapsiblePrimitive.CollapsibleContent>) { | ||
| 23 | return ( | ||
| 24 | <CollapsiblePrimitive.CollapsibleContent | ||
| 25 | data-slot="collapsible-content" | ||
| 26 | {...props} | ||
| 27 | /> | ||
| 28 | ) | ||
| 29 | } | ||
| 30 | |||
| 31 | export { Collapsible, CollapsibleTrigger, CollapsibleContent } | ||
| @@ -0,0 +1,310 @@ | |||
| 1 | "use client" | ||
| 2 | |||
| 3 | import * as React from "react" | ||
| 4 | import { Combobox as ComboboxPrimitive } from "@base-ui/react" | ||
| 5 | import { CheckIcon, ChevronDownIcon, XIcon } from "lucide-react" | ||
| 6 | |||
| 7 | import { cn } from "@executor/ui/lib/utils" | ||
| 8 | import { Button } from "@executor/ui/components/button" | ||
| 9 | import { | ||
| 10 | InputGroup, | ||
| 11 | InputGroupAddon, | ||
| 12 | InputGroupButton, | ||
| 13 | InputGroupInput, | ||
| 14 | } from "@executor/ui/components/input-group" | ||
| 15 | |||
| 16 | const Combobox = ComboboxPrimitive.Root | ||
| 17 | |||
| 18 | function ComboboxValue({ ...props }: ComboboxPrimitive.Value.Props) { | ||
| 19 | return <ComboboxPrimitive.Value data-slot="combobox-value" {...props} /> | ||
| 20 | } | ||
| 21 | |||
| 22 | function ComboboxTrigger({ | ||
| 23 | className, | ||
| 24 | children, | ||
| 25 | ...props | ||
| 26 | }: ComboboxPrimitive.Trigger.Props) { | ||
| 27 | return ( | ||
| 28 | <ComboboxPrimitive.Trigger | ||
| 29 | data-slot="combobox-trigger" | ||
| 30 | className={cn("[&_svg:not([class*='size-'])]:size-4", className)} | ||
| 31 | {...props} | ||
| 32 | > | ||
| 33 | {children} | ||
| 34 | <ChevronDownIcon | ||
| 35 | data-slot="combobox-trigger-icon" | ||
| 36 | className="pointer-events-none size-4 text-muted-foreground" | ||
| 37 | /> | ||
| 38 | </ComboboxPrimitive.Trigger> | ||
| 39 | ) | ||
| 40 | } | ||
| 41 | |||
| 42 | function ComboboxClear({ className, ...props }: ComboboxPrimitive.Clear.Props) { | ||
| 43 | return ( | ||
| 44 | <ComboboxPrimitive.Clear | ||
| 45 | data-slot="combobox-clear" | ||
| 46 | render={<InputGroupButton variant="ghost" size="icon-xs" />} | ||
| 47 | className={cn(className)} | ||
| 48 | {...props} | ||
| 49 | > | ||
| 50 | <XIcon className="pointer-events-none" /> | ||
| 51 | </ComboboxPrimitive.Clear> | ||
| 52 | ) | ||
| 53 | } | ||
| 54 | |||
| 55 | function ComboboxInput({ | ||
| 56 | className, | ||
| 57 | children, | ||
| 58 | disabled = false, | ||
| 59 | showTrigger = true, | ||
| 60 | showClear = false, | ||
| 61 | ...props | ||
| 62 | }: ComboboxPrimitive.Input.Props & { | ||
| 63 | showTrigger?: boolean | ||
| 64 | showClear?: boolean | ||
| 65 | }) { | ||
| 66 | return ( | ||
| 67 | <InputGroup className={cn("w-auto", className)}> | ||
| 68 | <ComboboxPrimitive.Input | ||
| 69 | render={<InputGroupInput disabled={disabled} />} | ||
| 70 | {...props} | ||
| 71 | /> | ||
| 72 | <InputGroupAddon align="inline-end"> | ||
| 73 | {showTrigger && ( | ||
| 74 | <InputGroupButton | ||
| 75 | size="icon-xs" | ||
| 76 | variant="ghost" | ||
| 77 | asChild | ||
| 78 | data-slot="input-group-button" | ||
| 79 | className="group-has-data-[slot=combobox-clear]/input-group:hidden data-pressed:bg-transparent" | ||
| 80 | disabled={disabled} | ||
| 81 | > | ||
| 82 | <ComboboxTrigger /> | ||
| 83 | </InputGroupButton> | ||
| 84 | )} | ||
| 85 | {showClear && <ComboboxClear disabled={disabled} />} | ||
| 86 | </InputGroupAddon> | ||
| 87 | {children} | ||
| 88 | </InputGroup> | ||
| 89 | ) | ||
| 90 | } | ||
| 91 | |||
| 92 | function ComboboxContent({ | ||
| 93 | className, | ||
| 94 | side = "bottom", | ||
| 95 | sideOffset = 6, | ||
| 96 | align = "start", | ||
| 97 | alignOffset = 0, | ||
| 98 | anchor, | ||
| 99 | ...props | ||
| 100 | }: ComboboxPrimitive.Popup.Props & | ||
| 101 | Pick< | ||
| 102 | ComboboxPrimitive.Positioner.Props, | ||
| 103 | "side" | "align" | "sideOffset" | "alignOffset" | "anchor" | ||
| 104 | >) { | ||
| 105 | return ( | ||
| 106 | <ComboboxPrimitive.Portal> | ||
| 107 | <ComboboxPrimitive.Positioner | ||
| 108 | side={side} | ||
| 109 | sideOffset={sideOffset} | ||
| 110 | align={align} | ||
| 111 | alignOffset={alignOffset} | ||
| 112 | anchor={anchor} | ||
| 113 | className="isolate z-50" | ||
| 114 | > | ||
| 115 | <ComboboxPrimitive.Popup | ||
| 116 | data-slot="combobox-content" | ||
| 117 | data-chips={!!anchor} | ||
| 118 | className={cn( | ||
| 119 | "group/combobox-content relative max-h-96 w-(--anchor-width) max-w-(--available-width) min-w-[calc(var(--anchor-width)+--spacing(7))] origin-(--transform-origin) overflow-hidden rounded-md bg-popover text-popover-foreground shadow-md ring-1 ring-foreground/10 duration-100 data-[chips=true]:min-w-(--anchor-width) data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 *:data-[slot=input-group]:m-1 *:data-[slot=input-group]:mb-0 *:data-[slot=input-group]:h-8 *:data-[slot=input-group]:border-input/30 *:data-[slot=input-group]:bg-input/30 *:data-[slot=input-group]:shadow-none data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95", | ||
| 120 | className | ||
| 121 | )} | ||
| 122 | {...props} | ||
| 123 | /> | ||
| 124 | </ComboboxPrimitive.Positioner> | ||
| 125 | </ComboboxPrimitive.Portal> | ||
| 126 | ) | ||
| 127 | } | ||
| 128 | |||
| 129 | function ComboboxList({ className, ...props }: ComboboxPrimitive.List.Props) { | ||
| 130 | return ( | ||
| 131 | <ComboboxPrimitive.List | ||
| 132 | data-slot="combobox-list" | ||
| 133 | className={cn( | ||
| 134 | "max-h-[min(calc(--spacing(96)---spacing(9)),calc(var(--available-height)---spacing(9)))] scroll-py-1 overflow-y-auto p-1 data-empty:p-0", | ||
| 135 | className | ||
| 136 | )} | ||
| 137 | {...props} | ||
| 138 | /> | ||
| 139 | ) | ||
| 140 | } | ||
| 141 | |||
| 142 | function ComboboxItem({ | ||
| 143 | className, | ||
| 144 | children, | ||
| 145 | ...props | ||
| 146 | }: ComboboxPrimitive.Item.Props) { | ||
| 147 | return ( | ||
| 148 | <ComboboxPrimitive.Item | ||
| 149 | data-slot="combobox-item" | ||
| 150 | className={cn( | ||
| 151 | "relative flex w-full cursor-default items-center gap-2 rounded-sm py-1.5 pr-8 pl-2 text-sm outline-hidden select-none data-highlighted:bg-accent data-highlighted:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4", | ||
| 152 | className | ||
| 153 | )} | ||
| 154 | {...props} | ||
| 155 | > | ||
| 156 | {children} | ||
| 157 | <ComboboxPrimitive.ItemIndicator | ||
| 158 | data-slot="combobox-item-indicator" | ||
| 159 | render={ | ||
| 160 | <span className="pointer-events-none absolute right-2 flex size-4 items-center justify-center" /> | ||
| 161 | } | ||
| 162 | > | ||
| 163 | <CheckIcon className="pointer-events-none size-4 pointer-coarse:size-5" /> | ||
| 164 | </ComboboxPrimitive.ItemIndicator> | ||
| 165 | </ComboboxPrimitive.Item> | ||
| 166 | ) | ||
| 167 | } | ||
| 168 | |||
| 169 | function ComboboxGroup({ className, ...props }: ComboboxPrimitive.Group.Props) { | ||
| 170 | return ( | ||
| 171 | <ComboboxPrimitive.Group | ||
| 172 | data-slot="combobox-group" | ||
| 173 | className={cn(className)} | ||
| 174 | {...props} | ||
| 175 | /> | ||
| 176 | ) | ||
| 177 | } | ||
| 178 | |||
| 179 | function ComboboxLabel({ | ||
| 180 | className, | ||
| 181 | ...props | ||
| 182 | }: ComboboxPrimitive.GroupLabel.Props) { | ||
| 183 | return ( | ||
| 184 | <ComboboxPrimitive.GroupLabel | ||
| 185 | data-slot="combobox-label" | ||
| 186 | className={cn( | ||
| 187 | "px-2 py-1.5 text-xs text-muted-foreground pointer-coarse:px-3 pointer-coarse:py-2 pointer-coarse:text-sm", | ||
| 188 | className | ||
| 189 | )} | ||
| 190 | {...props} | ||
| 191 | /> | ||
| 192 | ) | ||
| 193 | } | ||
| 194 | |||
| 195 | function ComboboxCollection({ ...props }: ComboboxPrimitive.Collection.Props) { | ||
| 196 | return ( | ||
| 197 | <ComboboxPrimitive.Collection data-slot="combobox-collection" {...props} /> | ||
| 198 | ) | ||
| 199 | } | ||
| 200 | |||
| 201 | function ComboboxEmpty({ className, ...props }: ComboboxPrimitive.Empty.Props) { | ||
| 202 | return ( | ||
| 203 | <ComboboxPrimitive.Empty | ||
| 204 | data-slot="combobox-empty" | ||
| 205 | className={cn( | ||
| 206 | "hidden w-full justify-center py-2 text-center text-sm text-muted-foreground group-data-empty/combobox-content:flex", | ||
| 207 | className | ||
| 208 | )} | ||
| 209 | {...props} | ||
| 210 | /> | ||
| 211 | ) | ||
| 212 | } | ||
| 213 | |||
| 214 | function ComboboxSeparator({ | ||
| 215 | className, | ||
| 216 | ...props | ||
| 217 | }: ComboboxPrimitive.Separator.Props) { | ||
| 218 | return ( | ||
| 219 | <ComboboxPrimitive.Separator | ||
| 220 | data-slot="combobox-separator" | ||
| 221 | className={cn("-mx-1 my-1 h-px bg-border", className)} | ||
| 222 | {...props} | ||
| 223 | /> | ||
| 224 | ) | ||
| 225 | } | ||
| 226 | |||
| 227 | function ComboboxChips({ | ||
| 228 | className, | ||
| 229 | ...props | ||
| 230 | }: React.ComponentPropsWithRef<typeof ComboboxPrimitive.Chips> & | ||
| 231 | ComboboxPrimitive.Chips.Props) { | ||
| 232 | return ( | ||
| 233 | <ComboboxPrimitive.Chips | ||
| 234 | data-slot="combobox-chips" | ||
| 235 | className={cn( | ||
| 236 | "flex min-h-9 flex-wrap items-center gap-1.5 rounded-md border border-input bg-transparent bg-clip-padding px-2.5 py-1.5 text-sm shadow-xs transition-[color,box-shadow] focus-within:border-ring focus-within:ring-[3px] focus-within:ring-ring/50 has-aria-invalid:border-destructive has-aria-invalid:ring-[3px] has-aria-invalid:ring-destructive/20 has-data-[slot=combobox-chip]:px-1.5 dark:bg-input/30 dark:has-aria-invalid:border-destructive/50 dark:has-aria-invalid:ring-destructive/40", | ||
| 237 | className | ||
| 238 | )} | ||
| 239 | {...props} | ||
| 240 | /> | ||
| 241 | ) | ||
| 242 | } | ||
| 243 | |||
| 244 | function ComboboxChip({ | ||
| 245 | className, | ||
| 246 | children, | ||
| 247 | showRemove = true, | ||
| 248 | ...props | ||
| 249 | }: ComboboxPrimitive.Chip.Props & { | ||
| 250 | showRemove?: boolean | ||
| 251 | }) { | ||
| 252 | return ( | ||
| 253 | <ComboboxPrimitive.Chip | ||
| 254 | data-slot="combobox-chip" | ||
| 255 | className={cn( | ||
| 256 | "flex h-[calc(--spacing(5.5))] w-fit items-center justify-center gap-1 rounded-sm bg-muted px-1.5 text-xs font-medium whitespace-nowrap text-foreground has-disabled:pointer-events-none has-disabled:cursor-not-allowed has-disabled:opacity-50 has-data-[slot=combobox-chip-remove]:pr-0", | ||
| 257 | className | ||
| 258 | )} | ||
| 259 | {...props} | ||
| 260 | > | ||
| 261 | {children} | ||
| 262 | {showRemove && ( | ||
| 263 | <ComboboxPrimitive.ChipRemove | ||
| 264 | render={<Button variant="ghost" size="icon-xs" />} | ||
| 265 | className="-ml-1 opacity-50 hover:opacity-100" | ||
| 266 | data-slot="combobox-chip-remove" | ||
| 267 | > | ||
| 268 | <XIcon className="pointer-events-none" /> | ||
| 269 | </ComboboxPrimitive.ChipRemove> | ||
| 270 | )} | ||
| 271 | </ComboboxPrimitive.Chip> | ||
| 272 | ) | ||
| 273 | } | ||
| 274 | |||
| 275 | function ComboboxChipsInput({ | ||
| 276 | className, | ||
| 277 | children, | ||
| 278 | ...props | ||
| 279 | }: ComboboxPrimitive.Input.Props) { | ||
| 280 | return ( | ||
| 281 | <ComboboxPrimitive.Input | ||
| 282 | data-slot="combobox-chip-input" | ||
| 283 | className={cn("min-w-16 flex-1 outline-none", className)} | ||
| 284 | {...props} | ||
| 285 | /> | ||
| 286 | ) | ||
| 287 | } | ||
| 288 | |||
| 289 | function useComboboxAnchor() { | ||
| 290 | return React.useRef<HTMLDivElement | null>(null) | ||
| 291 | } | ||
| 292 | |||
| 293 | export { | ||
| 294 | Combobox, | ||
| 295 | ComboboxInput, | ||
| 296 | ComboboxContent, | ||
| 297 | ComboboxList, | ||
| 298 | ComboboxItem, | ||
| 299 | ComboboxGroup, | ||
| 300 | ComboboxLabel, | ||
| 301 | ComboboxCollection, | ||
| 302 | ComboboxEmpty, | ||
| 303 | ComboboxSeparator, | ||
| 304 | ComboboxChips, | ||
| 305 | ComboboxChip, | ||
| 306 | ComboboxChipsInput, | ||
| 307 | ComboboxTrigger, | ||
| 308 | ComboboxValue, | ||
| 309 | useComboboxAnchor, | ||
| 310 | } | ||
| @@ -0,0 +1,184 @@ | |||
| 1 | "use client" | ||
| 2 | |||
| 3 | import * as React from "react" | ||
| 4 | import { Command as CommandPrimitive } from "cmdk" | ||
| 5 | import { SearchIcon } from "lucide-react" | ||
| 6 | |||
| 7 | import { cn } from "@executor/ui/lib/utils" | ||
| 8 | import { | ||
| 9 | Dialog, | ||
| 10 | DialogContent, | ||
| 11 | DialogDescription, | ||
| 12 | DialogHeader, | ||
| 13 | DialogTitle, | ||
| 14 | } from "@executor/ui/components/dialog" | ||
| 15 | |||
| 16 | function Command({ | ||
| 17 | className, | ||
| 18 | ...props | ||
| 19 | }: React.ComponentProps<typeof CommandPrimitive>) { | ||
| 20 | return ( | ||
| 21 | <CommandPrimitive | ||
| 22 | data-slot="command" | ||
| 23 | className={cn( | ||
| 24 | "flex h-full w-full flex-col overflow-hidden rounded-md bg-popover text-popover-foreground", | ||
| 25 | className | ||
| 26 | )} | ||
| 27 | {...props} | ||
| 28 | /> | ||
| 29 | ) | ||
| 30 | } | ||
| 31 | |||
| 32 | function CommandDialog({ | ||
| 33 | title = "Command Palette", | ||
| 34 | description = "Search for a command to run...", | ||
| 35 | children, | ||
| 36 | className, | ||
| 37 | showCloseButton = true, | ||
| 38 | ...props | ||
| 39 | }: React.ComponentProps<typeof Dialog> & { | ||
| 40 | title?: string | ||
| 41 | description?: string | ||
| 42 | className?: string | ||
| 43 | showCloseButton?: boolean | ||
| 44 | }) { | ||
| 45 | return ( | ||
| 46 | <Dialog {...props}> | ||
| 47 | <DialogHeader className="sr-only"> | ||
| 48 | <DialogTitle>{title}</DialogTitle> | ||
| 49 | <DialogDescription>{description}</DialogDescription> | ||
| 50 | </DialogHeader> | ||
| 51 | <DialogContent | ||
| 52 | className={cn("overflow-hidden p-0", className)} | ||
| 53 | showCloseButton={showCloseButton} | ||
| 54 | > | ||
| 55 | <Command className="**:data-[slot=command-input-wrapper]:h-12 [&_[cmdk-group-heading]]:px-2 [&_[cmdk-group-heading]]:font-medium [&_[cmdk-group-heading]]:text-muted-foreground [&_[cmdk-group]]:px-2 [&_[cmdk-group]:not([hidden])_~[cmdk-group]]:pt-0 [&_[cmdk-input-wrapper]_svg]:h-5 [&_[cmdk-input-wrapper]_svg]:w-5 [&_[cmdk-input]]:h-12 [&_[cmdk-item]]:px-2 [&_[cmdk-item]]:py-3 [&_[cmdk-item]_svg]:h-5 [&_[cmdk-item]_svg]:w-5"> | ||
| 56 | {children} | ||
| 57 | </Command> | ||
| 58 | </DialogContent> | ||
| 59 | </Dialog> | ||
| 60 | ) | ||
| 61 | } | ||
| 62 | |||
| 63 | function CommandInput({ | ||
| 64 | className, | ||
| 65 | ...props | ||
| 66 | }: React.ComponentProps<typeof CommandPrimitive.Input>) { | ||
| 67 | return ( | ||
| 68 | <div | ||
| 69 | data-slot="command-input-wrapper" | ||
| 70 | className="flex h-9 items-center gap-2 border-b px-3" | ||
| 71 | > | ||
| 72 | <SearchIcon className="size-4 shrink-0 opacity-50" /> | ||
| 73 | <CommandPrimitive.Input | ||
| 74 | data-slot="command-input" | ||
| 75 | className={cn( | ||
| 76 | "flex h-10 w-full rounded-md bg-transparent py-3 text-sm outline-hidden placeholder:text-muted-foreground disabled:cursor-not-allowed disabled:opacity-50", | ||
| 77 | className | ||
| 78 | )} | ||
| 79 | {...props} | ||
| 80 | /> | ||
| 81 | </div> | ||
| 82 | ) | ||
| 83 | } | ||
| 84 | |||
| 85 | function CommandList({ | ||
| 86 | className, | ||
| 87 | ...props | ||
| 88 | }: React.ComponentProps<typeof CommandPrimitive.List>) { | ||
| 89 | return ( | ||
| 90 | <CommandPrimitive.List | ||
| 91 | data-slot="command-list" | ||
| 92 | className={cn( | ||
| 93 | "max-h-[300px] scroll-py-1 overflow-x-hidden overflow-y-auto", | ||
| 94 | className | ||
| 95 | )} | ||
| 96 | {...props} | ||
| 97 | /> | ||
| 98 | ) | ||
| 99 | } | ||
| 100 | |||
| 101 | function CommandEmpty({ | ||
| 102 | ...props | ||
| 103 | }: React.ComponentProps<typeof CommandPrimitive.Empty>) { | ||
| 104 | return ( | ||
| 105 | <CommandPrimitive.Empty | ||
| 106 | data-slot="command-empty" | ||
| 107 | className="py-6 text-center text-sm" | ||
| 108 | {...props} | ||
| 109 | /> | ||
| 110 | ) | ||
| 111 | } | ||
| 112 | |||
| 113 | function CommandGroup({ | ||
| 114 | className, | ||
| 115 | ...props | ||
| 116 | }: React.ComponentProps<typeof CommandPrimitive.Group>) { | ||
| 117 | return ( | ||
| 118 | <CommandPrimitive.Group | ||
| 119 | data-slot="command-group" | ||
| 120 | className={cn( | ||
| 121 | "overflow-hidden p-1 text-foreground [&_[cmdk-group-heading]]:px-2 [&_[cmdk-group-heading]]:py-1.5 [&_[cmdk-group-heading]]:text-xs [&_[cmdk-group-heading]]:font-medium [&_[cmdk-group-heading]]:text-muted-foreground", | ||
| 122 | className | ||
| 123 | )} | ||
| 124 | {...props} | ||
| 125 | /> | ||
| 126 | ) | ||
| 127 | } | ||
| 128 | |||
| 129 | function CommandSeparator({ | ||
| 130 | className, | ||
| 131 | ...props | ||
| 132 | }: React.ComponentProps<typeof CommandPrimitive.Separator>) { | ||
| 133 | return ( | ||
| 134 | <CommandPrimitive.Separator | ||
| 135 | data-slot="command-separator" | ||
| 136 | className={cn("-mx-1 h-px bg-border", className)} | ||
| 137 | {...props} | ||
| 138 | /> | ||
| 139 | ) | ||
| 140 | } | ||
| 141 | |||
| 142 | function CommandItem({ | ||
| 143 | className, | ||
| 144 | ...props | ||
| 145 | }: React.ComponentProps<typeof CommandPrimitive.Item>) { | ||
| 146 | return ( | ||
| 147 | <CommandPrimitive.Item | ||
| 148 | data-slot="command-item" | ||
| 149 | className={cn( | ||
| 150 | "relative flex cursor-default items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-hidden select-none data-[disabled=true]:pointer-events-none data-[disabled=true]:opacity-50 data-[selected=true]:bg-accent data-[selected=true]:text-accent-foreground [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 [&_svg:not([class*='text-'])]:text-muted-foreground", | ||
| 151 | className | ||
| 152 | )} | ||
| 153 | {...props} | ||
| 154 | /> | ||
| 155 | ) | ||
| 156 | } | ||
| 157 | |||
| 158 | function CommandShortcut({ | ||
| 159 | className, | ||
| 160 | ...props | ||
| 161 | }: React.ComponentProps<"span">) { | ||
| 162 | return ( | ||
| 163 | <span | ||
| 164 | data-slot="command-shortcut" | ||
| 165 | className={cn( | ||
| 166 | "ml-auto text-xs tracking-widest text-muted-foreground", | ||
| 167 | className | ||
| 168 | )} | ||
| 169 | {...props} | ||
| 170 | /> | ||
| 171 | ) | ||
| 172 | } | ||
| 173 | |||
| 174 | export { | ||
| 175 | Command, | ||
| 176 | CommandDialog, | ||
| 177 | CommandInput, | ||
| 178 | CommandList, | ||
| 179 | CommandEmpty, | ||
| 180 | CommandGroup, | ||
| 181 | CommandItem, | ||
| 182 | CommandShortcut, | ||
| 183 | CommandSeparator, | ||
| 184 | } | ||
| @@ -0,0 +1,252 @@ | |||
| 1 | "use client" | ||
| 2 | |||
| 3 | import * as React from "react" | ||
| 4 | import { CheckIcon, ChevronRightIcon, CircleIcon } from "lucide-react" | ||
| 5 | import { ContextMenu as ContextMenuPrimitive } from "radix-ui" | ||
| 6 | |||
| 7 | import { cn } from "@executor/ui/lib/utils" | ||
| 8 | |||
| 9 | function ContextMenu({ | ||
| 10 | ...props | ||
| 11 | }: React.ComponentProps<typeof ContextMenuPrimitive.Root>) { | ||
| 12 | return <ContextMenuPrimitive.Root data-slot="context-menu" {...props} /> | ||
| 13 | } | ||
| 14 | |||
| 15 | function ContextMenuTrigger({ | ||
| 16 | ...props | ||
| 17 | }: React.ComponentProps<typeof ContextMenuPrimitive.Trigger>) { | ||
| 18 | return ( | ||
| 19 | <ContextMenuPrimitive.Trigger data-slot="context-menu-trigger" {...props} /> | ||
| 20 | ) | ||
| 21 | } | ||
| 22 | |||
| 23 | function ContextMenuGroup({ | ||
| 24 | ...props | ||
| 25 | }: React.ComponentProps<typeof ContextMenuPrimitive.Group>) { | ||
| 26 | return ( | ||
| 27 | <ContextMenuPrimitive.Group data-slot="context-menu-group" {...props} /> | ||
| 28 | ) | ||
| 29 | } | ||
| 30 | |||
| 31 | function ContextMenuPortal({ | ||
| 32 | ...props | ||
| 33 | }: React.ComponentProps<typeof ContextMenuPrimitive.Portal>) { | ||
| 34 | return ( | ||
| 35 | <ContextMenuPrimitive.Portal data-slot="context-menu-portal" {...props} /> | ||
| 36 | ) | ||
| 37 | } | ||
| 38 | |||
| 39 | function ContextMenuSub({ | ||
| 40 | ...props | ||
| 41 | }: React.ComponentProps<typeof ContextMenuPrimitive.Sub>) { | ||
| 42 | return <ContextMenuPrimitive.Sub data-slot="context-menu-sub" {...props} /> | ||
| 43 | } | ||
| 44 | |||
| 45 | function ContextMenuRadioGroup({ | ||
| 46 | ...props | ||
| 47 | }: React.ComponentProps<typeof ContextMenuPrimitive.RadioGroup>) { | ||
| 48 | return ( | ||
| 49 | <ContextMenuPrimitive.RadioGroup | ||
| 50 | data-slot="context-menu-radio-group" | ||
| 51 | {...props} | ||
| 52 | /> | ||
| 53 | ) | ||
| 54 | } | ||
| 55 | |||
| 56 | function ContextMenuSubTrigger({ | ||
| 57 | className, | ||
| 58 | inset, | ||
| 59 | children, | ||
| 60 | ...props | ||
| 61 | }: React.ComponentProps<typeof ContextMenuPrimitive.SubTrigger> & { | ||
| 62 | inset?: boolean | ||
| 63 | }) { | ||
| 64 | return ( | ||
| 65 | <ContextMenuPrimitive.SubTrigger | ||
| 66 | data-slot="context-menu-sub-trigger" | ||
| 67 | data-inset={inset} | ||
| 68 | className={cn( | ||
| 69 | "flex cursor-default items-center rounded-sm px-2 py-1.5 text-sm outline-hidden select-none focus:bg-accent focus:text-accent-foreground data-[inset]:pl-8 data-[state=open]:bg-accent data-[state=open]:text-accent-foreground [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 [&_svg:not([class*='text-'])]:text-muted-foreground", | ||
| 70 | className | ||
| 71 | )} | ||
| 72 | {...props} | ||
| 73 | > | ||
| 74 | {children} | ||
| 75 | <ChevronRightIcon className="ml-auto" /> | ||
| 76 | </ContextMenuPrimitive.SubTrigger> | ||
| 77 | ) | ||
| 78 | } | ||
| 79 | |||
| 80 | function ContextMenuSubContent({ | ||
| 81 | className, | ||
| 82 | ...props | ||
| 83 | }: React.ComponentProps<typeof ContextMenuPrimitive.SubContent>) { | ||
| 84 | return ( | ||
| 85 | <ContextMenuPrimitive.SubContent | ||
| 86 | data-slot="context-menu-sub-content" | ||
| 87 | className={cn( | ||
| 88 | "z-50 min-w-[8rem] origin-(--radix-context-menu-content-transform-origin) overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-lg data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95", | ||
| 89 | className | ||
| 90 | )} | ||
| 91 | {...props} | ||
| 92 | /> | ||
| 93 | ) | ||
| 94 | } | ||
| 95 | |||
| 96 | function ContextMenuContent({ | ||
| 97 | className, | ||
| 98 | ...props | ||
| 99 | }: React.ComponentProps<typeof ContextMenuPrimitive.Content>) { | ||
| 100 | return ( | ||
| 101 | <ContextMenuPrimitive.Portal> | ||
| 102 | <ContextMenuPrimitive.Content | ||
| 103 | data-slot="context-menu-content" | ||
| 104 | className={cn( | ||
| 105 | "z-50 max-h-(--radix-context-menu-content-available-height) min-w-[8rem] origin-(--radix-context-menu-content-transform-origin) overflow-x-hidden overflow-y-auto rounded-md border bg-popover p-1 text-popover-foreground shadow-md data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95", | ||
| 106 | className | ||
| 107 | )} | ||
| 108 | {...props} | ||
| 109 | /> | ||
| 110 | </ContextMenuPrimitive.Portal> | ||
| 111 | ) | ||
| 112 | } | ||
| 113 | |||
| 114 | function ContextMenuItem({ | ||
| 115 | className, | ||
| 116 | inset, | ||
| 117 | variant = "default", | ||
| 118 | ...props | ||
| 119 | }: React.ComponentProps<typeof ContextMenuPrimitive.Item> & { | ||
| 120 | inset?: boolean | ||
| 121 | variant?: "default" | "destructive" | ||
| 122 | }) { | ||
| 123 | return ( | ||
| 124 | <ContextMenuPrimitive.Item | ||
| 125 | data-slot="context-menu-item" | ||
| 126 | data-inset={inset} | ||
| 127 | data-variant={variant} | ||
| 128 | className={cn( | ||
| 129 | "relative flex cursor-default items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-hidden select-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50 data-[inset]:pl-8 data-[variant=destructive]:text-destructive data-[variant=destructive]:focus:bg-destructive/10 data-[variant=destructive]:focus:text-destructive dark:data-[variant=destructive]:focus:bg-destructive/20 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 [&_svg:not([class*='text-'])]:text-muted-foreground data-[variant=destructive]:*:[svg]:text-destructive!", | ||
| 130 | className | ||
| 131 | )} | ||
| 132 | {...props} | ||
| 133 | /> | ||
| 134 | ) | ||
| 135 | } | ||
| 136 | |||
| 137 | function ContextMenuCheckboxItem({ | ||
| 138 | className, | ||
| 139 | children, | ||
| 140 | checked, | ||
| 141 | ...props | ||
| 142 | }: React.ComponentProps<typeof ContextMenuPrimitive.CheckboxItem>) { | ||
| 143 | return ( | ||
| 144 | <ContextMenuPrimitive.CheckboxItem | ||
| 145 | data-slot="context-menu-checkbox-item" | ||
| 146 | className={cn( | ||
| 147 | "relative flex cursor-default items-center gap-2 rounded-sm py-1.5 pr-2 pl-8 text-sm outline-hidden select-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4", | ||
| 148 | className | ||
| 149 | )} | ||
| 150 | checked={checked} | ||
| 151 | {...props} | ||
| 152 | > | ||
| 153 | <span className="pointer-events-none absolute left-2 flex size-3.5 items-center justify-center"> | ||
| 154 | <ContextMenuPrimitive.ItemIndicator> | ||
| 155 | <CheckIcon className="size-4" /> | ||
| 156 | </ContextMenuPrimitive.ItemIndicator> | ||
| 157 | </span> | ||
| 158 | {children} | ||
| 159 | </ContextMenuPrimitive.CheckboxItem> | ||
| 160 | ) | ||
| 161 | } | ||
| 162 | |||
| 163 | function ContextMenuRadioItem({ | ||
| 164 | className, | ||
| 165 | children, | ||
| 166 | ...props | ||
| 167 | }: React.ComponentProps<typeof ContextMenuPrimitive.RadioItem>) { | ||
| 168 | return ( | ||
| 169 | <ContextMenuPrimitive.RadioItem | ||
| 170 | data-slot="context-menu-radio-item" | ||
| 171 | className={cn( | ||
| 172 | "relative flex cursor-default items-center gap-2 rounded-sm py-1.5 pr-2 pl-8 text-sm outline-hidden select-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4", | ||
| 173 | className | ||
| 174 | )} | ||
| 175 | {...props} | ||
| 176 | > | ||
| 177 | <span className="pointer-events-none absolute left-2 flex size-3.5 items-center justify-center"> | ||
| 178 | <ContextMenuPrimitive.ItemIndicator> | ||
| 179 | <CircleIcon className="size-2 fill-current" /> | ||
| 180 | </ContextMenuPrimitive.ItemIndicator> | ||
| 181 | </span> | ||
| 182 | {children} | ||
| 183 | </ContextMenuPrimitive.RadioItem> | ||
| 184 | ) | ||
| 185 | } | ||
| 186 | |||
| 187 | function ContextMenuLabel({ | ||
| 188 | className, | ||
| 189 | inset, | ||
| 190 | ...props | ||
| 191 | }: React.ComponentProps<typeof ContextMenuPrimitive.Label> & { | ||
| 192 | inset?: boolean | ||
| 193 | }) { | ||
| 194 | return ( | ||
| 195 | <ContextMenuPrimitive.Label | ||
| 196 | data-slot="context-menu-label" | ||
| 197 | data-inset={inset} | ||
| 198 | className={cn( | ||
| 199 | "px-2 py-1.5 text-sm font-medium text-foreground data-[inset]:pl-8", | ||
| 200 | className | ||
| 201 | )} | ||
| 202 | {...props} | ||
| 203 | /> | ||
| 204 | ) | ||
| 205 | } | ||
| 206 | |||
| 207 | function ContextMenuSeparator({ | ||
| 208 | className, | ||
| 209 | ...props | ||
| 210 | }: React.ComponentProps<typeof ContextMenuPrimitive.Separator>) { | ||
| 211 | return ( | ||
| 212 | <ContextMenuPrimitive.Separator | ||
| 213 | data-slot="context-menu-separator" | ||
| 214 | className={cn("-mx-1 my-1 h-px bg-border", className)} | ||
| 215 | {...props} | ||
| 216 | /> | ||
| 217 | ) | ||
| 218 | } | ||
| 219 | |||
| 220 | function ContextMenuShortcut({ | ||
| 221 | className, | ||
| 222 | ...props | ||
| 223 | }: React.ComponentProps<"span">) { | ||
| 224 | return ( | ||
| 225 | <span | ||
| 226 | data-slot="context-menu-shortcut" | ||
| 227 | className={cn( | ||
| 228 | "ml-auto text-xs tracking-widest text-muted-foreground", | ||
| 229 | className | ||
| 230 | )} | ||
| 231 | {...props} | ||
| 232 | /> | ||
| 233 | ) | ||
| 234 | } | ||
| 235 | |||
| 236 | export { | ||
| 237 | ContextMenu, | ||
| 238 | ContextMenuTrigger, | ||
| 239 | ContextMenuContent, | ||
| 240 | ContextMenuItem, | ||
| 241 | ContextMenuCheckboxItem, | ||
| 242 | ContextMenuRadioItem, | ||
| 243 | ContextMenuLabel, | ||
| 244 | ContextMenuSeparator, | ||
| 245 | ContextMenuShortcut, | ||
| 246 | ContextMenuGroup, | ||
| 247 | ContextMenuPortal, | ||
| 248 | ContextMenuSub, | ||
| 249 | ContextMenuSubContent, | ||
| 250 | ContextMenuSubTrigger, | ||
| 251 | ContextMenuRadioGroup, | ||
| 252 | } | ||
| @@ -0,0 +1,156 @@ | |||
| 1 | import * as React from "react" | ||
| 2 | import { XIcon } from "lucide-react" | ||
| 3 | import { Dialog as DialogPrimitive } from "radix-ui" | ||
| 4 | |||
| 5 | import { cn } from "@executor/ui/lib/utils" | ||
| 6 | import { Button } from "@executor/ui/components/button" | ||
| 7 | |||
| 8 | function Dialog({ | ||
| 9 | ...props | ||
| 10 | }: React.ComponentProps<typeof DialogPrimitive.Root>) { | ||
| 11 | return <DialogPrimitive.Root data-slot="dialog" {...props} /> | ||
| 12 | } | ||
| 13 | |||
| 14 | function DialogTrigger({ | ||
| 15 | ...props | ||
| 16 | }: React.ComponentProps<typeof DialogPrimitive.Trigger>) { | ||
| 17 | return <DialogPrimitive.Trigger data-slot="dialog-trigger" {...props} /> | ||
| 18 | } | ||
| 19 | |||
| 20 | function DialogPortal({ | ||
| 21 | ...props | ||
| 22 | }: React.ComponentProps<typeof DialogPrimitive.Portal>) { | ||
| 23 | return <DialogPrimitive.Portal data-slot="dialog-portal" {...props} /> | ||
| 24 | } | ||
| 25 | |||
| 26 | function DialogClose({ | ||
| 27 | ...props | ||
| 28 | }: React.ComponentProps<typeof DialogPrimitive.Close>) { | ||
| 29 | return <DialogPrimitive.Close data-slot="dialog-close" {...props} /> | ||
| 30 | } | ||
| 31 | |||
| 32 | function DialogOverlay({ | ||
| 33 | className, | ||
| 34 | ...props | ||
| 35 | }: React.ComponentProps<typeof DialogPrimitive.Overlay>) { | ||
| 36 | return ( | ||
| 37 | <DialogPrimitive.Overlay | ||
| 38 | data-slot="dialog-overlay" | ||
| 39 | className={cn( | ||
| 40 | "fixed inset-0 z-50 bg-black/50 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:animate-in data-[state=open]:fade-in-0", | ||
| 41 | className | ||
| 42 | )} | ||
| 43 | {...props} | ||
| 44 | /> | ||
| 45 | ) | ||
| 46 | } | ||
| 47 | |||
| 48 | function DialogContent({ | ||
| 49 | className, | ||
| 50 | children, | ||
| 51 | showCloseButton = true, | ||
| 52 | ...props | ||
| 53 | }: React.ComponentProps<typeof DialogPrimitive.Content> & { | ||
| 54 | showCloseButton?: boolean | ||
| 55 | }) { | ||
| 56 | return ( | ||
| 57 | <DialogPortal data-slot="dialog-portal"> | ||
| 58 | <DialogOverlay /> | ||
| 59 | <DialogPrimitive.Content | ||
| 60 | data-slot="dialog-content" | ||
| 61 | className={cn( | ||
| 62 | "fixed top-[50%] left-[50%] z-50 grid w-full max-w-[calc(100%-2rem)] translate-x-[-50%] translate-y-[-50%] gap-4 rounded-lg border bg-background p-6 shadow-lg duration-200 outline-none data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95 sm:max-w-lg", | ||
| 63 | className | ||
| 64 | )} | ||
| 65 | {...props} | ||
| 66 | > | ||
| 67 | {children} | ||
| 68 | {showCloseButton && ( | ||
| 69 | <DialogPrimitive.Close | ||
| 70 | data-slot="dialog-close" | ||
| 71 | className="absolute top-4 right-4 rounded-xs opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:ring-2 focus:ring-ring focus:ring-offset-2 focus:outline-hidden disabled:pointer-events-none data-[state=open]:bg-accent data-[state=open]:text-muted-foreground [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4" | ||
| 72 | > | ||
| 73 | <XIcon /> | ||
| 74 | <span className="sr-only">Close</span> | ||
| 75 | </DialogPrimitive.Close> | ||
| 76 | )} | ||
| 77 | </DialogPrimitive.Content> | ||
| 78 | </DialogPortal> | ||
| 79 | ) | ||
| 80 | } | ||
| 81 | |||
| 82 | function DialogHeader({ className, ...props }: React.ComponentProps<"div">) { | ||
| 83 | return ( | ||
| 84 | <div | ||
| 85 | data-slot="dialog-header" | ||
| 86 | className={cn("flex flex-col gap-2 text-center sm:text-left", className)} | ||
| 87 | {...props} | ||
| 88 | /> | ||
| 89 | ) | ||
| 90 | } | ||
| 91 | |||
| 92 | function DialogFooter({ | ||
| 93 | className, | ||
| 94 | showCloseButton = false, | ||
| 95 | children, | ||
| 96 | ...props | ||
| 97 | }: React.ComponentProps<"div"> & { | ||
| 98 | showCloseButton?: boolean | ||
| 99 | }) { | ||
| 100 | return ( | ||
| 101 | <div | ||
| 102 | data-slot="dialog-footer" | ||
| 103 | className={cn( | ||
| 104 | "flex flex-col-reverse gap-2 sm:flex-row sm:justify-end", | ||
| 105 | className | ||
| 106 | )} | ||
| 107 | {...props} | ||
| 108 | > | ||
| 109 | {children} | ||
| 110 | {showCloseButton && ( | ||
| 111 | <DialogPrimitive.Close asChild> | ||
| 112 | <Button variant="outline">Close</Button> | ||
| 113 | </DialogPrimitive.Close> | ||
| 114 | )} | ||
| 115 | </div> | ||
| 116 | ) | ||
| 117 | } | ||
| 118 | |||
| 119 | function DialogTitle({ | ||
| 120 | className, | ||
| 121 | ...props | ||
| 122 | }: React.ComponentProps<typeof DialogPrimitive.Title>) { | ||
| 123 | return ( | ||
| 124 | <DialogPrimitive.Title | ||
| 125 | data-slot="dialog-title" | ||
| 126 | className={cn("text-lg leading-none font-semibold", className)} | ||
| 127 | {...props} | ||
| 128 | /> | ||
| 129 | ) | ||
| 130 | } | ||
| 131 | |||
| 132 | function DialogDescription({ | ||
| 133 | className, | ||
| 134 | ...props | ||
| 135 | }: React.ComponentProps<typeof DialogPrimitive.Description>) { | ||
| 136 | return ( | ||
| 137 | <DialogPrimitive.Description | ||
| 138 | data-slot="dialog-description" | ||
| 139 | className={cn("text-sm text-muted-foreground", className)} | ||
| 140 | {...props} | ||
| 141 | /> | ||
| 142 | ) | ||
| 143 | } | ||
| 144 | |||
| 145 | export { | ||
| 146 | Dialog, | ||
| 147 | DialogClose, | ||
| 148 | DialogContent, | ||
| 149 | DialogDescription, | ||
| 150 | DialogFooter, | ||
| 151 | DialogHeader, | ||
| 152 | DialogOverlay, | ||
| 153 | DialogPortal, | ||
| 154 | DialogTitle, | ||
| 155 | DialogTrigger, | ||
| 156 | } | ||
| @@ -0,0 +1,22 @@ | |||
| 1 | "use client" | ||
| 2 | |||
| 3 | import * as React from "react" | ||
| 4 | import { Direction } from "radix-ui" | ||
| 5 | |||
| 6 | function DirectionProvider({ | ||
| 7 | dir, | ||
| 8 | direction, | ||
| 9 | children, | ||
| 10 | }: React.ComponentProps<typeof Direction.DirectionProvider> & { | ||
| 11 | direction?: React.ComponentProps<typeof Direction.DirectionProvider>["dir"] | ||
| 12 | }) { | ||
| 13 | return ( | ||
| 14 | <Direction.DirectionProvider dir={direction ?? dir}> | ||
| 15 | {children} | ||
| 16 | </Direction.DirectionProvider> | ||
| 17 | ) | ||
| 18 | } | ||
| 19 | |||
| 20 | const useDirection = Direction.useDirection | ||
| 21 | |||
| 22 | export { DirectionProvider, useDirection } | ||
| @@ -0,0 +1,133 @@ | |||
| 1 | import * as React from "react" | ||
| 2 | import { Drawer as DrawerPrimitive } from "vaul" | ||
| 3 | |||
| 4 | import { cn } from "@executor/ui/lib/utils" | ||
| 5 | |||
| 6 | function Drawer({ | ||
| 7 | ...props | ||
| 8 | }: React.ComponentProps<typeof DrawerPrimitive.Root>) { | ||
| 9 | return <DrawerPrimitive.Root data-slot="drawer" {...props} /> | ||
| 10 | } | ||
| 11 | |||
| 12 | function DrawerTrigger({ | ||
| 13 | ...props | ||
| 14 | }: React.ComponentProps<typeof DrawerPrimitive.Trigger>) { | ||
| 15 | return <DrawerPrimitive.Trigger data-slot="drawer-trigger" {...props} /> | ||
| 16 | } | ||
| 17 | |||
| 18 | function DrawerPortal({ | ||
| 19 | ...props | ||
| 20 | }: React.ComponentProps<typeof DrawerPrimitive.Portal>) { | ||
| 21 | return <DrawerPrimitive.Portal data-slot="drawer-portal" {...props} /> | ||
| 22 | } | ||
| 23 | |||
| 24 | function DrawerClose({ | ||
| 25 | ...props | ||
| 26 | }: React.ComponentProps<typeof DrawerPrimitive.Close>) { | ||
| 27 | return <DrawerPrimitive.Close data-slot="drawer-close" {...props} /> | ||
| 28 | } | ||
| 29 | |||
| 30 | function DrawerOverlay({ | ||
| 31 | className, | ||
| 32 | ...props | ||
| 33 | }: React.ComponentProps<typeof DrawerPrimitive.Overlay>) { | ||
| 34 | return ( | ||
| 35 | <DrawerPrimitive.Overlay | ||
| 36 | data-slot="drawer-overlay" | ||
| 37 | className={cn( | ||
| 38 | "fixed inset-0 z-50 bg-black/50 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:animate-in data-[state=open]:fade-in-0", | ||
| 39 | className | ||
| 40 | )} | ||
| 41 | {...props} | ||
| 42 | /> | ||
| 43 | ) | ||
| 44 | } | ||
| 45 | |||
| 46 | function DrawerContent({ | ||
| 47 | className, | ||
| 48 | children, | ||
| 49 | ...props | ||
| 50 | }: React.ComponentProps<typeof DrawerPrimitive.Content>) { | ||
| 51 | return ( | ||
| 52 | <DrawerPortal data-slot="drawer-portal"> | ||
| 53 | <DrawerOverlay /> | ||
| 54 | <DrawerPrimitive.Content | ||
| 55 | data-slot="drawer-content" | ||
| 56 | className={cn( | ||
| 57 | "group/drawer-content fixed z-50 flex h-auto flex-col bg-background", | ||
| 58 | "data-[vaul-drawer-direction=top]:inset-x-0 data-[vaul-drawer-direction=top]:top-0 data-[vaul-drawer-direction=top]:mb-24 data-[vaul-drawer-direction=top]:max-h-[80vh] data-[vaul-drawer-direction=top]:rounded-b-lg data-[vaul-drawer-direction=top]:border-b", | ||
| 59 | "data-[vaul-drawer-direction=bottom]:inset-x-0 data-[vaul-drawer-direction=bottom]:bottom-0 data-[vaul-drawer-direction=bottom]:mt-24 data-[vaul-drawer-direction=bottom]:max-h-[80vh] data-[vaul-drawer-direction=bottom]:rounded-t-lg data-[vaul-drawer-direction=bottom]:border-t", | ||
| 60 | "data-[vaul-drawer-direction=right]:inset-y-0 data-[vaul-drawer-direction=right]:right-0 data-[vaul-drawer-direction=right]:w-3/4 data-[vaul-drawer-direction=right]:border-l data-[vaul-drawer-direction=right]:sm:max-w-sm", | ||
| 61 | "data-[vaul-drawer-direction=left]:inset-y-0 data-[vaul-drawer-direction=left]:left-0 data-[vaul-drawer-direction=left]:w-3/4 data-[vaul-drawer-direction=left]:border-r data-[vaul-drawer-direction=left]:sm:max-w-sm", | ||
| 62 | className | ||
| 63 | )} | ||
| 64 | {...props} | ||
| 65 | > | ||
| 66 | <div className="mx-auto mt-4 hidden h-2 w-[100px] shrink-0 rounded-full bg-muted group-data-[vaul-drawer-direction=bottom]/drawer-content:block" /> | ||
| 67 | {children} | ||
| 68 | </DrawerPrimitive.Content> | ||
| 69 | </DrawerPortal> | ||
| 70 | ) | ||
| 71 | } | ||
| 72 | |||
| 73 | function DrawerHeader({ className, ...props }: React.ComponentProps<"div">) { | ||
| 74 | return ( | ||
| 75 | <div | ||
| 76 | data-slot="drawer-header" | ||
| 77 | className={cn( | ||
| 78 | "flex flex-col gap-0.5 p-4 group-data-[vaul-drawer-direction=bottom]/drawer-content:text-center group-data-[vaul-drawer-direction=top]/drawer-content:text-center md:gap-1.5 md:text-left", | ||
| 79 | className | ||
| 80 | )} | ||
| 81 | {...props} | ||
| 82 | /> | ||
| 83 | ) | ||
| 84 | } | ||
| 85 | |||
| 86 | function DrawerFooter({ className, ...props }: React.ComponentProps<"div">) { | ||
| 87 | return ( | ||
| 88 | <div | ||
| 89 | data-slot="drawer-footer" | ||
| 90 | className={cn("mt-auto flex flex-col gap-2 p-4", className)} | ||
| 91 | {...props} | ||
| 92 | /> | ||
| 93 | ) | ||
| 94 | } | ||
| 95 | |||
| 96 | function DrawerTitle({ | ||
| 97 | className, | ||
| 98 | ...props | ||
| 99 | }: React.ComponentProps<typeof DrawerPrimitive.Title>) { | ||
| 100 | return ( | ||
| 101 | <DrawerPrimitive.Title | ||
| 102 | data-slot="drawer-title" | ||
| 103 | className={cn("font-semibold text-foreground", className)} | ||
| 104 | {...props} | ||
| 105 | /> | ||
| 106 | ) | ||
| 107 | } | ||
| 108 | |||
| 109 | function DrawerDescription({ | ||
| 110 | className, | ||
| 111 | ...props | ||
| 112 | }: React.ComponentProps<typeof DrawerPrimitive.Description>) { | ||
| 113 | return ( | ||
| 114 | <DrawerPrimitive.Description | ||
| 115 | data-slot="drawer-description" | ||
| 116 | className={cn("text-sm text-muted-foreground", className)} | ||
| 117 | {...props} | ||
| 118 | /> | ||
| 119 | ) | ||
| 120 | } | ||
| 121 | |||
| 122 | export { | ||
| 123 | Drawer, | ||
| 124 | DrawerPortal, | ||
| 125 | DrawerOverlay, | ||
| 126 | DrawerTrigger, | ||
| 127 | DrawerClose, | ||
| 128 | DrawerContent, | ||
| 129 | DrawerHeader, | ||
| 130 | DrawerFooter, | ||
| 131 | DrawerTitle, | ||
| 132 | DrawerDescription, | ||
| 133 | } | ||
| @@ -0,0 +1,257 @@ | |||
| 1 | "use client" | ||
| 2 | |||
| 3 | import * as React from "react" | ||
| 4 | import { CheckIcon, ChevronRightIcon, CircleIcon } from "lucide-react" | ||
| 5 | import { DropdownMenu as DropdownMenuPrimitive } from "radix-ui" | ||
| 6 | |||
| 7 | import { cn } from "@executor/ui/lib/utils" | ||
| 8 | |||
| 9 | function DropdownMenu({ | ||
| 10 | ...props | ||
| 11 | }: React.ComponentProps<typeof DropdownMenuPrimitive.Root>) { | ||
| 12 | return <DropdownMenuPrimitive.Root data-slot="dropdown-menu" {...props} /> | ||
| 13 | } | ||
| 14 | |||
| 15 | function DropdownMenuPortal({ | ||
| 16 | ...props | ||
| 17 | }: React.ComponentProps<typeof DropdownMenuPrimitive.Portal>) { | ||
| 18 | return ( | ||
| 19 | <DropdownMenuPrimitive.Portal data-slot="dropdown-menu-portal" {...props} /> | ||
| 20 | ) | ||
| 21 | } | ||
| 22 | |||
| 23 | function DropdownMenuTrigger({ | ||
| 24 | ...props | ||
| 25 | }: React.ComponentProps<typeof DropdownMenuPrimitive.Trigger>) { | ||
| 26 | return ( | ||
| 27 | <DropdownMenuPrimitive.Trigger | ||
| 28 | data-slot="dropdown-menu-trigger" | ||
| 29 | {...props} | ||
| 30 | /> | ||
| 31 | ) | ||
| 32 | } | ||
| 33 | |||
| 34 | function DropdownMenuContent({ | ||
| 35 | className, | ||
| 36 | sideOffset = 4, | ||
| 37 | ...props | ||
| 38 | }: React.ComponentProps<typeof DropdownMenuPrimitive.Content>) { | ||
| 39 | return ( | ||
| 40 | <DropdownMenuPrimitive.Portal> | ||
| 41 | <DropdownMenuPrimitive.Content | ||
| 42 | data-slot="dropdown-menu-content" | ||
| 43 | sideOffset={sideOffset} | ||
| 44 | className={cn( | ||
| 45 | "z-50 max-h-(--radix-dropdown-menu-content-available-height) min-w-[8rem] origin-(--radix-dropdown-menu-content-transform-origin) overflow-x-hidden overflow-y-auto rounded-md border bg-popover p-1 text-popover-foreground shadow-md data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95", | ||
| 46 | className | ||
| 47 | )} | ||
| 48 | {...props} | ||
| 49 | /> | ||
| 50 | </DropdownMenuPrimitive.Portal> | ||
| 51 | ) | ||
| 52 | } | ||
| 53 | |||
| 54 | function DropdownMenuGroup({ | ||
| 55 | ...props | ||
| 56 | }: React.ComponentProps<typeof DropdownMenuPrimitive.Group>) { | ||
| 57 | return ( | ||
| 58 | <DropdownMenuPrimitive.Group data-slot="dropdown-menu-group" {...props} /> | ||
| 59 | ) | ||
| 60 | } | ||
| 61 | |||
| 62 | function DropdownMenuItem({ | ||
| 63 | className, | ||
| 64 | inset, | ||
| 65 | variant = "default", | ||
| 66 | ...props | ||
| 67 | }: React.ComponentProps<typeof DropdownMenuPrimitive.Item> & { | ||
| 68 | inset?: boolean | ||
| 69 | variant?: "default" | "destructive" | ||
| 70 | }) { | ||
| 71 | return ( | ||
| 72 | <DropdownMenuPrimitive.Item | ||
| 73 | data-slot="dropdown-menu-item" | ||
| 74 | data-inset={inset} | ||
| 75 | data-variant={variant} | ||
| 76 | className={cn( | ||
| 77 | "relative flex cursor-default items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-hidden select-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50 data-[inset]:pl-8 data-[variant=destructive]:text-destructive data-[variant=destructive]:focus:bg-destructive/10 data-[variant=destructive]:focus:text-destructive dark:data-[variant=destructive]:focus:bg-destructive/20 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 [&_svg:not([class*='text-'])]:text-muted-foreground data-[variant=destructive]:*:[svg]:text-destructive!", | ||
| 78 | className | ||
| 79 | )} | ||
| 80 | {...props} | ||
| 81 | /> | ||
| 82 | ) | ||
| 83 | } | ||
| 84 | |||
| 85 | function DropdownMenuCheckboxItem({ | ||
| 86 | className, | ||
| 87 | children, | ||
| 88 | checked, | ||
| 89 | ...props | ||
| 90 | }: React.ComponentProps<typeof DropdownMenuPrimitive.CheckboxItem>) { | ||
| 91 | return ( | ||
| 92 | <DropdownMenuPrimitive.CheckboxItem | ||
| 93 | data-slot="dropdown-menu-checkbox-item" | ||
| 94 | className={cn( | ||
| 95 | "relative flex cursor-default items-center gap-2 rounded-sm py-1.5 pr-2 pl-8 text-sm outline-hidden select-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4", | ||
| 96 | className | ||
| 97 | )} | ||
| 98 | checked={checked} | ||
| 99 | {...props} | ||
| 100 | > | ||
| 101 | <span className="pointer-events-none absolute left-2 flex size-3.5 items-center justify-center"> | ||
| 102 | <DropdownMenuPrimitive.ItemIndicator> | ||
| 103 | <CheckIcon className="size-4" /> | ||
| 104 | </DropdownMenuPrimitive.ItemIndicator> | ||
| 105 | </span> | ||
| 106 | {children} | ||
| 107 | </DropdownMenuPrimitive.CheckboxItem> | ||
| 108 | ) | ||
| 109 | } | ||
| 110 | |||
| 111 | function DropdownMenuRadioGroup({ | ||
| 112 | ...props | ||
| 113 | }: React.ComponentProps<typeof DropdownMenuPrimitive.RadioGroup>) { | ||
| 114 | return ( | ||
| 115 | <DropdownMenuPrimitive.RadioGroup | ||
| 116 | data-slot="dropdown-menu-radio-group" | ||
| 117 | {...props} | ||
| 118 | /> | ||
| 119 | ) | ||
| 120 | } | ||
| 121 | |||
| 122 | function DropdownMenuRadioItem({ | ||
| 123 | className, | ||
| 124 | children, | ||
| 125 | ...props | ||
| 126 | }: React.ComponentProps<typeof DropdownMenuPrimitive.RadioItem>) { | ||
| 127 | return ( | ||
| 128 | <DropdownMenuPrimitive.RadioItem | ||
| 129 | data-slot="dropdown-menu-radio-item" | ||
| 130 | className={cn( | ||
| 131 | "relative flex cursor-default items-center gap-2 rounded-sm py-1.5 pr-2 pl-8 text-sm outline-hidden select-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4", | ||
| 132 | className | ||
| 133 | )} | ||
| 134 | {...props} | ||
| 135 | > | ||
| 136 | <span className="pointer-events-none absolute left-2 flex size-3.5 items-center justify-center"> | ||
| 137 | <DropdownMenuPrimitive.ItemIndicator> | ||
| 138 | <CircleIcon className="size-2 fill-current" /> | ||
| 139 | </DropdownMenuPrimitive.ItemIndicator> | ||
| 140 | </span> | ||
| 141 | {children} | ||
| 142 | </DropdownMenuPrimitive.RadioItem> | ||
| 143 | ) | ||
| 144 | } | ||
| 145 | |||
| 146 | function DropdownMenuLabel({ | ||
| 147 | className, | ||
| 148 | inset, | ||
| 149 | ...props | ||
| 150 | }: React.ComponentProps<typeof DropdownMenuPrimitive.Label> & { | ||
| 151 | inset?: boolean | ||
| 152 | }) { | ||
| 153 | return ( | ||
| 154 | <DropdownMenuPrimitive.Label | ||
| 155 | data-slot="dropdown-menu-label" | ||
| 156 | data-inset={inset} | ||
| 157 | className={cn( | ||
| 158 | "px-2 py-1.5 text-sm font-medium data-[inset]:pl-8", | ||
| 159 | className | ||
| 160 | )} | ||
| 161 | {...props} | ||
| 162 | /> | ||
| 163 | ) | ||
| 164 | } | ||
| 165 | |||
| 166 | function DropdownMenuSeparator({ | ||
| 167 | className, | ||
| 168 | ...props | ||
| 169 | }: React.ComponentProps<typeof DropdownMenuPrimitive.Separator>) { | ||
| 170 | return ( | ||
| 171 | <DropdownMenuPrimitive.Separator | ||
| 172 | data-slot="dropdown-menu-separator" | ||
| 173 | className={cn("-mx-1 my-1 h-px bg-border", className)} | ||
| 174 | {...props} | ||
| 175 | /> | ||
| 176 | ) | ||
| 177 | } | ||
| 178 | |||
| 179 | function DropdownMenuShortcut({ | ||
| 180 | className, | ||
| 181 | ...props | ||
| 182 | }: React.ComponentProps<"span">) { | ||
| 183 | return ( | ||
| 184 | <span | ||
| 185 | data-slot="dropdown-menu-shortcut" | ||
| 186 | className={cn( | ||
| 187 | "ml-auto text-xs tracking-widest text-muted-foreground", | ||
| 188 | className | ||
| 189 | )} | ||
| 190 | {...props} | ||
| 191 | /> | ||
| 192 | ) | ||
| 193 | } | ||
| 194 | |||
| 195 | function DropdownMenuSub({ | ||
| 196 | ...props | ||
| 197 | }: React.ComponentProps<typeof DropdownMenuPrimitive.Sub>) { | ||
| 198 | return <DropdownMenuPrimitive.Sub data-slot="dropdown-menu-sub" {...props} /> | ||
| 199 | } | ||
| 200 | |||
| 201 | function DropdownMenuSubTrigger({ | ||
| 202 | className, | ||
| 203 | inset, | ||
| 204 | children, | ||
| 205 | ...props | ||
| 206 | }: React.ComponentProps<typeof DropdownMenuPrimitive.SubTrigger> & { | ||
| 207 | inset?: boolean | ||
| 208 | }) { | ||
| 209 | return ( | ||
| 210 | <DropdownMenuPrimitive.SubTrigger | ||
| 211 | data-slot="dropdown-menu-sub-trigger" | ||
| 212 | data-inset={inset} | ||
| 213 | className={cn( | ||
| 214 | "flex cursor-default items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-hidden select-none focus:bg-accent focus:text-accent-foreground data-[inset]:pl-8 data-[state=open]:bg-accent data-[state=open]:text-accent-foreground [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 [&_svg:not([class*='text-'])]:text-muted-foreground", | ||
| 215 | className | ||
| 216 | )} | ||
| 217 | {...props} | ||
| 218 | > | ||
| 219 | {children} | ||
| 220 | <ChevronRightIcon className="ml-auto size-4" /> | ||
| 221 | </DropdownMenuPrimitive.SubTrigger> | ||
| 222 | ) | ||
| 223 | } | ||
| 224 | |||
| 225 | function DropdownMenuSubContent({ | ||
| 226 | className, | ||
| 227 | ...props | ||
| 228 | }: React.ComponentProps<typeof DropdownMenuPrimitive.SubContent>) { | ||
| 229 | return ( | ||
| 230 | <DropdownMenuPrimitive.SubContent | ||
| 231 | data-slot="dropdown-menu-sub-content" | ||
| 232 | className={cn( | ||
| 233 | "z-50 min-w-[8rem] origin-(--radix-dropdown-menu-content-transform-origin) overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-lg data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95", | ||
| 234 | className | ||
| 235 | )} | ||
| 236 | {...props} | ||
| 237 | /> | ||
| 238 | ) | ||
| 239 | } | ||
| 240 | |||
| 241 | export { | ||
| 242 | DropdownMenu, | ||
| 243 | DropdownMenuPortal, | ||
| 244 | DropdownMenuTrigger, | ||
| 245 | DropdownMenuContent, | ||
| 246 | DropdownMenuGroup, | ||
| 247 | DropdownMenuLabel, | ||
| 248 | DropdownMenuItem, | ||
| 249 | DropdownMenuCheckboxItem, | ||
| 250 | DropdownMenuRadioGroup, | ||
| 251 | DropdownMenuRadioItem, | ||
| 252 | DropdownMenuSeparator, | ||
| 253 | DropdownMenuShortcut, | ||
| 254 | DropdownMenuSub, | ||
| 255 | DropdownMenuSubTrigger, | ||
| 256 | DropdownMenuSubContent, | ||
| 257 | } | ||
| @@ -0,0 +1,104 @@ | |||
| 1 | import { cva, type VariantProps } from "class-variance-authority" | ||
| 2 | |||
| 3 | import { cn } from "@executor/ui/lib/utils" | ||
| 4 | |||
| 5 | function Empty({ className, ...props }: React.ComponentProps<"div">) { | ||
| 6 | return ( | ||
| 7 | <div | ||
| 8 | data-slot="empty" | ||
| 9 | className={cn( | ||
| 10 | "flex min-w-0 flex-1 flex-col items-center justify-center gap-6 rounded-lg border-dashed p-6 text-center text-balance md:p-12", | ||
| 11 | className | ||
| 12 | )} | ||
| 13 | {...props} | ||
| 14 | /> | ||
| 15 | ) | ||
| 16 | } | ||
| 17 | |||
| 18 | function EmptyHeader({ className, ...props }: React.ComponentProps<"div">) { | ||
| 19 | return ( | ||
| 20 | <div | ||
| 21 | data-slot="empty-header" | ||
| 22 | className={cn( | ||
| 23 | "flex max-w-sm flex-col items-center gap-2 text-center", | ||
| 24 | className | ||
| 25 | )} | ||
| 26 | {...props} | ||
| 27 | /> | ||
| 28 | ) | ||
| 29 | } | ||
| 30 | |||
| 31 | const emptyMediaVariants = cva( | ||
| 32 | "mb-2 flex shrink-0 items-center justify-center [&_svg]:pointer-events-none [&_svg]:shrink-0", | ||
| 33 | { | ||
| 34 | variants: { | ||
| 35 | variant: { | ||
| 36 | default: "bg-transparent", | ||
| 37 | icon: "flex size-10 shrink-0 items-center justify-center rounded-lg bg-muted text-foreground [&_svg:not([class*='size-'])]:size-6", | ||
| 38 | }, | ||
| 39 | }, | ||
| 40 | defaultVariants: { | ||
| 41 | variant: "default", | ||
| 42 | }, | ||
| 43 | } | ||
| 44 | ) | ||
| 45 | |||
| 46 | function EmptyMedia({ | ||
| 47 | className, | ||
| 48 | variant = "default", | ||
| 49 | ...props | ||
| 50 | }: React.ComponentProps<"div"> & VariantProps<typeof emptyMediaVariants>) { | ||
| 51 | return ( | ||
| 52 | <div | ||
| 53 | data-slot="empty-icon" | ||
| 54 | data-variant={variant} | ||
| 55 | className={cn(emptyMediaVariants({ variant, className }))} | ||
| 56 | {...props} | ||
| 57 | /> | ||
| 58 | ) | ||
| 59 | } | ||
| 60 | |||
| 61 | function EmptyTitle({ className, ...props }: React.ComponentProps<"div">) { | ||
| 62 | return ( | ||
| 63 | <div | ||
| 64 | data-slot="empty-title" | ||
| 65 | className={cn("text-lg font-medium tracking-tight", className)} | ||
| 66 | {...props} | ||
| 67 | /> | ||
| 68 | ) | ||
| 69 | } | ||
| 70 | |||
| 71 | function EmptyDescription({ className, ...props }: React.ComponentProps<"p">) { | ||
| 72 | return ( | ||
| 73 | <div | ||
| 74 | data-slot="empty-description" | ||
| 75 | className={cn( | ||
| 76 | "text-sm/relaxed text-muted-foreground [&>a]:underline [&>a]:underline-offset-4 [&>a:hover]:text-primary", | ||
| 77 | className | ||
| 78 | )} | ||
| 79 | {...props} | ||
| 80 | /> | ||
| 81 | ) | ||
| 82 | } | ||
| 83 | |||
| 84 | function EmptyContent({ className, ...props }: React.ComponentProps<"div">) { | ||
| 85 | return ( | ||
| 86 | <div | ||
| 87 | data-slot="empty-content" | ||
| 88 | className={cn( | ||
| 89 | "flex w-full max-w-sm min-w-0 flex-col items-center gap-4 text-sm text-balance", | ||
| 90 | className | ||
| 91 | )} | ||
| 92 | {...props} | ||
| 93 | /> | ||
| 94 | ) | ||
| 95 | } | ||
| 96 | |||
| 97 | export { | ||
| 98 | Empty, | ||
| 99 | EmptyHeader, | ||
| 100 | EmptyTitle, | ||
| 101 | EmptyDescription, | ||
| 102 | EmptyContent, | ||
| 103 | EmptyMedia, | ||
| 104 | } | ||
| @@ -0,0 +1,248 @@ | |||
| 1 | "use client" | ||
| 2 | |||
| 3 | import { useMemo } from "react" | ||
| 4 | import { cva, type VariantProps } from "class-variance-authority" | ||
| 5 | |||
| 6 | import { cn } from "@executor/ui/lib/utils" | ||
| 7 | import { Label } from "@executor/ui/components/label" | ||
| 8 | import { Separator } from "@executor/ui/components/separator" | ||
| 9 | |||
| 10 | function FieldSet({ className, ...props }: React.ComponentProps<"fieldset">) { | ||
| 11 | return ( | ||
| 12 | <fieldset | ||
| 13 | data-slot="field-set" | ||
| 14 | className={cn( | ||
| 15 | "flex flex-col gap-6", | ||
| 16 | "has-[>[data-slot=checkbox-group]]:gap-3 has-[>[data-slot=radio-group]]:gap-3", | ||
| 17 | className | ||
| 18 | )} | ||
| 19 | {...props} | ||
| 20 | /> | ||
| 21 | ) | ||
| 22 | } | ||
| 23 | |||
| 24 | function FieldLegend({ | ||
| 25 | className, | ||
| 26 | variant = "legend", | ||
| 27 | ...props | ||
| 28 | }: React.ComponentProps<"legend"> & { variant?: "legend" | "label" }) { | ||
| 29 | return ( | ||
| 30 | <legend | ||
| 31 | data-slot="field-legend" | ||
| 32 | data-variant={variant} | ||
| 33 | className={cn( | ||
| 34 | "mb-3 font-medium", | ||
| 35 | "data-[variant=legend]:text-base", | ||
| 36 | "data-[variant=label]:text-sm", | ||
| 37 | className | ||
| 38 | )} | ||
| 39 | {...props} | ||
| 40 | /> | ||
| 41 | ) | ||
| 42 | } | ||
| 43 | |||
| 44 | function FieldGroup({ className, ...props }: React.ComponentProps<"div">) { | ||
| 45 | return ( | ||
| 46 | <div | ||
| 47 | data-slot="field-group" | ||
| 48 | className={cn( | ||
| 49 | "group/field-group @container/field-group flex w-full flex-col gap-7 data-[slot=checkbox-group]:gap-3 [&>[data-slot=field-group]]:gap-4", | ||
| 50 | className | ||
| 51 | )} | ||
| 52 | {...props} | ||
| 53 | /> | ||
| 54 | ) | ||
| 55 | } | ||
| 56 | |||
| 57 | const fieldVariants = cva( | ||
| 58 | "group/field flex w-full gap-3 data-[invalid=true]:text-destructive", | ||
| 59 | { | ||
| 60 | variants: { | ||
| 61 | orientation: { | ||
| 62 | vertical: ["flex-col [&>*]:w-full [&>.sr-only]:w-auto"], | ||
| 63 | horizontal: [ | ||
| 64 | "flex-row items-center", | ||
| 65 | "[&>[data-slot=field-label]]:flex-auto", | ||
| 66 | "has-[>[data-slot=field-content]]:items-start has-[>[data-slot=field-content]]:[&>[role=checkbox],[role=radio]]:mt-px", | ||
| 67 | ], | ||
| 68 | responsive: [ | ||
| 69 | "flex-col @md/field-group:flex-row @md/field-group:items-center [&>*]:w-full @md/field-group:[&>*]:w-auto [&>.sr-only]:w-auto", | ||
| 70 | "@md/field-group:[&>[data-slot=field-label]]:flex-auto", | ||
| 71 | "@md/field-group:has-[>[data-slot=field-content]]:items-start @md/field-group:has-[>[data-slot=field-content]]:[&>[role=checkbox],[role=radio]]:mt-px", | ||
| 72 | ], | ||
| 73 | }, | ||
| 74 | }, | ||
| 75 | defaultVariants: { | ||
| 76 | orientation: "vertical", | ||
| 77 | }, | ||
| 78 | } | ||
| 79 | ) | ||
| 80 | |||
| 81 | function Field({ | ||
| 82 | className, | ||
| 83 | orientation = "vertical", | ||
| 84 | ...props | ||
| 85 | }: React.ComponentProps<"div"> & VariantProps<typeof fieldVariants>) { | ||
| 86 | return ( | ||
| 87 | <div | ||
| 88 | role="group" | ||
| 89 | data-slot="field" | ||
| 90 | data-orientation={orientation} | ||
| 91 | className={cn(fieldVariants({ orientation }), className)} | ||
| 92 | {...props} | ||
| 93 | /> | ||
| 94 | ) | ||
| 95 | } | ||
| 96 | |||
| 97 | function FieldContent({ className, ...props }: React.ComponentProps<"div">) { | ||
| 98 | return ( | ||
| 99 | <div | ||
| 100 | data-slot="field-content" | ||
| 101 | className={cn( | ||
| 102 | "group/field-content flex flex-1 flex-col gap-1.5 leading-snug", | ||
| 103 | className | ||
| 104 | )} | ||
| 105 | {...props} | ||
| 106 | /> | ||
| 107 | ) | ||
| 108 | } | ||
| 109 | |||
| 110 | function FieldLabel({ | ||
| 111 | className, | ||
| 112 | ...props | ||
| 113 | }: React.ComponentProps<typeof Label>) { | ||
| 114 | return ( | ||
| 115 | <Label | ||
| 116 | data-slot="field-label" | ||
| 117 | className={cn( | ||
| 118 | "group/field-label peer/field-label flex w-fit gap-2 leading-snug group-data-[disabled=true]/field:opacity-50", | ||
| 119 | "has-[>[data-slot=field]]:w-full has-[>[data-slot=field]]:flex-col has-[>[data-slot=field]]:rounded-md has-[>[data-slot=field]]:border [&>*]:data-[slot=field]:p-4", | ||
| 120 | "has-data-[state=checked]:border-primary has-data-[state=checked]:bg-primary/5 dark:has-data-[state=checked]:bg-primary/10", | ||
| 121 | className | ||
| 122 | )} | ||
| 123 | {...props} | ||
| 124 | /> | ||
| 125 | ) | ||
| 126 | } | ||
| 127 | |||
| 128 | function FieldTitle({ className, ...props }: React.ComponentProps<"div">) { | ||
| 129 | return ( | ||
| 130 | <div | ||
| 131 | data-slot="field-label" | ||
| 132 | className={cn( | ||
| 133 | "flex w-fit items-center gap-2 text-sm leading-snug font-medium group-data-[disabled=true]/field:opacity-50", | ||
| 134 | className | ||
| 135 | )} | ||
| 136 | {...props} | ||
| 137 | /> | ||
| 138 | ) | ||
| 139 | } | ||
| 140 | |||
| 141 | function FieldDescription({ className, ...props }: React.ComponentProps<"p">) { | ||
| 142 | return ( | ||
| 143 | <p | ||
| 144 | data-slot="field-description" | ||
| 145 | className={cn( | ||
| 146 | "text-sm leading-normal font-normal text-muted-foreground group-has-[[data-orientation=horizontal]]/field:text-balance", | ||
| 147 | "last:mt-0 nth-last-2:-mt-1 [[data-variant=legend]+&]:-mt-1.5", | ||
| 148 | "[&>a]:underline [&>a]:underline-offset-4 [&>a:hover]:text-primary", | ||
| 149 | className | ||
| 150 | )} | ||
| 151 | {...props} | ||
| 152 | /> | ||
| 153 | ) | ||
| 154 | } | ||
| 155 | |||
| 156 | function FieldSeparator({ | ||
| 157 | children, | ||
| 158 | className, | ||
| 159 | ...props | ||
| 160 | }: React.ComponentProps<"div"> & { | ||
| 161 | children?: React.ReactNode | ||
| 162 | }) { | ||
| 163 | return ( | ||
| 164 | <div | ||
| 165 | data-slot="field-separator" | ||
| 166 | data-content={!!children} | ||
| 167 | className={cn( | ||
| 168 | "relative -my-2 h-5 text-sm group-data-[variant=outline]/field-group:-mb-2", | ||
| 169 | className | ||
| 170 | )} | ||
| 171 | {...props} | ||
| 172 | > | ||
| 173 | <Separator className="absolute inset-0 top-1/2" /> | ||
| 174 | {children && ( | ||
| 175 | <span | ||
| 176 | className="relative mx-auto block w-fit bg-background px-2 text-muted-foreground" | ||
| 177 | data-slot="field-separator-content" | ||
| 178 | > | ||
| 179 | {children} | ||
| 180 | </span> | ||
| 181 | )} | ||
| 182 | </div> | ||
| 183 | ) | ||
| 184 | } | ||
| 185 | |||
| 186 | function FieldError({ | ||
| 187 | className, | ||
| 188 | children, | ||
| 189 | errors, | ||
| 190 | ...props | ||
| 191 | }: React.ComponentProps<"div"> & { | ||
| 192 | errors?: Array<{ message?: string } | undefined> | ||
| 193 | }) { | ||
| 194 | const content = useMemo(() => { | ||
| 195 | if (children) { | ||
| 196 | return children | ||
| 197 | } | ||
| 198 | |||
| 199 | if (!errors?.length) { | ||
| 200 | return null | ||
| 201 | } | ||
| 202 | |||
| 203 | const uniqueErrors = [ | ||
| 204 | ...new Map(errors.map((error) => [error?.message, error])).values(), | ||
| 205 | ] | ||
| 206 | |||
| 207 | if (uniqueErrors?.length == 1) { | ||
| 208 | return uniqueErrors[0]?.message | ||
| 209 | } | ||
| 210 | |||
| 211 | return ( | ||
| 212 | <ul className="ml-4 flex list-disc flex-col gap-1"> | ||
| 213 | {uniqueErrors.map( | ||
| 214 | (error, index) => | ||
| 215 | error?.message && <li key={index}>{error.message}</li> | ||
| 216 | )} | ||
| 217 | </ul> | ||
| 218 | ) | ||
| 219 | }, [children, errors]) | ||
| 220 | |||
| 221 | if (!content) { | ||
| 222 | return null | ||
| 223 | } | ||
| 224 | |||
| 225 | return ( | ||
| 226 | <div | ||
| 227 | role="alert" | ||
| 228 | data-slot="field-error" | ||
| 229 | className={cn("text-sm font-normal text-destructive", className)} | ||
| 230 | {...props} | ||
| 231 | > | ||
| 232 | {content} | ||
| 233 | </div> | ||
| 234 | ) | ||
| 235 | } | ||
| 236 | |||
| 237 | export { | ||
| 238 | Field, | ||
| 239 | FieldLabel, | ||
| 240 | FieldDescription, | ||
| 241 | FieldError, | ||
| 242 | FieldGroup, | ||
| 243 | FieldLegend, | ||
| 244 | FieldSeparator, | ||
| 245 | FieldSet, | ||
| 246 | FieldContent, | ||
| 247 | FieldTitle, | ||
| 248 | } | ||
| @@ -0,0 +1,165 @@ | |||
| 1 | import * as React from "react" | ||
| 2 | import type { Label as LabelPrimitive } from "radix-ui" | ||
| 3 | import { Slot } from "radix-ui" | ||
| 4 | import { | ||
| 5 | Controller, | ||
| 6 | FormProvider, | ||
| 7 | useFormContext, | ||
| 8 | useFormState, | ||
| 9 | type ControllerProps, | ||
| 10 | type FieldPath, | ||
| 11 | type FieldValues, | ||
| 12 | } from "react-hook-form" | ||
| 13 | |||
| 14 | import { cn } from "@executor/ui/lib/utils" | ||
| 15 | import { Label } from "@executor/ui/components/label" | ||
| 16 | |||
| 17 | const Form = FormProvider | ||
| 18 | |||
| 19 | type FormFieldContextValue< | ||
| 20 | TFieldValues extends FieldValues = FieldValues, | ||
| 21 | TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>, | ||
| 22 | > = { | ||
| 23 | name: TName | ||
| 24 | } | ||
| 25 | |||
| 26 | const FormFieldContext = React.createContext<FormFieldContextValue>( | ||
| 27 | {} as FormFieldContextValue | ||
| 28 | ) | ||
| 29 | |||
| 30 | const FormField = < | ||
| 31 | TFieldValues extends FieldValues = FieldValues, | ||
| 32 | TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>, | ||
| 33 | >({ | ||
| 34 | ...props | ||
| 35 | }: ControllerProps<TFieldValues, TName>) => { | ||
| 36 | return ( | ||
| 37 | <FormFieldContext.Provider value={{ name: props.name }}> | ||
| 38 | <Controller {...props} /> | ||
| 39 | </FormFieldContext.Provider> | ||
| 40 | ) | ||
| 41 | } | ||
| 42 | |||
| 43 | const useFormField = () => { | ||
| 44 | const fieldContext = React.useContext(FormFieldContext) | ||
| 45 | const itemContext = React.useContext(FormItemContext) | ||
| 46 | const { getFieldState } = useFormContext() | ||
| 47 | const formState = useFormState({ name: fieldContext.name }) | ||
| 48 | const fieldState = getFieldState(fieldContext.name, formState) | ||
| 49 | |||
| 50 | if (!fieldContext) { | ||
| 51 | throw new Error("useFormField should be used within <FormField>") | ||
| 52 | } | ||
| 53 | |||
| 54 | const { id } = itemContext | ||
| 55 | |||
| 56 | return { | ||
| 57 | id, | ||
| 58 | name: fieldContext.name, | ||
| 59 | formItemId: `${id}-form-item`, | ||
| 60 | formDescriptionId: `${id}-form-item-description`, | ||
| 61 | formMessageId: `${id}-form-item-message`, | ||
| 62 | ...fieldState, | ||
| 63 | } | ||
| 64 | } | ||
| 65 | |||
| 66 | type FormItemContextValue = { | ||
| 67 | id: string | ||
| 68 | } | ||
| 69 | |||
| 70 | const FormItemContext = React.createContext<FormItemContextValue>( | ||
| 71 | {} as FormItemContextValue | ||
| 72 | ) | ||
| 73 | |||
| 74 | function FormItem({ className, ...props }: React.ComponentProps<"div">) { | ||
| 75 | const id = React.useId() | ||
| 76 | |||
| 77 | return ( | ||
| 78 | <FormItemContext.Provider value={{ id }}> | ||
| 79 | <div | ||
| 80 | data-slot="form-item" | ||
| 81 | className={cn("grid gap-2", className)} | ||
| 82 | {...props} | ||
| 83 | /> | ||
| 84 | </FormItemContext.Provider> | ||
| 85 | ) | ||
| 86 | } | ||
| 87 | |||
| 88 | function FormLabel({ | ||
| 89 | className, | ||
| 90 | ...props | ||
| 91 | }: React.ComponentProps<typeof LabelPrimitive.Root>) { | ||
| 92 | const { error, formItemId } = useFormField() | ||
| 93 | |||
| 94 | return ( | ||
| 95 | <Label | ||
| 96 | data-slot="form-label" | ||
| 97 | data-error={!!error} | ||
| 98 | className={cn("data-[error=true]:text-destructive", className)} | ||
| 99 | htmlFor={formItemId} | ||
| 100 | {...props} | ||
| 101 | /> | ||
| 102 | ) | ||
| 103 | } | ||
| 104 | |||
| 105 | function FormControl({ ...props }: React.ComponentProps<typeof Slot.Root>) { | ||
| 106 | const { error, formItemId, formDescriptionId, formMessageId } = useFormField() | ||
| 107 | |||
| 108 | return ( | ||
| 109 | <Slot.Root | ||
| 110 | data-slot="form-control" | ||
| 111 | id={formItemId} | ||
| 112 | aria-describedby={ | ||
| 113 | !error | ||
| 114 | ? `${formDescriptionId}` | ||
| 115 | : `${formDescriptionId} ${formMessageId}` | ||
| 116 | } | ||
| 117 | aria-invalid={!!error} | ||
| 118 | {...props} | ||
| 119 | /> | ||
| 120 | ) | ||
| 121 | } | ||
| 122 | |||
| 123 | function FormDescription({ className, ...props }: React.ComponentProps<"p">) { | ||
| 124 | const { formDescriptionId } = useFormField() | ||
| 125 | |||
| 126 | return ( | ||
| 127 | <p | ||
| 128 | data-slot="form-description" | ||
| 129 | id={formDescriptionId} | ||
| 130 | className={cn("text-sm text-muted-foreground", className)} | ||
| 131 | {...props} | ||
| 132 | /> | ||
| 133 | ) | ||
| 134 | } | ||
| 135 | |||
| 136 | function FormMessage({ className, ...props }: React.ComponentProps<"p">) { | ||
| 137 | const { error, formMessageId } = useFormField() | ||
| 138 | const body = error ? String(error?.message ?? "") : props.children | ||
| 139 | |||
| 140 | if (!body) { | ||
| 141 | return null | ||
| 142 | } | ||
| 143 | |||
| 144 | return ( | ||
| 145 | <p | ||
| 146 | data-slot="form-message" | ||
| 147 | id={formMessageId} | ||
| 148 | className={cn("text-sm text-destructive", className)} | ||
| 149 | {...props} | ||
| 150 | > | ||
| 151 | {body} | ||
| 152 | </p> | ||
| 153 | ) | ||
| 154 | } | ||
| 155 | |||
| 156 | export { | ||
| 157 | useFormField, | ||
| 158 | Form, | ||
| 159 | FormItem, | ||
| 160 | FormLabel, | ||
| 161 | FormControl, | ||
| 162 | FormDescription, | ||
| 163 | FormMessage, | ||
| 164 | FormField, | ||
| 165 | } | ||
| @@ -0,0 +1,42 @@ | |||
| 1 | import * as React from "react" | ||
| 2 | import { HoverCard as HoverCardPrimitive } from "radix-ui" | ||
| 3 | |||
| 4 | import { cn } from "@executor/ui/lib/utils" | ||
| 5 | |||
| 6 | function HoverCard({ | ||
| 7 | ...props | ||
| 8 | }: React.ComponentProps<typeof HoverCardPrimitive.Root>) { | ||
| 9 | return <HoverCardPrimitive.Root data-slot="hover-card" {...props} /> | ||
| 10 | } | ||
| 11 | |||
| 12 | function HoverCardTrigger({ | ||
| 13 | ...props | ||
| 14 | }: React.ComponentProps<typeof HoverCardPrimitive.Trigger>) { | ||
| 15 | return ( | ||
| 16 | <HoverCardPrimitive.Trigger data-slot="hover-card-trigger" {...props} /> | ||
| 17 | ) | ||
| 18 | } | ||
| 19 | |||
| 20 | function HoverCardContent({ | ||
| 21 | className, | ||
| 22 | align = "center", | ||
| 23 | sideOffset = 4, | ||
| 24 | ...props | ||
| 25 | }: React.ComponentProps<typeof HoverCardPrimitive.Content>) { | ||
| 26 | return ( | ||
| 27 | <HoverCardPrimitive.Portal data-slot="hover-card-portal"> | ||
| 28 | <HoverCardPrimitive.Content | ||
| 29 | data-slot="hover-card-content" | ||
| 30 | align={align} | ||
| 31 | sideOffset={sideOffset} | ||
| 32 | className={cn( | ||
| 33 | "z-50 w-64 origin-(--radix-hover-card-content-transform-origin) rounded-md border bg-popover p-4 text-popover-foreground shadow-md outline-hidden data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95", | ||
| 34 | className | ||
| 35 | )} | ||
| 36 | {...props} | ||
| 37 | /> | ||
| 38 | </HoverCardPrimitive.Portal> | ||
| 39 | ) | ||
| 40 | } | ||
| 41 | |||
| 42 | export { HoverCard, HoverCardTrigger, HoverCardContent } | ||
| @@ -0,0 +1,168 @@ | |||
| 1 | import * as React from "react" | ||
| 2 | import { cva, type VariantProps } from "class-variance-authority" | ||
| 3 | |||
| 4 | import { cn } from "@executor/ui/lib/utils" | ||
| 5 | import { Button } from "@executor/ui/components/button" | ||
| 6 | import { Input } from "@executor/ui/components/input" | ||
| 7 | import { Textarea } from "@executor/ui/components/textarea" | ||
| 8 | |||
| 9 | function InputGroup({ className, ...props }: React.ComponentProps<"div">) { | ||
| 10 | return ( | ||
| 11 | <div | ||
| 12 | data-slot="input-group" | ||
| 13 | role="group" | ||
| 14 | className={cn( | ||
| 15 | "group/input-group relative flex w-full items-center rounded-md border border-input shadow-xs transition-[color,box-shadow] outline-none dark:bg-input/30", | ||
| 16 | "h-9 min-w-0 has-[>textarea]:h-auto", | ||
| 17 | |||
| 18 | // Variants based on alignment. | ||
| 19 | "has-[>[data-align=inline-start]]:[&>input]:pl-2", | ||
| 20 | "has-[>[data-align=inline-end]]:[&>input]:pr-2", | ||
| 21 | "has-[>[data-align=block-start]]:h-auto has-[>[data-align=block-start]]:flex-col has-[>[data-align=block-start]]:[&>input]:pb-3", | ||
| 22 | "has-[>[data-align=block-end]]:h-auto has-[>[data-align=block-end]]:flex-col has-[>[data-align=block-end]]:[&>input]:pt-3", | ||
| 23 | |||
| 24 | // Focus state. | ||
| 25 | "has-[[data-slot=input-group-control]:focus-visible]:border-ring has-[[data-slot=input-group-control]:focus-visible]:ring-[3px] has-[[data-slot=input-group-control]:focus-visible]:ring-ring/50", | ||
| 26 | |||
| 27 | // Error state. | ||
| 28 | "has-[[data-slot][aria-invalid=true]]:border-destructive has-[[data-slot][aria-invalid=true]]:ring-destructive/20 dark:has-[[data-slot][aria-invalid=true]]:ring-destructive/40", | ||
| 29 | |||
| 30 | className | ||
| 31 | )} | ||
| 32 | {...props} | ||
| 33 | /> | ||
| 34 | ) | ||
| 35 | } | ||
| 36 | |||
| 37 | const inputGroupAddonVariants = cva( | ||
| 38 | "flex h-auto cursor-text items-center justify-center gap-2 py-1.5 text-sm font-medium text-muted-foreground select-none group-data-[disabled=true]/input-group:opacity-50 [&>kbd]:rounded-[calc(var(--radius)-5px)] [&>svg:not([class*='size-'])]:size-4", | ||
| 39 | { | ||
| 40 | variants: { | ||
| 41 | align: { | ||
| 42 | "inline-start": | ||
| 43 | "order-first pl-3 has-[>button]:ml-[-0.45rem] has-[>kbd]:ml-[-0.35rem]", | ||
| 44 | "inline-end": | ||
| 45 | "order-last pr-3 has-[>button]:mr-[-0.45rem] has-[>kbd]:mr-[-0.35rem]", | ||
| 46 | "block-start": | ||
| 47 | "order-first w-full justify-start px-3 pt-3 group-has-[>input]/input-group:pt-2.5 [.border-b]:pb-3", | ||
| 48 | "block-end": | ||
| 49 | "order-last w-full justify-start px-3 pb-3 group-has-[>input]/input-group:pb-2.5 [.border-t]:pt-3", | ||
| 50 | }, | ||
| 51 | }, | ||
| 52 | defaultVariants: { | ||
| 53 | align: "inline-start", | ||
| 54 | }, | ||
| 55 | } | ||
| 56 | ) | ||
| 57 | |||
| 58 | function InputGroupAddon({ | ||
| 59 | className, | ||
| 60 | align = "inline-start", | ||
| 61 | ...props | ||
| 62 | }: React.ComponentProps<"div"> & VariantProps<typeof inputGroupAddonVariants>) { | ||
| 63 | return ( | ||
| 64 | <div | ||
| 65 | role="group" | ||
| 66 | data-slot="input-group-addon" | ||
| 67 | data-align={align} | ||
| 68 | className={cn(inputGroupAddonVariants({ align }), className)} | ||
| 69 | onClick={(e) => { | ||
| 70 | if ((e.target as HTMLElement).closest("button")) { | ||
| 71 | return | ||
| 72 | } | ||
| 73 | e.currentTarget.parentElement?.querySelector("input")?.focus() | ||
| 74 | }} | ||
| 75 | {...props} | ||
| 76 | /> | ||
| 77 | ) | ||
| 78 | } | ||
| 79 | |||
| 80 | const inputGroupButtonVariants = cva( | ||
| 81 | "flex items-center gap-2 text-sm shadow-none", | ||
| 82 | { | ||
| 83 | variants: { | ||
| 84 | size: { | ||
| 85 | xs: "h-6 gap-1 rounded-[calc(var(--radius)-5px)] px-2 has-[>svg]:px-2 [&>svg:not([class*='size-'])]:size-3.5", | ||
| 86 | sm: "h-8 gap-1.5 rounded-md px-2.5 has-[>svg]:px-2.5", | ||
| 87 | "icon-xs": | ||
| 88 | "size-6 rounded-[calc(var(--radius)-5px)] p-0 has-[>svg]:p-0", | ||
| 89 | "icon-sm": "size-8 p-0 has-[>svg]:p-0", | ||
| 90 | }, | ||
| 91 | }, | ||
| 92 | defaultVariants: { | ||
| 93 | size: "xs", | ||
| 94 | }, | ||
| 95 | } | ||
| 96 | ) | ||
| 97 | |||
| 98 | function InputGroupButton({ | ||
| 99 | className, | ||
| 100 | type = "button", | ||
| 101 | variant = "ghost", | ||
| 102 | size = "xs", | ||
| 103 | ...props | ||
| 104 | }: Omit<React.ComponentProps<typeof Button>, "size"> & | ||
| 105 | VariantProps<typeof inputGroupButtonVariants>) { | ||
| 106 | return ( | ||
| 107 | <Button | ||
| 108 | type={type} | ||
| 109 | data-size={size} | ||
| 110 | variant={variant} | ||
| 111 | className={cn(inputGroupButtonVariants({ size }), className)} | ||
| 112 | {...props} | ||
| 113 | /> | ||
| 114 | ) | ||
| 115 | } | ||
| 116 | |||
| 117 | function InputGroupText({ className, ...props }: React.ComponentProps<"span">) { | ||
| 118 | return ( | ||
| 119 | <span | ||
| 120 | className={cn( | ||
| 121 | "flex items-center gap-2 text-sm text-muted-foreground [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4", | ||
| 122 | className | ||
| 123 | )} | ||
| 124 | {...props} | ||
| 125 | /> | ||
| 126 | ) | ||
| 127 | } | ||
| 128 | |||
| 129 | function InputGroupInput({ | ||
| 130 | className, | ||
| 131 | ...props | ||
| 132 | }: React.ComponentProps<"input">) { | ||
| 133 | return ( | ||
| 134 | <Input | ||
| 135 | data-slot="input-group-control" | ||
| 136 | className={cn( | ||
| 137 | "flex-1 rounded-none border-0 bg-transparent shadow-none focus-visible:ring-0 dark:bg-transparent", | ||
| 138 | className | ||
| 139 | )} | ||
| 140 | {...props} | ||
| 141 | /> | ||
| 142 | ) | ||
| 143 | } | ||
| 144 | |||
| 145 | function InputGroupTextarea({ | ||
| 146 | className, | ||
| 147 | ...props | ||
| 148 | }: React.ComponentProps<"textarea">) { | ||
| 149 | return ( | ||
| 150 | <Textarea | ||
| 151 | data-slot="input-group-control" | ||
| 152 | className={cn( | ||
| 153 | "flex-1 resize-none rounded-none border-0 bg-transparent py-3 shadow-none focus-visible:ring-0 dark:bg-transparent", | ||
| 154 | className | ||
| 155 | )} | ||
| 156 | {...props} | ||
| 157 | /> | ||
| 158 | ) | ||
| 159 | } | ||
| 160 | |||
| 161 | export { | ||
| 162 | InputGroup, | ||
| 163 | InputGroupAddon, | ||
| 164 | InputGroupButton, | ||
| 165 | InputGroupText, | ||
| 166 | InputGroupInput, | ||
| 167 | InputGroupTextarea, | ||
| 168 | } | ||
| @@ -0,0 +1,77 @@ | |||
| 1 | "use client" | ||
| 2 | |||
| 3 | import * as React from "react" | ||
| 4 | import { OTPInput, OTPInputContext } from "input-otp" | ||
| 5 | import { MinusIcon } from "lucide-react" | ||
| 6 | |||
| 7 | import { cn } from "@executor/ui/lib/utils" | ||
| 8 | |||
| 9 | function InputOTP({ | ||
| 10 | className, | ||
| 11 | containerClassName, | ||
| 12 | ...props | ||
| 13 | }: React.ComponentProps<typeof OTPInput> & { | ||
| 14 | containerClassName?: string | ||
| 15 | }) { | ||
| 16 | return ( | ||
| 17 | <OTPInput | ||
| 18 | data-slot="input-otp" | ||
| 19 | containerClassName={cn( | ||
| 20 | "flex items-center gap-2 has-disabled:opacity-50", | ||
| 21 | containerClassName | ||
| 22 | )} | ||
| 23 | className={cn("disabled:cursor-not-allowed", className)} | ||
| 24 | {...props} | ||
| 25 | /> | ||
| 26 | ) | ||
| 27 | } | ||
| 28 | |||
| 29 | function InputOTPGroup({ className, ...props }: React.ComponentProps<"div">) { | ||
| 30 | return ( | ||
| 31 | <div | ||
| 32 | data-slot="input-otp-group" | ||
| 33 | className={cn("flex items-center", className)} | ||
| 34 | {...props} | ||
| 35 | /> | ||
| 36 | ) | ||
| 37 | } | ||
| 38 | |||
| 39 | function InputOTPSlot({ | ||
| 40 | index, | ||
| 41 | className, | ||
| 42 | ...props | ||
| 43 | }: React.ComponentProps<"div"> & { | ||
| 44 | index: number | ||
| 45 | }) { | ||
| 46 | const inputOTPContext = React.useContext(OTPInputContext) | ||
| 47 | const { char, hasFakeCaret, isActive } = inputOTPContext?.slots[index] ?? {} | ||
| 48 | |||
| 49 | return ( | ||
| 50 | <div | ||
| 51 | data-slot="input-otp-slot" | ||
| 52 | data-active={isActive} | ||
| 53 | className={cn( | ||
| 54 | "relative flex h-9 w-9 items-center justify-center border-y border-r border-input text-sm shadow-xs transition-all outline-none first:rounded-l-md first:border-l last:rounded-r-md aria-invalid:border-destructive data-[active=true]:z-10 data-[active=true]:border-ring data-[active=true]:ring-[3px] data-[active=true]:ring-ring/50 data-[active=true]:aria-invalid:border-destructive data-[active=true]:aria-invalid:ring-destructive/20 dark:bg-input/30 dark:data-[active=true]:aria-invalid:ring-destructive/40", | ||
| 55 | className | ||
| 56 | )} | ||
| 57 | {...props} | ||
| 58 | > | ||
| 59 | {char} | ||
| 60 | {hasFakeCaret && ( | ||
| 61 | <div className="pointer-events-none absolute inset-0 flex items-center justify-center"> | ||
| 62 | <div className="h-4 w-px animate-caret-blink bg-foreground duration-1000" /> | ||
| 63 | </div> | ||
| 64 | )} | ||
| 65 | </div> | ||
| 66 | ) | ||
| 67 | } | ||
| 68 | |||
| 69 | function InputOTPSeparator({ ...props }: React.ComponentProps<"div">) { | ||
| 70 | return ( | ||
| 71 | <div data-slot="input-otp-separator" role="separator" {...props}> | ||
| 72 | <MinusIcon /> | ||
| 73 | </div> | ||
| 74 | ) | ||
| 75 | } | ||
| 76 | |||
| 77 | export { InputOTP, InputOTPGroup, InputOTPSlot, InputOTPSeparator } | ||
| @@ -0,0 +1,21 @@ | |||
| 1 | import * as React from "react" | ||
| 2 | |||
| 3 | import { cn } from "@executor/ui/lib/utils" | ||
| 4 | |||
| 5 | function Input({ className, type, ...props }: React.ComponentProps<"input">) { | ||
| 6 | return ( | ||
| 7 | <input | ||
| 8 | type={type} | ||
| 9 | data-slot="input" | ||
| 10 | className={cn( | ||
| 11 | "h-9 w-full min-w-0 rounded-md border border-input bg-transparent px-3 py-1 text-base shadow-xs transition-[color,box-shadow] outline-none selection:bg-primary selection:text-primary-foreground file:inline-flex file:h-7 file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground placeholder:text-muted-foreground disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50 md:text-sm dark:bg-input/30", | ||
| 12 | "focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50", | ||
| 13 | "aria-invalid:border-destructive aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40", | ||
| 14 | className | ||
| 15 | )} | ||
| 16 | {...props} | ||
| 17 | /> | ||
| 18 | ) | ||
| 19 | } | ||
| 20 | |||
| 21 | export { Input } | ||
| @@ -0,0 +1,193 @@ | |||
| 1 | import * as React from "react" | ||
| 2 | import { cva, type VariantProps } from "class-variance-authority" | ||
| 3 | import { Slot } from "radix-ui" | ||
| 4 | |||
| 5 | import { cn } from "@executor/ui/lib/utils" | ||
| 6 | import { Separator } from "@executor/ui/components/separator" | ||
| 7 | |||
| 8 | function ItemGroup({ className, ...props }: React.ComponentProps<"div">) { | ||
| 9 | return ( | ||
| 10 | <div | ||
| 11 | role="list" | ||
| 12 | data-slot="item-group" | ||
| 13 | className={cn("group/item-group flex flex-col", className)} | ||
| 14 | {...props} | ||
| 15 | /> | ||
| 16 | ) | ||
| 17 | } | ||
| 18 | |||
| 19 | function ItemSeparator({ | ||
| 20 | className, | ||
| 21 | ...props | ||
| 22 | }: React.ComponentProps<typeof Separator>) { | ||
| 23 | return ( | ||
| 24 | <Separator | ||
| 25 | data-slot="item-separator" | ||
| 26 | orientation="horizontal" | ||
| 27 | className={cn("my-0", className)} | ||
| 28 | {...props} | ||
| 29 | /> | ||
| 30 | ) | ||
| 31 | } | ||
| 32 | |||
| 33 | const itemVariants = cva( | ||
| 34 | "group/item flex flex-wrap items-center rounded-md border border-transparent text-sm transition-colors duration-100 outline-none focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 [a]:transition-colors [a]:hover:bg-accent/50", | ||
| 35 | { | ||
| 36 | variants: { | ||
| 37 | variant: { | ||
| 38 | default: "bg-transparent", | ||
| 39 | outline: "border-border", | ||
| 40 | muted: "bg-muted/50", | ||
| 41 | }, | ||
| 42 | size: { | ||
| 43 | default: "gap-4 p-4", | ||
| 44 | sm: "gap-2.5 px-4 py-3", | ||
| 45 | }, | ||
| 46 | }, | ||
| 47 | defaultVariants: { | ||
| 48 | variant: "default", | ||
| 49 | size: "default", | ||
| 50 | }, | ||
| 51 | } | ||
| 52 | ) | ||
| 53 | |||
| 54 | function Item({ | ||
| 55 | className, | ||
| 56 | variant = "default", | ||
| 57 | size = "default", | ||
| 58 | asChild = false, | ||
| 59 | ...props | ||
| 60 | }: React.ComponentProps<"div"> & | ||
| 61 | VariantProps<typeof itemVariants> & { asChild?: boolean }) { | ||
| 62 | const Comp = asChild ? Slot.Root : "div" | ||
| 63 | return ( | ||
| 64 | <Comp | ||
| 65 | data-slot="item" | ||
| 66 | data-variant={variant} | ||
| 67 | data-size={size} | ||
| 68 | className={cn(itemVariants({ variant, size, className }))} | ||
| 69 | {...props} | ||
| 70 | /> | ||
| 71 | ) | ||
| 72 | } | ||
| 73 | |||
| 74 | const itemMediaVariants = cva( | ||
| 75 | "flex shrink-0 items-center justify-center gap-2 group-has-[[data-slot=item-description]]/item:translate-y-0.5 group-has-[[data-slot=item-description]]/item:self-start [&_svg]:pointer-events-none", | ||
| 76 | { | ||
| 77 | variants: { | ||
| 78 | variant: { | ||
| 79 | default: "bg-transparent", | ||
| 80 | icon: "size-8 rounded-sm border bg-muted [&_svg:not([class*='size-'])]:size-4", | ||
| 81 | image: | ||
| 82 | "size-10 overflow-hidden rounded-sm [&_img]:size-full [&_img]:object-cover", | ||
| 83 | }, | ||
| 84 | }, | ||
| 85 | defaultVariants: { | ||
| 86 | variant: "default", | ||
| 87 | }, | ||
| 88 | } | ||
| 89 | ) | ||
| 90 | |||
| 91 | function ItemMedia({ | ||
| 92 | className, | ||
| 93 | variant = "default", | ||
| 94 | ...props | ||
| 95 | }: React.ComponentProps<"div"> & VariantProps<typeof itemMediaVariants>) { | ||
| 96 | return ( | ||
| 97 | <div | ||
| 98 | data-slot="item-media" | ||
| 99 | data-variant={variant} | ||
| 100 | className={cn(itemMediaVariants({ variant, className }))} | ||
| 101 | {...props} | ||
| 102 | /> | ||
| 103 | ) | ||
| 104 | } | ||
| 105 | |||
| 106 | function ItemContent({ className, ...props }: React.ComponentProps<"div">) { | ||
| 107 | return ( | ||
| 108 | <div | ||
| 109 | data-slot="item-content" | ||
| 110 | className={cn( | ||
| 111 | "flex flex-1 flex-col gap-1 [&+[data-slot=item-content]]:flex-none", | ||
| 112 | className | ||
| 113 | )} | ||
| 114 | {...props} | ||
| 115 | /> | ||
| 116 | ) | ||
| 117 | } | ||
| 118 | |||
| 119 | function ItemTitle({ className, ...props }: React.ComponentProps<"div">) { | ||
| 120 | return ( | ||
| 121 | <div | ||
| 122 | data-slot="item-title" | ||
| 123 | className={cn( | ||
| 124 | "flex w-fit items-center gap-2 text-sm leading-snug font-medium", | ||
| 125 | className | ||
| 126 | )} | ||
| 127 | {...props} | ||
| 128 | /> | ||
| 129 | ) | ||
| 130 | } | ||
| 131 | |||
| 132 | function ItemDescription({ className, ...props }: React.ComponentProps<"p">) { | ||
| 133 | return ( | ||
| 134 | <p | ||
| 135 | data-slot="item-description" | ||
| 136 | className={cn( | ||
| 137 | "line-clamp-2 text-sm leading-normal font-normal text-balance text-muted-foreground", | ||
| 138 | "[&>a]:underline [&>a]:underline-offset-4 [&>a:hover]:text-primary", | ||
| 139 | className | ||
| 140 | )} | ||
| 141 | {...props} | ||
| 142 | /> | ||
| 143 | ) | ||
| 144 | } | ||
| 145 | |||
| 146 | function ItemActions({ className, ...props }: React.ComponentProps<"div">) { | ||
| 147 | return ( | ||
| 148 | <div | ||
| 149 | data-slot="item-actions" | ||
| 150 | className={cn("flex items-center gap-2", className)} | ||
| 151 | {...props} | ||
| 152 | /> | ||
| 153 | ) | ||
| 154 | } | ||
| 155 | |||
| 156 | function ItemHeader({ className, ...props }: React.ComponentProps<"div">) { | ||
| 157 | return ( | ||
| 158 | <div | ||
| 159 | data-slot="item-header" | ||
| 160 | className={cn( | ||
| 161 | "flex basis-full items-center justify-between gap-2", | ||
| 162 | className | ||
| 163 | )} | ||
| 164 | {...props} | ||
| 165 | /> | ||
| 166 | ) | ||
| 167 | } | ||
| 168 | |||
| 169 | function ItemFooter({ className, ...props }: React.ComponentProps<"div">) { | ||
| 170 | return ( | ||
| 171 | <div | ||
| 172 | data-slot="item-footer" | ||
| 173 | className={cn( | ||
| 174 | "flex basis-full items-center justify-between gap-2", | ||
| 175 | className | ||
| 176 | )} | ||
| 177 | {...props} | ||
| 178 | /> | ||
| 179 | ) | ||
| 180 | } | ||
| 181 | |||
| 182 | export { | ||
| 183 | Item, | ||
| 184 | ItemMedia, | ||
| 185 | ItemContent, | ||
| 186 | ItemActions, | ||
| 187 | ItemGroup, | ||
| 188 | ItemSeparator, | ||
| 189 | ItemTitle, | ||
| 190 | ItemDescription, | ||
| 191 | ItemHeader, | ||
| 192 | ItemFooter, | ||
| 193 | } | ||
| @@ -0,0 +1,28 @@ | |||
| 1 | import { cn } from "@executor/ui/lib/utils" | ||
| 2 | |||
| 3 | function Kbd({ className, ...props }: React.ComponentProps<"kbd">) { | ||
| 4 | return ( | ||
| 5 | <kbd | ||
| 6 | data-slot="kbd" | ||
| 7 | className={cn( | ||
| 8 | "pointer-events-none inline-flex h-5 w-fit min-w-5 items-center justify-center gap-1 rounded-sm bg-muted px-1 font-sans text-xs font-medium text-muted-foreground select-none", | ||
| 9 | "[&_svg:not([class*='size-'])]:size-3", | ||
| 10 | "[[data-slot=tooltip-content]_&]:bg-background/20 [[data-slot=tooltip-content]_&]:text-background dark:[[data-slot=tooltip-content]_&]:bg-background/10", | ||
| 11 | className | ||
| 12 | )} | ||
| 13 | {...props} | ||
| 14 | /> | ||
| 15 | ) | ||
| 16 | } | ||
| 17 | |||
| 18 | function KbdGroup({ className, ...props }: React.ComponentProps<"div">) { | ||
| 19 | return ( | ||
| 20 | <kbd | ||
| 21 | data-slot="kbd-group" | ||
| 22 | className={cn("inline-flex items-center gap-1", className)} | ||
| 23 | {...props} | ||
| 24 | /> | ||
| 25 | ) | ||
| 26 | } | ||
| 27 | |||
| 28 | export { Kbd, KbdGroup } | ||
| @@ -0,0 +1,22 @@ | |||
| 1 | import * as React from "react" | ||
| 2 | import { Label as LabelPrimitive } from "radix-ui" | ||
| 3 | |||
| 4 | import { cn } from "@executor/ui/lib/utils" | ||
| 5 | |||
| 6 | function Label({ | ||
| 7 | className, | ||
| 8 | ...props | ||
| 9 | }: React.ComponentProps<typeof LabelPrimitive.Root>) { | ||
| 10 | return ( | ||
| 11 | <LabelPrimitive.Root | ||
| 12 | data-slot="label" | ||
| 13 | className={cn( | ||
| 14 | "flex items-center gap-2 text-sm leading-none font-medium select-none group-data-[disabled=true]:pointer-events-none group-data-[disabled=true]:opacity-50 peer-disabled:cursor-not-allowed peer-disabled:opacity-50", | ||
| 15 | className | ||
| 16 | )} | ||
| 17 | {...props} | ||
| 18 | /> | ||
| 19 | ) | ||
| 20 | } | ||
| 21 | |||
| 22 | export { Label } | ||
| @@ -0,0 +1,276 @@ | |||
| 1 | "use client" | ||
| 2 | |||
| 3 | import * as React from "react" | ||
| 4 | import { CheckIcon, ChevronRightIcon, CircleIcon } from "lucide-react" | ||
| 5 | import { Menubar as MenubarPrimitive } from "radix-ui" | ||
| 6 | |||
| 7 | import { cn } from "@executor/ui/lib/utils" | ||
| 8 | |||
| 9 | function Menubar({ | ||
| 10 | className, | ||
| 11 | ...props | ||
| 12 | }: React.ComponentProps<typeof MenubarPrimitive.Root>) { | ||
| 13 | return ( | ||
| 14 | <MenubarPrimitive.Root | ||
| 15 | data-slot="menubar" | ||
| 16 | className={cn( | ||
| 17 | "flex h-9 items-center gap-1 rounded-md border bg-background p-1 shadow-xs", | ||
| 18 | className | ||
| 19 | )} | ||
| 20 | {...props} | ||
| 21 | /> | ||
| 22 | ) | ||
| 23 | } | ||
| 24 | |||
| 25 | function MenubarMenu({ | ||
| 26 | ...props | ||
| 27 | }: React.ComponentProps<typeof MenubarPrimitive.Menu>) { | ||
| 28 | return <MenubarPrimitive.Menu data-slot="menubar-menu" {...props} /> | ||
| 29 | } | ||
| 30 | |||
| 31 | function MenubarGroup({ | ||
| 32 | ...props | ||
| 33 | }: React.ComponentProps<typeof MenubarPrimitive.Group>) { | ||
| 34 | return <MenubarPrimitive.Group data-slot="menubar-group" {...props} /> | ||
| 35 | } | ||
| 36 | |||
| 37 | function MenubarPortal({ | ||
| 38 | ...props | ||
| 39 | }: React.ComponentProps<typeof MenubarPrimitive.Portal>) { | ||
| 40 | return <MenubarPrimitive.Portal data-slot="menubar-portal" {...props} /> | ||
| 41 | } | ||
| 42 | |||
| 43 | function MenubarRadioGroup({ | ||
| 44 | ...props | ||
| 45 | }: React.ComponentProps<typeof MenubarPrimitive.RadioGroup>) { | ||
| 46 | return ( | ||
| 47 | <MenubarPrimitive.RadioGroup data-slot="menubar-radio-group" {...props} /> | ||
| 48 | ) | ||
| 49 | } | ||
| 50 | |||
| 51 | function MenubarTrigger({ | ||
| 52 | className, | ||
| 53 | ...props | ||
| 54 | }: React.ComponentProps<typeof MenubarPrimitive.Trigger>) { | ||
| 55 | return ( | ||
| 56 | <MenubarPrimitive.Trigger | ||
| 57 | data-slot="menubar-trigger" | ||
| 58 | className={cn( | ||
| 59 | "flex items-center rounded-sm px-2 py-1 text-sm font-medium outline-hidden select-none focus:bg-accent focus:text-accent-foreground data-[state=open]:bg-accent data-[state=open]:text-accent-foreground", | ||
| 60 | className | ||
| 61 | )} | ||
| 62 | {...props} | ||
| 63 | /> | ||
| 64 | ) | ||
| 65 | } | ||
| 66 | |||
| 67 | function MenubarContent({ | ||
| 68 | className, | ||
| 69 | align = "start", | ||
| 70 | alignOffset = -4, | ||
| 71 | sideOffset = 8, | ||
| 72 | ...props | ||
| 73 | }: React.ComponentProps<typeof MenubarPrimitive.Content>) { | ||
| 74 | return ( | ||
| 75 | <MenubarPortal> | ||
| 76 | <MenubarPrimitive.Content | ||
| 77 | data-slot="menubar-content" | ||
| 78 | align={align} | ||
| 79 | alignOffset={alignOffset} | ||
| 80 | sideOffset={sideOffset} | ||
| 81 | className={cn( | ||
| 82 | "z-50 min-w-[12rem] origin-(--radix-menubar-content-transform-origin) overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-md data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95", | ||
| 83 | className | ||
| 84 | )} | ||
| 85 | {...props} | ||
| 86 | /> | ||
| 87 | </MenubarPortal> | ||
| 88 | ) | ||
| 89 | } | ||
| 90 | |||
| 91 | function MenubarItem({ | ||
| 92 | className, | ||
| 93 | inset, | ||
| 94 | variant = "default", | ||
| 95 | ...props | ||
| 96 | }: React.ComponentProps<typeof MenubarPrimitive.Item> & { | ||
| 97 | inset?: boolean | ||
| 98 | variant?: "default" | "destructive" | ||
| 99 | }) { | ||
| 100 | return ( | ||
| 101 | <MenubarPrimitive.Item | ||
| 102 | data-slot="menubar-item" | ||
| 103 | data-inset={inset} | ||
| 104 | data-variant={variant} | ||
| 105 | className={cn( | ||
| 106 | "relative flex cursor-default items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-hidden select-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50 data-[inset]:pl-8 data-[variant=destructive]:text-destructive data-[variant=destructive]:focus:bg-destructive/10 data-[variant=destructive]:focus:text-destructive dark:data-[variant=destructive]:focus:bg-destructive/20 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 [&_svg:not([class*='text-'])]:text-muted-foreground data-[variant=destructive]:*:[svg]:text-destructive!", | ||
| 107 | className | ||
| 108 | )} | ||
| 109 | {...props} | ||
| 110 | /> | ||
| 111 | ) | ||
| 112 | } | ||
| 113 | |||
| 114 | function MenubarCheckboxItem({ | ||
| 115 | className, | ||
| 116 | children, | ||
| 117 | checked, | ||
| 118 | ...props | ||
| 119 | }: React.ComponentProps<typeof MenubarPrimitive.CheckboxItem>) { | ||
| 120 | return ( | ||
| 121 | <MenubarPrimitive.CheckboxItem | ||
| 122 | data-slot="menubar-checkbox-item" | ||
| 123 | className={cn( | ||
| 124 | "relative flex cursor-default items-center gap-2 rounded-xs py-1.5 pr-2 pl-8 text-sm outline-hidden select-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4", | ||
| 125 | className | ||
| 126 | )} | ||
| 127 | checked={checked} | ||
| 128 | {...props} | ||
| 129 | > | ||
| 130 | <span className="pointer-events-none absolute left-2 flex size-3.5 items-center justify-center"> | ||
| 131 | <MenubarPrimitive.ItemIndicator> | ||
| 132 | <CheckIcon className="size-4" /> | ||
| 133 | </MenubarPrimitive.ItemIndicator> | ||
| 134 | </span> | ||
| 135 | {children} | ||
| 136 | </MenubarPrimitive.CheckboxItem> | ||
| 137 | ) | ||
| 138 | } | ||
| 139 | |||
| 140 | function MenubarRadioItem({ | ||
| 141 | className, | ||
| 142 | children, | ||
| 143 | ...props | ||
| 144 | }: React.ComponentProps<typeof MenubarPrimitive.RadioItem>) { | ||
| 145 | return ( | ||
| 146 | <MenubarPrimitive.RadioItem | ||
| 147 | data-slot="menubar-radio-item" | ||
| 148 | className={cn( | ||
| 149 | "relative flex cursor-default items-center gap-2 rounded-xs py-1.5 pr-2 pl-8 text-sm outline-hidden select-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4", | ||
| 150 | className | ||
| 151 | )} | ||
| 152 | {...props} | ||
| 153 | > | ||
| 154 | <span className="pointer-events-none absolute left-2 flex size-3.5 items-center justify-center"> | ||
| 155 | <MenubarPrimitive.ItemIndicator> | ||
| 156 | <CircleIcon className="size-2 fill-current" /> | ||
| 157 | </MenubarPrimitive.ItemIndicator> | ||
| 158 | </span> | ||
| 159 | {children} | ||
| 160 | </MenubarPrimitive.RadioItem> | ||
| 161 | ) | ||
| 162 | } | ||
| 163 | |||
| 164 | function MenubarLabel({ | ||
| 165 | className, | ||
| 166 | inset, | ||
| 167 | ...props | ||
| 168 | }: React.ComponentProps<typeof MenubarPrimitive.Label> & { | ||
| 169 | inset?: boolean | ||
| 170 | }) { | ||
| 171 | return ( | ||
| 172 | <MenubarPrimitive.Label | ||
| 173 | data-slot="menubar-label" | ||
| 174 | data-inset={inset} | ||
| 175 | className={cn( | ||
| 176 | "px-2 py-1.5 text-sm font-medium data-[inset]:pl-8", | ||
| 177 | className | ||
| 178 | )} | ||
| 179 | {...props} | ||
| 180 | /> | ||
| 181 | ) | ||
| 182 | } | ||
| 183 | |||
| 184 | function MenubarSeparator({ | ||
| 185 | className, | ||
| 186 | ...props | ||
| 187 | }: React.ComponentProps<typeof MenubarPrimitive.Separator>) { | ||
| 188 | return ( | ||
| 189 | <MenubarPrimitive.Separator | ||
| 190 | data-slot="menubar-separator" | ||
| 191 | className={cn("-mx-1 my-1 h-px bg-border", className)} | ||
| 192 | {...props} | ||
| 193 | /> | ||
| 194 | ) | ||
| 195 | } | ||
| 196 | |||
| 197 | function MenubarShortcut({ | ||
| 198 | className, | ||
| 199 | ...props | ||
| 200 | }: React.ComponentProps<"span">) { | ||
| 201 | return ( | ||
| 202 | <span | ||
| 203 | data-slot="menubar-shortcut" | ||
| 204 | className={cn( | ||
| 205 | "ml-auto text-xs tracking-widest text-muted-foreground", | ||
| 206 | className | ||
| 207 | )} | ||
| 208 | {...props} | ||
| 209 | /> | ||
| 210 | ) | ||
| 211 | } | ||
| 212 | |||
| 213 | function MenubarSub({ | ||
| 214 | ...props | ||
| 215 | }: React.ComponentProps<typeof MenubarPrimitive.Sub>) { | ||
| 216 | return <MenubarPrimitive.Sub data-slot="menubar-sub" {...props} /> | ||
| 217 | } | ||
| 218 | |||
| 219 | function MenubarSubTrigger({ | ||
| 220 | className, | ||
| 221 | inset, | ||
| 222 | children, | ||
| 223 | ...props | ||
| 224 | }: React.ComponentProps<typeof MenubarPrimitive.SubTrigger> & { | ||
| 225 | inset?: boolean | ||
| 226 | }) { | ||
| 227 | return ( | ||
| 228 | <MenubarPrimitive.SubTrigger | ||
| 229 | data-slot="menubar-sub-trigger" | ||
| 230 | data-inset={inset} | ||
| 231 | className={cn( | ||
| 232 | "flex cursor-default items-center rounded-sm px-2 py-1.5 text-sm outline-none select-none focus:bg-accent focus:text-accent-foreground data-[inset]:pl-8 data-[state=open]:bg-accent data-[state=open]:text-accent-foreground", | ||
| 233 | className | ||
| 234 | )} | ||
| 235 | {...props} | ||
| 236 | > | ||
| 237 | {children} | ||
| 238 | <ChevronRightIcon className="ml-auto h-4 w-4" /> | ||
| 239 | </MenubarPrimitive.SubTrigger> | ||
| 240 | ) | ||
| 241 | } | ||
| 242 | |||
| 243 | function MenubarSubContent({ | ||
| 244 | className, | ||
| 245 | ...props | ||
| 246 | }: React.ComponentProps<typeof MenubarPrimitive.SubContent>) { | ||
| 247 | return ( | ||
| 248 | <MenubarPrimitive.SubContent | ||
| 249 | data-slot="menubar-sub-content" | ||
| 250 | className={cn( | ||
| 251 | "z-50 min-w-[8rem] origin-(--radix-menubar-content-transform-origin) overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-lg data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95", | ||
| 252 | className | ||
| 253 | )} | ||
| 254 | {...props} | ||
| 255 | /> | ||
| 256 | ) | ||
| 257 | } | ||
| 258 | |||
| 259 | export { | ||
| 260 | Menubar, | ||
| 261 | MenubarPortal, | ||
| 262 | MenubarMenu, | ||
| 263 | MenubarTrigger, | ||
| 264 | MenubarContent, | ||
| 265 | MenubarGroup, | ||
| 266 | MenubarSeparator, | ||
| 267 | MenubarLabel, | ||
| 268 | MenubarItem, | ||
| 269 | MenubarShortcut, | ||
| 270 | MenubarCheckboxItem, | ||
| 271 | MenubarRadioGroup, | ||
| 272 | MenubarRadioItem, | ||
| 273 | MenubarSub, | ||
| 274 | MenubarSubTrigger, | ||
| 275 | MenubarSubContent, | ||
| 276 | } | ||
| @@ -0,0 +1,53 @@ | |||
| 1 | import * as React from "react" | ||
| 2 | import { ChevronDownIcon } from "lucide-react" | ||
| 3 | |||
| 4 | import { cn } from "@executor/ui/lib/utils" | ||
| 5 | |||
| 6 | function NativeSelect({ | ||
| 7 | className, | ||
| 8 | size = "default", | ||
| 9 | ...props | ||
| 10 | }: Omit<React.ComponentProps<"select">, "size"> & { size?: "sm" | "default" }) { | ||
| 11 | return ( | ||
| 12 | <div | ||
| 13 | className="group/native-select relative w-fit has-[select:disabled]:opacity-50" | ||
| 14 | data-slot="native-select-wrapper" | ||
| 15 | > | ||
| 16 | <select | ||
| 17 | data-slot="native-select" | ||
| 18 | data-size={size} | ||
| 19 | className={cn( | ||
| 20 | "h-9 w-full min-w-0 appearance-none rounded-md border border-input bg-transparent px-3 py-2 pr-9 text-sm shadow-xs transition-[color,box-shadow] outline-none selection:bg-primary selection:text-primary-foreground placeholder:text-muted-foreground disabled:pointer-events-none disabled:cursor-not-allowed data-[size=sm]:h-8 data-[size=sm]:py-1 dark:bg-input/30 dark:hover:bg-input/50", | ||
| 21 | "focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50", | ||
| 22 | "aria-invalid:border-destructive aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40", | ||
| 23 | className | ||
| 24 | )} | ||
| 25 | {...props} | ||
| 26 | /> | ||
| 27 | <ChevronDownIcon | ||
| 28 | className="pointer-events-none absolute top-1/2 right-3.5 size-4 -translate-y-1/2 text-muted-foreground opacity-50 select-none" | ||
| 29 | aria-hidden="true" | ||
| 30 | data-slot="native-select-icon" | ||
| 31 | /> | ||
| 32 | </div> | ||
| 33 | ) | ||
| 34 | } | ||
| 35 | |||
| 36 | function NativeSelectOption({ ...props }: React.ComponentProps<"option">) { | ||
| 37 | return <option data-slot="native-select-option" {...props} /> | ||
| 38 | } | ||
| 39 | |||
| 40 | function NativeSelectOptGroup({ | ||
| 41 | className, | ||
| 42 | ...props | ||
| 43 | }: React.ComponentProps<"optgroup">) { | ||
| 44 | return ( | ||
| 45 | <optgroup | ||
| 46 | data-slot="native-select-optgroup" | ||
| 47 | className={cn(className)} | ||
| 48 | {...props} | ||
| 49 | /> | ||
| 50 | ) | ||
| 51 | } | ||
| 52 | |||
| 53 | export { NativeSelect, NativeSelectOptGroup, NativeSelectOption } | ||
| @@ -0,0 +1,168 @@ | |||
| 1 | import * as React from "react" | ||
| 2 | import { cva } from "class-variance-authority" | ||
| 3 | import { ChevronDownIcon } from "lucide-react" | ||
| 4 | import { NavigationMenu as NavigationMenuPrimitive } from "radix-ui" | ||
| 5 | |||
| 6 | import { cn } from "@executor/ui/lib/utils" | ||
| 7 | |||
| 8 | function NavigationMenu({ | ||
| 9 | className, | ||
| 10 | children, | ||
| 11 | viewport = true, | ||
| 12 | ...props | ||
| 13 | }: React.ComponentProps<typeof NavigationMenuPrimitive.Root> & { | ||
| 14 | viewport?: boolean | ||
| 15 | }) { | ||
| 16 | return ( | ||
| 17 | <NavigationMenuPrimitive.Root | ||
| 18 | data-slot="navigation-menu" | ||
| 19 | data-viewport={viewport} | ||
| 20 | className={cn( | ||
| 21 | "group/navigation-menu relative flex max-w-max flex-1 items-center justify-center", | ||
| 22 | className | ||
| 23 | )} | ||
| 24 | {...props} | ||
| 25 | > | ||
| 26 | {children} | ||
| 27 | {viewport && <NavigationMenuViewport />} | ||
| 28 | </NavigationMenuPrimitive.Root> | ||
| 29 | ) | ||
| 30 | } | ||
| 31 | |||
| 32 | function NavigationMenuList({ | ||
| 33 | className, | ||
| 34 | ...props | ||
| 35 | }: React.ComponentProps<typeof NavigationMenuPrimitive.List>) { | ||
| 36 | return ( | ||
| 37 | <NavigationMenuPrimitive.List | ||
| 38 | data-slot="navigation-menu-list" | ||
| 39 | className={cn( | ||
| 40 | "group flex flex-1 list-none items-center justify-center gap-1", | ||
| 41 | className | ||
| 42 | )} | ||
| 43 | {...props} | ||
| 44 | /> | ||
| 45 | ) | ||
| 46 | } | ||
| 47 | |||
| 48 | function NavigationMenuItem({ | ||
| 49 | className, | ||
| 50 | ...props | ||
| 51 | }: React.ComponentProps<typeof NavigationMenuPrimitive.Item>) { | ||
| 52 | return ( | ||
| 53 | <NavigationMenuPrimitive.Item | ||
| 54 | data-slot="navigation-menu-item" | ||
| 55 | className={cn("relative", className)} | ||
| 56 | {...props} | ||
| 57 | /> | ||
| 58 | ) | ||
| 59 | } | ||
| 60 | |||
| 61 | const navigationMenuTriggerStyle = cva( | ||
| 62 | "group inline-flex h-9 w-max items-center justify-center rounded-md bg-background px-4 py-2 text-sm font-medium transition-[color,box-shadow] outline-none hover:bg-accent hover:text-accent-foreground focus:bg-accent focus:text-accent-foreground focus-visible:ring-[3px] focus-visible:ring-ring/50 focus-visible:outline-1 disabled:pointer-events-none disabled:opacity-50 data-[state=open]:bg-accent/50 data-[state=open]:text-accent-foreground data-[state=open]:hover:bg-accent data-[state=open]:focus:bg-accent" | ||
| 63 | ) | ||
| 64 | |||
| 65 | function NavigationMenuTrigger({ | ||
| 66 | className, | ||
| 67 | children, | ||
| 68 | ...props | ||
| 69 | }: React.ComponentProps<typeof NavigationMenuPrimitive.Trigger>) { | ||
| 70 | return ( | ||
| 71 | <NavigationMenuPrimitive.Trigger | ||
| 72 | data-slot="navigation-menu-trigger" | ||
| 73 | className={cn(navigationMenuTriggerStyle(), "group", className)} | ||
| 74 | {...props} | ||
| 75 | > | ||
| 76 | {children}{" "} | ||
| 77 | <ChevronDownIcon | ||
| 78 | className="relative top-[1px] ml-1 size-3 transition duration-300 group-data-[state=open]:rotate-180" | ||
| 79 | aria-hidden="true" | ||
| 80 | /> | ||
| 81 | </NavigationMenuPrimitive.Trigger> | ||
| 82 | ) | ||
| 83 | } | ||
| 84 | |||
| 85 | function NavigationMenuContent({ | ||
| 86 | className, | ||
| 87 | ...props | ||
| 88 | }: React.ComponentProps<typeof NavigationMenuPrimitive.Content>) { | ||
| 89 | return ( | ||
| 90 | <NavigationMenuPrimitive.Content | ||
| 91 | data-slot="navigation-menu-content" | ||
| 92 | className={cn( | ||
| 93 | "top-0 left-0 w-full p-2 pr-2.5 data-[motion=from-end]:slide-in-from-right-52 data-[motion=from-start]:slide-in-from-left-52 data-[motion=to-end]:slide-out-to-right-52 data-[motion=to-start]:slide-out-to-left-52 data-[motion^=from-]:animate-in data-[motion^=from-]:fade-in data-[motion^=to-]:animate-out data-[motion^=to-]:fade-out md:absolute md:w-auto", | ||
| 94 | "group-data-[viewport=false]/navigation-menu:top-full group-data-[viewport=false]/navigation-menu:mt-1.5 group-data-[viewport=false]/navigation-menu:overflow-hidden group-data-[viewport=false]/navigation-menu:rounded-md group-data-[viewport=false]/navigation-menu:border group-data-[viewport=false]/navigation-menu:bg-popover group-data-[viewport=false]/navigation-menu:text-popover-foreground group-data-[viewport=false]/navigation-menu:shadow group-data-[viewport=false]/navigation-menu:duration-200 **:data-[slot=navigation-menu-link]:focus:ring-0 **:data-[slot=navigation-menu-link]:focus:outline-none group-data-[viewport=false]/navigation-menu:data-[state=closed]:animate-out group-data-[viewport=false]/navigation-menu:data-[state=closed]:fade-out-0 group-data-[viewport=false]/navigation-menu:data-[state=closed]:zoom-out-95 group-data-[viewport=false]/navigation-menu:data-[state=open]:animate-in group-data-[viewport=false]/navigation-menu:data-[state=open]:fade-in-0 group-data-[viewport=false]/navigation-menu:data-[state=open]:zoom-in-95", | ||
| 95 | className | ||
| 96 | )} | ||
| 97 | {...props} | ||
| 98 | /> | ||
| 99 | ) | ||
| 100 | } | ||
| 101 | |||
| 102 | function NavigationMenuViewport({ | ||
| 103 | className, | ||
| 104 | ...props | ||
| 105 | }: React.ComponentProps<typeof NavigationMenuPrimitive.Viewport>) { | ||
| 106 | return ( | ||
| 107 | <div | ||
| 108 | className={cn( | ||
| 109 | "absolute top-full left-0 isolate z-50 flex justify-center" | ||
| 110 | )} | ||
| 111 | > | ||
| 112 | <NavigationMenuPrimitive.Viewport | ||
| 113 | data-slot="navigation-menu-viewport" | ||
| 114 | className={cn( | ||
| 115 | "origin-top-center relative mt-1.5 h-[var(--radix-navigation-menu-viewport-height)] w-full overflow-hidden rounded-md border bg-popover text-popover-foreground shadow data-[state=closed]:animate-out data-[state=closed]:zoom-out-95 data-[state=open]:animate-in data-[state=open]:zoom-in-90 md:w-[var(--radix-navigation-menu-viewport-width)]", | ||
| 116 | className | ||
| 117 | )} | ||
| 118 | {...props} | ||
| 119 | /> | ||
| 120 | </div> | ||
| 121 | ) | ||
| 122 | } | ||
| 123 | |||
| 124 | function NavigationMenuLink({ | ||
| 125 | className, | ||
| 126 | ...props | ||
| 127 | }: React.ComponentProps<typeof NavigationMenuPrimitive.Link>) { | ||
| 128 | return ( | ||
| 129 | <NavigationMenuPrimitive.Link | ||
| 130 | data-slot="navigation-menu-link" | ||
| 131 | className={cn( | ||
| 132 | "flex flex-col gap-1 rounded-sm p-2 text-sm transition-all outline-none hover:bg-accent hover:text-accent-foreground focus:bg-accent focus:text-accent-foreground focus-visible:ring-[3px] focus-visible:ring-ring/50 focus-visible:outline-1 data-[active=true]:bg-accent/50 data-[active=true]:text-accent-foreground data-[active=true]:hover:bg-accent data-[active=true]:focus:bg-accent [&_svg:not([class*='size-'])]:size-4 [&_svg:not([class*='text-'])]:text-muted-foreground", | ||
| 133 | className | ||
| 134 | )} | ||
| 135 | {...props} | ||
| 136 | /> | ||
| 137 | ) | ||
| 138 | } | ||
| 139 | |||
| 140 | function NavigationMenuIndicator({ | ||
| 141 | className, | ||
| 142 | ...props | ||
| 143 | }: React.ComponentProps<typeof NavigationMenuPrimitive.Indicator>) { | ||
| 144 | return ( | ||
| 145 | <NavigationMenuPrimitive.Indicator | ||
| 146 | data-slot="navigation-menu-indicator" | ||
| 147 | className={cn( | ||
| 148 | "top-full z-[1] flex h-1.5 items-end justify-center overflow-hidden data-[state=hidden]:animate-out data-[state=hidden]:fade-out data-[state=visible]:animate-in data-[state=visible]:fade-in", | ||
| 149 | className | ||
| 150 | )} | ||
| 151 | {...props} | ||
| 152 | > | ||
| 153 | <div className="relative top-[60%] h-2 w-2 rotate-45 rounded-tl-sm bg-border shadow-md" /> | ||
| 154 | </NavigationMenuPrimitive.Indicator> | ||
| 155 | ) | ||
| 156 | } | ||
| 157 | |||
| 158 | export { | ||
| 159 | NavigationMenu, | ||
| 160 | NavigationMenuList, | ||
| 161 | NavigationMenuItem, | ||
| 162 | NavigationMenuContent, | ||
| 163 | NavigationMenuTrigger, | ||
| 164 | NavigationMenuLink, | ||
| 165 | NavigationMenuIndicator, | ||
| 166 | NavigationMenuViewport, | ||
| 167 | navigationMenuTriggerStyle, | ||
| 168 | } | ||
| @@ -0,0 +1,127 @@ | |||
| 1 | import * as React from "react" | ||
| 2 | import { | ||
| 3 | ChevronLeftIcon, | ||
| 4 | ChevronRightIcon, | ||
| 5 | MoreHorizontalIcon, | ||
| 6 | } from "lucide-react" | ||
| 7 | |||
| 8 | import { cn } from "@executor/ui/lib/utils" | ||
| 9 | import { buttonVariants, type Button } from "@executor/ui/components/button" | ||
| 10 | |||
| 11 | function Pagination({ className, ...props }: React.ComponentProps<"nav">) { | ||
| 12 | return ( | ||
| 13 | <nav | ||
| 14 | role="navigation" | ||
| 15 | aria-label="pagination" | ||
| 16 | data-slot="pagination" | ||
| 17 | className={cn("mx-auto flex w-full justify-center", className)} | ||
| 18 | {...props} | ||
| 19 | /> | ||
| 20 | ) | ||
| 21 | } | ||
| 22 | |||
| 23 | function PaginationContent({ | ||
| 24 | className, | ||
| 25 | ...props | ||
| 26 | }: React.ComponentProps<"ul">) { | ||
| 27 | return ( | ||
| 28 | <ul | ||
| 29 | data-slot="pagination-content" | ||
| 30 | className={cn("flex flex-row items-center gap-1", className)} | ||
| 31 | {...props} | ||
| 32 | /> | ||
| 33 | ) | ||
| 34 | } | ||
| 35 | |||
| 36 | function PaginationItem({ ...props }: React.ComponentProps<"li">) { | ||
| 37 | return <li data-slot="pagination-item" {...props} /> | ||
| 38 | } | ||
| 39 | |||
| 40 | type PaginationLinkProps = { | ||
| 41 | isActive?: boolean | ||
| 42 | } & Pick<React.ComponentProps<typeof Button>, "size"> & | ||
| 43 | React.ComponentProps<"a"> | ||
| 44 | |||
| 45 | function PaginationLink({ | ||
| 46 | className, | ||
| 47 | isActive, | ||
| 48 | size = "icon", | ||
| 49 | ...props | ||
| 50 | }: PaginationLinkProps) { | ||
| 51 | return ( | ||
| 52 | <a | ||
| 53 | aria-current={isActive ? "page" : undefined} | ||
| 54 | data-slot="pagination-link" | ||
| 55 | data-active={isActive} | ||
| 56 | className={cn( | ||
| 57 | buttonVariants({ | ||
| 58 | variant: isActive ? "outline" : "ghost", | ||
| 59 | size, | ||
| 60 | }), | ||
| 61 | className | ||
| 62 | )} | ||
| 63 | {...props} | ||
| 64 | /> | ||
| 65 | ) | ||
| 66 | } | ||
| 67 | |||
| 68 | function PaginationPrevious({ | ||
| 69 | className, | ||
| 70 | ...props | ||
| 71 | }: React.ComponentProps<typeof PaginationLink>) { | ||
| 72 | return ( | ||
| 73 | <PaginationLink | ||
| 74 | aria-label="Go to previous page" | ||
| 75 | size="default" | ||
| 76 | className={cn("gap-1 px-2.5 sm:pl-2.5", className)} | ||
| 77 | {...props} | ||
| 78 | > | ||
| 79 | <ChevronLeftIcon /> | ||
| 80 | <span className="hidden sm:block">Previous</span> | ||
| 81 | </PaginationLink> | ||
| 82 | ) | ||
| 83 | } | ||
| 84 | |||
| 85 | function PaginationNext({ | ||
| 86 | className, | ||
| 87 | ...props | ||
| 88 | }: React.ComponentProps<typeof PaginationLink>) { | ||
| 89 | return ( | ||
| 90 | <PaginationLink | ||
| 91 | aria-label="Go to next page" | ||
| 92 | size="default" | ||
| 93 | className={cn("gap-1 px-2.5 sm:pr-2.5", className)} | ||
| 94 | {...props} | ||
| 95 | > | ||
| 96 | <span className="hidden sm:block">Next</span> | ||
| 97 | <ChevronRightIcon /> | ||
| 98 | </PaginationLink> | ||
| 99 | ) | ||
| 100 | } | ||
| 101 | |||
| 102 | function PaginationEllipsis({ | ||
| 103 | className, | ||
| 104 | ...props | ||
| 105 | }: React.ComponentProps<"span">) { | ||
| 106 | return ( | ||
| 107 | <span | ||
| 108 | aria-hidden | ||
| 109 | data-slot="pagination-ellipsis" | ||
| 110 | className={cn("flex size-9 items-center justify-center", className)} | ||
| 111 | {...props} | ||
| 112 | > | ||
| 113 | <MoreHorizontalIcon className="size-4" /> | ||
| 114 | <span className="sr-only">More pages</span> | ||
| 115 | </span> | ||
| 116 | ) | ||
| 117 | } | ||
| 118 | |||
| 119 | export { | ||
| 120 | Pagination, | ||
| 121 | PaginationContent, | ||
| 122 | PaginationLink, | ||
| 123 | PaginationItem, | ||
| 124 | PaginationPrevious, | ||
| 125 | PaginationNext, | ||
| 126 | PaginationEllipsis, | ||
| 127 | } | ||
| @@ -0,0 +1,87 @@ | |||
| 1 | import * as React from "react" | ||
| 2 | import { Popover as PopoverPrimitive } from "radix-ui" | ||
| 3 | |||
| 4 | import { cn } from "@executor/ui/lib/utils" | ||
| 5 | |||
| 6 | function Popover({ | ||
| 7 | ...props | ||
| 8 | }: React.ComponentProps<typeof PopoverPrimitive.Root>) { | ||
| 9 | return <PopoverPrimitive.Root data-slot="popover" {...props} /> | ||
| 10 | } | ||
| 11 | |||
| 12 | function PopoverTrigger({ | ||
| 13 | ...props | ||
| 14 | }: React.ComponentProps<typeof PopoverPrimitive.Trigger>) { | ||
| 15 | return <PopoverPrimitive.Trigger data-slot="popover-trigger" {...props} /> | ||
| 16 | } | ||
| 17 | |||
| 18 | function PopoverContent({ | ||
| 19 | className, | ||
| 20 | align = "center", | ||
| 21 | sideOffset = 4, | ||
| 22 | ...props | ||
| 23 | }: React.ComponentProps<typeof PopoverPrimitive.Content>) { | ||
| 24 | return ( | ||
| 25 | <PopoverPrimitive.Portal> | ||
| 26 | <PopoverPrimitive.Content | ||
| 27 | data-slot="popover-content" | ||
| 28 | align={align} | ||
| 29 | sideOffset={sideOffset} | ||
| 30 | className={cn( | ||
| 31 | "z-50 w-72 origin-(--radix-popover-content-transform-origin) rounded-md border bg-popover p-4 text-popover-foreground shadow-md outline-hidden data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95", | ||
| 32 | className | ||
| 33 | )} | ||
| 34 | {...props} | ||
| 35 | /> | ||
| 36 | </PopoverPrimitive.Portal> | ||
| 37 | ) | ||
| 38 | } | ||
| 39 | |||
| 40 | function PopoverAnchor({ | ||
| 41 | ...props | ||
| 42 | }: React.ComponentProps<typeof PopoverPrimitive.Anchor>) { | ||
| 43 | return <PopoverPrimitive.Anchor data-slot="popover-anchor" {...props} /> | ||
| 44 | } | ||
| 45 | |||
| 46 | function PopoverHeader({ className, ...props }: React.ComponentProps<"div">) { | ||
| 47 | return ( | ||
| 48 | <div | ||
| 49 | data-slot="popover-header" | ||
| 50 | className={cn("flex flex-col gap-1 text-sm", className)} | ||
| 51 | {...props} | ||
| 52 | /> | ||
| 53 | ) | ||
| 54 | } | ||
| 55 | |||
| 56 | function PopoverTitle({ className, ...props }: React.ComponentProps<"h2">) { | ||
| 57 | return ( | ||
| 58 | <div | ||
| 59 | data-slot="popover-title" | ||
| 60 | className={cn("font-medium", className)} | ||
| 61 | {...props} | ||
| 62 | /> | ||
| 63 | ) | ||
| 64 | } | ||
| 65 | |||
| 66 | function PopoverDescription({ | ||
| 67 | className, | ||
| 68 | ...props | ||
| 69 | }: React.ComponentProps<"p">) { | ||
| 70 | return ( | ||
| 71 | <p | ||
| 72 | data-slot="popover-description" | ||
| 73 | className={cn("text-muted-foreground", className)} | ||
| 74 | {...props} | ||
| 75 | /> | ||
| 76 | ) | ||
| 77 | } | ||
| 78 | |||
| 79 | export { | ||
| 80 | Popover, | ||
| 81 | PopoverTrigger, | ||
| 82 | PopoverContent, | ||
| 83 | PopoverAnchor, | ||
| 84 | PopoverHeader, | ||
| 85 | PopoverTitle, | ||
| 86 | PopoverDescription, | ||
| 87 | } | ||
| @@ -0,0 +1,31 @@ | |||
| 1 | "use client" | ||
| 2 | |||
| 3 | import * as React from "react" | ||
| 4 | import { Progress as ProgressPrimitive } from "radix-ui" | ||
| 5 | |||
| 6 | import { cn } from "@executor/ui/lib/utils" | ||
| 7 | |||
| 8 | function Progress({ | ||
| 9 | className, | ||
| 10 | value, | ||
| 11 | ...props | ||
| 12 | }: React.ComponentProps<typeof ProgressPrimitive.Root>) { | ||
| 13 | return ( | ||
| 14 | <ProgressPrimitive.Root | ||
| 15 | data-slot="progress" | ||
| 16 | className={cn( | ||
| 17 | "relative h-2 w-full overflow-hidden rounded-full bg-primary/20", | ||
| 18 | className | ||
| 19 | )} | ||
| 20 | {...props} | ||
| 21 | > | ||
| 22 | <ProgressPrimitive.Indicator | ||
| 23 | data-slot="progress-indicator" | ||
| 24 | className="h-full w-full flex-1 bg-primary transition-all" | ||
| 25 | style={{ transform: `translateX(-${100 - (value || 0)}%)` }} | ||
| 26 | /> | ||
| 27 | </ProgressPrimitive.Root> | ||
| 28 | ) | ||
| 29 | } | ||
| 30 | |||
| 31 | export { Progress } | ||
| @@ -0,0 +1,43 @@ | |||
| 1 | import * as React from "react" | ||
| 2 | import { CircleIcon } from "lucide-react" | ||
| 3 | import { RadioGroup as RadioGroupPrimitive } from "radix-ui" | ||
| 4 | |||
| 5 | import { cn } from "@executor/ui/lib/utils" | ||
| 6 | |||
| 7 | function RadioGroup({ | ||
| 8 | className, | ||
| 9 | ...props | ||
| 10 | }: React.ComponentProps<typeof RadioGroupPrimitive.Root>) { | ||
| 11 | return ( | ||
| 12 | <RadioGroupPrimitive.Root | ||
| 13 | data-slot="radio-group" | ||
| 14 | className={cn("grid gap-3", className)} | ||
| 15 | {...props} | ||
| 16 | /> | ||
| 17 | ) | ||
| 18 | } | ||
| 19 | |||
| 20 | function RadioGroupItem({ | ||
| 21 | className, | ||
| 22 | ...props | ||
| 23 | }: React.ComponentProps<typeof RadioGroupPrimitive.Item>) { | ||
| 24 | return ( | ||
| 25 | <RadioGroupPrimitive.Item | ||
| 26 | data-slot="radio-group-item" | ||
| 27 | className={cn( | ||
| 28 | "aspect-square size-4 shrink-0 rounded-full border border-input text-primary shadow-xs transition-[color,box-shadow] outline-none focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 disabled:cursor-not-allowed disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-destructive/20 dark:bg-input/30 dark:aria-invalid:ring-destructive/40", | ||
| 29 | className | ||
| 30 | )} | ||
| 31 | {...props} | ||
| 32 | > | ||
| 33 | <RadioGroupPrimitive.Indicator | ||
| 34 | data-slot="radio-group-indicator" | ||
| 35 | className="relative flex items-center justify-center" | ||
| 36 | > | ||
| 37 | <CircleIcon className="absolute top-1/2 left-1/2 size-2 -translate-x-1/2 -translate-y-1/2 fill-primary" /> | ||
| 38 | </RadioGroupPrimitive.Indicator> | ||
| 39 | </RadioGroupPrimitive.Item> | ||
| 40 | ) | ||
| 41 | } | ||
| 42 | |||
| 43 | export { RadioGroup, RadioGroupItem } | ||
| @@ -0,0 +1,53 @@ | |||
| 1 | "use client" | ||
| 2 | |||
| 3 | import { GripVerticalIcon } from "lucide-react" | ||
| 4 | import * as ResizablePrimitive from "react-resizable-panels" | ||
| 5 | |||
| 6 | import { cn } from "@executor/ui/lib/utils" | ||
| 7 | |||
| 8 | function ResizablePanelGroup({ | ||
| 9 | className, | ||
| 10 | ...props | ||
| 11 | }: ResizablePrimitive.GroupProps) { | ||
| 12 | return ( | ||
| 13 | <ResizablePrimitive.Group | ||
| 14 | data-slot="resizable-panel-group" | ||
| 15 | className={cn( | ||
| 16 | "flex h-full w-full aria-[orientation=vertical]:flex-col", | ||
| 17 | className | ||
| 18 | )} | ||
| 19 | {...props} | ||
| 20 | /> | ||
| 21 | ) | ||
| 22 | } | ||
| 23 | |||
| 24 | function ResizablePanel({ ...props }: ResizablePrimitive.PanelProps) { | ||
| 25 | return <ResizablePrimitive.Panel data-slot="resizable-panel" {...props} /> | ||
| 26 | } | ||
| 27 | |||
| 28 | function ResizableHandle({ | ||
| 29 | withHandle, | ||
| 30 | className, | ||
| 31 | ...props | ||
| 32 | }: ResizablePrimitive.SeparatorProps & { | ||
| 33 | withHandle?: boolean | ||
| 34 | }) { | ||
| 35 | return ( | ||
| 36 | <ResizablePrimitive.Separator | ||
| 37 | data-slot="resizable-handle" | ||
| 38 | className={cn( | ||
| 39 | "relative flex w-px items-center justify-center bg-border after:absolute after:inset-y-0 after:left-1/2 after:w-1 after:-translate-x-1/2 focus-visible:ring-1 focus-visible:ring-ring focus-visible:ring-offset-1 focus-visible:outline-hidden aria-[orientation=horizontal]:h-px aria-[orientation=horizontal]:w-full aria-[orientation=horizontal]:after:left-0 aria-[orientation=horizontal]:after:h-1 aria-[orientation=horizontal]:after:w-full aria-[orientation=horizontal]:after:translate-x-0 aria-[orientation=horizontal]:after:-translate-y-1/2 [&[aria-orientation=horizontal]>div]:rotate-90", | ||
| 40 | className | ||
| 41 | )} | ||
| 42 | {...props} | ||
| 43 | > | ||
| 44 | {withHandle && ( | ||
| 45 | <div className="z-10 flex h-4 w-3 items-center justify-center rounded-xs border bg-border"> | ||
| 46 | <GripVerticalIcon className="size-2.5" /> | ||
| 47 | </div> | ||
| 48 | )} | ||
| 49 | </ResizablePrimitive.Separator> | ||
| 50 | ) | ||
| 51 | } | ||
| 52 | |||
| 53 | export { ResizableHandle, ResizablePanel, ResizablePanelGroup } | ||
| @@ -0,0 +1,56 @@ | |||
| 1 | import * as React from "react" | ||
| 2 | import { ScrollArea as ScrollAreaPrimitive } from "radix-ui" | ||
| 3 | |||
| 4 | import { cn } from "@executor/ui/lib/utils" | ||
| 5 | |||
| 6 | function ScrollArea({ | ||
| 7 | className, | ||
| 8 | children, | ||
| 9 | ...props | ||
| 10 | }: React.ComponentProps<typeof ScrollAreaPrimitive.Root>) { | ||
| 11 | return ( | ||
| 12 | <ScrollAreaPrimitive.Root | ||
| 13 | data-slot="scroll-area" | ||
| 14 | className={cn("relative", className)} | ||
| 15 | {...props} | ||
| 16 | > | ||
| 17 | <ScrollAreaPrimitive.Viewport | ||
| 18 | data-slot="scroll-area-viewport" | ||
| 19 | className="size-full rounded-[inherit] transition-[color,box-shadow] outline-none focus-visible:ring-[3px] focus-visible:ring-ring/50 focus-visible:outline-1" | ||
| 20 | > | ||
| 21 | {children} | ||
| 22 | </ScrollAreaPrimitive.Viewport> | ||
| 23 | <ScrollBar /> | ||
| 24 | <ScrollAreaPrimitive.Corner /> | ||
| 25 | </ScrollAreaPrimitive.Root> | ||
| 26 | ) | ||
| 27 | } | ||
| 28 | |||
| 29 | function ScrollBar({ | ||
| 30 | className, | ||
| 31 | orientation = "vertical", | ||
| 32 | ...props | ||
| 33 | }: React.ComponentProps<typeof ScrollAreaPrimitive.ScrollAreaScrollbar>) { | ||
| 34 | return ( | ||
| 35 | <ScrollAreaPrimitive.ScrollAreaScrollbar | ||
| 36 | data-slot="scroll-area-scrollbar" | ||
| 37 | orientation={orientation} | ||
| 38 | className={cn( | ||
| 39 | "flex touch-none p-px transition-colors select-none", | ||
| 40 | orientation === "vertical" && | ||
| 41 | "h-full w-2.5 border-l border-l-transparent", | ||
| 42 | orientation === "horizontal" && | ||
| 43 | "h-2.5 flex-col border-t border-t-transparent", | ||
| 44 | className | ||
| 45 | )} | ||
| 46 | {...props} | ||
| 47 | > | ||
| 48 | <ScrollAreaPrimitive.ScrollAreaThumb | ||
| 49 | data-slot="scroll-area-thumb" | ||
| 50 | className="relative flex-1 rounded-full bg-border" | ||
| 51 | /> | ||
| 52 | </ScrollAreaPrimitive.ScrollAreaScrollbar> | ||
| 53 | ) | ||
| 54 | } | ||
| 55 | |||
| 56 | export { ScrollArea, ScrollBar } | ||
| @@ -0,0 +1,190 @@ | |||
| 1 | "use client" | ||
| 2 | |||
| 3 | import * as React from "react" | ||
| 4 | import { CheckIcon, ChevronDownIcon, ChevronUpIcon } from "lucide-react" | ||
| 5 | import { Select as SelectPrimitive } from "radix-ui" | ||
| 6 | |||
| 7 | import { cn } from "@executor/ui/lib/utils" | ||
| 8 | |||
| 9 | function Select({ | ||
| 10 | ...props | ||
| 11 | }: React.ComponentProps<typeof SelectPrimitive.Root>) { | ||
| 12 | return <SelectPrimitive.Root data-slot="select" {...props} /> | ||
| 13 | } | ||
| 14 | |||
| 15 | function SelectGroup({ | ||
| 16 | ...props | ||
| 17 | }: React.ComponentProps<typeof SelectPrimitive.Group>) { | ||
| 18 | return <SelectPrimitive.Group data-slot="select-group" {...props} /> | ||
| 19 | } | ||
| 20 | |||
| 21 | function SelectValue({ | ||
| 22 | ...props | ||
| 23 | }: React.ComponentProps<typeof SelectPrimitive.Value>) { | ||
| 24 | return <SelectPrimitive.Value data-slot="select-value" {...props} /> | ||
| 25 | } | ||
| 26 | |||
| 27 | function SelectTrigger({ | ||
| 28 | className, | ||
| 29 | size = "default", | ||
| 30 | children, | ||
| 31 | ...props | ||
| 32 | }: React.ComponentProps<typeof SelectPrimitive.Trigger> & { | ||
| 33 | size?: "sm" | "default" | ||
| 34 | }) { | ||
| 35 | return ( | ||
| 36 | <SelectPrimitive.Trigger | ||
| 37 | data-slot="select-trigger" | ||
| 38 | data-size={size} | ||
| 39 | className={cn( | ||
| 40 | "flex w-fit items-center justify-between gap-2 rounded-md border border-input bg-transparent px-3 py-2 text-sm whitespace-nowrap shadow-xs transition-[color,box-shadow] outline-none focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 disabled:cursor-not-allowed disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-destructive/20 data-[placeholder]:text-muted-foreground data-[size=default]:h-9 data-[size=sm]:h-8 *:data-[slot=select-value]:line-clamp-1 *:data-[slot=select-value]:flex *:data-[slot=select-value]:items-center *:data-[slot=select-value]:gap-2 dark:bg-input/30 dark:hover:bg-input/50 dark:aria-invalid:ring-destructive/40 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 [&_svg:not([class*='text-'])]:text-muted-foreground", | ||
| 41 | className | ||
| 42 | )} | ||
| 43 | {...props} | ||
| 44 | > | ||
| 45 | {children} | ||
| 46 | <SelectPrimitive.Icon asChild> | ||
| 47 | <ChevronDownIcon className="size-4 opacity-50" /> | ||
| 48 | </SelectPrimitive.Icon> | ||
| 49 | </SelectPrimitive.Trigger> | ||
| 50 | ) | ||
| 51 | } | ||
| 52 | |||
| 53 | function SelectContent({ | ||
| 54 | className, | ||
| 55 | children, | ||
| 56 | position = "item-aligned", | ||
| 57 | align = "center", | ||
| 58 | ...props | ||
| 59 | }: React.ComponentProps<typeof SelectPrimitive.Content>) { | ||
| 60 | return ( | ||
| 61 | <SelectPrimitive.Portal> | ||
| 62 | <SelectPrimitive.Content | ||
| 63 | data-slot="select-content" | ||
| 64 | className={cn( | ||
| 65 | "relative z-50 max-h-(--radix-select-content-available-height) min-w-[8rem] origin-(--radix-select-content-transform-origin) overflow-x-hidden overflow-y-auto rounded-md border bg-popover text-popover-foreground shadow-md data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95", | ||
| 66 | position === "popper" && | ||
| 67 | "data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1", | ||
| 68 | className | ||
| 69 | )} | ||
| 70 | position={position} | ||
| 71 | align={align} | ||
| 72 | {...props} | ||
| 73 | > | ||
| 74 | <SelectScrollUpButton /> | ||
| 75 | <SelectPrimitive.Viewport | ||
| 76 | className={cn( | ||
| 77 | "p-1", | ||
| 78 | position === "popper" && | ||
| 79 | "h-[var(--radix-select-trigger-height)] w-full min-w-[var(--radix-select-trigger-width)] scroll-my-1" | ||
| 80 | )} | ||
| 81 | > | ||
| 82 | {children} | ||
| 83 | </SelectPrimitive.Viewport> | ||
| 84 | <SelectScrollDownButton /> | ||
| 85 | </SelectPrimitive.Content> | ||
| 86 | </SelectPrimitive.Portal> | ||
| 87 | ) | ||
| 88 | } | ||
| 89 | |||
| 90 | function SelectLabel({ | ||
| 91 | className, | ||
| 92 | ...props | ||
| 93 | }: React.ComponentProps<typeof SelectPrimitive.Label>) { | ||
| 94 | return ( | ||
| 95 | <SelectPrimitive.Label | ||
| 96 | data-slot="select-label" | ||
| 97 | className={cn("px-2 py-1.5 text-xs text-muted-foreground", className)} | ||
| 98 | {...props} | ||
| 99 | /> | ||
| 100 | ) | ||
| 101 | } | ||
| 102 | |||
| 103 | function SelectItem({ | ||
| 104 | className, | ||
| 105 | children, | ||
| 106 | ...props | ||
| 107 | }: React.ComponentProps<typeof SelectPrimitive.Item>) { | ||
| 108 | return ( | ||
| 109 | <SelectPrimitive.Item | ||
| 110 | data-slot="select-item" | ||
| 111 | className={cn( | ||
| 112 | "relative flex w-full cursor-default items-center gap-2 rounded-sm py-1.5 pr-8 pl-2 text-sm outline-hidden select-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 [&_svg:not([class*='text-'])]:text-muted-foreground *:[span]:last:flex *:[span]:last:items-center *:[span]:last:gap-2", | ||
| 113 | className | ||
| 114 | )} | ||
| 115 | {...props} | ||
| 116 | > | ||
| 117 | <span | ||
| 118 | data-slot="select-item-indicator" | ||
| 119 | className="absolute right-2 flex size-3.5 items-center justify-center" | ||
| 120 | > | ||
| 121 | <SelectPrimitive.ItemIndicator> | ||
| 122 | <CheckIcon className="size-4" /> | ||
| 123 | </SelectPrimitive.ItemIndicator> | ||
| 124 | </span> | ||
| 125 | <SelectPrimitive.ItemText>{children}</SelectPrimitive.ItemText> | ||
| 126 | </SelectPrimitive.Item> | ||
| 127 | ) | ||
| 128 | } | ||
| 129 | |||
| 130 | function SelectSeparator({ | ||
| 131 | className, | ||
| 132 | ...props | ||
| 133 | }: React.ComponentProps<typeof SelectPrimitive.Separator>) { | ||
| 134 | return ( | ||
| 135 | <SelectPrimitive.Separator | ||
| 136 | data-slot="select-separator" | ||
| 137 | className={cn("pointer-events-none -mx-1 my-1 h-px bg-border", className)} | ||
| 138 | {...props} | ||
| 139 | /> | ||
| 140 | ) | ||
| 141 | } | ||
| 142 | |||
| 143 | function SelectScrollUpButton({ | ||
| 144 | className, | ||
| 145 | ...props | ||
| 146 | }: React.ComponentProps<typeof SelectPrimitive.ScrollUpButton>) { | ||
| 147 | return ( | ||
| 148 | <SelectPrimitive.ScrollUpButton | ||
| 149 | data-slot="select-scroll-up-button" | ||
| 150 | className={cn( | ||
| 151 | "flex cursor-default items-center justify-center py-1", | ||
| 152 | className | ||
| 153 | )} | ||
| 154 | {...props} | ||
| 155 | > | ||
| 156 | <ChevronUpIcon className="size-4" /> | ||
| 157 | </SelectPrimitive.ScrollUpButton> | ||
| 158 | ) | ||
| 159 | } | ||
| 160 | |||
| 161 | function SelectScrollDownButton({ | ||
| 162 | className, | ||
| 163 | ...props | ||
| 164 | }: React.ComponentProps<typeof SelectPrimitive.ScrollDownButton>) { | ||
| 165 | return ( | ||
| 166 | <SelectPrimitive.ScrollDownButton | ||
| 167 | data-slot="select-scroll-down-button" | ||
| 168 | className={cn( | ||
| 169 | "flex cursor-default items-center justify-center py-1", | ||
| 170 | className | ||
| 171 | )} | ||
| 172 | {...props} | ||
| 173 | > | ||
| 174 | <ChevronDownIcon className="size-4" /> | ||
| 175 | </SelectPrimitive.ScrollDownButton> | ||
| 176 | ) | ||
| 177 | } | ||
| 178 | |||
| 179 | export { | ||
| 180 | Select, | ||
| 181 | SelectContent, | ||
| 182 | SelectGroup, | ||
| 183 | SelectItem, | ||
| 184 | SelectLabel, | ||
| 185 | SelectScrollDownButton, | ||
| 186 | SelectScrollUpButton, | ||
| 187 | SelectSeparator, | ||
| 188 | SelectTrigger, | ||
| 189 | SelectValue, | ||
| 190 | } | ||
| @@ -0,0 +1,26 @@ | |||
| 1 | import * as React from "react" | ||
| 2 | import { Separator as SeparatorPrimitive } from "radix-ui" | ||
| 3 | |||
| 4 | import { cn } from "@executor/ui/lib/utils" | ||
| 5 | |||
| 6 | function Separator({ | ||
| 7 | className, | ||
| 8 | orientation = "horizontal", | ||
| 9 | decorative = true, | ||
| 10 | ...props | ||
| 11 | }: React.ComponentProps<typeof SeparatorPrimitive.Root>) { | ||
| 12 | return ( | ||
| 13 | <SeparatorPrimitive.Root | ||
| 14 | data-slot="separator" | ||
| 15 | decorative={decorative} | ||
| 16 | orientation={orientation} | ||
| 17 | className={cn( | ||
| 18 | "shrink-0 bg-border data-[orientation=horizontal]:h-px data-[orientation=horizontal]:w-full data-[orientation=vertical]:h-full data-[orientation=vertical]:w-px", | ||
| 19 | className | ||
| 20 | )} | ||
| 21 | {...props} | ||
| 22 | /> | ||
| 23 | ) | ||
| 24 | } | ||
| 25 | |||
| 26 | export { Separator } | ||
| @@ -0,0 +1,143 @@ | |||
| 1 | "use client" | ||
| 2 | |||
| 3 | import * as React from "react" | ||
| 4 | import { XIcon } from "lucide-react" | ||
| 5 | import { Dialog as SheetPrimitive } from "radix-ui" | ||
| 6 | |||
| 7 | import { cn } from "@executor/ui/lib/utils" | ||
| 8 | |||
| 9 | function Sheet({ ...props }: React.ComponentProps<typeof SheetPrimitive.Root>) { | ||
| 10 | return <SheetPrimitive.Root data-slot="sheet" {...props} /> | ||
| 11 | } | ||
| 12 | |||
| 13 | function SheetTrigger({ | ||
| 14 | ...props | ||
| 15 | }: React.ComponentProps<typeof SheetPrimitive.Trigger>) { | ||
| 16 | return <SheetPrimitive.Trigger data-slot="sheet-trigger" {...props} /> | ||
| 17 | } | ||
| 18 | |||
| 19 | function SheetClose({ | ||
| 20 | ...props | ||
| 21 | }: React.ComponentProps<typeof SheetPrimitive.Close>) { | ||
| 22 | return <SheetPrimitive.Close data-slot="sheet-close" {...props} /> | ||
| 23 | } | ||
| 24 | |||
| 25 | function SheetPortal({ | ||
| 26 | ...props | ||
| 27 | }: React.ComponentProps<typeof SheetPrimitive.Portal>) { | ||
| 28 | return <SheetPrimitive.Portal data-slot="sheet-portal" {...props} /> | ||
| 29 | } | ||
| 30 | |||
| 31 | function SheetOverlay({ | ||
| 32 | className, | ||
| 33 | ...props | ||
| 34 | }: React.ComponentProps<typeof SheetPrimitive.Overlay>) { | ||
| 35 | return ( | ||
| 36 | <SheetPrimitive.Overlay | ||
| 37 | data-slot="sheet-overlay" | ||
| 38 | className={cn( | ||
| 39 | "fixed inset-0 z-50 bg-black/50 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:animate-in data-[state=open]:fade-in-0", | ||
| 40 | className | ||
| 41 | )} | ||
| 42 | {...props} | ||
| 43 | /> | ||
| 44 | ) | ||
| 45 | } | ||
| 46 | |||
| 47 | function SheetContent({ | ||
| 48 | className, | ||
| 49 | children, | ||
| 50 | side = "right", | ||
| 51 | showCloseButton = true, | ||
| 52 | ...props | ||
| 53 | }: React.ComponentProps<typeof SheetPrimitive.Content> & { | ||
| 54 | side?: "top" | "right" | "bottom" | "left" | ||
| 55 | showCloseButton?: boolean | ||
| 56 | }) { | ||
| 57 | return ( | ||
| 58 | <SheetPortal> | ||
| 59 | <SheetOverlay /> | ||
| 60 | <SheetPrimitive.Content | ||
| 61 | data-slot="sheet-content" | ||
| 62 | className={cn( | ||
| 63 | "fixed z-50 flex flex-col gap-4 bg-background shadow-lg transition ease-in-out data-[state=closed]:animate-out data-[state=closed]:duration-300 data-[state=open]:animate-in data-[state=open]:duration-500", | ||
| 64 | side === "right" && | ||
| 65 | "inset-y-0 right-0 h-full w-3/4 border-l data-[state=closed]:slide-out-to-right data-[state=open]:slide-in-from-right sm:max-w-sm", | ||
| 66 | side === "left" && | ||
| 67 | "inset-y-0 left-0 h-full w-3/4 border-r data-[state=closed]:slide-out-to-left data-[state=open]:slide-in-from-left sm:max-w-sm", | ||
| 68 | side === "top" && | ||
| 69 | "inset-x-0 top-0 h-auto border-b data-[state=closed]:slide-out-to-top data-[state=open]:slide-in-from-top", | ||
| 70 | side === "bottom" && | ||
| 71 | "inset-x-0 bottom-0 h-auto border-t data-[state=closed]:slide-out-to-bottom data-[state=open]:slide-in-from-bottom", | ||
| 72 | className | ||
| 73 | )} | ||
| 74 | {...props} | ||
| 75 | > | ||
| 76 | {children} | ||
| 77 | {showCloseButton && ( | ||
| 78 | <SheetPrimitive.Close className="absolute top-4 right-4 rounded-xs opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:ring-2 focus:ring-ring focus:ring-offset-2 focus:outline-hidden disabled:pointer-events-none data-[state=open]:bg-secondary"> | ||
| 79 | <XIcon className="size-4" /> | ||
| 80 | <span className="sr-only">Close</span> | ||
| 81 | </SheetPrimitive.Close> | ||
| 82 | )} | ||
| 83 | </SheetPrimitive.Content> | ||
| 84 | </SheetPortal> | ||
| 85 | ) | ||
| 86 | } | ||
| 87 | |||
| 88 | function SheetHeader({ className, ...props }: React.ComponentProps<"div">) { | ||
| 89 | return ( | ||
| 90 | <div | ||
| 91 | data-slot="sheet-header" | ||
| 92 | className={cn("flex flex-col gap-1.5 p-4", className)} | ||
| 93 | {...props} | ||
| 94 | /> | ||
| 95 | ) | ||
| 96 | } | ||
| 97 | |||
| 98 | function SheetFooter({ className, ...props }: React.ComponentProps<"div">) { | ||
| 99 | return ( | ||
| 100 | <div | ||
| 101 | data-slot="sheet-footer" | ||
| 102 | className={cn("mt-auto flex flex-col gap-2 p-4", className)} | ||
| 103 | {...props} | ||
| 104 | /> | ||
| 105 | ) | ||
| 106 | } | ||
| 107 | |||
| 108 | function SheetTitle({ | ||
| 109 | className, | ||
| 110 | ...props | ||
| 111 | }: React.ComponentProps<typeof SheetPrimitive.Title>) { | ||
| 112 | return ( | ||
| 113 | <SheetPrimitive.Title | ||
| 114 | data-slot="sheet-title" | ||
| 115 | className={cn("font-semibold text-foreground", className)} | ||
| 116 | {...props} | ||
| 117 | /> | ||
| 118 | ) | ||
| 119 | } | ||
| 120 | |||
| 121 | function SheetDescription({ | ||
| 122 | className, | ||
| 123 | ...props | ||
| 124 | }: React.ComponentProps<typeof SheetPrimitive.Description>) { | ||
| 125 | return ( | ||
| 126 | <SheetPrimitive.Description | ||
| 127 | data-slot="sheet-description" | ||
| 128 | className={cn("text-sm text-muted-foreground", className)} | ||
| 129 | {...props} | ||
| 130 | /> | ||
| 131 | ) | ||
| 132 | } | ||
| 133 | |||
| 134 | export { | ||
| 135 | Sheet, | ||
| 136 | SheetTrigger, | ||
| 137 | SheetClose, | ||
| 138 | SheetContent, | ||
| 139 | SheetHeader, | ||
| 140 | SheetFooter, | ||
| 141 | SheetTitle, | ||
| 142 | SheetDescription, | ||
| 143 | } | ||
| @@ -0,0 +1,724 @@ | |||
| 1 | import * as React from "react" | ||
| 2 | import { cva, type VariantProps } from "class-variance-authority" | ||
| 3 | import { PanelLeftIcon } from "lucide-react" | ||
| 4 | import { Slot } from "radix-ui" | ||
| 5 | |||
| 6 | import { useIsMobile } from "@executor/ui/hooks/use-mobile" | ||
| 7 | import { cn } from "@executor/ui/lib/utils" | ||
| 8 | import { Button } from "@executor/ui/components/button" | ||
| 9 | import { Input } from "@executor/ui/components/input" | ||
| 10 | import { Separator } from "@executor/ui/components/separator" | ||
| 11 | import { | ||
| 12 | Sheet, | ||
| 13 | SheetContent, | ||
| 14 | SheetDescription, | ||
| 15 | SheetHeader, | ||
| 16 | SheetTitle, | ||
| 17 | } from "@executor/ui/components/sheet" | ||
| 18 | import { Skeleton } from "@executor/ui/components/skeleton" | ||
| 19 | import { | ||
| 20 | Tooltip, | ||
| 21 | TooltipContent, | ||
| 22 | TooltipProvider, | ||
| 23 | TooltipTrigger, | ||
| 24 | } from "@executor/ui/components/tooltip" | ||
| 25 | |||
| 26 | const SIDEBAR_COOKIE_NAME = "sidebar_state" | ||
| 27 | const SIDEBAR_COOKIE_MAX_AGE = 60 * 60 * 24 * 7 | ||
| 28 | const SIDEBAR_WIDTH = "16rem" | ||
| 29 | const SIDEBAR_WIDTH_MOBILE = "18rem" | ||
| 30 | const SIDEBAR_WIDTH_ICON = "3rem" | ||
| 31 | const SIDEBAR_KEYBOARD_SHORTCUT = "b" | ||
| 32 | |||
| 33 | type SidebarContextProps = { | ||
| 34 | state: "expanded" | "collapsed" | ||
| 35 | open: boolean | ||
| 36 | setOpen: (open: boolean) => void | ||
| 37 | openMobile: boolean | ||
| 38 | setOpenMobile: (open: boolean) => void | ||
| 39 | isMobile: boolean | ||
| 40 | toggleSidebar: () => void | ||
| 41 | } | ||
| 42 | |||
| 43 | const SidebarContext = React.createContext<SidebarContextProps | null>(null) | ||
| 44 | |||
| 45 | function useSidebar() { | ||
| 46 | const context = React.useContext(SidebarContext) | ||
| 47 | if (!context) { | ||
| 48 | throw new Error("useSidebar must be used within a SidebarProvider.") | ||
| 49 | } | ||
| 50 | |||
| 51 | return context | ||
| 52 | } | ||
| 53 | |||
| 54 | function SidebarProvider({ | ||
| 55 | defaultOpen = true, | ||
| 56 | open: openProp, | ||
| 57 | onOpenChange: setOpenProp, | ||
| 58 | className, | ||
| 59 | style, | ||
| 60 | children, | ||
| 61 | ...props | ||
| 62 | }: React.ComponentProps<"div"> & { | ||
| 63 | defaultOpen?: boolean | ||
| 64 | open?: boolean | ||
| 65 | onOpenChange?: (open: boolean) => void | ||
| 66 | }) { | ||
| 67 | const isMobile = useIsMobile() | ||
| 68 | const [openMobile, setOpenMobile] = React.useState(false) | ||
| 69 | |||
| 70 | // This is the internal state of the sidebar. | ||
| 71 | // We use openProp and setOpenProp for control from outside the component. | ||
| 72 | const [_open, _setOpen] = React.useState(defaultOpen) | ||
| 73 | const open = openProp ?? _open | ||
| 74 | const setOpen = React.useCallback( | ||
| 75 | (value: boolean | ((value: boolean) => boolean)) => { | ||
| 76 | const openState = typeof value === "function" ? value(open) : value | ||
| 77 | if (setOpenProp) { | ||
| 78 | setOpenProp(openState) | ||
| 79 | } else { | ||
| 80 | _setOpen(openState) | ||
| 81 | } | ||
| 82 | |||
| 83 | // This sets the cookie to keep the sidebar state. | ||
| 84 | document.cookie = `${SIDEBAR_COOKIE_NAME}=${openState}; path=/; max-age=${SIDEBAR_COOKIE_MAX_AGE}` | ||
| 85 | }, | ||
| 86 | [setOpenProp, open] | ||
| 87 | ) | ||
| 88 | |||
| 89 | // Helper to toggle the sidebar. | ||
| 90 | const toggleSidebar = React.useCallback(() => { | ||
| 91 | return isMobile ? setOpenMobile((open) => !open) : setOpen((open) => !open) | ||
| 92 | }, [isMobile, setOpen, setOpenMobile]) | ||
| 93 | |||
| 94 | // Adds a keyboard shortcut to toggle the sidebar. | ||
| 95 | React.useEffect(() => { | ||
| 96 | const handleKeyDown = (event: KeyboardEvent) => { | ||
| 97 | if ( | ||
| 98 | event.key === SIDEBAR_KEYBOARD_SHORTCUT && | ||
| 99 | (event.metaKey || event.ctrlKey) | ||
| 100 | ) { | ||
| 101 | event.preventDefault() | ||
| 102 | toggleSidebar() | ||
| 103 | } | ||
| 104 | } | ||
| 105 | |||
| 106 | window.addEventListener("keydown", handleKeyDown) | ||
| 107 | return () => window.removeEventListener("keydown", handleKeyDown) | ||
| 108 | }, [toggleSidebar]) | ||
| 109 | |||
| 110 | // We add a state so that we can do data-state="expanded" or "collapsed". | ||
| 111 | // This makes it easier to style the sidebar with Tailwind classes. | ||
| 112 | const state = open ? "expanded" : "collapsed" | ||
| 113 | |||
| 114 | const contextValue = React.useMemo<SidebarContextProps>( | ||
| 115 | () => ({ | ||
| 116 | state, | ||
| 117 | open, | ||
| 118 | setOpen, | ||
| 119 | isMobile, | ||
| 120 | openMobile, | ||
| 121 | setOpenMobile, | ||
| 122 | toggleSidebar, | ||
| 123 | }), | ||
| 124 | [state, open, setOpen, isMobile, openMobile, setOpenMobile, toggleSidebar] | ||
| 125 | ) | ||
| 126 | |||
| 127 | return ( | ||
| 128 | <SidebarContext.Provider value={contextValue}> | ||
| 129 | <TooltipProvider delayDuration={0}> | ||
| 130 | <div | ||
| 131 | data-slot="sidebar-wrapper" | ||
| 132 | style={ | ||
| 133 | { | ||
| 134 | "--sidebar-width": SIDEBAR_WIDTH, | ||
| 135 | "--sidebar-width-icon": SIDEBAR_WIDTH_ICON, | ||
| 136 | ...style, | ||
| 137 | } as React.CSSProperties | ||
| 138 | } | ||
| 139 | className={cn( | ||
| 140 | "group/sidebar-wrapper flex min-h-svh w-full has-data-[variant=inset]:bg-sidebar", | ||
| 141 | className | ||
| 142 | )} | ||
| 143 | {...props} | ||
| 144 | > | ||
| 145 | {children} | ||
| 146 | </div> | ||
| 147 | </TooltipProvider> | ||
| 148 | </SidebarContext.Provider> | ||
| 149 | ) | ||
| 150 | } | ||
| 151 | |||
| 152 | function Sidebar({ | ||
| 153 | side = "left", | ||
| 154 | variant = "sidebar", | ||
| 155 | collapsible = "offcanvas", | ||
| 156 | className, | ||
| 157 | children, | ||
| 158 | ...props | ||
| 159 | }: React.ComponentProps<"div"> & { | ||
| 160 | side?: "left" | "right" | ||
| 161 | variant?: "sidebar" | "floating" | "inset" | ||
| 162 | collapsible?: "offcanvas" | "icon" | "none" | ||
| 163 | }) { | ||
| 164 | const { isMobile, state, openMobile, setOpenMobile } = useSidebar() | ||
| 165 | |||
| 166 | if (collapsible === "none") { | ||
| 167 | return ( | ||
| 168 | <div | ||
| 169 | data-slot="sidebar" | ||
| 170 | className={cn( | ||
| 171 | "flex h-full w-(--sidebar-width) flex-col bg-sidebar text-sidebar-foreground", | ||
| 172 | className | ||
| 173 | )} | ||
| 174 | {...props} | ||
| 175 | > | ||
| 176 | {children} | ||
| 177 | </div> | ||
| 178 | ) | ||
| 179 | } | ||
| 180 | |||
| 181 | if (isMobile) { | ||
| 182 | return ( | ||
| 183 | <Sheet open={openMobile} onOpenChange={setOpenMobile} {...props}> | ||
| 184 | <SheetContent | ||
| 185 | data-sidebar="sidebar" | ||
| 186 | data-slot="sidebar" | ||
| 187 | data-mobile="true" | ||
| 188 | className="w-(--sidebar-width) bg-sidebar p-0 text-sidebar-foreground [&>button]:hidden" | ||
| 189 | style={ | ||
| 190 | { | ||
| 191 | "--sidebar-width": SIDEBAR_WIDTH_MOBILE, | ||
| 192 | } as React.CSSProperties | ||
| 193 | } | ||
| 194 | side={side} | ||
| 195 | > | ||
| 196 | <SheetHeader className="sr-only"> | ||
| 197 | <SheetTitle>Sidebar</SheetTitle> | ||
| 198 | <SheetDescription>Displays the mobile sidebar.</SheetDescription> | ||
| 199 | </SheetHeader> | ||
| 200 | <div className="flex h-full w-full flex-col">{children}</div> | ||
| 201 | </SheetContent> | ||
| 202 | </Sheet> | ||
| 203 | ) | ||
| 204 | } | ||
| 205 | |||
| 206 | return ( | ||
| 207 | <div | ||
| 208 | className="group peer hidden text-sidebar-foreground md:block" | ||
| 209 | data-state={state} | ||
| 210 | data-collapsible={state === "collapsed" ? collapsible : ""} | ||
| 211 | data-variant={variant} | ||
| 212 | data-side={side} | ||
| 213 | data-slot="sidebar" | ||
| 214 | > | ||
| 215 | {/* This is what handles the sidebar gap on desktop */} | ||
| 216 | <div | ||
| 217 | data-slot="sidebar-gap" | ||
| 218 | className={cn( | ||
| 219 | "relative w-(--sidebar-width) bg-transparent transition-[width] duration-200 ease-linear", | ||
| 220 | "group-data-[collapsible=offcanvas]:w-0", | ||
| 221 | "group-data-[side=right]:rotate-180", | ||
| 222 | variant === "floating" || variant === "inset" | ||
| 223 | ? "group-data-[collapsible=icon]:w-[calc(var(--sidebar-width-icon)+(--spacing(4)))]" | ||
| 224 | : "group-data-[collapsible=icon]:w-(--sidebar-width-icon)" | ||
| 225 | )} | ||
| 226 | /> | ||
| 227 | <div | ||
| 228 | data-slot="sidebar-container" | ||
| 229 | className={cn( | ||
| 230 | "fixed inset-y-0 z-10 hidden h-svh w-(--sidebar-width) transition-[left,right,width] duration-200 ease-linear md:flex", | ||
| 231 | side === "left" | ||
| 232 | ? "left-0 group-data-[collapsible=offcanvas]:left-[calc(var(--sidebar-width)*-1)]" | ||
| 233 | : "right-0 group-data-[collapsible=offcanvas]:right-[calc(var(--sidebar-width)*-1)]", | ||
| 234 | // Adjust the padding for floating and inset variants. | ||
| 235 | variant === "floating" || variant === "inset" | ||
| 236 | ? "p-2 group-data-[collapsible=icon]:w-[calc(var(--sidebar-width-icon)+(--spacing(4))+2px)]" | ||
| 237 | : "group-data-[collapsible=icon]:w-(--sidebar-width-icon) group-data-[side=left]:border-r group-data-[side=right]:border-l", | ||
| 238 | className | ||
| 239 | )} | ||
| 240 | {...props} | ||
| 241 | > | ||
| 242 | <div | ||
| 243 | data-sidebar="sidebar" | ||
| 244 | data-slot="sidebar-inner" | ||
| 245 | className="flex h-full w-full flex-col bg-sidebar group-data-[variant=floating]:rounded-lg group-data-[variant=floating]:border group-data-[variant=floating]:border-sidebar-border group-data-[variant=floating]:shadow-sm" | ||
| 246 | > | ||
| 247 | {children} | ||
| 248 | </div> | ||
| 249 | </div> | ||
| 250 | </div> | ||
| 251 | ) | ||
| 252 | } | ||
| 253 | |||
| 254 | function SidebarTrigger({ | ||
| 255 | className, | ||
| 256 | onClick, | ||
| 257 | ...props | ||
| 258 | }: React.ComponentProps<typeof Button>) { | ||
| 259 | const { toggleSidebar } = useSidebar() | ||
| 260 | |||
| 261 | return ( | ||
| 262 | <Button | ||
| 263 | data-sidebar="trigger" | ||
| 264 | data-slot="sidebar-trigger" | ||
| 265 | variant="ghost" | ||
| 266 | size="icon" | ||
| 267 | className={cn("size-7", className)} | ||
| 268 | onClick={(event) => { | ||
| 269 | onClick?.(event) | ||
| 270 | toggleSidebar() | ||
| 271 | }} | ||
| 272 | {...props} | ||
| 273 | > | ||
| 274 | <PanelLeftIcon /> | ||
| 275 | <span className="sr-only">Toggle Sidebar</span> | ||
| 276 | </Button> | ||
| 277 | ) | ||
| 278 | } | ||
| 279 | |||
| 280 | function SidebarRail({ className, ...props }: React.ComponentProps<"button">) { | ||
| 281 | const { toggleSidebar } = useSidebar() | ||
| 282 | |||
| 283 | return ( | ||
| 284 | <button | ||
| 285 | data-sidebar="rail" | ||
| 286 | data-slot="sidebar-rail" | ||
| 287 | aria-label="Toggle Sidebar" | ||
| 288 | tabIndex={-1} | ||
| 289 | onClick={toggleSidebar} | ||
| 290 | title="Toggle Sidebar" | ||
| 291 | className={cn( | ||
| 292 | "absolute inset-y-0 z-20 hidden w-4 -translate-x-1/2 transition-all ease-linear group-data-[side=left]:-right-4 group-data-[side=right]:left-0 after:absolute after:inset-y-0 after:left-1/2 after:w-[2px] hover:after:bg-sidebar-border sm:flex", | ||
| 293 | "in-data-[side=left]:cursor-w-resize in-data-[side=right]:cursor-e-resize", | ||
| 294 | "[[data-side=left][data-state=collapsed]_&]:cursor-e-resize [[data-side=right][data-state=collapsed]_&]:cursor-w-resize", | ||
| 295 | "group-data-[collapsible=offcanvas]:translate-x-0 group-data-[collapsible=offcanvas]:after:left-full hover:group-data-[collapsible=offcanvas]:bg-sidebar", | ||
| 296 | "[[data-side=left][data-collapsible=offcanvas]_&]:-right-2", | ||
| 297 | "[[data-side=right][data-collapsible=offcanvas]_&]:-left-2", | ||
| 298 | className | ||
| 299 | )} | ||
| 300 | {...props} | ||
| 301 | /> | ||
| 302 | ) | ||
| 303 | } | ||
| 304 | |||
| 305 | function SidebarInset({ className, ...props }: React.ComponentProps<"main">) { | ||
| 306 | return ( | ||
| 307 | <main | ||
| 308 | data-slot="sidebar-inset" | ||
| 309 | className={cn( | ||
| 310 | "relative flex w-full flex-1 flex-col bg-background", | ||
| 311 | "md:peer-data-[variant=inset]:m-2 md:peer-data-[variant=inset]:ml-0 md:peer-data-[variant=inset]:rounded-xl md:peer-data-[variant=inset]:shadow-sm md:peer-data-[variant=inset]:peer-data-[state=collapsed]:ml-2", | ||
| 312 | className | ||
| 313 | )} | ||
| 314 | {...props} | ||
| 315 | /> | ||
| 316 | ) | ||
| 317 | } | ||
| 318 | |||
| 319 | function SidebarInput({ | ||
| 320 | className, | ||
| 321 | ...props | ||
| 322 | }: React.ComponentProps<typeof Input>) { | ||
| 323 | return ( | ||
| 324 | <Input | ||
| 325 | data-slot="sidebar-input" | ||
| 326 | data-sidebar="input" | ||
| 327 | className={cn("h-8 w-full bg-background shadow-none", className)} | ||
| 328 | {...props} | ||
| 329 | /> | ||
| 330 | ) | ||
| 331 | } | ||
| 332 | |||
| 333 | function SidebarHeader({ className, ...props }: React.ComponentProps<"div">) { | ||
| 334 | return ( | ||
| 335 | <div | ||
| 336 | data-slot="sidebar-header" | ||
| 337 | data-sidebar="header" | ||
| 338 | className={cn("flex flex-col gap-2 p-2", className)} | ||
| 339 | {...props} | ||
| 340 | /> | ||
| 341 | ) | ||
| 342 | } | ||
| 343 | |||
| 344 | function SidebarFooter({ className, ...props }: React.ComponentProps<"div">) { | ||
| 345 | return ( | ||
| 346 | <div | ||
| 347 | data-slot="sidebar-footer" | ||
| 348 | data-sidebar="footer" | ||
| 349 | className={cn("flex flex-col gap-2 p-2", className)} | ||
| 350 | {...props} | ||
| 351 | /> | ||
| 352 | ) | ||
| 353 | } | ||
| 354 | |||
| 355 | function SidebarSeparator({ | ||
| 356 | className, | ||
| 357 | ...props | ||
| 358 | }: React.ComponentProps<typeof Separator>) { | ||
| 359 | return ( | ||
| 360 | <Separator | ||
| 361 | data-slot="sidebar-separator" | ||
| 362 | data-sidebar="separator" | ||
| 363 | className={cn("mx-2 w-auto bg-sidebar-border", className)} | ||
| 364 | {...props} | ||
| 365 | /> | ||
| 366 | ) | ||
| 367 | } | ||
| 368 | |||
| 369 | function SidebarContent({ className, ...props }: React.ComponentProps<"div">) { | ||
| 370 | return ( | ||
| 371 | <div | ||
| 372 | data-slot="sidebar-content" | ||
| 373 | data-sidebar="content" | ||
| 374 | className={cn( | ||
| 375 | "flex min-h-0 flex-1 flex-col gap-2 overflow-auto group-data-[collapsible=icon]:overflow-hidden", | ||
| 376 | className | ||
| 377 | )} | ||
| 378 | {...props} | ||
| 379 | /> | ||
| 380 | ) | ||
| 381 | } | ||
| 382 | |||
| 383 | function SidebarGroup({ className, ...props }: React.ComponentProps<"div">) { | ||
| 384 | return ( | ||
| 385 | <div | ||
| 386 | data-slot="sidebar-group" | ||
| 387 | data-sidebar="group" | ||
| 388 | className={cn("relative flex w-full min-w-0 flex-col p-2", className)} | ||
| 389 | {...props} | ||
| 390 | /> | ||
| 391 | ) | ||
| 392 | } | ||
| 393 | |||
| 394 | function SidebarGroupLabel({ | ||
| 395 | className, | ||
| 396 | asChild = false, | ||
| 397 | ...props | ||
| 398 | }: React.ComponentProps<"div"> & { asChild?: boolean }) { | ||
| 399 | const Comp = asChild ? Slot.Root : "div" | ||
| 400 | |||
| 401 | return ( | ||
| 402 | <Comp | ||
| 403 | data-slot="sidebar-group-label" | ||
| 404 | data-sidebar="group-label" | ||
| 405 | className={cn( | ||
| 406 | "flex h-8 shrink-0 items-center rounded-md px-2 text-xs font-medium text-sidebar-foreground/70 ring-sidebar-ring outline-hidden transition-[margin,opacity] duration-200 ease-linear focus-visible:ring-2 [&>svg]:size-4 [&>svg]:shrink-0", | ||
| 407 | "group-data-[collapsible=icon]:-mt-8 group-data-[collapsible=icon]:opacity-0", | ||
| 408 | className | ||
| 409 | )} | ||
| 410 | {...props} | ||
| 411 | /> | ||
| 412 | ) | ||
| 413 | } | ||
| 414 | |||
| 415 | function SidebarGroupAction({ | ||
| 416 | className, | ||
| 417 | asChild = false, | ||
| 418 | ...props | ||
| 419 | }: React.ComponentProps<"button"> & { asChild?: boolean }) { | ||
| 420 | const Comp = asChild ? Slot.Root : "button" | ||
| 421 | |||
| 422 | return ( | ||
| 423 | <Comp | ||
| 424 | data-slot="sidebar-group-action" | ||
| 425 | data-sidebar="group-action" | ||
| 426 | className={cn( | ||
| 427 | "absolute top-3.5 right-3 flex aspect-square w-5 items-center justify-center rounded-md p-0 text-sidebar-foreground ring-sidebar-ring outline-hidden transition-transform hover:bg-sidebar-accent hover:text-sidebar-accent-foreground focus-visible:ring-2 [&>svg]:size-4 [&>svg]:shrink-0", | ||
| 428 | // Increases the hit area of the button on mobile. | ||
| 429 | "after:absolute after:-inset-2 md:after:hidden", | ||
| 430 | "group-data-[collapsible=icon]:hidden", | ||
| 431 | className | ||
| 432 | )} | ||
| 433 | {...props} | ||
| 434 | /> | ||
| 435 | ) | ||
| 436 | } | ||
| 437 | |||
| 438 | function SidebarGroupContent({ | ||
| 439 | className, | ||
| 440 | ...props | ||
| 441 | }: React.ComponentProps<"div">) { | ||
| 442 | return ( | ||
| 443 | <div | ||
| 444 | data-slot="sidebar-group-content" | ||
| 445 | data-sidebar="group-content" | ||
| 446 | className={cn("w-full text-sm", className)} | ||
| 447 | {...props} | ||
| 448 | /> | ||
| 449 | ) | ||
| 450 | } | ||
| 451 | |||
| 452 | function SidebarMenu({ className, ...props }: React.ComponentProps<"ul">) { | ||
| 453 | return ( | ||
| 454 | <ul | ||
| 455 | data-slot="sidebar-menu" | ||
| 456 | data-sidebar="menu" | ||
| 457 | className={cn("flex w-full min-w-0 flex-col gap-1", className)} | ||
| 458 | {...props} | ||
| 459 | /> | ||
| 460 | ) | ||
| 461 | } | ||
| 462 | |||
| 463 | function SidebarMenuItem({ className, ...props }: React.ComponentProps<"li">) { | ||
| 464 | return ( | ||
| 465 | <li | ||
| 466 | data-slot="sidebar-menu-item" | ||
| 467 | data-sidebar="menu-item" | ||
| 468 | className={cn("group/menu-item relative", className)} | ||
| 469 | {...props} | ||
| 470 | /> | ||
| 471 | ) | ||
| 472 | } | ||
| 473 | |||
| 474 | const sidebarMenuButtonVariants = cva( | ||
| 475 | "peer/menu-button flex w-full items-center gap-2 overflow-hidden rounded-md p-2 text-left text-sm ring-sidebar-ring outline-hidden transition-[width,height,padding] group-has-data-[sidebar=menu-action]/menu-item:pr-8 group-data-[collapsible=icon]:size-8! group-data-[collapsible=icon]:p-2! hover:bg-sidebar-accent hover:text-sidebar-accent-foreground focus-visible:ring-2 active:bg-sidebar-accent active:text-sidebar-accent-foreground disabled:pointer-events-none disabled:opacity-50 aria-disabled:pointer-events-none aria-disabled:opacity-50 data-[active=true]:bg-sidebar-accent data-[active=true]:font-medium data-[active=true]:text-sidebar-accent-foreground data-[state=open]:hover:bg-sidebar-accent data-[state=open]:hover:text-sidebar-accent-foreground [&>span:last-child]:truncate [&>svg]:size-4 [&>svg]:shrink-0", | ||
| 476 | { | ||
| 477 | variants: { | ||
| 478 | variant: { | ||
| 479 | default: "hover:bg-sidebar-accent hover:text-sidebar-accent-foreground", | ||
| 480 | outline: | ||
| 481 | "bg-background shadow-[0_0_0_1px_hsl(var(--sidebar-border))] hover:bg-sidebar-accent hover:text-sidebar-accent-foreground hover:shadow-[0_0_0_1px_hsl(var(--sidebar-accent))]", | ||
| 482 | }, | ||
| 483 | size: { | ||
| 484 | default: "h-8 text-sm", | ||
| 485 | sm: "h-7 text-xs", | ||
| 486 | lg: "h-12 text-sm group-data-[collapsible=icon]:p-0!", | ||
| 487 | }, | ||
| 488 | }, | ||
| 489 | defaultVariants: { | ||
| 490 | variant: "default", | ||
| 491 | size: "default", | ||
| 492 | }, | ||
| 493 | } | ||
| 494 | ) | ||
| 495 | |||
| 496 | function SidebarMenuButton({ | ||
| 497 | asChild = false, | ||
| 498 | isActive = false, | ||
| 499 | variant = "default", | ||
| 500 | size = "default", | ||
| 501 | tooltip, | ||
| 502 | className, | ||
| 503 | ...props | ||
| 504 | }: React.ComponentProps<"button"> & { | ||
| 505 | asChild?: boolean | ||
| 506 | isActive?: boolean | ||
| 507 | tooltip?: string | React.ComponentProps<typeof TooltipContent> | ||
| 508 | } & VariantProps<typeof sidebarMenuButtonVariants>) { | ||
| 509 | const Comp = asChild ? Slot.Root : "button" | ||
| 510 | const { isMobile, state } = useSidebar() | ||
| 511 | |||
| 512 | const button = ( | ||
| 513 | <Comp | ||
| 514 | data-slot="sidebar-menu-button" | ||
| 515 | data-sidebar="menu-button" | ||
| 516 | data-size={size} | ||
| 517 | data-active={isActive} | ||
| 518 | className={cn(sidebarMenuButtonVariants({ variant, size }), className)} | ||
| 519 | {...props} | ||
| 520 | /> | ||
| 521 | ) | ||
| 522 | |||
| 523 | if (!tooltip) { | ||
| 524 | return button | ||
| 525 | } | ||
| 526 | |||
| 527 | if (typeof tooltip === "string") { | ||
| 528 | tooltip = { | ||
| 529 | children: tooltip, | ||
| 530 | } | ||
| 531 | } | ||
| 532 | |||
| 533 | return ( | ||
| 534 | <Tooltip> | ||
| 535 | <TooltipTrigger asChild>{button}</TooltipTrigger> | ||
| 536 | <TooltipContent | ||
| 537 | side="right" | ||
| 538 | align="center" | ||
| 539 | hidden={state !== "collapsed" || isMobile} | ||
| 540 | {...tooltip} | ||
| 541 | /> | ||
| 542 | </Tooltip> | ||
| 543 | ) | ||
| 544 | } | ||
| 545 | |||
| 546 | function SidebarMenuAction({ | ||
| 547 | className, | ||
| 548 | asChild = false, | ||
| 549 | showOnHover = false, | ||
| 550 | ...props | ||
| 551 | }: React.ComponentProps<"button"> & { | ||
| 552 | asChild?: boolean | ||
| 553 | showOnHover?: boolean | ||
| 554 | }) { | ||
| 555 | const Comp = asChild ? Slot.Root : "button" | ||
| 556 | |||
| 557 | return ( | ||
| 558 | <Comp | ||
| 559 | data-slot="sidebar-menu-action" | ||
| 560 | data-sidebar="menu-action" | ||
| 561 | className={cn( | ||
| 562 | "absolute top-1.5 right-1 flex aspect-square w-5 items-center justify-center rounded-md p-0 text-sidebar-foreground ring-sidebar-ring outline-hidden transition-transform peer-hover/menu-button:text-sidebar-accent-foreground hover:bg-sidebar-accent hover:text-sidebar-accent-foreground focus-visible:ring-2 [&>svg]:size-4 [&>svg]:shrink-0", | ||
| 563 | // Increases the hit area of the button on mobile. | ||
| 564 | "after:absolute after:-inset-2 md:after:hidden", | ||
| 565 | "peer-data-[size=sm]/menu-button:top-1", | ||
| 566 | "peer-data-[size=default]/menu-button:top-1.5", | ||
| 567 | "peer-data-[size=lg]/menu-button:top-2.5", | ||
| 568 | "group-data-[collapsible=icon]:hidden", | ||
| 569 | showOnHover && | ||
| 570 | "group-focus-within/menu-item:opacity-100 group-hover/menu-item:opacity-100 peer-data-[active=true]/menu-button:text-sidebar-accent-foreground data-[state=open]:opacity-100 md:opacity-0", | ||
| 571 | className | ||
| 572 | )} | ||
| 573 | {...props} | ||
| 574 | /> | ||
| 575 | ) | ||
| 576 | } | ||
| 577 | |||
| 578 | function SidebarMenuBadge({ | ||
| 579 | className, | ||
| 580 | ...props | ||
| 581 | }: React.ComponentProps<"div">) { | ||
| 582 | return ( | ||
| 583 | <div | ||
| 584 | data-slot="sidebar-menu-badge" | ||
| 585 | data-sidebar="menu-badge" | ||
| 586 | className={cn( | ||
| 587 | "pointer-events-none absolute right-1 flex h-5 min-w-5 items-center justify-center rounded-md px-1 text-xs font-medium text-sidebar-foreground tabular-nums select-none", | ||
| 588 | "peer-hover/menu-button:text-sidebar-accent-foreground peer-data-[active=true]/menu-button:text-sidebar-accent-foreground", | ||
| 589 | "peer-data-[size=sm]/menu-button:top-1", | ||
| 590 | "peer-data-[size=default]/menu-button:top-1.5", | ||
| 591 | "peer-data-[size=lg]/menu-button:top-2.5", | ||
| 592 | "group-data-[collapsible=icon]:hidden", | ||
| 593 | className | ||
| 594 | )} | ||
| 595 | {...props} | ||
| 596 | /> | ||
| 597 | ) | ||
| 598 | } | ||
| 599 | |||
| 600 | function SidebarMenuSkeleton({ | ||
| 601 | className, | ||
| 602 | showIcon = false, | ||
| 603 | ...props | ||
| 604 | }: React.ComponentProps<"div"> & { | ||
| 605 | showIcon?: boolean | ||
| 606 | }) { | ||
| 607 | // Random width between 50 to 90%. | ||
| 608 | const width = React.useMemo(() => { | ||
| 609 | return `${Math.floor(Math.random() * 40) + 50}%` | ||
| 610 | }, []) | ||
| 611 | |||
| 612 | return ( | ||
| 613 | <div | ||
| 614 | data-slot="sidebar-menu-skeleton" | ||
| 615 | data-sidebar="menu-skeleton" | ||
| 616 | className={cn("flex h-8 items-center gap-2 rounded-md px-2", className)} | ||
| 617 | {...props} | ||
| 618 | > | ||
| 619 | {showIcon && ( | ||
| 620 | <Skeleton | ||
| 621 | className="size-4 rounded-md" | ||
| 622 | data-sidebar="menu-skeleton-icon" | ||
| 623 | /> | ||
| 624 | )} | ||
| 625 | <Skeleton | ||
| 626 | className="h-4 max-w-(--skeleton-width) flex-1" | ||
| 627 | data-sidebar="menu-skeleton-text" | ||
| 628 | style={ | ||
| 629 | { | ||
| 630 | "--skeleton-width": width, | ||
| 631 | } as React.CSSProperties | ||
| 632 | } | ||
| 633 | /> | ||
| 634 | </div> | ||
| 635 | ) | ||
| 636 | } | ||
| 637 | |||
| 638 | function SidebarMenuSub({ className, ...props }: React.ComponentProps<"ul">) { | ||
| 639 | return ( | ||
| 640 | <ul | ||
| 641 | data-slot="sidebar-menu-sub" | ||
| 642 | data-sidebar="menu-sub" | ||
| 643 | className={cn( | ||
| 644 | "mx-3.5 flex min-w-0 translate-x-px flex-col gap-1 border-l border-sidebar-border px-2.5 py-0.5", | ||
| 645 | "group-data-[collapsible=icon]:hidden", | ||
| 646 | className | ||
| 647 | )} | ||
| 648 | {...props} | ||
| 649 | /> | ||
| 650 | ) | ||
| 651 | } | ||
| 652 | |||
| 653 | function SidebarMenuSubItem({ | ||
| 654 | className, | ||
| 655 | ...props | ||
| 656 | }: React.ComponentProps<"li">) { | ||
| 657 | return ( | ||
| 658 | <li | ||
| 659 | data-slot="sidebar-menu-sub-item" | ||
| 660 | data-sidebar="menu-sub-item" | ||
| 661 | className={cn("group/menu-sub-item relative", className)} | ||
| 662 | {...props} | ||
| 663 | /> | ||
| 664 | ) | ||
| 665 | } | ||
| 666 | |||
| 667 | function SidebarMenuSubButton({ | ||
| 668 | asChild = false, | ||
| 669 | size = "md", | ||
| 670 | isActive = false, | ||
| 671 | className, | ||
| 672 | ...props | ||
| 673 | }: React.ComponentProps<"a"> & { | ||
| 674 | asChild?: boolean | ||
| 675 | size?: "sm" | "md" | ||
| 676 | isActive?: boolean | ||
| 677 | }) { | ||
| 678 | const Comp = asChild ? Slot.Root : "a" | ||
| 679 | |||
| 680 | return ( | ||
| 681 | <Comp | ||
| 682 | data-slot="sidebar-menu-sub-button" | ||
| 683 | data-sidebar="menu-sub-button" | ||
| 684 | data-size={size} | ||
| 685 | data-active={isActive} | ||
| 686 | className={cn( | ||
| 687 | "flex h-7 min-w-0 -translate-x-px items-center gap-2 overflow-hidden rounded-md px-2 text-sidebar-foreground ring-sidebar-ring outline-hidden hover:bg-sidebar-accent hover:text-sidebar-accent-foreground focus-visible:ring-2 active:bg-sidebar-accent active:text-sidebar-accent-foreground disabled:pointer-events-none disabled:opacity-50 aria-disabled:pointer-events-none aria-disabled:opacity-50 [&>span:last-child]:truncate [&>svg]:size-4 [&>svg]:shrink-0 [&>svg]:text-sidebar-accent-foreground", | ||
| 688 | "data-[active=true]:bg-sidebar-accent data-[active=true]:text-sidebar-accent-foreground", | ||
| 689 | size === "sm" && "text-xs", | ||
| 690 | size === "md" && "text-sm", | ||
| 691 | "group-data-[collapsible=icon]:hidden", | ||
| 692 | className | ||
| 693 | )} | ||
| 694 | {...props} | ||
| 695 | /> | ||
| 696 | ) | ||
| 697 | } | ||
| 698 | |||
| 699 | export { | ||
| 700 | Sidebar, | ||
| 701 | SidebarContent, | ||
| 702 | SidebarFooter, | ||
| 703 | SidebarGroup, | ||
| 704 | SidebarGroupAction, | ||
| 705 | SidebarGroupContent, | ||
| 706 | SidebarGroupLabel, | ||
| 707 | SidebarHeader, | ||
| 708 | SidebarInput, | ||
| 709 | SidebarInset, | ||
| 710 | SidebarMenu, | ||
| 711 | SidebarMenuAction, | ||
| 712 | SidebarMenuBadge, | ||
| 713 | SidebarMenuButton, | ||
| 714 | SidebarMenuItem, | ||
| 715 | SidebarMenuSkeleton, | ||
| 716 | SidebarMenuSub, | ||
| 717 | SidebarMenuSubButton, | ||
| 718 | SidebarMenuSubItem, | ||
| 719 | SidebarProvider, | ||
| 720 | SidebarRail, | ||
| 721 | SidebarSeparator, | ||
| 722 | SidebarTrigger, | ||
| 723 | useSidebar, | ||
| 724 | } | ||
| @@ -0,0 +1,13 @@ | |||
| 1 | import { cn } from "@executor/ui/lib/utils" | ||
| 2 | |||
| 3 | function Skeleton({ className, ...props }: React.ComponentProps<"div">) { | ||
| 4 | return ( | ||
| 5 | <div | ||
| 6 | data-slot="skeleton" | ||
| 7 | className={cn("animate-pulse rounded-md bg-accent", className)} | ||
| 8 | {...props} | ||
| 9 | /> | ||
| 10 | ) | ||
| 11 | } | ||
| 12 | |||
| 13 | export { Skeleton } | ||
| @@ -0,0 +1,61 @@ | |||
| 1 | import * as React from "react" | ||
| 2 | import { Slider as SliderPrimitive } from "radix-ui" | ||
| 3 | |||
| 4 | import { cn } from "@executor/ui/lib/utils" | ||
| 5 | |||
| 6 | function Slider({ | ||
| 7 | className, | ||
| 8 | defaultValue, | ||
| 9 | value, | ||
| 10 | min = 0, | ||
| 11 | max = 100, | ||
| 12 | ...props | ||
| 13 | }: React.ComponentProps<typeof SliderPrimitive.Root>) { | ||
| 14 | const _values = React.useMemo( | ||
| 15 | () => | ||
| 16 | Array.isArray(value) | ||
| 17 | ? value | ||
| 18 | : Array.isArray(defaultValue) | ||
| 19 | ? defaultValue | ||
| 20 | : [min, max], | ||
| 21 | [value, defaultValue, min, max] | ||
| 22 | ) | ||
| 23 | |||
| 24 | return ( | ||
| 25 | <SliderPrimitive.Root | ||
| 26 | data-slot="slider" | ||
| 27 | defaultValue={defaultValue} | ||
| 28 | value={value} | ||
| 29 | min={min} | ||
| 30 | max={max} | ||
| 31 | className={cn( | ||
| 32 | "relative flex w-full touch-none items-center select-none data-[disabled]:opacity-50 data-[orientation=vertical]:h-full data-[orientation=vertical]:min-h-44 data-[orientation=vertical]:w-auto data-[orientation=vertical]:flex-col", | ||
| 33 | className | ||
| 34 | )} | ||
| 35 | {...props} | ||
| 36 | > | ||
| 37 | <SliderPrimitive.Track | ||
| 38 | data-slot="slider-track" | ||
| 39 | className={cn( | ||
| 40 | "relative grow overflow-hidden rounded-full bg-muted data-[orientation=horizontal]:h-1.5 data-[orientation=horizontal]:w-full data-[orientation=vertical]:h-full data-[orientation=vertical]:w-1.5" | ||
| 41 | )} | ||
| 42 | > | ||
| 43 | <SliderPrimitive.Range | ||
| 44 | data-slot="slider-range" | ||
| 45 | className={cn( | ||
| 46 | "absolute bg-primary data-[orientation=horizontal]:h-full data-[orientation=vertical]:w-full" | ||
| 47 | )} | ||
| 48 | /> | ||
| 49 | </SliderPrimitive.Track> | ||
| 50 | {Array.from({ length: _values.length }, (_, index) => ( | ||
| 51 | <SliderPrimitive.Thumb | ||
| 52 | data-slot="slider-thumb" | ||
| 53 | key={index} | ||
| 54 | className="block size-4 shrink-0 rounded-full border border-primary bg-white shadow-sm ring-ring/50 transition-[color,box-shadow] hover:ring-4 focus-visible:ring-4 focus-visible:outline-hidden disabled:pointer-events-none disabled:opacity-50" | ||
| 55 | /> | ||
| 56 | ))} | ||
| 57 | </SliderPrimitive.Root> | ||
| 58 | ) | ||
| 59 | } | ||
| 60 | |||
| 61 | export { Slider } | ||
| @@ -0,0 +1,40 @@ | |||
| 1 | "use client" | ||
| 2 | |||
| 3 | import { | ||
| 4 | CircleCheckIcon, | ||
| 5 | InfoIcon, | ||
| 6 | Loader2Icon, | ||
| 7 | OctagonXIcon, | ||
| 8 | TriangleAlertIcon, | ||
| 9 | } from "lucide-react" | ||
| 10 | import { useTheme } from "next-themes" | ||
| 11 | import { Toaster as Sonner, type ToasterProps } from "sonner" | ||
| 12 | |||
| 13 | const Toaster = ({ ...props }: ToasterProps) => { | ||
| 14 | const { theme = "system" } = useTheme() | ||
| 15 | |||
| 16 | return ( | ||
| 17 | <Sonner | ||
| 18 | theme={theme as ToasterProps["theme"]} | ||
| 19 | className="toaster group" | ||
| 20 | icons={{ | ||
| 21 | success: <CircleCheckIcon className="size-4" />, | ||
| 22 | info: <InfoIcon className="size-4" />, | ||
| 23 | warning: <TriangleAlertIcon className="size-4" />, | ||
| 24 | error: <OctagonXIcon className="size-4" />, | ||
| 25 | loading: <Loader2Icon className="size-4 animate-spin" />, | ||
| 26 | }} | ||
| 27 | style={ | ||
| 28 | { | ||
| 29 | "--normal-bg": "var(--popover)", | ||
| 30 | "--normal-text": "var(--popover-foreground)", | ||
| 31 | "--normal-border": "var(--border)", | ||
| 32 | "--border-radius": "var(--radius)", | ||
| 33 | } as React.CSSProperties | ||
| 34 | } | ||
| 35 | {...props} | ||
| 36 | /> | ||
| 37 | ) | ||
| 38 | } | ||
| 39 | |||
| 40 | export { Toaster } | ||
| @@ -0,0 +1,16 @@ | |||
| 1 | import { Loader2Icon } from "lucide-react" | ||
| 2 | |||
| 3 | import { cn } from "@executor/ui/lib/utils" | ||
| 4 | |||
| 5 | function Spinner({ className, ...props }: React.ComponentProps<"svg">) { | ||
| 6 | return ( | ||
| 7 | <Loader2Icon | ||
| 8 | role="status" | ||
| 9 | aria-label="Loading" | ||
| 10 | className={cn("size-4 animate-spin", className)} | ||
| 11 | {...props} | ||
| 12 | /> | ||
| 13 | ) | ||
| 14 | } | ||
| 15 | |||
| 16 | export { Spinner } | ||
| @@ -0,0 +1,33 @@ | |||
| 1 | import * as React from "react" | ||
| 2 | import { Switch as SwitchPrimitive } from "radix-ui" | ||
| 3 | |||
| 4 | import { cn } from "@executor/ui/lib/utils" | ||
| 5 | |||
| 6 | function Switch({ | ||
| 7 | className, | ||
| 8 | size = "default", | ||
| 9 | ...props | ||
| 10 | }: React.ComponentProps<typeof SwitchPrimitive.Root> & { | ||
| 11 | size?: "sm" | "default" | ||
| 12 | }) { | ||
| 13 | return ( | ||
| 14 | <SwitchPrimitive.Root | ||
| 15 | data-slot="switch" | ||
| 16 | data-size={size} | ||
| 17 | className={cn( | ||
| 18 | "peer group/switch inline-flex shrink-0 items-center rounded-full border border-transparent shadow-xs transition-all outline-none focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 disabled:cursor-not-allowed disabled:opacity-50 data-[size=default]:h-[1.15rem] data-[size=default]:w-8 data-[size=sm]:h-3.5 data-[size=sm]:w-6 data-[state=checked]:bg-primary data-[state=unchecked]:bg-input dark:data-[state=unchecked]:bg-input/80", | ||
| 19 | className | ||
| 20 | )} | ||
| 21 | {...props} | ||
| 22 | > | ||
| 23 | <SwitchPrimitive.Thumb | ||
| 24 | data-slot="switch-thumb" | ||
| 25 | className={cn( | ||
| 26 | "pointer-events-none block rounded-full bg-background ring-0 transition-transform group-data-[size=default]/switch:size-4 group-data-[size=sm]/switch:size-3 data-[state=checked]:translate-x-[calc(100%-2px)] data-[state=unchecked]:translate-x-0 dark:data-[state=checked]:bg-primary-foreground dark:data-[state=unchecked]:bg-foreground" | ||
| 27 | )} | ||
| 28 | /> | ||
| 29 | </SwitchPrimitive.Root> | ||
| 30 | ) | ||
| 31 | } | ||
| 32 | |||
| 33 | export { Switch } | ||
| @@ -0,0 +1,116 @@ | |||
| 1 | "use client" | ||
| 2 | |||
| 3 | import * as React from "react" | ||
| 4 | |||
| 5 | import { cn } from "@executor/ui/lib/utils" | ||
| 6 | |||
| 7 | function Table({ className, ...props }: React.ComponentProps<"table">) { | ||
| 8 | return ( | ||
| 9 | <div | ||
| 10 | data-slot="table-container" | ||
| 11 | className="relative w-full overflow-x-auto" | ||
| 12 | > | ||
| 13 | <table | ||
| 14 | data-slot="table" | ||
| 15 | className={cn("w-full caption-bottom text-sm", className)} | ||
| 16 | {...props} | ||
| 17 | /> | ||
| 18 | </div> | ||
| 19 | ) | ||
| 20 | } | ||
| 21 | |||
| 22 | function TableHeader({ className, ...props }: React.ComponentProps<"thead">) { | ||
| 23 | return ( | ||
| 24 | <thead | ||
| 25 | data-slot="table-header" | ||
| 26 | className={cn("[&_tr]:border-b", className)} | ||
| 27 | {...props} | ||
| 28 | /> | ||
| 29 | ) | ||
| 30 | } | ||
| 31 | |||
| 32 | function TableBody({ className, ...props }: React.ComponentProps<"tbody">) { | ||
| 33 | return ( | ||
| 34 | <tbody | ||
| 35 | data-slot="table-body" | ||
| 36 | className={cn("[&_tr:last-child]:border-0", className)} | ||
| 37 | {...props} | ||
| 38 | /> | ||
| 39 | ) | ||
| 40 | } | ||
| 41 | |||
| 42 | function TableFooter({ className, ...props }: React.ComponentProps<"tfoot">) { | ||
| 43 | return ( | ||
| 44 | <tfoot | ||
| 45 | data-slot="table-footer" | ||
| 46 | className={cn( | ||
| 47 | "border-t bg-muted/50 font-medium [&>tr]:last:border-b-0", | ||
| 48 | className | ||
| 49 | )} | ||
| 50 | {...props} | ||
| 51 | /> | ||
| 52 | ) | ||
| 53 | } | ||
| 54 | |||
| 55 | function TableRow({ className, ...props }: React.ComponentProps<"tr">) { | ||
| 56 | return ( | ||
| 57 | <tr | ||
| 58 | data-slot="table-row" | ||
| 59 | className={cn( | ||
| 60 | "border-b transition-colors hover:bg-muted/50 has-aria-expanded:bg-muted/50 data-[state=selected]:bg-muted", | ||
| 61 | className | ||
| 62 | )} | ||
| 63 | {...props} | ||
| 64 | /> | ||
| 65 | ) | ||
| 66 | } | ||
| 67 | |||
| 68 | function TableHead({ className, ...props }: React.ComponentProps<"th">) { | ||
| 69 | return ( | ||
| 70 | <th | ||
| 71 | data-slot="table-head" | ||
| 72 | className={cn( | ||
| 73 | "h-10 px-2 text-left align-middle font-medium whitespace-nowrap text-foreground [&:has([role=checkbox])]:pr-0 [&>[role=checkbox]]:translate-y-[2px]", | ||
| 74 | className | ||
| 75 | )} | ||
| 76 | {...props} | ||
| 77 | /> | ||
| 78 | ) | ||
| 79 | } | ||
| 80 | |||
| 81 | function TableCell({ className, ...props }: React.ComponentProps<"td">) { | ||
| 82 | return ( | ||
| 83 | <td | ||
| 84 | data-slot="table-cell" | ||
| 85 | className={cn( | ||
| 86 | "p-2 align-middle whitespace-nowrap [&:has([role=checkbox])]:pr-0 [&>[role=checkbox]]:translate-y-[2px]", | ||
| 87 | className | ||
| 88 | )} | ||
| 89 | {...props} | ||
| 90 | /> | ||
| 91 | ) | ||
| 92 | } | ||
| 93 | |||
| 94 | function TableCaption({ | ||
| 95 | className, | ||
| 96 | ...props | ||
| 97 | }: React.ComponentProps<"caption">) { | ||
| 98 | return ( | ||
| 99 | <caption | ||
| 100 | data-slot="table-caption" | ||
| 101 | className={cn("mt-4 text-sm text-muted-foreground", className)} | ||
| 102 | {...props} | ||
| 103 | /> | ||
| 104 | ) | ||
| 105 | } | ||
| 106 | |||
| 107 | export { | ||
| 108 | Table, | ||
| 109 | TableHeader, | ||
| 110 | TableBody, | ||
| 111 | TableFooter, | ||
| 112 | TableHead, | ||
| 113 | TableRow, | ||
| 114 | TableCell, | ||
| 115 | TableCaption, | ||
| 116 | } | ||
| @@ -0,0 +1,89 @@ | |||
| 1 | import * as React from "react" | ||
| 2 | import { cva, type VariantProps } from "class-variance-authority" | ||
| 3 | import { Tabs as TabsPrimitive } from "radix-ui" | ||
| 4 | |||
| 5 | import { cn } from "@executor/ui/lib/utils" | ||
| 6 | |||
| 7 | function Tabs({ | ||
| 8 | className, | ||
| 9 | orientation = "horizontal", | ||
| 10 | ...props | ||
| 11 | }: React.ComponentProps<typeof TabsPrimitive.Root>) { | ||
| 12 | return ( | ||
| 13 | <TabsPrimitive.Root | ||
| 14 | data-slot="tabs" | ||
| 15 | data-orientation={orientation} | ||
| 16 | orientation={orientation} | ||
| 17 | className={cn( | ||
| 18 | "group/tabs flex gap-2 data-[orientation=horizontal]:flex-col", | ||
| 19 | className | ||
| 20 | )} | ||
| 21 | {...props} | ||
| 22 | /> | ||
| 23 | ) | ||
| 24 | } | ||
| 25 | |||
| 26 | const tabsListVariants = cva( | ||
| 27 | "group/tabs-list inline-flex w-fit items-center justify-center rounded-lg p-[3px] text-muted-foreground group-data-[orientation=horizontal]/tabs:h-9 group-data-[orientation=vertical]/tabs:h-fit group-data-[orientation=vertical]/tabs:flex-col data-[variant=line]:rounded-none", | ||
| 28 | { | ||
| 29 | variants: { | ||
| 30 | variant: { | ||
| 31 | default: "bg-muted", | ||
| 32 | line: "gap-1 bg-transparent", | ||
| 33 | }, | ||
| 34 | }, | ||
| 35 | defaultVariants: { | ||
| 36 | variant: "default", | ||
| 37 | }, | ||
| 38 | } | ||
| 39 | ) | ||
| 40 | |||
| 41 | function TabsList({ | ||
| 42 | className, | ||
| 43 | variant = "default", | ||
| 44 | ...props | ||
| 45 | }: React.ComponentProps<typeof TabsPrimitive.List> & | ||
| 46 | VariantProps<typeof tabsListVariants>) { | ||
| 47 | return ( | ||
| 48 | <TabsPrimitive.List | ||
| 49 | data-slot="tabs-list" | ||
| 50 | data-variant={variant} | ||
| 51 | className={cn(tabsListVariants({ variant }), className)} | ||
| 52 | {...props} | ||
| 53 | /> | ||
| 54 | ) | ||
| 55 | } | ||
| 56 | |||
| 57 | function TabsTrigger({ | ||
| 58 | className, | ||
| 59 | ...props | ||
| 60 | }: React.ComponentProps<typeof TabsPrimitive.Trigger>) { | ||
| 61 | return ( | ||
| 62 | <TabsPrimitive.Trigger | ||
| 63 | data-slot="tabs-trigger" | ||
| 64 | className={cn( | ||
| 65 | "relative inline-flex h-[calc(100%-1px)] flex-1 items-center justify-center gap-1.5 rounded-md border border-transparent px-2 py-1 text-sm font-medium whitespace-nowrap text-foreground/60 transition-all group-data-[orientation=vertical]/tabs:w-full group-data-[orientation=vertical]/tabs:justify-start hover:text-foreground focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 focus-visible:outline-1 focus-visible:outline-ring disabled:pointer-events-none disabled:opacity-50 group-data-[variant=default]/tabs-list:data-[state=active]:shadow-sm group-data-[variant=line]/tabs-list:data-[state=active]:shadow-none dark:text-muted-foreground dark:hover:text-foreground [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4", | ||
| 66 | "group-data-[variant=line]/tabs-list:bg-transparent group-data-[variant=line]/tabs-list:data-[state=active]:bg-transparent dark:group-data-[variant=line]/tabs-list:data-[state=active]:border-transparent dark:group-data-[variant=line]/tabs-list:data-[state=active]:bg-transparent", | ||
| 67 | "data-[state=active]:bg-background data-[state=active]:text-foreground dark:data-[state=active]:border-input dark:data-[state=active]:bg-input/30 dark:data-[state=active]:text-foreground", | ||
| 68 | "after:absolute after:bg-foreground after:opacity-0 after:transition-opacity group-data-[orientation=horizontal]/tabs:after:inset-x-0 group-data-[orientation=horizontal]/tabs:after:bottom-[-5px] group-data-[orientation=horizontal]/tabs:after:h-0.5 group-data-[orientation=vertical]/tabs:after:inset-y-0 group-data-[orientation=vertical]/tabs:after:-right-1 group-data-[orientation=vertical]/tabs:after:w-0.5 group-data-[variant=line]/tabs-list:data-[state=active]:after:opacity-100", | ||
| 69 | className | ||
| 70 | )} | ||
| 71 | {...props} | ||
| 72 | /> | ||
| 73 | ) | ||
| 74 | } | ||
| 75 | |||
| 76 | function TabsContent({ | ||
| 77 | className, | ||
| 78 | ...props | ||
| 79 | }: React.ComponentProps<typeof TabsPrimitive.Content>) { | ||
| 80 | return ( | ||
| 81 | <TabsPrimitive.Content | ||
| 82 | data-slot="tabs-content" | ||
| 83 | className={cn("flex-1 outline-none", className)} | ||
| 84 | {...props} | ||
| 85 | /> | ||
| 86 | ) | ||
| 87 | } | ||
| 88 | |||
| 89 | export { Tabs, TabsList, TabsTrigger, TabsContent, tabsListVariants } | ||
| @@ -0,0 +1,18 @@ | |||
| 1 | import * as React from "react" | ||
| 2 | |||
| 3 | import { cn } from "@executor/ui/lib/utils" | ||
| 4 | |||
| 5 | function Textarea({ className, ...props }: React.ComponentProps<"textarea">) { | ||
| 6 | return ( | ||
| 7 | <textarea | ||
| 8 | data-slot="textarea" | ||
| 9 | className={cn( | ||
| 10 | "flex field-sizing-content min-h-16 w-full rounded-md border border-input bg-transparent px-3 py-2 text-base shadow-xs transition-[color,box-shadow] outline-none placeholder:text-muted-foreground focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 disabled:cursor-not-allowed disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-destructive/20 md:text-sm dark:bg-input/30 dark:aria-invalid:ring-destructive/40", | ||
| 11 | className | ||
| 12 | )} | ||
| 13 | {...props} | ||
| 14 | /> | ||
| 15 | ) | ||
| 16 | } | ||
| 17 | |||
| 18 | export { Textarea } | ||
| @@ -0,0 +1,83 @@ | |||
| 1 | "use client" | ||
| 2 | |||
| 3 | import * as React from "react" | ||
| 4 | import { type VariantProps } from "class-variance-authority" | ||
| 5 | import { ToggleGroup as ToggleGroupPrimitive } from "radix-ui" | ||
| 6 | |||
| 7 | import { cn } from "@executor/ui/lib/utils" | ||
| 8 | import { toggleVariants } from "@executor/ui/components/toggle" | ||
| 9 | |||
| 10 | const ToggleGroupContext = React.createContext< | ||
| 11 | VariantProps<typeof toggleVariants> & { | ||
| 12 | spacing?: number | ||
| 13 | } | ||
| 14 | >({ | ||
| 15 | size: "default", | ||
| 16 | variant: "default", | ||
| 17 | spacing: 0, | ||
| 18 | }) | ||
| 19 | |||
| 20 | function ToggleGroup({ | ||
| 21 | className, | ||
| 22 | variant, | ||
| 23 | size, | ||
| 24 | spacing = 0, | ||
| 25 | children, | ||
| 26 | ...props | ||
| 27 | }: React.ComponentProps<typeof ToggleGroupPrimitive.Root> & | ||
| 28 | VariantProps<typeof toggleVariants> & { | ||
| 29 | spacing?: number | ||
| 30 | }) { | ||
| 31 | return ( | ||
| 32 | <ToggleGroupPrimitive.Root | ||
| 33 | data-slot="toggle-group" | ||
| 34 | data-variant={variant} | ||
| 35 | data-size={size} | ||
| 36 | data-spacing={spacing} | ||
| 37 | style={{ "--gap": spacing } as React.CSSProperties} | ||
| 38 | className={cn( | ||
| 39 | "group/toggle-group flex w-fit items-center gap-[--spacing(var(--gap))] rounded-md data-[spacing=default]:data-[variant=outline]:shadow-xs", | ||
| 40 | className | ||
| 41 | )} | ||
| 42 | {...props} | ||
| 43 | > | ||
| 44 | <ToggleGroupContext.Provider value={{ variant, size, spacing }}> | ||
| 45 | {children} | ||
| 46 | </ToggleGroupContext.Provider> | ||
| 47 | </ToggleGroupPrimitive.Root> | ||
| 48 | ) | ||
| 49 | } | ||
| 50 | |||
| 51 | function ToggleGroupItem({ | ||
| 52 | className, | ||
| 53 | children, | ||
| 54 | variant, | ||
| 55 | size, | ||
| 56 | ...props | ||
| 57 | }: React.ComponentProps<typeof ToggleGroupPrimitive.Item> & | ||
| 58 | VariantProps<typeof toggleVariants>) { | ||
| 59 | const context = React.useContext(ToggleGroupContext) | ||
| 60 | |||
| 61 | return ( | ||
| 62 | <ToggleGroupPrimitive.Item | ||
| 63 | data-slot="toggle-group-item" | ||
| 64 | data-variant={context.variant || variant} | ||
| 65 | data-size={context.size || size} | ||
| 66 | data-spacing={context.spacing} | ||
| 67 | className={cn( | ||
| 68 | toggleVariants({ | ||
| 69 | variant: context.variant || variant, | ||
| 70 | size: context.size || size, | ||
| 71 | }), | ||
| 72 | "w-auto min-w-0 shrink-0 px-3 focus:z-10 focus-visible:z-10", | ||
| 73 | "data-[spacing=0]:rounded-none data-[spacing=0]:shadow-none data-[spacing=0]:first:rounded-l-md data-[spacing=0]:last:rounded-r-md data-[spacing=0]:data-[variant=outline]:border-l-0 data-[spacing=0]:data-[variant=outline]:first:border-l", | ||
| 74 | className | ||
| 75 | )} | ||
| 76 | {...props} | ||
| 77 | > | ||
| 78 | {children} | ||
| 79 | </ToggleGroupPrimitive.Item> | ||
| 80 | ) | ||
| 81 | } | ||
| 82 | |||
| 83 | export { ToggleGroup, ToggleGroupItem } | ||
| @@ -0,0 +1,47 @@ | |||
| 1 | "use client" | ||
| 2 | |||
| 3 | import * as React from "react" | ||
| 4 | import { cva, type VariantProps } from "class-variance-authority" | ||
| 5 | import { Toggle as TogglePrimitive } from "radix-ui" | ||
| 6 | |||
| 7 | import { cn } from "@executor/ui/lib/utils" | ||
| 8 | |||
| 9 | const toggleVariants = cva( | ||
| 10 | "inline-flex items-center justify-center gap-2 rounded-md text-sm font-medium whitespace-nowrap transition-[color,box-shadow] outline-none hover:bg-muted hover:text-muted-foreground focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 disabled:pointer-events-none disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-destructive/20 data-[state=on]:bg-accent data-[state=on]:text-accent-foreground dark:aria-invalid:ring-destructive/40 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4", | ||
| 11 | { | ||
| 12 | variants: { | ||
| 13 | variant: { | ||
| 14 | default: "bg-transparent", | ||
| 15 | outline: | ||
| 16 | "border border-input bg-transparent shadow-xs hover:bg-accent hover:text-accent-foreground", | ||
| 17 | }, | ||
| 18 | size: { | ||
| 19 | default: "h-9 min-w-9 px-2", | ||
| 20 | sm: "h-8 min-w-8 px-1.5", | ||
| 21 | lg: "h-10 min-w-10 px-2.5", | ||
| 22 | }, | ||
| 23 | }, | ||
| 24 | defaultVariants: { | ||
| 25 | variant: "default", | ||
| 26 | size: "default", | ||
| 27 | }, | ||
| 28 | } | ||
| 29 | ) | ||
| 30 | |||
| 31 | function Toggle({ | ||
| 32 | className, | ||
| 33 | variant, | ||
| 34 | size, | ||
| 35 | ...props | ||
| 36 | }: React.ComponentProps<typeof TogglePrimitive.Root> & | ||
| 37 | VariantProps<typeof toggleVariants>) { | ||
| 38 | return ( | ||
| 39 | <TogglePrimitive.Root | ||
| 40 | data-slot="toggle" | ||
| 41 | className={cn(toggleVariants({ variant, size, className }))} | ||
| 42 | {...props} | ||
| 43 | /> | ||
| 44 | ) | ||
| 45 | } | ||
| 46 | |||
| 47 | export { Toggle, toggleVariants } | ||
| @@ -0,0 +1,55 @@ | |||
| 1 | import * as React from "react" | ||
| 2 | import { Tooltip as TooltipPrimitive } from "radix-ui" | ||
| 3 | |||
| 4 | import { cn } from "@executor/ui/lib/utils" | ||
| 5 | |||
| 6 | function TooltipProvider({ | ||
| 7 | delayDuration = 0, | ||
| 8 | ...props | ||
| 9 | }: React.ComponentProps<typeof TooltipPrimitive.Provider>) { | ||
| 10 | return ( | ||
| 11 | <TooltipPrimitive.Provider | ||
| 12 | data-slot="tooltip-provider" | ||
| 13 | delayDuration={delayDuration} | ||
| 14 | {...props} | ||
| 15 | /> | ||
| 16 | ) | ||
| 17 | } | ||
| 18 | |||
| 19 | function Tooltip({ | ||
| 20 | ...props | ||
| 21 | }: React.ComponentProps<typeof TooltipPrimitive.Root>) { | ||
| 22 | return <TooltipPrimitive.Root data-slot="tooltip" {...props} /> | ||
| 23 | } | ||
| 24 | |||
| 25 | function TooltipTrigger({ | ||
| 26 | ...props | ||
| 27 | }: React.ComponentProps<typeof TooltipPrimitive.Trigger>) { | ||
| 28 | return <TooltipPrimitive.Trigger data-slot="tooltip-trigger" {...props} /> | ||
| 29 | } | ||
| 30 | |||
| 31 | function TooltipContent({ | ||
| 32 | className, | ||
| 33 | sideOffset = 0, | ||
| 34 | children, | ||
| 35 | ...props | ||
| 36 | }: React.ComponentProps<typeof TooltipPrimitive.Content>) { | ||
| 37 | return ( | ||
| 38 | <TooltipPrimitive.Portal> | ||
| 39 | <TooltipPrimitive.Content | ||
| 40 | data-slot="tooltip-content" | ||
| 41 | sideOffset={sideOffset} | ||
| 42 | className={cn( | ||
| 43 | "z-50 w-fit origin-(--radix-tooltip-content-transform-origin) animate-in rounded-md bg-foreground px-3 py-1.5 text-xs text-balance text-background fade-in-0 zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95", | ||
| 44 | className | ||
| 45 | )} | ||
| 46 | {...props} | ||
| 47 | > | ||
| 48 | {children} | ||
| 49 | <TooltipPrimitive.Arrow className="z-50 size-2.5 translate-y-[calc(-50%_-_2px)] rotate-45 rounded-[2px] bg-foreground fill-foreground" /> | ||
| 50 | </TooltipPrimitive.Content> | ||
| 51 | </TooltipPrimitive.Portal> | ||
| 52 | ) | ||
| 53 | } | ||
| 54 | |||
| 55 | export { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider } | ||
| @@ -0,0 +1,19 @@ | |||
| 1 | import * as React from "react" | ||
| 2 | |||
| 3 | const MOBILE_BREAKPOINT = 768 | ||
| 4 | |||
| 5 | export function useIsMobile() { | ||
| 6 | const [isMobile, setIsMobile] = React.useState<boolean | undefined>(undefined) | ||
| 7 | |||
| 8 | React.useEffect(() => { | ||
| 9 | const mql = window.matchMedia(`(max-width: ${MOBILE_BREAKPOINT - 1}px)`) | ||
| 10 | const onChange = () => { | ||
| 11 | setIsMobile(window.innerWidth < MOBILE_BREAKPOINT) | ||
| 12 | } | ||
| 13 | mql.addEventListener("change", onChange) | ||
| 14 | setIsMobile(window.innerWidth < MOBILE_BREAKPOINT) | ||
| 15 | return () => mql.removeEventListener("change", onChange) | ||
| 16 | }, []) | ||
| 17 | |||
| 18 | return !!isMobile | ||
| 19 | } | ||
| @@ -0,0 +1,6 @@ | |||
| 1 | import { type ClassValue, clsx } from "clsx"; | ||
| 2 | import { twMerge } from "tailwind-merge"; | ||
| 3 | |||
| 4 | export function cn(...inputs: ClassValue[]) { | ||
| 5 | return twMerge(clsx(inputs)); | ||
| 6 | } | ||
| @@ -1,7 +1,11 @@ | |||
| 1 | @import "tailwindcss"; | 1 | @import "tailwindcss"; |
| 2 | 2 | ||
| 3 | @source "../../../packages/clients/react/src/**/*.{ts,tsx}"; | 3 | @custom-variant dark (&:is(.dark *)); |
| 4 | @source "../../../packages/plugins/openapi/src/react/**/*.{ts,tsx}"; | 4 | |
| 5 | @source "../components/**/*.{ts,tsx}"; | ||
| 6 | @source "../../../../apps/web/src/**/*.{ts,tsx}"; | ||
| 7 | @source "../../../clients/react/src/**/*.{ts,tsx}"; | ||
| 8 | @source "../../../plugins/openapi/src/react/**/*.{ts,tsx}"; | ||
| 5 | 9 | ||
| 6 | @theme inline { | 10 | @theme inline { |
| 7 | --font-sans: "DM Sans", ui-sans-serif, system-ui, sans-serif; | 11 | --font-sans: "DM Sans", ui-sans-serif, system-ui, sans-serif; |
| @@ -34,6 +38,11 @@ · 26 unmodified lines | |||
| 34 | --radius-md: calc(var(--radius) * 0.8); | 38 | --radius-md: calc(var(--radius) * 0.8); |
| 35 | --radius-lg: var(--radius); | 39 | --radius-lg: var(--radius); |
| 36 | --radius-xl: calc(var(--radius) * 1.4); | 40 | --radius-xl: calc(var(--radius) * 1.4); |
| 41 | --color-sidebar-ring: var(--sidebar-ring); | ||
| 42 | --color-sidebar-accent-foreground: var(--sidebar-accent-foreground); | ||
| 43 | --color-sidebar-accent: var(--sidebar-accent); | ||
| 44 | --color-sidebar-primary-foreground: var(--sidebar-primary-foreground); | ||
| 45 | --color-sidebar-primary: var(--sidebar-primary); | ||
| 37 | } | 46 | } |
| 38 | 47 | ||
| 39 | /* ——— Light theme ——— */ | 48 | /* ——— Light theme ——— */ |
| @@ -65,6 +74,11 @@ · 25 unmodified lines | |||
| 65 | 74 | ||
| 66 | --scrollbar-thumb: oklch(0.78 0.005 260); | 75 | --scrollbar-thumb: oklch(0.78 0.005 260); |
| 67 | --scrollbar-thumb-hover: oklch(0.68 0.005 260); | 76 | --scrollbar-thumb-hover: oklch(0.68 0.005 260); |
| 77 | --sidebar-primary: hsl(240 5.9% 10%); | ||
| 78 | --sidebar-primary-foreground: hsl(0 0% 98%); | ||
| 79 | --sidebar-accent: hsl(240 4.8% 95.9%); | ||
| 80 | --sidebar-accent-foreground: hsl(240 5.9% 10%); | ||
| 81 | --sidebar-ring: hsl(217.2 91.2% 59.8%); | ||
| 68 | } | 82 | } |
| 69 | 83 | ||
| 70 | /* ——— Dark theme ——— */ | 84 | /* ——— Dark theme ——— */ |
| @@ -126,3 +140,14 @@ · 55 unmodified lines | |||
| 126 | background: var(--scrollbar-thumb-hover); | 140 | background: var(--scrollbar-thumb-hover); |
| 127 | } | 141 | } |
| 128 | } | 142 | } |
| 143 | |||
| 144 | .dark { | ||
| 145 | --sidebar: hsl(240 5.9% 10%); | ||
| 146 | --sidebar-foreground: hsl(240 4.8% 95.9%); | ||
| 147 | --sidebar-primary: hsl(224.3 76.3% 48%); | ||
| 148 | --sidebar-primary-foreground: hsl(0 0% 100%); | ||
| 149 | --sidebar-accent: hsl(240 3.7% 15.9%); | ||
| 150 | --sidebar-accent-foreground: hsl(240 4.8% 95.9%); | ||
| 151 | --sidebar-border: hsl(240 3.7% 15.9%); | ||
| 152 | --sidebar-ring: hsl(217.2 91.2% 59.8%); | ||
| 153 | } | ||
| @@ -0,0 +1,25 @@ | |||
| 1 | { | ||
| 2 | "compilerOptions": { | ||
| 3 | "target": "ESNext", | ||
| 4 | "module": "ESNext", | ||
| 5 | "moduleResolution": "bundler", | ||
| 6 | "strict": true, | ||
| 7 | "esModuleInterop": true, | ||
| 8 | "skipLibCheck": true, | ||
| 9 | "outDir": "dist", | ||
| 10 | "rootDir": "src", | ||
| 11 | "declaration": true, | ||
| 12 | "declarationMap": true, | ||
| 13 | "sourceMap": true, | ||
| 14 | "jsx": "react-jsx", | ||
| 15 | "paths": { | ||
| 16 | "@executor/ui/*": ["./src/*"] | ||
| 17 | }, | ||
| 18 | "plugins": [ | ||
| 19 | { | ||
| 20 | "name": "@effect/language-service" | ||
| 21 | } | ||
| 22 | ] | ||
| 23 | }, | ||
| 24 | "include": ["src"] | ||
| 25 | } | ||