- 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 | 5 | "type": "module", |
| 6 | 6 | "dependencies": { |
| 7 | 7 | "@executor/plugin-openapi": "workspace:*", |
| 8 | + "@executor/ui": "workspace:*", | |
| 8 | 9 | "tailwindcss": "^4.1.10", |
| 9 | 10 | "@executor/react": "workspace:*", |
| 10 | 11 | "@executor/server": "workspace:*", |
| @@ -1,6 +1,6 @@ | ||
| 1 | 1 | import React from "react"; |
| 2 | 2 | import { createRoot } from "react-dom/client"; |
| 3 | −import "./styles.css"; | |
| 3 | +import "@executor/ui/globals.css"; | |
| 4 | 4 | import { App } from "./App"; |
| 5 | 5 | |
| 6 | 6 | const root = createRoot(document.getElementById("root")!); |
| @@ -22,10 +22,10 @@ export function SourcesPage() { · 21 unmodified lines | ||
| 22 | 22 | if (tools._tag !== "Success") return []; |
| 23 | 23 | const namespaces = new Map<string, number>(); |
| 24 | 24 | for (const tool of tools.value) { |
| 25 | − const ns = tool.tags.find( | |
| 26 | − (t) => t !== "openapi" && !sourcePlugins.some((p) => p.key === t), | |
| 27 | − ); | |
| 28 | − if (ns) { | |
| 25 | + if (!tool.tags.includes("openapi")) continue; | |
| 26 | + // Namespace is the last tag (after op tags and "openapi") | |
| 27 | + const ns = tool.tags[tool.tags.length - 1]; | |
| 28 | + if (ns && ns !== "openapi") { | |
| 29 | 29 | namespaces.set(ns, (namespaces.get(ns) ?? 0) + 1); |
| 30 | 30 | } |
| 31 | 31 | } |
| @@ -34,8 +34,9 @@ function SourceList() { · 33 unmodified lines | ||
| 34 | 34 | if (tools._tag !== "Success") return []; |
| 35 | 35 | const namespaces = new Map<string, number>(); |
| 36 | 36 | for (const tool of tools.value) { |
| 37 | − const ns = tool.tags.find((t) => t !== "openapi"); | |
| 38 | − if (ns && ns !== tool.tags[0]) { | |
| 37 | + if (!tool.tags.includes("openapi")) continue; | |
| 38 | + const ns = tool.tags[tool.tags.length - 1]; | |
| 39 | + if (ns && ns !== "openapi") { | |
| 39 | 40 | namespaces.set(ns, (namespaces.get(ns) ?? 0) + 1); |
| 40 | 41 | } |
| 41 | 42 | } |
| @@ -34,6 +34,7 @@ · 33 unmodified lines | ||
| 34 | 34 | "@executor/plugin-openapi": "workspace:*", |
| 35 | 35 | "@executor/react": "workspace:*", |
| 36 | 36 | "@executor/server": "workspace:*", |
| 37 | + "@executor/ui": "workspace:*", | |
| 37 | 38 | "@tanstack/react-router": "^1.168.10", |
| 38 | 39 | "react": "^19.1.0", |
| 39 | 40 | "react-dom": "^19.1.0", |
| @@ -190,6 +191,37 @@ · 150 unmodified lines | ||
| 190 | 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 | 226 | "catalog": { |
| 195 | 227 | "@effect/cluster": "^0.58.0", |
| @@ -243,12 +275,20 @@ · 47 unmodified lines | ||
| 243 | 275 | |
| 244 | 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 | 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 | 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 | 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 | 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 | 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 | 384 | "@executor/server": ["@executor/server@workspace:apps/server"], |
| 345 | 385 | |
| 386 | + "@executor/ui": ["@executor/ui@workspace:packages/ui"], | |
| 387 | + | |
| 346 | 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 | 400 | "@jitl/quickjs-ffi-types": ["@jitl/quickjs-ffi-types@0.31.0", "", {}, "sha512-1yrgvXlmXH2oNj3eFTrkwacGJbmM0crwipA3ohCrjv52gBeDaD7PsTvFYinlAnqU8iPME3LGP437yk05a2oejw=="], |
| 349 | 401 | |
| 350 | 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 | 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 | 646 | "@rolldown/pluginutils": ["@rolldown/pluginutils@1.0.0-beta.27", "", {}, "sha512-+d0F4MKMCbeVUJwG96uQ4SgAznZNSq93I3V+9NHA4OpvqG8mRCpGdKmK8l/dl02h2CCDHwW2FqilnTyDcAnqjA=="], |
| 473 | 647 | |
| 474 | 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 | 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 | 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 | 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 | 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 | 784 | "@types/deep-eql": ["@types/deep-eql@4.0.2", "", {}, "sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw=="], |
| 589 | 785 | |
| 590 | 786 | "@types/estree": ["@types/estree@1.0.8", "", {}, "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w=="], |
| @@ -597,6 +793,8 @@ · 6 unmodified lines | ||
| 597 | 793 | |
| 598 | 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 | 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 | 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 | 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 | 824 | "assertion-error": ["assertion-error@2.0.1", "", {}, "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA=="], |
| 625 | 825 | |
| 626 | 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 | 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 | 848 | "convert-source-map": ["convert-source-map@2.0.0", "", {}, "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg=="], |
| 643 | 849 | |
| 644 | 850 | "cookie-es": ["cookie-es@2.0.0", "", {}, "sha512-RAj4E421UYRgqokKUmotqAwuplYw15qtdXfY+hGzgCJ/MBjCVZcSoHK/kH9kocfjRjcDME7IiDWR/1WX1TM2Pg=="], |
| 645 | 851 | |
| 646 | 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 | 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 | 884 | "deep-eql": ["deep-eql@5.0.2", "", {}, "sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q=="], |
| 651 | 885 | |
| 652 | 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 | 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 | 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 | 900 | "enhanced-resolve": ["enhanced-resolve@5.20.1", "", { "dependencies": { "graceful-fs": "^4.2.4", "tapable": "^2.3.0" } }, "sha512-Qohcme7V1inbAfvjItgw0EaxVX5q2rdVEZHRBrEQdRZTssLDGsL8Lwrznl8oQ/6kuTJONLaDcGjkNP247XEhcA=="], |
| 659 | 901 | |
| 660 | 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 | 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 | 908 | "escalade": ["escalade@3.2.0", "", {}, "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA=="], |
| 665 | 909 | |
| 666 | 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 | 914 | "expect-type": ["expect-type@1.3.0", "", {}, "sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA=="], |
| 669 | 915 | |
| 670 | 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 | 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 | 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 | 940 | "is-extglob": ["is-extglob@2.1.1", "", {}, "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ=="], |
| 687 | 941 | |
| 688 | 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 | 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 | 990 | "magic-string": ["magic-string@0.30.21", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.5" } }, "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ=="], |
| 735 | 991 | |
| 736 | 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 | 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 | 1006 | "node-addon-api": ["node-addon-api@7.1.1", "", {}, "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ=="], |
| 749 | 1007 | |
| 750 | 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 | 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 | 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 | 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 | 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 | 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 | 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 | 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 | 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 | 1080 | "source-map-js": ["source-map-js@1.2.1", "", {}, "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA=="], |
| 795 | 1081 | |
| 796 | 1082 | "stackback": ["stackback@0.0.2", "", {}, "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw=="], |
| @@ -799,10 +1085,16 @@ · 2 unmodified lines | ||
| 799 | 1085 | |
| 800 | 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 | 1092 | "tailwindcss": ["tailwindcss@4.2.2", "", {}, "sha512-KWBIxs1Xb6NoLdMVqhbhgwZf2PGBpPEiwOqgI4pFIYbNTfBXiKYyWoTsXgBQ9WFg/OlhnvHaY+AEpW7wSmFo2Q=="], |
| 803 | 1093 | |
| 804 | 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 | 1098 | "tinybench": ["tinybench@2.9.0", "", {}, "sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg=="], |
| 807 | 1099 | |
| 808 | 1100 | "tinyexec": ["tinyexec@0.3.2", "", {}, "sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA=="], |
| @@ -815,6 +1107,8 @@ · 6 unmodified lines | ||
| 815 | 1107 | |
| 816 | 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 | 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 | 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 | 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 | 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 | 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 | 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 | 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 | 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 | 1150 | "@babel/code-frame/js-tokens": ["js-tokens@4.0.0", "", {}, "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="], |
| 847 | 1151 | |
| 848 | 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 | 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 | 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 | 5 | "packageManager": "bun@1.2.22", |
| 6 | 6 | "workspaces": [ |
| 7 | 7 | "packages/*/*", |
| 8 | + "packages/ui", | |
| 8 | 9 | "apps/*" |
| 9 | 10 | ], |
| 10 | 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 | 1 | @import "tailwindcss"; |
| 2 | 2 | |
| 3 | −@source "../../../packages/clients/react/src/**/*.{ts,tsx}"; | |
| 4 | −@source "../../../packages/plugins/openapi/src/react/**/*.{ts,tsx}"; | |
| 3 | +@custom-variant dark (&:is(.dark *)); | |
| 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 | 10 | @theme inline { |
| 7 | 11 | --font-sans: "DM Sans", ui-sans-serif, system-ui, sans-serif; |
| @@ -34,6 +38,11 @@ · 26 unmodified lines | ||
| 34 | 38 | --radius-md: calc(var(--radius) * 0.8); |
| 35 | 39 | --radius-lg: var(--radius); |
| 36 | 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 | 48 | /* ——— Light theme ——— */ |
| @@ -65,6 +74,11 @@ · 25 unmodified lines | ||
| 65 | 74 | |
| 66 | 75 | --scrollbar-thumb: oklch(0.78 0.005 260); |
| 67 | 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 | 84 | /* ——— Dark theme ——— */ |
| @@ -126,3 +140,14 @@ · 55 unmodified lines | ||
| 126 | 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 | +} | |