@multicomma/arkcn 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +78 -0
- package/bin/arkcn.mjs +78 -0
- package/cli/commands.mjs +251 -0
- package/cli/project.mjs +168 -0
- package/cli/registry.mjs +50 -0
- package/cli/ui.mjs +46 -0
- package/mcp/server.mjs +149 -0
- package/package.json +201 -0
- package/registry/base.css +680 -0
- package/registry/index.json +1833 -0
- package/registry/items/accordion.json +18 -0
- package/registry/items/activity-feed.json +18 -0
- package/registry/items/alert-dialog.json +18 -0
- package/registry/items/alert.json +17 -0
- package/registry/items/angle-slider.json +17 -0
- package/registry/items/app-shell.json +28 -0
- package/registry/items/aspect-ratio.json +13 -0
- package/registry/items/attachment.json +19 -0
- package/registry/items/avatar.json +17 -0
- package/registry/items/badge.json +18 -0
- package/registry/items/breadcrumb.json +18 -0
- package/registry/items/bubble.json +18 -0
- package/registry/items/button-group.json +19 -0
- package/registry/items/button.json +18 -0
- package/registry/items/calendar.json +19 -0
- package/registry/items/canvas.json +24 -0
- package/registry/items/card.json +15 -0
- package/registry/items/carousel.json +19 -0
- package/registry/items/cascader.json +23 -0
- package/registry/items/chart.json +17 -0
- package/registry/items/chat.json +23 -0
- package/registry/items/checkbox.json +18 -0
- package/registry/items/clipboard.json +19 -0
- package/registry/items/collapsible.json +15 -0
- package/registry/items/color-picker.json +19 -0
- package/registry/items/combobox.json +20 -0
- package/registry/items/command.json +21 -0
- package/registry/items/comment-thread.json +25 -0
- package/registry/items/context-menu.json +18 -0
- package/registry/items/controllable.json +14 -0
- package/registry/items/data-grid.json +24 -0
- package/registry/items/data-table-adapter.json +14 -0
- package/registry/items/data-table.json +32 -0
- package/registry/items/date-input.json +17 -0
- package/registry/items/dialog.json +19 -0
- package/registry/items/direction.json +13 -0
- package/registry/items/drag-preview.json +16 -0
- package/registry/items/drawer.json +18 -0
- package/registry/items/dropdown-menu.json +18 -0
- package/registry/items/editable.json +17 -0
- package/registry/items/empty.json +17 -0
- package/registry/items/field.json +19 -0
- package/registry/items/file-upload.json +19 -0
- package/registry/items/floating-panel.json +19 -0
- package/registry/items/floating-toolbar.json +16 -0
- package/registry/items/form.json +14 -0
- package/registry/items/format.json +15 -0
- package/registry/items/gantt.json +22 -0
- package/registry/items/history.json +14 -0
- package/registry/items/hotkeys.json +18 -0
- package/registry/items/hover-card.json +17 -0
- package/registry/items/image-cropper.json +17 -0
- package/registry/items/input-group.json +20 -0
- package/registry/items/input-otp.json +18 -0
- package/registry/items/input.json +15 -0
- package/registry/items/item.json +19 -0
- package/registry/items/json-tree-view.json +17 -0
- package/registry/items/kanban.json +26 -0
- package/registry/items/kbd.json +15 -0
- package/registry/items/label.json +15 -0
- package/registry/items/live-region.json +16 -0
- package/registry/items/marker.json +18 -0
- package/registry/items/marquee.json +17 -0
- package/registry/items/menubar.json +19 -0
- package/registry/items/message.json +15 -0
- package/registry/items/navigation-menu.json +19 -0
- package/registry/items/node-graph.json +22 -0
- package/registry/items/number-input.json +18 -0
- package/registry/items/pagination.json +18 -0
- package/registry/items/password-input.json +18 -0
- package/registry/items/popconfirm.json +20 -0
- package/registry/items/popover.json +18 -0
- package/registry/items/progress.json +17 -0
- package/registry/items/qr-code.json +17 -0
- package/registry/items/query-builder.json +23 -0
- package/registry/items/radio-group.json +17 -0
- package/registry/items/rating-group.json +18 -0
- package/registry/items/resizable.json +17 -0
- package/registry/items/rich-text-editor.json +37 -0
- package/registry/items/row-layout.json +15 -0
- package/registry/items/scheduler.json +23 -0
- package/registry/items/scroll-area.json +17 -0
- package/registry/items/segment-group.json +17 -0
- package/registry/items/select.json +19 -0
- package/registry/items/separator.json +15 -0
- package/registry/items/sheet.json +19 -0
- package/registry/items/sidebar.json +27 -0
- package/registry/items/signature-pad.json +19 -0
- package/registry/items/skeleton.json +15 -0
- package/registry/items/slider.json +17 -0
- package/registry/items/sonner.json +17 -0
- package/registry/items/spinner.json +17 -0
- package/registry/items/steps.json +19 -0
- package/registry/items/swap.json +17 -0
- package/registry/items/switch.json +17 -0
- package/registry/items/table.json +16 -0
- package/registry/items/tabs.json +18 -0
- package/registry/items/tags-input.json +18 -0
- package/registry/items/textarea.json +15 -0
- package/registry/items/time.json +14 -0
- package/registry/items/timer.json +18 -0
- package/registry/items/toc.json +17 -0
- package/registry/items/toggle-group.json +19 -0
- package/registry/items/toggle.json +18 -0
- package/registry/items/tooltip.json +17 -0
- package/registry/items/tour.json +19 -0
- package/registry/items/transfer-list.json +24 -0
- package/registry/items/tree-select.json +24 -0
- package/registry/items/tree-view.json +18 -0
- package/registry/items/use-mobile.json +13 -0
- package/registry/items/utils.json +17 -0
- package/registry/items/virtual-list.json +16 -0
- package/src/components/ui/accordion.tsx +111 -0
- package/src/components/ui/activity-feed.tsx +228 -0
- package/src/components/ui/alert-dialog.tsx +204 -0
- package/src/components/ui/alert.tsx +55 -0
- package/src/components/ui/angle-slider.tsx +117 -0
- package/src/components/ui/app-shell.tsx +985 -0
- package/src/components/ui/aspect-ratio.tsx +35 -0
- package/src/components/ui/attachment.tsx +193 -0
- package/src/components/ui/avatar.tsx +94 -0
- package/src/components/ui/badge.tsx +45 -0
- package/src/components/ui/breadcrumb.tsx +93 -0
- package/src/components/ui/bubble.tsx +119 -0
- package/src/components/ui/button-group.tsx +79 -0
- package/src/components/ui/button.tsx +65 -0
- package/src/components/ui/calendar.tsx +172 -0
- package/src/components/ui/canvas.tsx +723 -0
- package/src/components/ui/card.tsx +69 -0
- package/src/components/ui/carousel.tsx +228 -0
- package/src/components/ui/cascader.tsx +754 -0
- package/src/components/ui/chart.tsx +303 -0
- package/src/components/ui/chat.tsx +544 -0
- package/src/components/ui/checkbox.tsx +94 -0
- package/src/components/ui/clipboard.tsx +94 -0
- package/src/components/ui/collapsible.tsx +32 -0
- package/src/components/ui/color-picker.tsx +441 -0
- package/src/components/ui/combobox.tsx +400 -0
- package/src/components/ui/command.tsx +292 -0
- package/src/components/ui/comment-thread.tsx +923 -0
- package/src/components/ui/context-menu.tsx +331 -0
- package/src/components/ui/data-grid.tsx +1227 -0
- package/src/components/ui/data-table.tsx +993 -0
- package/src/components/ui/date-input.tsx +103 -0
- package/src/components/ui/dialog.tsx +159 -0
- package/src/components/ui/direction.tsx +32 -0
- package/src/components/ui/drawer.tsx +200 -0
- package/src/components/ui/dropdown-menu.tsx +329 -0
- package/src/components/ui/editable.tsx +90 -0
- package/src/components/ui/empty.tsx +86 -0
- package/src/components/ui/field.tsx +218 -0
- package/src/components/ui/file-upload.tsx +204 -0
- package/src/components/ui/floating-panel.tsx +199 -0
- package/src/components/ui/floating-toolbar.tsx +79 -0
- package/src/components/ui/format.tsx +22 -0
- package/src/components/ui/gantt.tsx +950 -0
- package/src/components/ui/hotkeys.tsx +340 -0
- package/src/components/ui/hover-card.tsx +83 -0
- package/src/components/ui/image-cropper.tsx +100 -0
- package/src/components/ui/input-group.tsx +133 -0
- package/src/components/ui/input-otp.tsx +82 -0
- package/src/components/ui/input.tsx +18 -0
- package/src/components/ui/item.tsx +174 -0
- package/src/components/ui/json-tree-view.tsx +37 -0
- package/src/components/ui/kanban.tsx +884 -0
- package/src/components/ui/kbd.tsx +20 -0
- package/src/components/ui/label.tsx +30 -0
- package/src/components/ui/live-region.tsx +54 -0
- package/src/components/ui/marker.tsx +66 -0
- package/src/components/ui/marquee.tsx +61 -0
- package/src/components/ui/menubar.tsx +456 -0
- package/src/components/ui/message.tsx +74 -0
- package/src/components/ui/navigation-menu.tsx +202 -0
- package/src/components/ui/node-graph.tsx +1723 -0
- package/src/components/ui/number-input.tsx +148 -0
- package/src/components/ui/pagination.tsx +88 -0
- package/src/components/ui/password-input.tsx +104 -0
- package/src/components/ui/popconfirm.tsx +149 -0
- package/src/components/ui/popover.tsx +126 -0
- package/src/components/ui/progress.tsx +114 -0
- package/src/components/ui/qr-code.tsx +51 -0
- package/src/components/ui/query-builder.tsx +938 -0
- package/src/components/ui/radio-group.tsx +108 -0
- package/src/components/ui/rating-group.tsx +91 -0
- package/src/components/ui/resizable.tsx +41 -0
- package/src/components/ui/rich-text-editor.tsx +845 -0
- package/src/components/ui/scheduler.tsx +1164 -0
- package/src/components/ui/scroll-area.tsx +82 -0
- package/src/components/ui/segment-group.tsx +95 -0
- package/src/components/ui/select.tsx +354 -0
- package/src/components/ui/separator.tsx +32 -0
- package/src/components/ui/sheet.tsx +130 -0
- package/src/components/ui/sidebar.tsx +665 -0
- package/src/components/ui/signature-pad.tsx +112 -0
- package/src/components/ui/skeleton.tsx +7 -0
- package/src/components/ui/slider.tsx +183 -0
- package/src/components/ui/sonner.tsx +37 -0
- package/src/components/ui/spinner.tsx +16 -0
- package/src/components/ui/steps.tsx +152 -0
- package/src/components/ui/swap.tsx +33 -0
- package/src/components/ui/switch.tsx +83 -0
- package/src/components/ui/table.tsx +72 -0
- package/src/components/ui/tabs.tsx +100 -0
- package/src/components/ui/tags-input.tsx +153 -0
- package/src/components/ui/textarea.tsx +17 -0
- package/src/components/ui/timer.tsx +67 -0
- package/src/components/ui/toc.tsx +64 -0
- package/src/components/ui/toggle-group.tsx +89 -0
- package/src/components/ui/toggle.tsx +46 -0
- package/src/components/ui/tooltip.tsx +113 -0
- package/src/components/ui/tour.tsx +168 -0
- package/src/components/ui/transfer-list.tsx +700 -0
- package/src/components/ui/tree-select.tsx +638 -0
- package/src/components/ui/tree-view.tsx +217 -0
- package/src/components/ui/virtual-list.tsx +343 -0
- package/src/hooks/use-mobile.ts +19 -0
- package/src/lib/controllable.ts +31 -0
- package/src/lib/data-table-adapter.ts +67 -0
- package/src/lib/drag-preview.ts +39 -0
- package/src/lib/form.ts +39 -0
- package/src/lib/history.ts +55 -0
- package/src/lib/row-layout.ts +81 -0
- package/src/lib/table.ts +483 -0
- package/src/lib/time.ts +37 -0
- package/src/lib/utils.ts +6 -0
- package/src/styles/arkcn.css +764 -0
- package/src/styles/index.css +3 -0
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "accordion",
|
|
3
|
+
"type": "ui",
|
|
4
|
+
"description": "",
|
|
5
|
+
"dependencies": {
|
|
6
|
+
"@ark-ui/react": "^5.39.1",
|
|
7
|
+
"lucide-react": "^1.41.0"
|
|
8
|
+
},
|
|
9
|
+
"registryDependencies": [
|
|
10
|
+
"utils"
|
|
11
|
+
],
|
|
12
|
+
"files": [
|
|
13
|
+
{
|
|
14
|
+
"path": "components/ui/accordion.tsx",
|
|
15
|
+
"content": "import * as React from \"react\"\nimport { cn } from \"@/lib/utils\"\nimport { Accordion as AccordionPrimitive } from \"@ark-ui/react\"\nimport { ChevronDownIcon, ChevronUpIcon } from \"lucide-react\"\n\nfunction Accordion({\n className,\n lazyMount = true,\n unmountOnExit = true,\n ...props\n}: React.ComponentProps<typeof AccordionPrimitive.Root>) {\n return (\n <AccordionPrimitive.Root\n data-slot=\"accordion\"\n lazyMount={lazyMount}\n unmountOnExit={unmountOnExit}\n className={cn(\"flex w-full flex-col\", className)}\n {...props}\n />\n )\n}\n\nfunction AccordionContext({ ...props }: React.ComponentProps<typeof AccordionPrimitive.Context>) {\n return <AccordionPrimitive.Context {...props} />\n}\n\nfunction AccordionItem({ className, ...props }: React.ComponentProps<typeof AccordionPrimitive.Item>) {\n return (\n <AccordionPrimitive.Item data-slot=\"accordion-item\" className={cn(\"not-last:border-b\", className)} {...props} />\n )\n}\n\nfunction AccordionItemContext({ ...props }: React.ComponentProps<typeof AccordionPrimitive.ItemContext>) {\n return <AccordionPrimitive.ItemContext {...props} />\n}\n\nfunction AccordionTrigger({\n className,\n children,\n ...props\n}: React.ComponentProps<typeof AccordionPrimitive.ItemTrigger>) {\n return (\n <AccordionPrimitive.ItemTrigger\n data-slot=\"accordion-trigger\"\n className={cn(\n \"group/accordion-trigger relative flex w-full flex-1 items-start justify-between rounded-lg border border-transparent py-2.5 text-left text-sm font-medium transition-all outline-none hover:underline focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50 focus-visible:after:border-ring disabled:pointer-events-none disabled:opacity-50 **:data-[slot=accordion-trigger-icon]:ml-auto **:data-[slot=accordion-trigger-icon]:size-4 **:data-[slot=accordion-trigger-icon]:text-muted-foreground\",\n className\n )}\n {...props}\n >\n {children}\n <ChevronDownIcon\n data-slot=\"accordion-trigger-icon\"\n className=\"pointer-events-none shrink-0 group-aria-expanded/accordion-trigger:hidden\"\n />\n <ChevronUpIcon\n data-slot=\"accordion-trigger-icon\"\n className=\"pointer-events-none hidden shrink-0 group-aria-expanded/accordion-trigger:inline\"\n />\n </AccordionPrimitive.ItemTrigger>\n )\n}\n\nfunction AccordionItemIndicator({\n className,\n ...props\n}: React.ComponentProps<typeof AccordionPrimitive.ItemIndicator>) {\n return (\n <AccordionPrimitive.ItemIndicator\n data-slot=\"accordion-item-indicator\"\n className={cn(\n \"ml-auto size-4 shrink-0 text-muted-foreground transition-transform data-open:rotate-180\",\n className\n )}\n {...props}\n />\n )\n}\n\nfunction AccordionContent({\n className,\n children,\n ...props\n}: React.ComponentProps<typeof AccordionPrimitive.ItemContent>) {\n return (\n <AccordionPrimitive.ItemContent\n data-slot=\"accordion-content\"\n className=\"overflow-hidden text-sm [--accordion-panel-height:var(--height)] data-open:animate-accordion-down data-closed:animate-accordion-up\"\n {...props}\n >\n <div\n className={cn(\n \"pt-0 pb-2.5 [&_a]:underline [&_a]:underline-offset-3 [&_a]:hover:text-foreground [&_p:not(:last-child)]:mb-4\",\n className\n )}\n >\n {children}\n </div>\n </AccordionPrimitive.ItemContent>\n )\n}\n\nexport {\n Accordion,\n AccordionContent,\n AccordionContext,\n AccordionItem,\n AccordionItemContext,\n AccordionItemIndicator,\n AccordionTrigger,\n}\n"
|
|
16
|
+
}
|
|
17
|
+
]
|
|
18
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "activity-feed",
|
|
3
|
+
"type": "ui",
|
|
4
|
+
"description": "ActivityFeed — a compositional, data-agnostic timeline of events. The consumer maps its events to items; the feed adds the connector line, the marker column, relative times and the WAI-ARIA feed pattern (articles are focusable; PageUp/PageD",
|
|
5
|
+
"dependencies": {},
|
|
6
|
+
"registryDependencies": [
|
|
7
|
+
"button",
|
|
8
|
+
"time",
|
|
9
|
+
"utils"
|
|
10
|
+
],
|
|
11
|
+
"files": [
|
|
12
|
+
{
|
|
13
|
+
"path": "components/ui/activity-feed.tsx",
|
|
14
|
+
"content": "import * as React from \"react\"\nimport { Button } from \"@/components/ui/button\"\nimport { formatRelativeTime } from \"@/lib/time\"\nimport { cn } from \"@/lib/utils\"\n\n/**\n * ActivityFeed — a compositional, data-agnostic timeline of events. The\n * consumer maps its events to items; the feed adds the connector line, the\n * marker column, relative times and the WAI-ARIA feed pattern (articles are\n * focusable; PageUp/PageDown move between them, Ctrl+Home/End jump).\n *\n * Anatomy:\n * ActivityFeed\n * ActivityFeedGroup > ActivityFeedGroupLabel + ActivityFeedItems\n * ActivityFeedItem value=…\n * ActivityFeedItemMarker dot / icon / avatar on the line\n * ActivityFeedItemContent\n * ActivityFeedItemHeader > ActivityFeedItemActor … ActivityFeedItemTime date=…\n * ActivityFeedItemBody\n * ActivityFeedItemActions\n * ActivityFeedLoadMoreTrigger / ActivityFeedEmpty\n */\n\nfunction ActivityFeed({ className, busy, onKeyDown, ...props }: React.ComponentProps<\"div\"> & { busy?: boolean }) {\n const ref = React.useRef<HTMLDivElement>(null)\n return (\n <div\n ref={ref}\n data-slot=\"activity-feed\"\n role=\"feed\"\n aria-busy={busy || undefined}\n className={cn(\"flex flex-col gap-6\", className)}\n onKeyDown={(event) => {\n onKeyDown?.(event)\n if (event.defaultPrevented) return\n const articles = Array.from(ref.current?.querySelectorAll<HTMLElement>(\"[data-slot=activity-feed-item]\") ?? [])\n const current = (event.target as HTMLElement).closest<HTMLElement>(\"[data-slot=activity-feed-item]\")\n const index = current ? articles.indexOf(current) : -1\n const meta = event.metaKey || event.ctrlKey\n let next: number | null = null\n if (event.key === \"PageDown\") next = Math.min(articles.length - 1, index + 1)\n else if (event.key === \"PageUp\") next = Math.max(0, index - 1)\n else if (event.key === \"Home\" && meta) next = 0\n else if (event.key === \"End\" && meta) next = articles.length - 1\n if (next === null || !articles[next]) return\n event.preventDefault()\n articles[next].focus()\n }}\n {...props}\n />\n )\n}\n\nfunction ActivityFeedGroup({ className, ...props }: React.ComponentProps<\"section\">) {\n return <section data-slot=\"activity-feed-group\" className={cn(\"flex flex-col gap-3\", className)} {...props} />\n}\n\nfunction ActivityFeedGroupLabel({ className, ...props }: React.ComponentProps<\"h3\">) {\n return (\n <h3\n data-slot=\"activity-feed-group-label\"\n className={cn(\"text-xs font-medium tracking-wide text-muted-foreground uppercase\", className)}\n {...props}\n />\n )\n}\n\n/** The list; draws the vertical connector behind the markers. */\nfunction ActivityFeedItems({ className, ...props }: React.ComponentProps<\"ol\">) {\n return (\n <ol\n data-slot=\"activity-feed-items\"\n className={cn(\n \"relative flex flex-col gap-5 before:absolute before:inset-y-2 before:inset-s-4 before:w-px before:-translate-x-1/2 before:bg-border\",\n className\n )}\n {...props}\n />\n )\n}\n\nfunction ActivityFeedItem({ value, className, ...props }: React.ComponentProps<\"li\"> & { value: string }) {\n return (\n <li\n data-slot=\"activity-feed-item\"\n data-value={value}\n role=\"article\"\n tabIndex={0}\n className={cn(\n \"group/activity relative flex gap-3 rounded-lg outline-none focus-visible:ring-2 focus-visible:ring-ring/50\",\n className\n )}\n {...props}\n />\n )\n}\n\n/** Sits on the line: pass an icon, an Avatar, or nothing for a dot. */\nfunction ActivityFeedItemMarker({ className, children, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"activity-feed-item-marker\"\n className={cn(\n \"relative z-10 flex size-8 shrink-0 items-center justify-center rounded-full bg-background ring-4 ring-background\",\n \"[&>svg]:size-4 [&>svg]:text-muted-foreground\",\n !children && \"after:size-2 after:rounded-full after:bg-muted-foreground/60\",\n children && \"border bg-muted\",\n className\n )}\n {...props}\n >\n {children}\n </div>\n )\n}\n\nfunction ActivityFeedItemContent({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"activity-feed-item-content\"\n className={cn(\"flex min-w-0 flex-1 flex-col gap-1.5 pt-1.5\", className)}\n {...props}\n />\n )\n}\n\nfunction ActivityFeedItemHeader({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"activity-feed-item-header\"\n className={cn(\"flex flex-wrap items-baseline gap-x-1.5 gap-y-0.5 text-sm text-muted-foreground\", className)}\n {...props}\n />\n )\n}\n\nfunction ActivityFeedItemActor({ className, ...props }: React.ComponentProps<\"span\">) {\n return (\n <span data-slot=\"activity-feed-item-actor\" className={cn(\"font-medium text-foreground\", className)} {...props} />\n )\n}\n\n/** `<time>` with a relative label by default; the full date is in the title. */\nfunction ActivityFeedItemTime({\n date,\n now,\n className,\n children,\n ...props\n}: Omit<React.ComponentProps<\"time\">, \"dateTime\"> & { date: Date; now?: Date }) {\n return (\n <time\n data-slot=\"activity-feed-item-time\"\n dateTime={date.toISOString()}\n title={date.toLocaleString()}\n className={cn(\"text-xs whitespace-nowrap text-muted-foreground/80\", className)}\n {...props}\n >\n {children ?? formatRelativeTime(date, { now })}\n </time>\n )\n}\n\n/** Optional detail block: a quote, a diff, a preview card. */\nfunction ActivityFeedItemBody({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"activity-feed-item-body\"\n className={cn(\"rounded-lg border bg-muted/40 px-3 py-2 text-sm\", className)}\n {...props}\n />\n )\n}\n\nfunction ActivityFeedItemActions({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"activity-feed-item-actions\"\n className={cn(\"flex items-center gap-1 text-xs\", className)}\n {...props}\n />\n )\n}\n\nfunction ActivityFeedLoadMoreTrigger({ asChild, children, className, ...props }: React.ComponentProps<typeof Button>) {\n return (\n <Button\n data-slot=\"activity-feed-load-more-trigger\"\n variant=\"outline\"\n size=\"sm\"\n asChild={asChild}\n className={cn(\"self-center\", className)}\n {...props}\n >\n {asChild ? children : (children ?? \"Load older activity\")}\n </Button>\n )\n}\n\nfunction ActivityFeedEmpty({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"activity-feed-empty\"\n className={cn(\n \"flex h-32 flex-col items-center justify-center gap-1 rounded-lg border border-dashed text-sm text-muted-foreground\",\n className\n )}\n {...props}\n />\n )\n}\n\nexport {\n ActivityFeed,\n ActivityFeedGroup,\n ActivityFeedGroupLabel,\n ActivityFeedItems,\n ActivityFeedItem,\n ActivityFeedItemMarker,\n ActivityFeedItemContent,\n ActivityFeedItemHeader,\n ActivityFeedItemActor,\n ActivityFeedItemTime,\n ActivityFeedItemBody,\n ActivityFeedItemActions,\n ActivityFeedLoadMoreTrigger,\n ActivityFeedEmpty,\n}\n"
|
|
15
|
+
}
|
|
16
|
+
],
|
|
17
|
+
"docs": "## Activity feed and comments\n`src/components/ui/activity-feed.tsx` is a compositional timeline of events on the WAI-ARIA feed\npattern (`role=\"feed\"`, focusable articles, PageUp/PageDown move, Ctrl+Home/End jump):\n`ActivityFeed` > `ActivityFeedGroup` > `ActivityFeedGroupLabel` + `ActivityFeedItems` (draws the\nconnector line) > `ActivityFeedItem value=` > `ActivityFeedItemMarker` (dot by default; pass an\nicon or an Avatar) + `ActivityFeedItemContent` > `ActivityFeedItemHeader` > `ActivityFeedItemActor`,\n`ActivityFeedItemTime date=` (`<time>` with a relative label from `src/lib/time.ts`\n`formatRelativeTime`; full date in the title), `ActivityFeedItemBody`, `ActivityFeedItemActions`;\nplus `ActivityFeedLoadMoreTrigger` and `ActivityFeedEmpty`. Data, grouping and read state are the\nconsumer's.\n`src/components/ui/comment-thread.tsx` is compositional comments with replies, reactions and a\nmentions composer. `CommentThread { people, currentUserId, replyTo/onReplyToChange }` owns only\nwhich comment is being replied to or edited (`useCommentThread()` → `replyTo`, `editing`, setters).\nParts: `CommentList` > `Comment value= authorId=` (`data-own/replying/editing/depth`) >\n`CommentAvatar` (initials from `people`) + `CommentContent` > `CommentHeader` > `CommentAuthor`,\n`CommentTime date=`, `CommentMeta`; `CommentBody text=` (plain text with `@Full Name` mentions\nhighlighted as `CommentMention`, `data-self` for the current user); `CommentReactions` >\n`CommentReaction emoji= count= active=`; `CommentActions` (hover-revealed) > `CommentReplyTrigger`,\n`CommentEditTrigger`; `CommentReplies` (nested list with a guide line); `CommentEmpty`.\n`CommentComposer { people, value/onValueChange, onSubmit({ text, mentions }), onCancel }` >\n`CommentComposerReplyingTo` (render prop gets the comment id), `CommentComposerInput` (a\ncontenteditable, not a textarea: picked mentions become atomic grey chips\n`[data-slot=comment-mention-chip]` that one Backspace removes, while `value` stays plain\n`@Full Name` text and `defaultValue`/`value` text is hydrated back into chips;\n`@query` at the caret opens `CommentComposerMentionList` (a portaled Popover anchored to the input, focus stays in the textarea, so no `overflow-hidden` ancestor clips it and nothing shifts), arrows/Enter/Tab pick, Escape closes,\n⌘/Ctrl+Enter submits, `aria-activedescendant` wired), `CommentComposerFooter` >\n`CommentComposerHint`, `CommentComposerCancelTrigger`, `CommentComposerSubmitTrigger`. Mentions are\nplain `@Full Name` text; `extractMentions(text, people)` returns ids. The same composer edits in\nplace (`defaultValue`, Save). `src/demo/activity/` is the reference (`/activity`): grouped feed\nwith All/Mentions/Comments filter, unread dots, load more, and a ticket thread with nested\nreplies, reactions, edit/delete of own comments (Popconfirm), and posting that also prepends a\nfeed item."
|
|
18
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "alert-dialog",
|
|
3
|
+
"type": "ui",
|
|
4
|
+
"description": "",
|
|
5
|
+
"dependencies": {
|
|
6
|
+
"@ark-ui/react": "^5.39.1"
|
|
7
|
+
},
|
|
8
|
+
"registryDependencies": [
|
|
9
|
+
"button",
|
|
10
|
+
"utils"
|
|
11
|
+
],
|
|
12
|
+
"files": [
|
|
13
|
+
{
|
|
14
|
+
"path": "components/ui/alert-dialog.tsx",
|
|
15
|
+
"content": "import * as React from \"react\"\nimport { cn } from \"@/lib/utils\"\nimport { Dialog as AlertDialogPrimitive, Portal as PortalPrimitive } from \"@ark-ui/react\"\n\nimport { Button } from \"@/components/ui/button\"\n\nfunction getDefaultInitialFocusEl() {\n return document.querySelector<HTMLElement>(\n '[data-slot=\"alert-dialog-content\"][data-state=\"open\"] [data-slot=\"alert-dialog-cancel\"]'\n )\n}\n\nfunction AlertDialog({\n role = \"alertdialog\",\n closeOnInteractOutside = false,\n initialFocusEl = getDefaultInitialFocusEl,\n lazyMount = true,\n unmountOnExit = true,\n ...props\n}: React.ComponentProps<typeof AlertDialogPrimitive.Root>) {\n return (\n <AlertDialogPrimitive.Root\n role={role}\n closeOnInteractOutside={closeOnInteractOutside}\n initialFocusEl={initialFocusEl}\n lazyMount={lazyMount}\n unmountOnExit={unmountOnExit}\n {...props}\n />\n )\n}\n\nfunction AlertDialogTrigger({ ...props }: React.ComponentProps<typeof AlertDialogPrimitive.Trigger>) {\n return <AlertDialogPrimitive.Trigger data-slot=\"alert-dialog-trigger\" {...props} />\n}\n\nfunction AlertDialogPortal({ ...props }: React.ComponentProps<typeof PortalPrimitive>) {\n return <PortalPrimitive {...props} />\n}\n\nfunction AlertDialogContext({ ...props }: React.ComponentProps<typeof AlertDialogPrimitive.Context>) {\n return <AlertDialogPrimitive.Context {...props} />\n}\n\nfunction AlertDialogOverlay({ className, ...props }: React.ComponentProps<typeof AlertDialogPrimitive.Backdrop>) {\n return (\n <AlertDialogPrimitive.Backdrop\n data-slot=\"alert-dialog-overlay\"\n className={cn(\n \"fixed inset-0 z-50 bg-black/10 duration-100 supports-backdrop-filter:backdrop-blur-xs data-open:animate-in data-open:fade-in-0 data-closed:animate-out data-closed:fade-out-0\",\n className\n )}\n {...props}\n />\n )\n}\n\nfunction AlertDialogPositioner({ className, ...props }: React.ComponentProps<typeof AlertDialogPrimitive.Positioner>) {\n return (\n <AlertDialogPrimitive.Positioner\n data-slot=\"alert-dialog-positioner\"\n className={cn(\"fixed inset-0 z-50 flex items-center justify-center\", className)}\n {...props}\n />\n )\n}\n\nfunction AlertDialogContent({\n className,\n size = \"default\",\n ...props\n}: React.ComponentProps<typeof AlertDialogPrimitive.Content> & {\n size?: \"default\" | \"sm\"\n}) {\n return (\n <AlertDialogPortal>\n <AlertDialogOverlay />\n <AlertDialogPositioner>\n <AlertDialogPrimitive.Content\n data-slot=\"alert-dialog-content\"\n data-size={size}\n className={cn(\n \"group/alert-dialog-content relative grid w-full gap-4 rounded-xl bg-popover p-4 text-popover-foreground ring-1 ring-foreground/10 duration-100 outline-none data-[size=default]:max-w-xs data-[size=sm]:max-w-xs data-[size=default]:sm:max-w-sm 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\",\n className\n )}\n {...props}\n />\n </AlertDialogPositioner>\n </AlertDialogPortal>\n )\n}\n\nfunction AlertDialogHeader({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"alert-dialog-header\"\n className={cn(\n \"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-4 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]\",\n className\n )}\n {...props}\n />\n )\n}\n\nfunction AlertDialogFooter({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"alert-dialog-footer\"\n className={cn(\n \"-mx-4 -mb-4 flex flex-col-reverse gap-2 rounded-b-xl border-t bg-muted/50 p-4 group-data-[size=sm]/alert-dialog-content:grid group-data-[size=sm]/alert-dialog-content:grid-cols-2 sm:flex-row sm:justify-end\",\n className\n )}\n {...props}\n />\n )\n}\n\nfunction AlertDialogMedia({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"alert-dialog-media\"\n className={cn(\n \"mb-2 inline-flex size-10 items-center justify-center rounded-md bg-muted sm:group-data-[size=default]/alert-dialog-content:row-span-2 *:[svg:not([class*='size-'])]:size-6\",\n className\n )}\n {...props}\n />\n )\n}\n\nfunction AlertDialogTitle({ className, ...props }: React.ComponentProps<typeof AlertDialogPrimitive.Title>) {\n return (\n <AlertDialogPrimitive.Title\n data-slot=\"alert-dialog-title\"\n className={cn(\n \"font-heading text-base font-medium sm:group-data-[size=default]/alert-dialog-content:group-has-data-[slot=alert-dialog-media]/alert-dialog-content:col-start-2\",\n className\n )}\n {...props}\n />\n )\n}\n\nfunction AlertDialogDescription({\n className,\n ...props\n}: React.ComponentProps<typeof AlertDialogPrimitive.Description>) {\n return (\n <AlertDialogPrimitive.Description\n data-slot=\"alert-dialog-description\"\n className={cn(\n \"text-sm text-balance text-muted-foreground md:text-pretty *:[a]:underline *:[a]:underline-offset-3 *:[a]:hover:text-foreground\",\n className\n )}\n {...props}\n />\n )\n}\n\nfunction AlertDialogAction({\n className,\n variant = \"default\",\n size = \"default\",\n ...props\n}: React.ComponentProps<typeof AlertDialogPrimitive.CloseTrigger> &\n Pick<React.ComponentProps<typeof Button>, \"variant\" | \"size\">) {\n return (\n <Button variant={variant} size={size} asChild>\n <AlertDialogPrimitive.CloseTrigger data-slot=\"alert-dialog-action\" className={cn(className)} {...props} />\n </Button>\n )\n}\n\nfunction AlertDialogCancel({\n className,\n variant = \"outline\",\n size = \"default\",\n ...props\n}: React.ComponentProps<typeof AlertDialogPrimitive.CloseTrigger> &\n Pick<React.ComponentProps<typeof Button>, \"variant\" | \"size\">) {\n return (\n <Button variant={variant} size={size} asChild>\n <AlertDialogPrimitive.CloseTrigger data-slot=\"alert-dialog-cancel\" className={cn(className)} {...props} />\n </Button>\n )\n}\n\nexport {\n AlertDialog,\n AlertDialogAction,\n AlertDialogCancel,\n AlertDialogContent,\n AlertDialogContext,\n AlertDialogDescription,\n AlertDialogFooter,\n AlertDialogHeader,\n AlertDialogMedia,\n AlertDialogOverlay,\n AlertDialogPortal,\n AlertDialogPositioner,\n AlertDialogTitle,\n AlertDialogTrigger,\n}\n"
|
|
16
|
+
}
|
|
17
|
+
]
|
|
18
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "alert",
|
|
3
|
+
"type": "ui",
|
|
4
|
+
"description": "",
|
|
5
|
+
"dependencies": {
|
|
6
|
+
"class-variance-authority": "^0.7.1"
|
|
7
|
+
},
|
|
8
|
+
"registryDependencies": [
|
|
9
|
+
"utils"
|
|
10
|
+
],
|
|
11
|
+
"files": [
|
|
12
|
+
{
|
|
13
|
+
"path": "components/ui/alert.tsx",
|
|
14
|
+
"content": "import * as React from \"react\"\nimport { cva, type VariantProps } from \"class-variance-authority\"\nimport { cn } from \"@/lib/utils\"\n\nconst alertVariants = cva(\n \"group/alert relative grid w-full gap-0.5 rounded-lg border px-2.5 py-2 text-left text-sm has-data-[slot=alert-action]:relative has-data-[slot=alert-action]:pr-18 has-[>svg]:grid-cols-[auto_1fr] has-[>svg]:gap-x-2 *:[svg]:row-span-2 *:[svg]:translate-y-0.5 *:[svg]:text-current *:[svg:not([class*='size-'])]:size-4\",\n {\n variants: {\n variant: {\n default: \"bg-card text-card-foreground\",\n destructive:\n \"bg-card text-destructive *:data-[slot=alert-description]:text-destructive/90 *:[svg]:text-current\",\n },\n },\n defaultVariants: {\n variant: \"default\",\n },\n }\n)\n\nfunction Alert({ className, variant, ...props }: React.ComponentProps<\"div\"> & VariantProps<typeof alertVariants>) {\n return <div data-slot=\"alert\" role=\"alert\" className={cn(alertVariants({ variant }), className)} {...props} />\n}\n\nfunction AlertTitle({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"alert-title\"\n className={cn(\n \"font-medium group-has-[>svg]/alert:col-start-2 [&_a]:underline [&_a]:underline-offset-3 [&_a]:hover:text-foreground\",\n className\n )}\n {...props}\n />\n )\n}\n\nfunction AlertDescription({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"alert-description\"\n className={cn(\n \"text-sm text-balance text-muted-foreground md:text-pretty [&_a]:underline [&_a]:underline-offset-3 [&_a]:hover:text-foreground [&_p:not(:last-child)]:mb-4\",\n className\n )}\n {...props}\n />\n )\n}\n\nfunction AlertAction({ className, ...props }: React.ComponentProps<\"div\">) {\n return <div data-slot=\"alert-action\" className={cn(\"absolute top-2 right-2\", className)} {...props} />\n}\n\nexport { Alert, AlertTitle, AlertDescription, AlertAction }\n"
|
|
15
|
+
}
|
|
16
|
+
]
|
|
17
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "angle-slider",
|
|
3
|
+
"type": "ui",
|
|
4
|
+
"description": "",
|
|
5
|
+
"dependencies": {
|
|
6
|
+
"@ark-ui/react": "^5.39.1"
|
|
7
|
+
},
|
|
8
|
+
"registryDependencies": [
|
|
9
|
+
"utils"
|
|
10
|
+
],
|
|
11
|
+
"files": [
|
|
12
|
+
{
|
|
13
|
+
"path": "components/ui/angle-slider.tsx",
|
|
14
|
+
"content": "\"use client\"\n\nimport * as React from \"react\"\nimport { cn } from \"@/lib/utils\"\nimport { AngleSlider as AngleSliderPrimitive } from \"@ark-ui/react\"\n\nfunction AngleSlider({ className, children, ...props }: React.ComponentProps<typeof AngleSliderPrimitive.Root>) {\n return (\n <AngleSliderPrimitive.Root\n data-slot=\"angle-slider\"\n className={cn(\"inline-flex flex-col items-center gap-2\", className)}\n {...props}\n >\n {children ?? (\n <>\n <AngleSliderControl>\n <AngleSliderThumb />\n </AngleSliderControl>\n <AngleSliderValueText />\n <AngleSliderHiddenInput />\n </>\n )}\n </AngleSliderPrimitive.Root>\n )\n}\n\nfunction AngleSliderContext({ ...props }: React.ComponentProps<typeof AngleSliderPrimitive.Context>) {\n return <AngleSliderPrimitive.Context {...props} />\n}\n\nfunction AngleSliderLabel({ className, ...props }: React.ComponentProps<typeof AngleSliderPrimitive.Label>) {\n return (\n <AngleSliderPrimitive.Label\n data-slot=\"angle-slider-label\"\n className={cn(\"text-sm font-medium select-none\", className)}\n {...props}\n />\n )\n}\n\nfunction AngleSliderControl({ className, ...props }: React.ComponentProps<typeof AngleSliderPrimitive.Control>) {\n return (\n <AngleSliderPrimitive.Control\n data-slot=\"angle-slider-control\"\n className={cn(\n \"relative size-24 rounded-full border border-input bg-muted/50 outline-none focus-visible:ring-3 focus-visible:ring-ring/50 data-disabled:opacity-50\",\n className\n )}\n {...props}\n />\n )\n}\n\nfunction AngleSliderThumb({ className, ...props }: React.ComponentProps<typeof AngleSliderPrimitive.Thumb>) {\n return (\n <AngleSliderPrimitive.Thumb\n data-slot=\"angle-slider-thumb\"\n className={cn(\n \"absolute inset-0 m-auto h-full w-0.5 origin-center rotate-(--angle) after:absolute after:top-1 after:left-1/2 after:size-3 after:-translate-x-1/2 after:rounded-full after:border after:border-ring after:bg-white\",\n className\n )}\n {...props}\n />\n )\n}\n\nfunction AngleSliderMarkerGroup({\n className,\n ...props\n}: React.ComponentProps<typeof AngleSliderPrimitive.MarkerGroup>) {\n return (\n <AngleSliderPrimitive.MarkerGroup\n data-slot=\"angle-slider-marker-group\"\n className={cn(\"pointer-events-none absolute inset-0\", className)}\n {...props}\n />\n )\n}\n\nfunction AngleSliderMarker({ className, ...props }: React.ComponentProps<typeof AngleSliderPrimitive.Marker>) {\n return (\n <AngleSliderPrimitive.Marker\n data-slot=\"angle-slider-marker\"\n className={cn(\n \"absolute inset-0 m-auto h-full w-px origin-center rotate-(--marker-value) before:absolute before:top-0 before:left-0 before:h-1.5 before:w-px before:bg-border data-[state=under-value]:before:bg-primary\",\n className\n )}\n {...props}\n />\n )\n}\n\nfunction AngleSliderValueText({ className, ...props }: React.ComponentProps<typeof AngleSliderPrimitive.ValueText>) {\n return (\n <AngleSliderPrimitive.ValueText\n data-slot=\"angle-slider-value-text\"\n className={cn(\"text-sm text-muted-foreground tabular-nums\", className)}\n {...props}\n />\n )\n}\n\nfunction AngleSliderHiddenInput({ ...props }: React.ComponentProps<typeof AngleSliderPrimitive.HiddenInput>) {\n return <AngleSliderPrimitive.HiddenInput {...props} />\n}\n\nexport {\n AngleSlider,\n AngleSliderContext,\n AngleSliderControl,\n AngleSliderHiddenInput,\n AngleSliderLabel,\n AngleSliderMarker,\n AngleSliderMarkerGroup,\n AngleSliderThumb,\n AngleSliderValueText,\n}\n"
|
|
15
|
+
}
|
|
16
|
+
]
|
|
17
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "app-shell",
|
|
3
|
+
"type": "ui",
|
|
4
|
+
"description": "`src/components/ui/app-shell.tsx` is a compositional, router-agnostic shell built on `sidebar.tsx` (shadcn-admin layout): `AppShell` (context: sidebar variant/collapsible, search open state, `searchShortcut` for cmd/ctrl+K), `AppShellSideba",
|
|
5
|
+
"dependencies": {
|
|
6
|
+
"lucide-react": "^1.41.0"
|
|
7
|
+
},
|
|
8
|
+
"registryDependencies": [
|
|
9
|
+
"avatar",
|
|
10
|
+
"badge",
|
|
11
|
+
"button",
|
|
12
|
+
"collapsible",
|
|
13
|
+
"command",
|
|
14
|
+
"dropdown-menu",
|
|
15
|
+
"kbd",
|
|
16
|
+
"popover",
|
|
17
|
+
"separator",
|
|
18
|
+
"sidebar",
|
|
19
|
+
"utils"
|
|
20
|
+
],
|
|
21
|
+
"files": [
|
|
22
|
+
{
|
|
23
|
+
"path": "components/ui/app-shell.tsx",
|
|
24
|
+
"content": "\"use client\"\n\nimport * as React from \"react\"\nimport {\n BellIcon,\n CheckIcon,\n ChevronRightIcon,\n ChevronsUpDownIcon,\n MenuIcon,\n MoonIcon,\n SearchIcon,\n SunIcon,\n} from \"lucide-react\"\nimport { cn } from \"@/lib/utils\"\n\nimport { Avatar, AvatarFallback, AvatarImage } from \"@/components/ui/avatar\"\nimport { Badge } from \"@/components/ui/badge\"\nimport { Button } from \"@/components/ui/button\"\nimport { Collapsible, CollapsibleContent, CollapsibleTrigger } from \"@/components/ui/collapsible\"\nimport { CommandDialog } from \"@/components/ui/command\"\nimport {\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuGroup,\n DropdownMenuItem,\n DropdownMenuLabel,\n DropdownMenuSeparator,\n DropdownMenuTrigger,\n} from \"@/components/ui/dropdown-menu\"\nimport { Kbd } from \"@/components/ui/kbd\"\nimport { Popover, PopoverContent, PopoverTrigger } from \"@/components/ui/popover\"\nimport { Separator } from \"@/components/ui/separator\"\nimport {\n Sidebar,\n SidebarContent,\n SidebarFooter,\n SidebarGroup,\n SidebarGroupLabel,\n SidebarHeader,\n SidebarInset,\n SidebarMenu,\n SidebarMenuButton,\n SidebarMenuItem,\n SidebarMenuSub,\n SidebarMenuSubButton,\n SidebarMenuSubItem,\n SidebarProvider,\n SidebarRail,\n SidebarTrigger,\n useSidebar,\n} from \"@/components/ui/sidebar\"\n\n/* -------------------------------------------------------------------------- */\n/* Root */\n/* -------------------------------------------------------------------------- */\n\ntype SidebarVariant = \"sidebar\" | \"floating\" | \"inset\"\ntype SidebarCollapsible = \"offcanvas\" | \"icon\" | \"none\"\n\ntype AppShellContextValue = {\n variant: SidebarVariant\n setVariant: (variant: SidebarVariant) => void\n collapsible: SidebarCollapsible\n setCollapsible: (collapsible: SidebarCollapsible) => void\n searchOpen: boolean\n setSearchOpen: React.Dispatch<React.SetStateAction<boolean>>\n}\n\nconst AppShellContext = React.createContext<AppShellContextValue | null>(null)\n\nfunction useAppShell() {\n const ctx = React.useContext(AppShellContext)\n if (!ctx) throw new Error(\"useAppShell must be used within <AppShell>\")\n return ctx\n}\n\n/**\n * Root of the shell. Owns the sidebar open state (via `SidebarProvider`), the\n * sidebar variant and collapse mode, and the global search open state with its\n * Cmd/Ctrl+K shortcut. Routing, theming, and data are the consumer's.\n */\nfunction AppShell({\n variant: variantProp,\n defaultVariant = \"inset\",\n onVariantChange,\n collapsible: collapsibleProp,\n defaultCollapsible = \"icon\",\n onCollapsibleChange,\n searchShortcut = true,\n children,\n ...sidebarProviderProps\n}: Omit<React.ComponentProps<typeof SidebarProvider>, \"children\"> & {\n variant?: SidebarVariant\n defaultVariant?: SidebarVariant\n onVariantChange?: (variant: SidebarVariant) => void\n collapsible?: SidebarCollapsible\n defaultCollapsible?: SidebarCollapsible\n onCollapsibleChange?: (collapsible: SidebarCollapsible) => void\n /** Toggle the search dialog with Cmd/Ctrl+K. */\n searchShortcut?: boolean\n children?: React.ReactNode\n}) {\n const [variantState, setVariantState] = React.useState(defaultVariant)\n const [collapsibleState, setCollapsibleState] = React.useState(defaultCollapsible)\n const [searchOpen, setSearchOpen] = React.useState(false)\n const variant = variantProp ?? variantState\n const collapsible = collapsibleProp ?? collapsibleState\n\n React.useEffect(() => {\n if (!searchShortcut) return\n const down = (event: KeyboardEvent) => {\n if (event.key === \"k\" && (event.metaKey || event.ctrlKey)) {\n event.preventDefault()\n setSearchOpen((open) => !open)\n }\n }\n document.addEventListener(\"keydown\", down)\n return () => document.removeEventListener(\"keydown\", down)\n }, [searchShortcut])\n\n const ctx = React.useMemo<AppShellContextValue>(\n () => ({\n variant,\n setVariant: (next) => {\n if (variantProp === undefined) setVariantState(next)\n onVariantChange?.(next)\n },\n collapsible,\n setCollapsible: (next) => {\n if (collapsibleProp === undefined) setCollapsibleState(next)\n onCollapsibleChange?.(next)\n },\n searchOpen,\n setSearchOpen,\n }),\n [variant, variantProp, onVariantChange, collapsible, collapsibleProp, onCollapsibleChange, searchOpen]\n )\n\n return (\n <AppShellContext.Provider value={ctx}>\n <SidebarProvider {...sidebarProviderProps}>{children}</SidebarProvider>\n </AppShellContext.Provider>\n )\n}\n\nfunction AppShellSkipLink({\n className,\n href = \"#content\",\n children = \"Skip to main content\",\n ...props\n}: React.ComponentProps<\"a\">) {\n return (\n <a\n data-slot=\"app-shell-skip-link\"\n href={href}\n className={cn(\n \"fixed inset-s-44 z-999 -translate-y-52 rounded-md bg-primary px-4 py-2 text-sm font-medium whitespace-nowrap text-primary-foreground opacity-95 shadow-sm transition focus:translate-y-3 focus-visible:ring-2 focus-visible:ring-ring focus-visible:outline-none\",\n className\n )}\n {...props}\n >\n {children}\n </a>\n )\n}\n\n/* -------------------------------------------------------------------------- */\n/* Sidebar */\n/* -------------------------------------------------------------------------- */\n\nfunction AppShellSidebar({ variant, collapsible, children, ...props }: React.ComponentProps<typeof Sidebar>) {\n const shell = useAppShell()\n return (\n <Sidebar\n data-slot=\"app-shell-sidebar\"\n variant={variant ?? shell.variant}\n collapsible={collapsible ?? shell.collapsible}\n {...props}\n >\n {children}\n <SidebarRail />\n </Sidebar>\n )\n}\n\n/* Brand / team switcher trigger ------------------------------------------- */\n\nfunction AppShellBrand({ className, ...props }: React.ComponentProps<typeof SidebarMenuButton>) {\n return (\n <SidebarMenu>\n <SidebarMenuItem>\n <SidebarMenuButton\n data-slot=\"app-shell-brand\"\n size=\"lg\"\n className={cn(\"data-open:bg-sidebar-accent data-open:text-sidebar-accent-foreground\", className)}\n {...props}\n />\n </SidebarMenuItem>\n </SidebarMenu>\n )\n}\n\nfunction AppShellBrandLogo({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"app-shell-brand-logo\"\n className={cn(\n \"flex aspect-square size-8 items-center justify-center rounded-lg bg-sidebar-primary text-sidebar-primary-foreground [&_svg]:size-4\",\n className\n )}\n {...props}\n />\n )\n}\n\nfunction AppShellBrandText({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"app-shell-brand-text\"\n className={cn(\"grid flex-1 text-start text-sm/tight\", className)}\n {...props}\n />\n )\n}\n\nfunction AppShellBrandTitle({ className, ...props }: React.ComponentProps<\"span\">) {\n return <span data-slot=\"app-shell-brand-title\" className={cn(\"truncate font-semibold\", className)} {...props} />\n}\n\nfunction AppShellBrandDescription({ className, ...props }: React.ComponentProps<\"span\">) {\n return <span data-slot=\"app-shell-brand-description\" className={cn(\"truncate text-xs\", className)} {...props} />\n}\n\nfunction AppShellBrandChevron({ className, ...props }: React.ComponentProps<typeof ChevronsUpDownIcon>) {\n return <ChevronsUpDownIcon data-slot=\"app-shell-brand-chevron\" className={cn(\"ms-auto\", className)} {...props} />\n}\n\n/* Navigation --------------------------------------------------------------- */\n\nfunction AppShellNav({ ...props }: React.ComponentProps<typeof SidebarGroup>) {\n return <SidebarGroup data-slot=\"app-shell-nav\" {...props} />\n}\n\nfunction AppShellNavLabel({ ...props }: React.ComponentProps<typeof SidebarGroupLabel>) {\n return <SidebarGroupLabel data-slot=\"app-shell-nav-label\" {...props} />\n}\n\nfunction AppShellNavList({ ...props }: React.ComponentProps<typeof SidebarMenu>) {\n return <SidebarMenu data-slot=\"app-shell-nav-list\" {...props} />\n}\n\nfunction AppShellNavItem({ ...props }: React.ComponentProps<typeof SidebarMenuItem>) {\n return <SidebarMenuItem data-slot=\"app-shell-nav-item\" {...props} />\n}\n\n/**\n * A top-level navigation link. Pass the link element as the child with\n * `asChild` (default) so any router's link works. `active` marks the current\n * route; `tooltip` shows when the sidebar is collapsed to icons.\n */\nfunction AppShellNavLink({\n active = false,\n asChild = true,\n onClick,\n ...props\n}: Omit<React.ComponentProps<typeof SidebarMenuButton>, \"isActive\"> & {\n active?: boolean\n}) {\n const { setOpenMobile } = useSidebar()\n return (\n <SidebarMenuButton\n data-slot=\"app-shell-nav-link\"\n asChild={asChild}\n isActive={active}\n onClick={(event) => {\n onClick?.(event)\n setOpenMobile(false)\n }}\n {...props}\n />\n )\n}\n\nfunction AppShellNavBadge({ className, ...props }: React.ComponentProps<typeof Badge>) {\n return (\n <Badge\n data-slot=\"app-shell-nav-badge\"\n className={cn(\"ms-auto rounded-full px-1 py-0 text-xs\", className)}\n {...props}\n />\n )\n}\n\n/**\n * A navigation item with children. Expanded sidebar: a collapsible sub-list.\n * Icon-collapsed sidebar on desktop: a flyout menu. Supply `trigger` for the\n * button content and `menu` for the flyout items; `children` is the sub-list.\n */\nfunction AppShellNavCollapsible({\n active = false,\n defaultOpen,\n tooltip,\n trigger,\n menu,\n children,\n ...props\n}: React.ComponentProps<typeof SidebarMenuItem> & {\n active?: boolean\n defaultOpen?: boolean\n tooltip?: string\n trigger: React.ReactNode\n /** Rendered inside the flyout when the sidebar is collapsed to icons. */\n menu?: React.ReactNode\n}) {\n const { state, isMobile } = useSidebar()\n\n if (state === \"collapsed\" && !isMobile) {\n return (\n <SidebarMenuItem data-slot=\"app-shell-nav-collapsible\" {...props}>\n <DropdownMenu positioning={{ placement: \"right-start\", gutter: 4 }}>\n <DropdownMenuTrigger asChild>\n <SidebarMenuButton tooltip={tooltip} isActive={active}>\n {trigger}\n <ChevronRightIcon className=\"ms-auto\" />\n </SidebarMenuButton>\n </DropdownMenuTrigger>\n <DropdownMenuContent data-slot=\"app-shell-nav-flyout\">\n <DropdownMenuGroup>\n {tooltip && (\n <>\n <DropdownMenuLabel>{tooltip}</DropdownMenuLabel>\n <DropdownMenuSeparator />\n </>\n )}\n {menu}\n </DropdownMenuGroup>\n </DropdownMenuContent>\n </DropdownMenu>\n </SidebarMenuItem>\n )\n }\n\n return (\n <Collapsible\n defaultOpen={defaultOpen ?? active}\n className=\"group/collapsible\"\n unmountOnExit={false}\n lazyMount={false}\n >\n <SidebarMenuItem data-slot=\"app-shell-nav-collapsible\" {...props}>\n <CollapsibleTrigger asChild>\n <SidebarMenuButton tooltip={tooltip} isActive={active}>\n {trigger}\n <ChevronRightIcon className=\"ms-auto transition-transform duration-200 group-data-[state=open]/collapsible:rotate-90 rtl:rotate-180\" />\n </SidebarMenuButton>\n </CollapsibleTrigger>\n <CollapsibleContent>\n <SidebarMenuSub data-slot=\"app-shell-nav-sublist\">{children}</SidebarMenuSub>\n </CollapsibleContent>\n </SidebarMenuItem>\n </Collapsible>\n )\n}\n\nfunction AppShellNavSubItem({ ...props }: React.ComponentProps<typeof SidebarMenuSubItem>) {\n return <SidebarMenuSubItem data-slot=\"app-shell-nav-subitem\" {...props} />\n}\n\nfunction AppShellNavSubLink({\n active = false,\n asChild = true,\n onClick,\n ...props\n}: Omit<React.ComponentProps<typeof SidebarMenuSubButton>, \"isActive\"> & { active?: boolean }) {\n const { setOpenMobile } = useSidebar()\n return (\n <SidebarMenuSubButton\n data-slot=\"app-shell-nav-sublink\"\n asChild={asChild}\n isActive={active}\n onClick={(event) => {\n onClick?.(event)\n setOpenMobile(false)\n }}\n {...props}\n />\n )\n}\n\n/** A flyout menu entry for the icon-collapsed state. */\nfunction AppShellNavMenuLink({\n active = false,\n className,\n asChild = true,\n ...props\n}: React.ComponentProps<typeof DropdownMenuItem> & { active?: boolean }) {\n return (\n <DropdownMenuItem\n data-slot=\"app-shell-nav-menu-link\"\n asChild={asChild}\n className={cn(active && \"bg-secondary\", className)}\n {...props}\n />\n )\n}\n\n/* User footer trigger ------------------------------------------------------ */\n\nfunction AppShellUser({ className, ...props }: React.ComponentProps<typeof SidebarMenuButton>) {\n return (\n <SidebarMenu>\n <SidebarMenuItem>\n <SidebarMenuButton\n data-slot=\"app-shell-user\"\n size=\"lg\"\n className={cn(\"data-open:bg-sidebar-accent data-open:text-sidebar-accent-foreground\", className)}\n {...props}\n />\n </SidebarMenuItem>\n </SidebarMenu>\n )\n}\n\nfunction AppShellUserAvatar({\n src,\n alt,\n fallback,\n className,\n ...props\n}: React.ComponentProps<typeof Avatar> & { src?: string; alt?: string; fallback: React.ReactNode }) {\n return (\n <Avatar data-slot=\"app-shell-user-avatar\" className={cn(\"rounded-lg\", className)} {...props}>\n {src && <AvatarImage src={src} alt={alt} />}\n <AvatarFallback className=\"rounded-lg\">{fallback}</AvatarFallback>\n </Avatar>\n )\n}\n\nfunction AppShellUserText({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div data-slot=\"app-shell-user-text\" className={cn(\"grid flex-1 text-start text-sm/tight\", className)} {...props} />\n )\n}\n\nfunction AppShellUserName({ className, ...props }: React.ComponentProps<\"span\">) {\n return <span data-slot=\"app-shell-user-name\" className={cn(\"truncate font-semibold\", className)} {...props} />\n}\n\nfunction AppShellUserEmail({ className, ...props }: React.ComponentProps<\"span\">) {\n return <span data-slot=\"app-shell-user-email\" className={cn(\"truncate text-xs\", className)} {...props} />\n}\n\n/* -------------------------------------------------------------------------- */\n/* Content area: header, main */\n/* -------------------------------------------------------------------------- */\n\nfunction AppShellContent({ className, ...props }: React.ComponentProps<typeof SidebarInset>) {\n return (\n <SidebarInset\n data-slot=\"app-shell-content\"\n id=\"content\"\n className={cn(\n \"@container/content\",\n \"has-data-[layout=fixed]:h-svh\",\n \"peer-data-[variant=inset]:has-data-[layout=fixed]:h-[calc(100svh-(var(--spacing)*4))]\",\n className\n )}\n {...props}\n />\n )\n}\n\nfunction AppShellHeader({\n className,\n fixed = false,\n children,\n ...props\n}: React.ComponentProps<\"header\"> & { fixed?: boolean }) {\n const [scrolled, setScrolled] = React.useState(false)\n React.useEffect(() => {\n if (!fixed) return\n const onScroll = () => setScrolled((document.body.scrollTop || document.documentElement.scrollTop) > 10)\n onScroll()\n document.addEventListener(\"scroll\", onScroll, { passive: true })\n return () => document.removeEventListener(\"scroll\", onScroll)\n }, [fixed])\n return (\n <header\n data-slot=\"app-shell-header\"\n data-fixed={fixed ? \"\" : undefined}\n data-scrolled={scrolled ? \"\" : undefined}\n className={cn(\n // Solid background; the top corners follow the inset card's radius so the\n // header never squares off the rounded content area.\n \"z-50 h-16 rounded-t-[inherit] bg-background\",\n fixed && \"peer/header sticky top-0 w-[inherit]\",\n fixed && scrolled ? \"shadow-sm\" : \"shadow-none\",\n className\n )}\n {...props}\n >\n <div\n className={cn(\n \"relative flex h-full items-center gap-3 p-4 sm:gap-4\",\n fixed &&\n scrolled &&\n \"after:absolute after:inset-0 after:-z-10 after:rounded-[inherit] after:bg-background/60 after:backdrop-blur-lg\"\n )}\n >\n <SidebarTrigger variant=\"outline\" className=\"max-md:scale-125\" />\n <Separator orientation=\"vertical\" className=\"h-6\" />\n {children}\n </div>\n </header>\n )\n}\n\nfunction AppShellHeaderActions({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"app-shell-header-actions\"\n className={cn(\"ms-auto flex items-center gap-3 sm:gap-4\", className)}\n {...props}\n />\n )\n}\n\nfunction AppShellMain({\n className,\n fixed = false,\n fluid = false,\n ...props\n}: React.ComponentProps<\"main\"> & { fixed?: boolean; fluid?: boolean }) {\n return (\n <main\n data-slot=\"app-shell-main\"\n data-layout={fixed ? \"fixed\" : \"auto\"}\n className={cn(\n \"px-4 py-6\",\n fixed && \"flex grow flex-col overflow-hidden\",\n !fluid && \"@7xl/content:mx-auto @7xl/content:w-full @7xl/content:max-w-7xl\",\n className\n )}\n {...props}\n />\n )\n}\n\n/* Top nav (secondary, in the header) --------------------------------------- */\n\nfunction AppShellTopNav({ className, ...props }: React.ComponentProps<\"nav\">) {\n return (\n <nav\n data-slot=\"app-shell-top-nav\"\n className={cn(\"hidden items-center gap-4 lg:flex xl:gap-6\", className)}\n {...props}\n />\n )\n}\n\nfunction AppShellTopNavLink({ active = false, className, ...props }: React.ComponentProps<\"a\"> & { active?: boolean }) {\n return (\n <a\n data-slot=\"app-shell-top-nav-link\"\n data-active={active ? \"\" : undefined}\n className={cn(\n \"text-sm font-medium text-muted-foreground transition-colors hover:text-primary data-active:text-foreground\",\n className\n )}\n {...props}\n />\n )\n}\n\n/** The small-screen counterpart of `AppShellTopNav`: the same links in a menu. */\nfunction AppShellTopNavMenu({\n className,\n children,\n ...props\n}: React.ComponentProps<typeof DropdownMenu> & { className?: string }) {\n return (\n <DropdownMenu positioning={{ placement: \"bottom-start\" }} {...props}>\n <DropdownMenuTrigger asChild>\n <Button\n data-slot=\"app-shell-top-nav-menu-trigger\"\n size=\"icon\"\n variant=\"outline\"\n className={cn(\"md:size-7 lg:hidden\", className)}\n >\n <MenuIcon />\n <span className=\"sr-only\">Toggle navigation menu</span>\n </Button>\n </DropdownMenuTrigger>\n <DropdownMenuContent>{children}</DropdownMenuContent>\n </DropdownMenu>\n )\n}\n\n/* -------------------------------------------------------------------------- */\n/* Search and command menu */\n/* -------------------------------------------------------------------------- */\n\nfunction AppShellSearch({\n className,\n placeholder = \"Search\",\n onClick,\n asChild,\n children,\n ...props\n}: React.ComponentProps<typeof Button> & { placeholder?: string }) {\n const shell = useAppShell()\n return (\n <Button\n data-slot=\"app-shell-search\"\n variant=\"outline\"\n asChild={asChild}\n className={cn(\n \"group relative h-8 w-full flex-1 justify-start rounded-md bg-muted/25 text-sm font-normal text-muted-foreground shadow-none hover:bg-accent sm:w-40 sm:pe-12 md:flex-none lg:w-52 xl:w-64\",\n className\n )}\n aria-keyshortcuts=\"Meta+K Control+K\"\n onClick={(event) => {\n onClick?.(event)\n if (!event.defaultPrevented) shell.setSearchOpen(true)\n }}\n {...props}\n >\n {asChild\n ? children\n : (children ?? (\n <>\n <SearchIcon aria-hidden className=\"absolute inset-s-1.5 top-1/2 size-4 -translate-y-1/2\" />\n <span className=\"ms-4\">{placeholder}</span>\n <Kbd className=\"pointer-events-none absolute inset-e-1.5 top-1.5 hidden sm:flex\">⌘K</Kbd>\n </>\n ))}\n </Button>\n )\n}\n\n/** A `CommandDialog` bound to the shell's search state. */\nfunction AppShellCommandDialog({\n ...props\n}: Omit<React.ComponentProps<typeof CommandDialog>, \"open\" | \"onOpenChange\">) {\n const shell = useAppShell()\n return <CommandDialog open={shell.searchOpen} onOpenChange={({ open }) => shell.setSearchOpen(open)} {...props} />\n}\n\n/* -------------------------------------------------------------------------- */\n/* Notifications */\n/* -------------------------------------------------------------------------- */\n\n/**\n * A header notifications popover. Data-agnostic: the consumer renders the\n * items and owns read state; pass `count` to the trigger for the unread badge.\n */\nfunction AppShellNotifications({ positioning, ...props }: React.ComponentProps<typeof Popover>) {\n return (\n <Popover\n data-slot=\"app-shell-notifications\"\n positioning={{ placement: \"bottom-end\", gutter: 8, ...positioning }}\n {...props}\n />\n )\n}\n\nfunction AppShellNotificationsTrigger({\n count = 0,\n max = 99,\n className,\n children,\n asChild,\n ...props\n}: React.ComponentProps<typeof Button> & {\n /** Unread count shown as a badge; hidden when 0. */\n count?: number\n max?: number\n}) {\n const label = count > max ? `${max}+` : String(count)\n return (\n <PopoverTrigger asChild>\n <Button\n data-slot=\"app-shell-notifications-trigger\"\n data-unread={count > 0 ? \"\" : undefined}\n variant=\"ghost\"\n size=\"icon-lg\"\n asChild={asChild}\n className={cn(\"relative scale-95 rounded-full\", className)}\n aria-label={count > 0 ? `Notifications, ${label} unread` : \"Notifications\"}\n {...props}\n >\n {asChild ? children : (children ?? <BellIcon className=\"size-[1.2rem]\" />)}\n {!asChild && count > 0 && (\n <span\n data-slot=\"app-shell-notifications-badge\"\n aria-hidden\n className=\"absolute inset-e-0.5 top-0.5 flex h-4 min-w-4 items-center justify-center rounded-full bg-destructive px-1 text-[10px] leading-none font-medium text-white ring-2 ring-background\"\n >\n {label}\n </span>\n )}\n </Button>\n </PopoverTrigger>\n )\n}\n\nfunction AppShellNotificationsContent({ className, ...props }: React.ComponentProps<typeof PopoverContent>) {\n return (\n <PopoverContent\n data-slot=\"app-shell-notifications-content\"\n className={cn(\"w-80 gap-0 p-0 sm:w-96\", className)}\n {...props}\n />\n )\n}\n\nfunction AppShellNotificationsHeader({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"app-shell-notifications-header\"\n className={cn(\"flex items-center justify-between gap-2 border-b px-3.5 py-2.5\", className)}\n {...props}\n />\n )\n}\n\nfunction AppShellNotificationsTitle({ className, ...props }: React.ComponentProps<\"h3\">) {\n return <h3 data-slot=\"app-shell-notifications-title\" className={cn(\"text-sm font-semibold\", className)} {...props} />\n}\n\n/** A small text action for the header or footer, e.g. \"Mark all as read\". */\nfunction AppShellNotificationsActionTrigger({\n className,\n variant = \"link\",\n size = \"sm\",\n ...props\n}: React.ComponentProps<typeof Button>) {\n return (\n <Button\n data-slot=\"app-shell-notifications-action-trigger\"\n variant={variant}\n size={size}\n className={cn(\"h-auto p-0 text-xs text-muted-foreground hover:text-foreground\", className)}\n {...props}\n />\n )\n}\n\nfunction AppShellNotificationsList({ className, ...props }: React.ComponentProps<\"ul\">) {\n return (\n <ul\n data-slot=\"app-shell-notifications-list\"\n className={cn(\"no-scrollbar flex max-h-96 flex-col gap-0.5 overflow-y-auto p-1\", className)}\n {...props}\n />\n )\n}\n\nfunction AppShellNotificationItem({\n unread,\n asChild,\n className,\n children,\n ...props\n}: React.ComponentProps<\"li\"> & {\n unread?: boolean\n /** Render the item's child (e.g. an anchor or button) as the interactive surface. */\n asChild?: boolean\n}) {\n const itemClassName = cn(\n \"group/notification relative flex w-full cursor-default gap-3 rounded-md px-2.5 py-2 text-start text-sm outline-hidden transition-colors select-none hover:bg-accent hover:text-accent-foreground focus-visible:bg-accent focus-visible:text-accent-foreground data-unread:bg-primary/5 dark:data-unread:bg-primary/10\",\n className\n )\n const inner =\n asChild && React.isValidElement(children)\n ? React.cloneElement(children as React.ReactElement<Record<string, unknown>>, {\n \"data-slot\": \"app-shell-notification-item-surface\",\n \"data-unread\": unread ? \"\" : undefined,\n className: cn(itemClassName, (children as React.ReactElement<{ className?: string }>).props.className),\n })\n : children\n return (\n <li\n data-slot=\"app-shell-notification-item\"\n data-unread={unread ? \"\" : undefined}\n className={asChild ? \"flex\" : itemClassName}\n {...props}\n >\n {inner}\n </li>\n )\n}\n\nfunction AppShellNotificationItemIcon({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"app-shell-notification-item-icon\"\n className={cn(\n \"flex size-8 shrink-0 items-center justify-center rounded-full bg-muted text-muted-foreground [&_svg]:size-4\",\n className\n )}\n {...props}\n />\n )\n}\n\nfunction AppShellNotificationItemContent({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"app-shell-notification-item-content\"\n className={cn(\"flex min-w-0 flex-1 flex-col gap-0.5\", className)}\n {...props}\n />\n )\n}\n\nfunction AppShellNotificationItemTitle({ className, ...props }: React.ComponentProps<\"p\">) {\n return (\n <p\n data-slot=\"app-shell-notification-item-title\"\n className={cn(\"truncate leading-tight font-medium group-data-unread/notification:text-foreground\", className)}\n {...props}\n />\n )\n}\n\nfunction AppShellNotificationItemDescription({ className, ...props }: React.ComponentProps<\"p\">) {\n return (\n <p\n data-slot=\"app-shell-notification-item-description\"\n className={cn(\"line-clamp-2 text-xs text-muted-foreground\", className)}\n {...props}\n />\n )\n}\n\nfunction AppShellNotificationItemTime({ className, ...props }: React.ComponentProps<\"time\">) {\n return (\n <time\n data-slot=\"app-shell-notification-item-time\"\n className={cn(\"text-[11px] text-muted-foreground\", className)}\n {...props}\n />\n )\n}\n\n/** The unread dot; renders only inside an unread item. */\nfunction AppShellNotificationItemIndicator({ className, ...props }: React.ComponentProps<\"span\">) {\n return (\n <span\n data-slot=\"app-shell-notification-item-indicator\"\n aria-hidden\n className={cn(\n \"mt-1.5 hidden size-2 shrink-0 rounded-full bg-primary group-data-unread/notification:block\",\n className\n )}\n {...props}\n />\n )\n}\n\nfunction AppShellNotificationsEmpty({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"app-shell-notifications-empty\"\n className={cn(\n \"flex flex-col items-center justify-center gap-1 px-4 py-10 text-center text-sm text-muted-foreground [&_svg]:mb-1 [&_svg]:size-6\",\n className\n )}\n {...props}\n />\n )\n}\n\nfunction AppShellNotificationsFooter({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"app-shell-notifications-footer\"\n className={cn(\"flex items-center justify-center border-t px-3.5 py-2\", className)}\n {...props}\n />\n )\n}\n\n/* -------------------------------------------------------------------------- */\n/* Theme toggle */\n/* -------------------------------------------------------------------------- */\n\ntype Theme = \"light\" | \"dark\" | \"system\"\n\nfunction AppShellThemeToggle({\n theme,\n onThemeChange,\n className,\n ...props\n}: Omit<React.ComponentProps<typeof Button>, \"onChange\"> & {\n theme: Theme\n onThemeChange: (theme: Theme) => void\n}) {\n return (\n <DropdownMenu positioning={{ placement: \"bottom-end\" }}>\n <DropdownMenuTrigger asChild>\n <Button\n data-slot=\"app-shell-theme-toggle\"\n variant=\"ghost\"\n size=\"icon-lg\"\n className={cn(\"scale-95 rounded-full\", className)}\n {...props}\n >\n <SunIcon className=\"size-[1.2rem] scale-100 rotate-0 transition-all dark:scale-0 dark:-rotate-90\" />\n <MoonIcon className=\"absolute size-[1.2rem] scale-0 rotate-90 transition-all dark:scale-100 dark:rotate-0\" />\n <span className=\"sr-only\">Toggle theme</span>\n </Button>\n </DropdownMenuTrigger>\n <DropdownMenuContent>\n {([\"light\", \"dark\", \"system\"] as const).map((option) => (\n <DropdownMenuItem key={option} value={option} onSelect={() => onThemeChange(option)}>\n <span className=\"capitalize\">{option}</span>\n <CheckIcon className={cn(\"ms-auto size-3.5\", theme !== option && \"invisible\")} />\n </DropdownMenuItem>\n ))}\n </DropdownMenuContent>\n </DropdownMenu>\n )\n}\n\nexport {\n AppShell,\n AppShellBrand,\n AppShellBrandChevron,\n AppShellBrandDescription,\n AppShellBrandLogo,\n AppShellBrandText,\n AppShellBrandTitle,\n AppShellCommandDialog,\n AppShellContent,\n AppShellHeader,\n AppShellHeaderActions,\n AppShellMain,\n AppShellNav,\n AppShellNavBadge,\n AppShellNavCollapsible,\n AppShellNavItem,\n AppShellNavLabel,\n AppShellNavLink,\n AppShellNavList,\n AppShellNavMenuLink,\n AppShellNavSubItem,\n AppShellNavSubLink,\n AppShellNotificationItem,\n AppShellNotificationItemContent,\n AppShellNotificationItemDescription,\n AppShellNotificationItemIcon,\n AppShellNotificationItemIndicator,\n AppShellNotificationItemTime,\n AppShellNotificationItemTitle,\n AppShellNotifications,\n AppShellNotificationsActionTrigger,\n AppShellNotificationsContent,\n AppShellNotificationsEmpty,\n AppShellNotificationsFooter,\n AppShellNotificationsHeader,\n AppShellNotificationsList,\n AppShellNotificationsTitle,\n AppShellNotificationsTrigger,\n AppShellSearch,\n AppShellSidebar,\n AppShellSkipLink,\n AppShellThemeToggle,\n AppShellTopNav,\n AppShellTopNavLink,\n AppShellTopNavMenu,\n AppShellUser,\n AppShellUserAvatar,\n AppShellUserEmail,\n AppShellUserName,\n AppShellUserText,\n SidebarContent as AppShellSidebarContent,\n SidebarFooter as AppShellSidebarFooter,\n SidebarHeader as AppShellSidebarHeader,\n useAppShell,\n type SidebarCollapsible,\n type SidebarVariant,\n type Theme,\n}\n"
|
|
25
|
+
}
|
|
26
|
+
],
|
|
27
|
+
"docs": "## App shell\n`src/components/ui/app-shell.tsx` is a compositional, router-agnostic shell built on\n`sidebar.tsx` (shadcn-admin layout): `AppShell` (context: sidebar variant/collapsible,\nsearch open state, `searchShortcut` for cmd/ctrl+K), `AppShellSidebar` + `AppShellBrand*`,\n`AppShellNav*` (groups, links with `active`, badges, `AppShellNavCollapsible` that becomes\na dropdown flyout when the sidebar is icon-collapsed), `AppShellUser*`, `AppShellContent`,\n`AppShellHeader` (fixed/sticky with scroll shadow, includes the sidebar trigger),\n`AppShellHeaderActions`, `AppShellMain` (`fixed` = viewport-height, `fluid` = full width),\n`AppShellTopNav*`, `AppShellSearch` + `AppShellCommandDialog` (bound to shell search\nstate; nest a `Command` inside), `AppShellNotifications*` (Popover-based bell with a `count`\nbadge on the trigger; header/title/action, list, `AppShellNotificationItem` with `unread` +\n`asChild` surface, icon/content/title/description/time/indicator, empty, footer; data and read\nstate are the consumer's), and `AppShellThemeToggle` (`theme`/`onThemeChange`, no theme\nlibrary assumed). Header icon buttons use `size=\"icon-lg\"` (size-9, `scale-95 rounded-full`)\nand `AppShellHeaderActions` uses the header's `gap-3 sm:gap-4` to match shadcn-admin. Navigation is plain anchors with `asChild` so any router works.\n`src/demo/shell/` is the reference (nav data, hash router, team/user menus, command menu)\nand `src/app.tsx` wraps every demo route in it. `AppShellDemo` takes `headerStart` for\npage-specific header content (the dashboard passes its `AppShellTopNav` + `AppShellTopNavMenu`)."
|
|
28
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "aspect-ratio",
|
|
3
|
+
"type": "ui",
|
|
4
|
+
"description": "Ark UI has no AspectRatio primitive. This mirrors Radix's: a wrapper with a percentage padding-bottom, and an absolutely positioned content box.",
|
|
5
|
+
"dependencies": {},
|
|
6
|
+
"registryDependencies": [],
|
|
7
|
+
"files": [
|
|
8
|
+
{
|
|
9
|
+
"path": "components/ui/aspect-ratio.tsx",
|
|
10
|
+
"content": "\"use client\"\n\nimport * as React from \"react\"\n\n/**\n * Ark UI has no AspectRatio primitive. This mirrors Radix's: a wrapper with a\n * percentage padding-bottom, and an absolutely positioned content box.\n */\nfunction AspectRatio({ ratio = 1 / 1, style, ...props }: React.ComponentProps<\"div\"> & { ratio?: number }) {\n return (\n <div\n data-slot=\"aspect-ratio-wrapper\"\n style={{\n position: \"relative\",\n width: \"100%\",\n paddingBottom: `${100 / ratio}%`,\n }}\n >\n <div\n data-slot=\"aspect-ratio\"\n style={{\n position: \"absolute\",\n top: 0,\n right: 0,\n bottom: 0,\n left: 0,\n ...style,\n }}\n {...props}\n />\n </div>\n )\n}\n\nexport { AspectRatio }\n"
|
|
11
|
+
}
|
|
12
|
+
]
|
|
13
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "attachment",
|
|
3
|
+
"type": "ui",
|
|
4
|
+
"description": "",
|
|
5
|
+
"dependencies": {
|
|
6
|
+
"@ark-ui/react": "^5.39.1",
|
|
7
|
+
"class-variance-authority": "^0.7.1"
|
|
8
|
+
},
|
|
9
|
+
"registryDependencies": [
|
|
10
|
+
"button",
|
|
11
|
+
"utils"
|
|
12
|
+
],
|
|
13
|
+
"files": [
|
|
14
|
+
{
|
|
15
|
+
"path": "components/ui/attachment.tsx",
|
|
16
|
+
"content": "import * as React from \"react\"\nimport { cva, type VariantProps } from \"class-variance-authority\"\nimport { cn } from \"@/lib/utils\"\nimport { ark } from \"@ark-ui/react\"\n\nimport { Button } from \"@/components/ui/button\"\n\nconst attachmentVariants = cva(\n \"group/attachment relative flex w-fit max-w-full min-w-0 shrink-0 flex-wrap rounded-xl border bg-card text-card-foreground transition-colors has-focus-visible:ring-1 has-focus-visible:ring-ring/50 has-[>a,>button]:hover:bg-muted/50 data-[state=error]:border-destructive/30 data-[state=idle]:border-dashed\",\n {\n variants: {\n size: {\n default:\n \"gap-2 text-sm has-data-[slot=attachment-content]:px-2.5 has-data-[slot=attachment-content]:py-2 has-data-[slot=attachment-media]:p-2\",\n sm: \"gap-2.5 text-xs has-data-[slot=attachment-content]:px-2 has-data-[slot=attachment-content]:py-1.5 has-data-[slot=attachment-media]:p-1.5\",\n xs: \"gap-1.5 rounded-lg text-xs has-data-[slot=attachment-content]:px-1.5 has-data-[slot=attachment-content]:py-1 has-data-[slot=attachment-media]:p-1\",\n },\n orientation: {\n horizontal: \"min-w-40 items-center\",\n vertical: \"w-24 flex-col has-data-[slot=attachment-content]:w-30\",\n },\n },\n }\n)\n\nfunction Attachment({\n className,\n state = \"done\",\n size = \"default\",\n orientation = \"horizontal\",\n ...props\n}: React.ComponentProps<\"div\"> &\n VariantProps<typeof attachmentVariants> & {\n state?: \"idle\" | \"uploading\" | \"processing\" | \"error\" | \"done\"\n }) {\n return (\n <div\n data-slot=\"attachment\"\n data-state={state}\n data-size={size}\n data-orientation={orientation}\n className={cn(attachmentVariants({ size, orientation }), className)}\n {...props}\n />\n )\n}\n\nconst attachmentMediaVariants = cva(\n \"relative flex aspect-square w-10 shrink-0 items-center justify-center overflow-hidden rounded-lg bg-muted text-foreground group-data-[orientation=vertical]/attachment:w-full group-data-[size=sm]/attachment:w-8 group-data-[size=xs]/attachment:w-7 group-data-[size=xs]/attachment:rounded-md group-data-[state=error]/attachment:bg-destructive/10 group-data-[state=error]/attachment:text-destructive group-data-[orientation=vertical]/attachment:*:data-[slot=spinner]:size-6! [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 group-data-[orientation=vertical]/attachment:[&_svg:not([class*='size-'])]:size-6 group-data-[size=xs]/attachment:[&_svg:not([class*='size-'])]:size-3.5\",\n {\n variants: {\n variant: {\n icon: \"\",\n image:\n \"opacity-60 group-data-[state=done]/attachment:opacity-100 group-data-[state=idle]/attachment:opacity-100 *:[img]:aspect-square *:[img]:w-full *:[img]:object-cover\",\n },\n },\n defaultVariants: {\n variant: \"icon\",\n },\n }\n)\n\nfunction AttachmentMedia({\n className,\n variant = \"icon\",\n ...props\n}: React.ComponentProps<\"div\"> & VariantProps<typeof attachmentMediaVariants>) {\n return (\n <div\n data-slot=\"attachment-media\"\n data-variant={variant}\n className={cn(attachmentMediaVariants({ variant }), className)}\n {...props}\n />\n )\n}\n\nfunction AttachmentContent({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"attachment-content\"\n className={cn(\n \"max-w-full min-w-0 flex-1 leading-tight group-data-[orientation=vertical]/attachment:px-1\",\n className\n )}\n {...props}\n />\n )\n}\n\nfunction AttachmentTitle({ className, ...props }: React.ComponentProps<\"span\">) {\n return (\n <span\n data-slot=\"attachment-title\"\n className={cn(\n \"block max-w-full min-w-0 truncate font-medium group-data-[state=processing]/attachment:shimmer group-data-[state=uploading]/attachment:shimmer\",\n className\n )}\n {...props}\n />\n )\n}\n\nfunction AttachmentDescription({ className, ...props }: React.ComponentProps<\"span\">) {\n return (\n <span\n data-slot=\"attachment-description\"\n className={cn(\n \"mt-0.5 block min-w-0 truncate text-xs text-muted-foreground group-data-[state=error]/attachment:text-destructive/80\",\n \"max-w-full\",\n className\n )}\n {...props}\n />\n )\n}\n\nfunction AttachmentActions({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"attachment-actions\"\n className={cn(\n \"relative z-20 flex shrink-0 items-center group-data-[orientation=vertical]/attachment:absolute group-data-[orientation=vertical]/attachment:top-3 group-data-[orientation=vertical]/attachment:right-3 group-data-[orientation=vertical]/attachment:gap-1\",\n className\n )}\n {...props}\n />\n )\n}\n\nfunction AttachmentActionTrigger({\n className,\n variant,\n size = \"icon-xs\",\n ...props\n}: React.ComponentProps<typeof Button>) {\n return (\n <Button\n data-slot=\"attachment-action-trigger\"\n variant={variant ?? \"ghost\"}\n size={size}\n className={cn(className)}\n {...props}\n />\n )\n}\n\nfunction AttachmentTrigger({\n className,\n asChild = false,\n type,\n ...props\n}: React.ComponentProps<\"button\"> & {\n asChild?: boolean\n}) {\n const Comp = ark.button\n\n return (\n <Comp\n asChild={asChild}\n data-slot=\"attachment-trigger\"\n type={asChild ? undefined : (type ?? \"button\")}\n className={cn(\"absolute inset-0 z-10 outline-none\", className)}\n {...props}\n />\n )\n}\n\nfunction AttachmentGroup({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"attachment-group\"\n className={cn(\n \"flex min-w-0 scroll-fade-x snap-x snap-mandatory scroll-px-1 scrollbar-none gap-3 overflow-x-auto overscroll-x-contain py-1 *:data-[slot=attachment]:flex-none *:data-[slot=attachment]:snap-start\",\n className\n )}\n {...props}\n />\n )\n}\n\nexport {\n Attachment,\n AttachmentGroup,\n AttachmentMedia,\n AttachmentContent,\n AttachmentTitle,\n AttachmentDescription,\n AttachmentActions,\n AttachmentActionTrigger,\n AttachmentTrigger,\n}\n"
|
|
17
|
+
}
|
|
18
|
+
]
|
|
19
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "avatar",
|
|
3
|
+
"type": "ui",
|
|
4
|
+
"description": "",
|
|
5
|
+
"dependencies": {
|
|
6
|
+
"@ark-ui/react": "^5.39.1"
|
|
7
|
+
},
|
|
8
|
+
"registryDependencies": [
|
|
9
|
+
"utils"
|
|
10
|
+
],
|
|
11
|
+
"files": [
|
|
12
|
+
{
|
|
13
|
+
"path": "components/ui/avatar.tsx",
|
|
14
|
+
"content": "import * as React from \"react\"\nimport { cn } from \"@/lib/utils\"\nimport { Avatar as AvatarPrimitive } from \"@ark-ui/react\"\n\nfunction Avatar({\n className,\n size = \"default\",\n ...props\n}: React.ComponentProps<typeof AvatarPrimitive.Root> & {\n size?: \"default\" | \"sm\" | \"lg\"\n}) {\n return (\n <AvatarPrimitive.Root\n data-slot=\"avatar\"\n data-size={size}\n className={cn(\n \"group/avatar relative flex size-8 shrink-0 rounded-full select-none after:absolute after:inset-0 after:rounded-full after:border after:border-border after:mix-blend-darken data-[size=lg]:size-10 data-[size=sm]:size-6 dark:after:mix-blend-lighten\",\n className\n )}\n {...props}\n />\n )\n}\n\nfunction AvatarContext({ ...props }: React.ComponentProps<typeof AvatarPrimitive.Context>) {\n return <AvatarPrimitive.Context {...props} />\n}\n\nfunction AvatarImage({ className, ...props }: React.ComponentProps<typeof AvatarPrimitive.Image>) {\n return (\n <AvatarPrimitive.Image\n data-slot=\"avatar-image\"\n className={cn(\"aspect-square size-full rounded-full object-cover\", className)}\n {...props}\n />\n )\n}\n\nfunction AvatarFallback({ className, ...props }: React.ComponentProps<typeof AvatarPrimitive.Fallback>) {\n return (\n <AvatarPrimitive.Fallback\n data-slot=\"avatar-fallback\"\n className={cn(\n \"flex size-full items-center justify-center rounded-full bg-muted text-sm text-muted-foreground group-data-[size=sm]/avatar:text-xs\",\n className\n )}\n {...props}\n />\n )\n}\n\nfunction AvatarBadge({ className, ...props }: React.ComponentProps<\"span\">) {\n return (\n <span\n data-slot=\"avatar-badge\"\n className={cn(\n \"absolute right-0 bottom-0 z-10 inline-flex items-center justify-center rounded-full bg-primary text-primary-foreground bg-blend-color ring-2 ring-background select-none\",\n \"group-data-[size=sm]/avatar:size-2 group-data-[size=sm]/avatar:[&>svg]:hidden\",\n \"group-data-[size=default]/avatar:size-2.5 group-data-[size=default]/avatar:[&>svg]:size-2\",\n \"group-data-[size=lg]/avatar:size-3 group-data-[size=lg]/avatar:[&>svg]:size-2\",\n className\n )}\n {...props}\n />\n )\n}\n\nfunction AvatarGroup({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"avatar-group\"\n className={cn(\n \"group/avatar-group flex -space-x-2 *:data-[slot=avatar]:ring-2 *:data-[slot=avatar]:ring-background\",\n className\n )}\n {...props}\n />\n )\n}\n\nfunction AvatarGroupCount({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"avatar-group-count\"\n className={cn(\n \"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\",\n className\n )}\n {...props}\n />\n )\n}\n\nexport { Avatar, AvatarBadge, AvatarContext, AvatarFallback, AvatarGroup, AvatarGroupCount, AvatarImage }\n"
|
|
15
|
+
}
|
|
16
|
+
]
|
|
17
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "badge",
|
|
3
|
+
"type": "ui",
|
|
4
|
+
"description": "",
|
|
5
|
+
"dependencies": {
|
|
6
|
+
"@ark-ui/react": "^5.39.1",
|
|
7
|
+
"class-variance-authority": "^0.7.1"
|
|
8
|
+
},
|
|
9
|
+
"registryDependencies": [
|
|
10
|
+
"utils"
|
|
11
|
+
],
|
|
12
|
+
"files": [
|
|
13
|
+
{
|
|
14
|
+
"path": "components/ui/badge.tsx",
|
|
15
|
+
"content": "import * as React from \"react\"\nimport { cva, type VariantProps } from \"class-variance-authority\"\nimport { cn } from \"@/lib/utils\"\nimport { ark } from \"@ark-ui/react\"\n\nconst badgeVariants = cva(\n \"group/badge inline-flex h-5 w-fit shrink-0 items-center justify-center gap-1 overflow-hidden rounded-4xl border border-transparent px-2 py-0.5 text-xs font-medium whitespace-nowrap transition-all focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5 aria-invalid:border-destructive aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 [&>svg]:pointer-events-none [&>svg]:size-3!\",\n {\n variants: {\n variant: {\n default: \"bg-primary text-primary-foreground [a]:hover:bg-primary/80\",\n secondary: \"bg-secondary text-secondary-foreground [a]:hover:bg-secondary/80\",\n destructive:\n \"bg-destructive/10 text-destructive focus-visible:ring-destructive/20 dark:bg-destructive/20 dark:focus-visible:ring-destructive/40 [a]:hover:bg-destructive/20\",\n outline: \"border-border text-foreground [a]:hover:bg-muted [a]:hover:text-muted-foreground\",\n ghost: \"hover:bg-muted hover:text-muted-foreground dark:hover:bg-muted/50\",\n link: \"text-primary underline-offset-4 hover:underline\",\n },\n },\n defaultVariants: {\n variant: \"default\",\n },\n }\n)\n\nfunction Badge({\n className,\n variant = \"default\",\n asChild = false,\n ...props\n}: React.ComponentProps<\"span\"> & VariantProps<typeof badgeVariants> & { asChild?: boolean }) {\n const Comp = ark.span\n\n return (\n <Comp\n asChild={asChild}\n data-slot=\"badge\"\n data-variant={variant}\n className={cn(badgeVariants({ variant }), className)}\n {...props}\n />\n )\n}\n\nexport { Badge, badgeVariants }\n"
|
|
16
|
+
}
|
|
17
|
+
]
|
|
18
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "breadcrumb",
|
|
3
|
+
"type": "ui",
|
|
4
|
+
"description": "",
|
|
5
|
+
"dependencies": {
|
|
6
|
+
"@ark-ui/react": "^5.39.1",
|
|
7
|
+
"lucide-react": "^1.41.0"
|
|
8
|
+
},
|
|
9
|
+
"registryDependencies": [
|
|
10
|
+
"utils"
|
|
11
|
+
],
|
|
12
|
+
"files": [
|
|
13
|
+
{
|
|
14
|
+
"path": "components/ui/breadcrumb.tsx",
|
|
15
|
+
"content": "import * as React from \"react\"\nimport { cn } from \"@/lib/utils\"\nimport { ark } from \"@ark-ui/react\"\nimport { ChevronRightIcon, MoreHorizontalIcon } from \"lucide-react\"\n\nfunction Breadcrumb({ className, ...props }: React.ComponentProps<\"nav\">) {\n return <nav aria-label=\"breadcrumb\" data-slot=\"breadcrumb\" className={cn(className)} {...props} />\n}\n\nfunction BreadcrumbList({ className, ...props }: React.ComponentProps<\"ol\">) {\n return (\n <ol\n data-slot=\"breadcrumb-list\"\n className={cn(\"flex flex-wrap items-center gap-1.5 text-sm wrap-break-word text-muted-foreground\", className)}\n {...props}\n />\n )\n}\n\nfunction BreadcrumbItem({ className, ...props }: React.ComponentProps<\"li\">) {\n return <li data-slot=\"breadcrumb-item\" className={cn(\"inline-flex items-center gap-1\", className)} {...props} />\n}\n\nfunction BreadcrumbLink({\n asChild,\n className,\n ...props\n}: React.ComponentProps<\"a\"> & {\n asChild?: boolean\n}) {\n const Comp = ark.a\n\n return (\n <Comp\n asChild={asChild}\n data-slot=\"breadcrumb-link\"\n className={cn(\"transition-colors hover:text-foreground\", className)}\n {...props}\n />\n )\n}\n\nfunction BreadcrumbPage({ className, ...props }: React.ComponentProps<\"span\">) {\n return (\n <span\n data-slot=\"breadcrumb-page\"\n role=\"link\"\n aria-disabled=\"true\"\n aria-current=\"page\"\n className={cn(\"font-normal text-foreground\", className)}\n {...props}\n />\n )\n}\n\nfunction BreadcrumbSeparator({ children, className, ...props }: React.ComponentProps<\"li\">) {\n return (\n <li\n data-slot=\"breadcrumb-separator\"\n role=\"presentation\"\n aria-hidden=\"true\"\n className={cn(\"[&>svg]:size-3.5\", className)}\n {...props}\n >\n {children ?? <ChevronRightIcon />}\n </li>\n )\n}\n\nfunction BreadcrumbEllipsis({ className, ...props }: React.ComponentProps<\"span\">) {\n return (\n <span\n data-slot=\"breadcrumb-ellipsis\"\n role=\"presentation\"\n aria-hidden=\"true\"\n className={cn(\"flex size-5 items-center justify-center [&>svg]:size-4\", className)}\n {...props}\n >\n <MoreHorizontalIcon />\n <span className=\"sr-only\">More</span>\n </span>\n )\n}\n\nexport {\n Breadcrumb,\n BreadcrumbList,\n BreadcrumbItem,\n BreadcrumbLink,\n BreadcrumbPage,\n BreadcrumbSeparator,\n BreadcrumbEllipsis,\n}\n"
|
|
16
|
+
}
|
|
17
|
+
]
|
|
18
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "bubble",
|
|
3
|
+
"type": "ui",
|
|
4
|
+
"description": "",
|
|
5
|
+
"dependencies": {
|
|
6
|
+
"@ark-ui/react": "^5.39.1",
|
|
7
|
+
"class-variance-authority": "^0.7.1"
|
|
8
|
+
},
|
|
9
|
+
"registryDependencies": [
|
|
10
|
+
"utils"
|
|
11
|
+
],
|
|
12
|
+
"files": [
|
|
13
|
+
{
|
|
14
|
+
"path": "components/ui/bubble.tsx",
|
|
15
|
+
"content": "import * as React from \"react\"\nimport { cva, type VariantProps } from \"class-variance-authority\"\nimport { cn } from \"@/lib/utils\"\nimport { ark } from \"@ark-ui/react\"\n\nfunction BubbleGroup({ className, ...props }: React.ComponentProps<\"div\">) {\n return <div data-slot=\"bubble-group\" className={cn(\"flex min-w-0 flex-col gap-2\", className)} {...props} />\n}\n\nconst bubbleVariants = cva(\n \"group/bubble relative flex w-fit max-w-[80%] min-w-0 flex-col gap-1 group-data-[align=end]/message:self-end data-[align=end]:self-end data-[variant=ghost]:max-w-full\",\n {\n variants: {\n variant: {\n default:\n \"*:data-[slot=bubble-content]:bg-primary *:data-[slot=bubble-content]:text-primary-foreground [&>[data-slot=bubble-content]:is(button,a):hover]:bg-primary/80\",\n secondary:\n \"*:data-[slot=bubble-content]:bg-secondary *:data-[slot=bubble-content]:text-secondary-foreground [&>[data-slot=bubble-content]:is(button,a):hover]:bg-[color-mix(in_oklch,var(--secondary),var(--foreground)_5%)]\",\n muted:\n \"*:data-[slot=bubble-content]:bg-muted [&>[data-slot=bubble-content]:is(button,a):hover]:bg-[color-mix(in_oklch,var(--muted),var(--foreground)_5%)]\",\n tinted:\n \"*:data-[slot=bubble-content]:bg-[oklch(from_var(--primary)_0.93_calc(c*0.4)_h)] *:data-[slot=bubble-content]:text-foreground dark:*:data-[slot=bubble-content]:bg-[oklch(from_var(--primary)_0.3_calc(c*0.4)_h)] [&>[data-slot=bubble-content]:is(button,a):hover]:bg-[oklch(from_var(--primary)_0.88_calc(c*0.5)_h)] dark:[&>[data-slot=bubble-content]:is(button,a):hover]:bg-[oklch(from_var(--primary)_0.35_calc(c*0.5)_h)]\",\n outline:\n \"*:data-[slot=bubble-content]:border-border *:data-[slot=bubble-content]:bg-background [&>[data-slot=bubble-content]:is(button,a):hover]:bg-muted [&>[data-slot=bubble-content]:is(button,a):hover]:text-foreground dark:[&>[data-slot=bubble-content]:is(button,a):hover]:bg-input/30\",\n ghost:\n \"border-none *:data-[slot=bubble-content]:rounded-none *:data-[slot=bubble-content]:bg-transparent *:data-[slot=bubble-content]:p-0 [&>[data-slot=bubble-content]:is(button,a):hover]:bg-muted [&>[data-slot=bubble-content]:is(button,a):hover]:text-foreground dark:[&>[data-slot=bubble-content]:is(button,a):hover]:bg-muted/50\",\n destructive:\n \"*:data-[slot=bubble-content]:bg-destructive/10 *:data-[slot=bubble-content]:text-destructive dark:*:data-[slot=bubble-content]:bg-destructive/20 [&>[data-slot=bubble-content]:is(button,a):hover]:bg-destructive/20 dark:[&>[data-slot=bubble-content]:is(button,a):hover]:bg-destructive/30\",\n },\n },\n defaultVariants: {\n variant: \"default\",\n },\n }\n)\n\nfunction Bubble({\n variant = \"default\",\n align = \"start\",\n className,\n ...props\n}: React.ComponentProps<\"div\"> &\n VariantProps<typeof bubbleVariants> & {\n align?: \"start\" | \"end\"\n }) {\n return (\n <div\n data-slot=\"bubble\"\n data-variant={variant}\n data-align={align}\n className={cn(bubbleVariants({ variant }), className)}\n {...props}\n />\n )\n}\n\nfunction BubbleContent({\n asChild = false,\n className,\n ...props\n}: React.ComponentProps<\"div\"> & {\n asChild?: boolean\n}) {\n const Comp = ark.div\n\n return (\n <Comp\n asChild={asChild}\n data-slot=\"bubble-content\"\n className={cn(\n \"w-fit max-w-full min-w-0 overflow-hidden rounded-xl border border-transparent px-3 py-2 text-sm/relaxed wrap-break-word group-data-[align=end]/bubble:self-end [button]:text-left [button,a]:transition-colors [button,a]:outline-none [button,a]:focus-visible:border-ring [button,a]:focus-visible:ring-3 [button,a]:focus-visible:ring-ring/50\",\n className\n )}\n {...props}\n />\n )\n}\n\nconst bubbleReactionsVariants = cva(\n \"absolute z-10 flex w-fit shrink-0 items-center justify-center gap-1 rounded-full bg-muted px-1.5 py-0.5 text-sm ring-3 ring-card has-[button]:p-0\",\n {\n variants: {\n side: {\n top: \"top-0 -translate-y-3/4\",\n bottom: \"bottom-0 translate-y-3/4\",\n },\n align: {\n start: \"left-3\",\n end: \"right-3\",\n },\n },\n defaultVariants: {\n side: \"bottom\",\n align: \"end\",\n },\n }\n)\n\nfunction BubbleReactions({\n side = \"bottom\",\n align = \"end\",\n className,\n ...props\n}: React.ComponentProps<\"div\"> & {\n align?: \"start\" | \"end\"\n side?: \"top\" | \"bottom\"\n}) {\n return (\n <div\n data-slot=\"bubble-reactions\"\n data-align={align}\n data-side={side}\n className={cn(bubbleReactionsVariants({ side, align }), className)}\n {...props}\n />\n )\n}\n\nexport { BubbleGroup, Bubble, BubbleContent, BubbleReactions }\n"
|
|
16
|
+
}
|
|
17
|
+
]
|
|
18
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "button-group",
|
|
3
|
+
"type": "ui",
|
|
4
|
+
"description": "",
|
|
5
|
+
"dependencies": {
|
|
6
|
+
"@ark-ui/react": "^5.39.1",
|
|
7
|
+
"class-variance-authority": "^0.7.1"
|
|
8
|
+
},
|
|
9
|
+
"registryDependencies": [
|
|
10
|
+
"separator",
|
|
11
|
+
"utils"
|
|
12
|
+
],
|
|
13
|
+
"files": [
|
|
14
|
+
{
|
|
15
|
+
"path": "components/ui/button-group.tsx",
|
|
16
|
+
"content": "import { cva, type VariantProps } from \"class-variance-authority\"\nimport { cn } from \"@/lib/utils\"\nimport { ark } from \"@ark-ui/react\"\n\nimport { Separator } from \"@/components/ui/separator\"\n\nconst buttonGroupVariants = cva(\n \"group/button-group flex w-fit items-stretch *:focus-visible:relative *:focus-visible:z-10 has-[>[data-slot=button-group]]:gap-2 has-[select[aria-hidden=true]:last-child]:[&>[data-slot=select-trigger]:last-of-type]:rounded-r-lg [&>[data-slot=select-trigger]:not([class*='w-'])]:w-fit [&>input]:flex-1\",\n {\n variants: {\n orientation: {\n horizontal:\n \"[&>*:not(:first-child)]:rounded-l-none [&>*:not(:first-child)]:border-l-0 [&>*:not(:last-child)]:rounded-r-none [&>[data-slot]:not(:has(~[data-slot]))]:rounded-r-lg!\",\n vertical:\n \"flex-col [&>*:not(:first-child)]:rounded-t-none [&>*:not(:first-child)]:border-t-0 [&>*:not(:last-child)]:rounded-b-none [&>[data-slot]:not(:has(~[data-slot]))]:rounded-b-lg!\",\n },\n },\n defaultVariants: {\n orientation: \"horizontal\",\n },\n }\n)\n\nfunction ButtonGroup({\n className,\n orientation,\n ...props\n}: React.ComponentProps<\"div\"> & VariantProps<typeof buttonGroupVariants>) {\n return (\n <div\n role=\"group\"\n data-slot=\"button-group\"\n data-orientation={orientation}\n className={cn(buttonGroupVariants({ orientation }), className)}\n {...props}\n />\n )\n}\n\nfunction ButtonGroupText({\n className,\n asChild = false,\n ...props\n}: React.ComponentProps<\"div\"> & {\n asChild?: boolean\n}) {\n const Comp = ark.div\n\n return (\n <Comp\n asChild={asChild}\n className={cn(\n \"flex items-center gap-2 rounded-lg border bg-muted px-2.5 text-sm font-medium [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4\",\n className\n )}\n {...props}\n />\n )\n}\n\nfunction ButtonGroupSeparator({\n className,\n orientation = \"vertical\",\n ...props\n}: React.ComponentProps<typeof Separator>) {\n return (\n <Separator\n data-slot=\"button-group-separator\"\n orientation={orientation}\n className={cn(\n \"relative self-stretch bg-input data-horizontal:mx-px data-horizontal:w-auto data-vertical:my-px data-vertical:h-auto\",\n className\n )}\n {...props}\n />\n )\n}\n\nexport { ButtonGroup, ButtonGroupSeparator, ButtonGroupText, buttonGroupVariants }\n"
|
|
17
|
+
}
|
|
18
|
+
]
|
|
19
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "button",
|
|
3
|
+
"type": "ui",
|
|
4
|
+
"description": "",
|
|
5
|
+
"dependencies": {
|
|
6
|
+
"@ark-ui/react": "^5.39.1",
|
|
7
|
+
"class-variance-authority": "^0.7.1"
|
|
8
|
+
},
|
|
9
|
+
"registryDependencies": [
|
|
10
|
+
"utils"
|
|
11
|
+
],
|
|
12
|
+
"files": [
|
|
13
|
+
{
|
|
14
|
+
"path": "components/ui/button.tsx",
|
|
15
|
+
"content": "import * as React from \"react\"\nimport { cva, type VariantProps } from \"class-variance-authority\"\nimport { cn } from \"@/lib/utils\"\nimport { ark } from \"@ark-ui/react\"\n\nconst buttonVariants = cva(\n \"group/button inline-flex shrink-0 items-center justify-center rounded-lg border border-transparent bg-clip-padding text-sm font-medium whitespace-nowrap transition-all outline-none select-none focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50 active:not-aria-[haspopup]:translate-y-px disabled:pointer-events-none disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-3 aria-invalid:ring-destructive/20 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4\",\n {\n variants: {\n variant: {\n default: \"bg-primary text-primary-foreground hover:bg-primary/80\",\n outline:\n \"border-border bg-background hover:bg-muted hover:text-foreground aria-expanded:bg-muted aria-expanded:text-foreground dark:border-input dark:bg-input/30 dark:hover:bg-input/50\",\n secondary:\n \"bg-secondary text-secondary-foreground hover:bg-[color-mix(in_oklch,var(--secondary),var(--foreground)_5%)] aria-expanded:bg-secondary aria-expanded:text-secondary-foreground\",\n ghost:\n \"hover:bg-muted hover:text-foreground aria-expanded:bg-muted aria-expanded:text-foreground dark:hover:bg-muted/50\",\n destructive:\n \"bg-destructive/10 text-destructive hover:bg-destructive/20 focus-visible:border-destructive/40 focus-visible:ring-destructive/20 dark:bg-destructive/20 dark:hover:bg-destructive/30 dark:focus-visible:ring-destructive/40\",\n link: \"text-primary underline-offset-4 hover:underline\",\n },\n size: {\n default: \"h-8 gap-1.5 px-2.5 has-data-[icon=inline-end]:pr-2 has-data-[icon=inline-start]:pl-2\",\n xs: \"h-6 gap-1 rounded-[min(var(--radius-md),10px)] px-2 text-xs in-data-[slot=button-group]:rounded-lg has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5 [&_svg:not([class*='size-'])]:size-3\",\n sm: \"h-7 gap-1 rounded-[min(var(--radius-md),12px)] px-2.5 text-[0.8rem] in-data-[slot=button-group]:rounded-lg has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5 [&_svg:not([class*='size-'])]:size-3.5\",\n lg: \"h-9 gap-1.5 px-2.5 has-data-[icon=inline-end]:pr-2 has-data-[icon=inline-start]:pl-2\",\n icon: \"size-8\",\n \"icon-xs\":\n \"size-6 rounded-[min(var(--radius-md),10px)] in-data-[slot=button-group]:rounded-lg [&_svg:not([class*='size-'])]:size-3\",\n \"icon-sm\": \"size-7 rounded-[min(var(--radius-md),12px)] in-data-[slot=button-group]:rounded-lg\",\n \"icon-lg\": \"size-9\",\n },\n },\n defaultVariants: {\n variant: \"default\",\n size: \"default\",\n },\n }\n)\n\nfunction Button({\n className,\n variant = \"default\",\n size = \"default\",\n asChild = false,\n ...props\n}: React.ComponentProps<\"button\"> &\n VariantProps<typeof buttonVariants> & {\n asChild?: boolean\n }) {\n const Comp = ark.button\n\n return (\n <Comp\n asChild={asChild}\n data-slot=\"button\"\n data-variant={variant}\n data-size={size}\n className={cn(buttonVariants({ variant, size, className }))}\n {...props}\n />\n )\n}\n\nexport { Button, buttonVariants }\n"
|
|
16
|
+
}
|
|
17
|
+
]
|
|
18
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "calendar",
|
|
3
|
+
"type": "ui",
|
|
4
|
+
"description": "",
|
|
5
|
+
"dependencies": {
|
|
6
|
+
"lucide-react": "^1.41.0",
|
|
7
|
+
"react-day-picker": "^10.0.1"
|
|
8
|
+
},
|
|
9
|
+
"registryDependencies": [
|
|
10
|
+
"button",
|
|
11
|
+
"utils"
|
|
12
|
+
],
|
|
13
|
+
"files": [
|
|
14
|
+
{
|
|
15
|
+
"path": "components/ui/calendar.tsx",
|
|
16
|
+
"content": "\"use client\"\n\nimport * as React from \"react\"\nimport { cn } from \"@/lib/utils\"\nimport { DayPicker, getDefaultClassNames, type DayButton, type Locale } from \"react-day-picker\"\n\nimport { Button, buttonVariants } from \"@/components/ui/button\"\nimport { ChevronLeftIcon, ChevronRightIcon, ChevronDownIcon } from \"lucide-react\"\n\nfunction Calendar({\n className,\n classNames,\n showOutsideDays = true,\n captionLayout = \"label\",\n buttonVariant = \"ghost\",\n locale,\n formatters,\n components,\n ...props\n}: React.ComponentProps<typeof DayPicker> & {\n buttonVariant?: React.ComponentProps<typeof Button>[\"variant\"]\n}) {\n const defaultClassNames = getDefaultClassNames()\n\n return (\n <DayPicker\n showOutsideDays={showOutsideDays}\n className={cn(\n \"group/calendar bg-background p-2 [--cell-radius:var(--radius-md)] [--cell-size:--spacing(7)] in-data-[slot=card-content]:bg-transparent in-data-[slot=popover-content]:bg-transparent\",\n String.raw`rtl:**:[.rdp-button\\_next>svg]:rotate-180`,\n String.raw`rtl:**:[.rdp-button\\_previous>svg]:rotate-180`,\n className\n )}\n captionLayout={captionLayout}\n locale={locale}\n formatters={{\n formatMonthDropdown: (date) => date.toLocaleString(locale?.code, { month: \"short\" }),\n ...formatters,\n }}\n classNames={{\n root: cn(\"w-fit\", defaultClassNames.root),\n months: cn(\"relative flex flex-col gap-4 md:flex-row\", defaultClassNames.months),\n month: cn(\"flex w-full flex-col gap-4\", defaultClassNames.month),\n nav: cn(\"absolute inset-x-0 top-0 flex w-full items-center justify-between gap-1\", defaultClassNames.nav),\n button_previous: cn(\n buttonVariants({ variant: buttonVariant }),\n \"size-(--cell-size) p-0 select-none aria-disabled:opacity-50\",\n defaultClassNames.button_previous\n ),\n button_next: cn(\n buttonVariants({ variant: buttonVariant }),\n \"size-(--cell-size) p-0 select-none aria-disabled:opacity-50\",\n defaultClassNames.button_next\n ),\n month_caption: cn(\n \"flex h-(--cell-size) w-full items-center justify-center px-(--cell-size)\",\n defaultClassNames.month_caption\n ),\n dropdowns: cn(\n \"flex h-(--cell-size) w-full items-center justify-center gap-1.5 text-sm font-medium\",\n defaultClassNames.dropdowns\n ),\n dropdown_root: cn(\"relative rounded-(--cell-radius)\", defaultClassNames.dropdown_root),\n dropdown: cn(\"absolute inset-0 bg-popover opacity-0\", defaultClassNames.dropdown),\n caption_label: cn(\n \"font-medium select-none\",\n captionLayout === \"label\"\n ? \"text-sm\"\n : \"flex items-center gap-1 rounded-(--cell-radius) text-sm [&>svg]:size-3.5 [&>svg]:text-muted-foreground\",\n defaultClassNames.caption_label\n ),\n month_grid: cn(\"w-full border-collapse\", defaultClassNames.month_grid),\n weekdays: cn(\"flex\", defaultClassNames.weekdays),\n weekday: cn(\n \"flex-1 rounded-(--cell-radius) text-[0.8rem] font-normal text-muted-foreground select-none\",\n defaultClassNames.weekday\n ),\n week: cn(\"mt-2 flex w-full\", defaultClassNames.week),\n week_number_header: cn(\"w-(--cell-size) select-none\", defaultClassNames.week_number_header),\n week_number: cn(\"text-[0.8rem] text-muted-foreground select-none\", defaultClassNames.week_number),\n day: cn(\n \"group/day relative aspect-square size-full rounded-(--cell-radius) p-0 text-center select-none [&:last-child[data-selected=true]_button]:rounded-r-(--cell-radius)\",\n props.showWeekNumber\n ? \"[&:nth-child(2)[data-selected=true]_button]:rounded-l-(--cell-radius)\"\n : \"[&:first-child[data-selected=true]_button]:rounded-l-(--cell-radius)\",\n defaultClassNames.day\n ),\n range_start: cn(\n \"relative isolate z-0 rounded-l-(--cell-radius) bg-muted after:absolute after:inset-y-0 after:right-0 after:w-4 after:bg-muted\",\n defaultClassNames.range_start\n ),\n range_middle: cn(\"rounded-none\", defaultClassNames.range_middle),\n range_end: cn(\n \"relative isolate z-0 rounded-r-(--cell-radius) bg-muted after:absolute after:inset-y-0 after:left-0 after:w-4 after:bg-muted\",\n defaultClassNames.range_end\n ),\n today: cn(\n \"rounded-(--cell-radius) bg-muted text-foreground data-[selected=true]:rounded-none\",\n defaultClassNames.today\n ),\n outside: cn(\"text-muted-foreground aria-selected:text-muted-foreground\", defaultClassNames.outside),\n disabled: cn(\"text-muted-foreground opacity-50\", defaultClassNames.disabled),\n hidden: cn(\"invisible\", defaultClassNames.hidden),\n ...classNames,\n }}\n components={{\n Root: ({ className, rootRef, ...props }) => {\n return <div data-slot=\"calendar\" ref={rootRef} className={cn(className)} {...props} />\n },\n Chevron: ({ className, orientation, ...props }) => {\n if (orientation === \"left\") {\n return <ChevronLeftIcon className={cn(\"size-4\", className)} {...props} />\n }\n\n if (orientation === \"right\") {\n return <ChevronRightIcon className={cn(\"size-4\", className)} {...props} />\n }\n\n return <ChevronDownIcon className={cn(\"size-4\", className)} {...props} />\n },\n DayButton: ({ ...props }) => <CalendarDayButton locale={locale} {...props} />,\n WeekNumber: ({ children, ...props }) => {\n return (\n <td {...props}>\n <div className=\"flex size-(--cell-size) items-center justify-center text-center\">{children}</div>\n </td>\n )\n },\n ...components,\n }}\n {...props}\n />\n )\n}\n\nfunction CalendarDayButton({\n className,\n day,\n modifiers,\n locale,\n ...props\n}: React.ComponentProps<typeof DayButton> & { locale?: Partial<Locale> }) {\n const defaultClassNames = getDefaultClassNames()\n\n const ref = React.useRef<HTMLButtonElement>(null)\n React.useEffect(() => {\n if (modifiers.focused) ref.current?.focus()\n }, [modifiers.focused])\n\n return (\n <Button\n ref={ref}\n variant=\"ghost\"\n size=\"icon\"\n data-day={day.date.toLocaleDateString(locale?.code)}\n data-selected-single={\n modifiers.selected && !modifiers.range_start && !modifiers.range_end && !modifiers.range_middle\n }\n data-range-start={modifiers.range_start}\n data-range-end={modifiers.range_end}\n data-range-middle={modifiers.range_middle}\n className={cn(\n \"relative isolate z-10 flex aspect-square size-auto w-full min-w-(--cell-size) flex-col gap-1 border-0 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-(--cell-radius) data-[range-end=true]:rounded-r-(--cell-radius) data-[range-end=true]:bg-primary data-[range-end=true]:text-primary-foreground data-[range-middle=true]:rounded-none data-[range-middle=true]:bg-muted data-[range-middle=true]:text-foreground data-[range-start=true]:rounded-(--cell-radius) data-[range-start=true]:rounded-l-(--cell-radius) 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-foreground [&>span]:text-xs [&>span]:opacity-70\",\n defaultClassNames.day,\n className\n )}\n {...props}\n />\n )\n}\n\nexport { Calendar, CalendarDayButton }\n"
|
|
17
|
+
}
|
|
18
|
+
]
|
|
19
|
+
}
|