@mostrom/app-shell 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/.claude/ralph-loop.local.md +9 -0
- package/README.md +172 -0
- package/bin/init.js +269 -0
- package/bun.lock +401 -0
- package/components.json +28 -0
- package/package.json +74 -0
- package/scripts/publish-npm.sh +202 -0
- package/src/AppShell.tsx +847 -0
- package/src/components/PageHeader.tsx +160 -0
- package/src/components/data-table/README.md +447 -0
- package/src/components/data-table/data-table-preferences.tsx +184 -0
- package/src/components/data-table/data-table-toolbar.tsx +118 -0
- package/src/components/data-table/data-table.tsx +37 -0
- package/src/components/data-table/index.ts +32 -0
- package/src/components/global-header/AllServicesButton.tsx +127 -0
- package/src/components/global-header/CategoriesButton.tsx +120 -0
- package/src/components/global-header/GlobalHeader.tsx +59 -0
- package/src/components/global-header/GlobalHeaderSearch.tsx +57 -0
- package/src/components/global-header/HeaderUtilities.tsx +243 -0
- package/src/components/global-header/ServicesMenu.tsx +246 -0
- package/src/components/layout/AppBreadcrumb.tsx +70 -0
- package/src/components/layout/AppFlashbar.tsx +95 -0
- package/src/components/layout/AppLayout.tsx +271 -0
- package/src/components/layout/AppNavigation.tsx +313 -0
- package/src/components/layout/AppSidebar.tsx +229 -0
- package/src/components/patterns/index.ts +14 -0
- package/src/components/patterns/p-alert-5.tsx +19 -0
- package/src/components/patterns/p-autocomplete-5.tsx +89 -0
- package/src/components/patterns/p-breadcrumb-1.tsx +28 -0
- package/src/components/patterns/p-button-42.tsx +37 -0
- package/src/components/patterns/p-button-51.tsx +14 -0
- package/src/components/patterns/p-button-6.tsx +5 -0
- package/src/components/patterns/p-calendar-1.tsx +18 -0
- package/src/components/patterns/p-card-1.tsx +33 -0
- package/src/components/patterns/p-card-2.tsx +26 -0
- package/src/components/patterns/p-card-5.tsx +31 -0
- package/src/components/patterns/p-collapsible-7.tsx +121 -0
- package/src/components/patterns/p-command-6.tsx +113 -0
- package/src/components/patterns/p-dialog-1.tsx +56 -0
- package/src/components/patterns/p-dropdown-menu-1.tsx +38 -0
- package/src/components/patterns/p-dropdown-menu-11.tsx +122 -0
- package/src/components/patterns/p-dropdown-menu-14.tsx +165 -0
- package/src/components/patterns/p-dropdown-menu-9.tsx +108 -0
- package/src/components/patterns/p-empty-2.tsx +34 -0
- package/src/components/patterns/p-file-upload-1.tsx +72 -0
- package/src/components/patterns/p-filters-1.tsx +666 -0
- package/src/components/patterns/p-frame-2.tsx +26 -0
- package/src/components/patterns/p-tabs-2.tsx +129 -0
- package/src/components/reui/alert.tsx +92 -0
- package/src/components/reui/autocomplete.tsx +343 -0
- package/src/components/reui/badge.tsx +87 -0
- package/src/components/reui/data-grid/data-grid-column-filter.tsx +165 -0
- package/src/components/reui/data-grid/data-grid-column-header.tsx +339 -0
- package/src/components/reui/data-grid/data-grid-column-visibility.tsx +55 -0
- package/src/components/reui/data-grid/data-grid-pagination.tsx +224 -0
- package/src/components/reui/data-grid/data-grid-table-dnd-rows.tsx +260 -0
- package/src/components/reui/data-grid/data-grid-table-dnd.tsx +253 -0
- package/src/components/reui/data-grid/data-grid-table.tsx +639 -0
- package/src/components/reui/data-grid/data-grid.tsx +209 -0
- package/src/components/reui/date-selector.tsx +1330 -0
- package/src/components/reui/filters.tsx +1869 -0
- package/src/components/reui/frame.tsx +134 -0
- package/src/components/reui/index.ts +17 -0
- package/src/components/reui/timeline.tsx +219 -0
- package/src/components/search/Autocomplete.tsx +183 -0
- package/src/components/search/AutocompleteClient.tsx +293 -0
- package/src/components/search/GlobalSearch.tsx +187 -0
- package/src/components/section-drawer/deal-drawer-content.tsx +891 -0
- package/src/components/section-drawer/index.ts +19 -0
- package/src/components/section-drawer/section-drawer.css +665 -0
- package/src/components/section-drawer/section-drawer.tsx +467 -0
- package/src/components/sectioned-list-board/README.md +78 -0
- package/src/components/sectioned-list-board/board-card-content.tsx +340 -0
- package/src/components/sectioned-list-board/date-range-filter.tsx +249 -0
- package/src/components/sectioned-list-board/index.ts +19 -0
- package/src/components/sectioned-list-board/sectioned-list-board.css +564 -0
- package/src/components/sectioned-list-board/sectioned-list-board.tsx +731 -0
- package/src/components/sectioned-list-board/sortable-card.tsx +314 -0
- package/src/components/sectioned-list-board/sortable-section.tsx +319 -0
- package/src/components/sectioned-list-board/types.ts +216 -0
- package/src/components/sectioned-list-table/README.md +80 -0
- package/src/components/sectioned-list-table/index.ts +14 -0
- package/src/components/sectioned-list-table/sectioned-list-table.css +534 -0
- package/src/components/sectioned-list-table/sectioned-list-table.tsx +740 -0
- package/src/components/sectioned-list-table/sortable-column-header.tsx +120 -0
- package/src/components/sectioned-list-table/sortable-row.tsx +420 -0
- package/src/components/sectioned-list-table/sortable-section.tsx +251 -0
- package/src/components/sectioned-list-table/table-cell-content.tsx +129 -0
- package/src/components/sectioned-list-table/types.ts +120 -0
- package/src/components/sectioned-list-table/use-column-preferences.ts +103 -0
- package/src/components/ui/actions-dropdown.tsx +109 -0
- package/src/components/ui/assignee-selector.tsx +209 -0
- package/src/components/ui/avatar.tsx +107 -0
- package/src/components/ui/breadcrumb.tsx +109 -0
- package/src/components/ui/button-group.tsx +83 -0
- package/src/components/ui/button.tsx +64 -0
- package/src/components/ui/calendar.tsx +220 -0
- package/src/components/ui/card.tsx +92 -0
- package/src/components/ui/chart.tsx +376 -0
- package/src/components/ui/checkbox.tsx +30 -0
- package/src/components/ui/collapsible.tsx +33 -0
- package/src/components/ui/command.tsx +182 -0
- package/src/components/ui/context-menu.tsx +250 -0
- package/src/components/ui/create-button-group.tsx +128 -0
- package/src/components/ui/dialog.tsx +156 -0
- package/src/components/ui/drawer.tsx +133 -0
- package/src/components/ui/dropdown-menu.tsx +255 -0
- package/src/components/ui/empty.tsx +104 -0
- package/src/components/ui/field.tsx +248 -0
- package/src/components/ui/form.tsx +165 -0
- package/src/components/ui/index.ts +37 -0
- package/src/components/ui/input-group.tsx +168 -0
- package/src/components/ui/input.tsx +21 -0
- package/src/components/ui/kbd.tsx +28 -0
- package/src/components/ui/label.tsx +22 -0
- package/src/components/ui/navigation-menu.tsx +168 -0
- package/src/components/ui/page-header.tsx +80 -0
- package/src/components/ui/popover.tsx +87 -0
- package/src/components/ui/scroll-area.tsx +56 -0
- package/src/components/ui/select.tsx +190 -0
- package/src/components/ui/separator.tsx +26 -0
- package/src/components/ui/sheet.tsx +141 -0
- package/src/components/ui/sidebar.tsx +726 -0
- package/src/components/ui/skeleton.tsx +13 -0
- package/src/components/ui/sonner.tsx +38 -0
- package/src/components/ui/switch.tsx +33 -0
- package/src/components/ui/tabs.tsx +91 -0
- package/src/components/ui/textarea.tsx +18 -0
- package/src/components/ui/toggle-group.tsx +83 -0
- package/src/components/ui/toggle.tsx +45 -0
- package/src/components/ui/tooltip.tsx +57 -0
- package/src/hooks/use-copy-to-clipboard.ts +37 -0
- package/src/hooks/use-file-upload.ts +415 -0
- package/src/hooks/use-mobile.ts +19 -0
- package/src/index.ts +95 -0
- package/src/lib/utils.ts +6 -0
- package/src/styles.css +1859 -0
- package/src/urls.ts +83 -0
- package/src/vite.d.ts +22 -0
- package/src/vite.js +241 -0
- package/tsconfig.base.json +18 -0
- package/tsconfig.json +24 -0
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import { Button } from "@/components/ui/button"
|
|
2
|
+
import {
|
|
3
|
+
Card,
|
|
4
|
+
CardContent,
|
|
5
|
+
CardDescription,
|
|
6
|
+
CardFooter,
|
|
7
|
+
CardHeader,
|
|
8
|
+
CardTitle,
|
|
9
|
+
} from "@/components/ui/card"
|
|
10
|
+
import { Input } from "@/components/ui/input"
|
|
11
|
+
import { Label } from "@/components/ui/label"
|
|
12
|
+
import {
|
|
13
|
+
Tabs,
|
|
14
|
+
TabsContent,
|
|
15
|
+
TabsList,
|
|
16
|
+
TabsTrigger,
|
|
17
|
+
} from "@/components/ui/tabs"
|
|
18
|
+
|
|
19
|
+
export function Pattern() {
|
|
20
|
+
return (
|
|
21
|
+
<div className="flex w-full max-w-xs flex-col gap-6">
|
|
22
|
+
<Tabs defaultValue="account">
|
|
23
|
+
<TabsList variant="line" className="mb-3.5 w-full">
|
|
24
|
+
<TabsTrigger value="account">Account</TabsTrigger>
|
|
25
|
+
<TabsTrigger value="password">Password</TabsTrigger>
|
|
26
|
+
<TabsTrigger value="settings">Settings</TabsTrigger>
|
|
27
|
+
</TabsList>
|
|
28
|
+
<TabsContent value="account">
|
|
29
|
+
<Card>
|
|
30
|
+
<CardHeader className="pb-3">
|
|
31
|
+
<CardTitle className="text-base">Account</CardTitle>
|
|
32
|
+
<CardDescription className="text-sm">
|
|
33
|
+
Update your account information.
|
|
34
|
+
</CardDescription>
|
|
35
|
+
</CardHeader>
|
|
36
|
+
<CardContent className="space-y-4">
|
|
37
|
+
<div className="space-y-2">
|
|
38
|
+
<Label htmlFor="underline-name" className="text-sm">
|
|
39
|
+
Name
|
|
40
|
+
</Label>
|
|
41
|
+
<Input
|
|
42
|
+
id="underline-name"
|
|
43
|
+
defaultValue="Alex Chen"
|
|
44
|
+
className="h-9"
|
|
45
|
+
/>
|
|
46
|
+
</div>
|
|
47
|
+
<div className="space-y-2">
|
|
48
|
+
<Label htmlFor="underline-email" className="text-sm">
|
|
49
|
+
Email
|
|
50
|
+
</Label>
|
|
51
|
+
<Input
|
|
52
|
+
id="underline-email"
|
|
53
|
+
type="email"
|
|
54
|
+
defaultValue="alex.chen@example.com"
|
|
55
|
+
className="h-9"
|
|
56
|
+
/>
|
|
57
|
+
</div>
|
|
58
|
+
</CardContent>
|
|
59
|
+
<CardFooter className="pt-3">
|
|
60
|
+
<Button size="sm">Save changes</Button>
|
|
61
|
+
</CardFooter>
|
|
62
|
+
</Card>
|
|
63
|
+
</TabsContent>
|
|
64
|
+
<TabsContent value="password">
|
|
65
|
+
<Card>
|
|
66
|
+
<CardHeader className="pb-3">
|
|
67
|
+
<CardTitle className="text-base">Password</CardTitle>
|
|
68
|
+
<CardDescription className="text-sm">
|
|
69
|
+
Change your password here.
|
|
70
|
+
</CardDescription>
|
|
71
|
+
</CardHeader>
|
|
72
|
+
<CardContent className="space-y-4">
|
|
73
|
+
<div className="space-y-2">
|
|
74
|
+
<Label htmlFor="underline-current" className="text-sm">
|
|
75
|
+
Current password
|
|
76
|
+
</Label>
|
|
77
|
+
<Input id="underline-current" type="password" className="h-9" />
|
|
78
|
+
</div>
|
|
79
|
+
<div className="space-y-2">
|
|
80
|
+
<Label htmlFor="underline-new" className="text-sm">
|
|
81
|
+
New password
|
|
82
|
+
</Label>
|
|
83
|
+
<Input id="underline-new" type="password" className="h-9" />
|
|
84
|
+
</div>
|
|
85
|
+
</CardContent>
|
|
86
|
+
<CardFooter className="pt-3">
|
|
87
|
+
<Button size="sm">Update password</Button>
|
|
88
|
+
</CardFooter>
|
|
89
|
+
</Card>
|
|
90
|
+
</TabsContent>
|
|
91
|
+
<TabsContent value="settings">
|
|
92
|
+
<Card>
|
|
93
|
+
<CardHeader className="pb-3">
|
|
94
|
+
<CardTitle className="text-base">Settings</CardTitle>
|
|
95
|
+
<CardDescription className="text-sm">
|
|
96
|
+
Manage your preferences.
|
|
97
|
+
</CardDescription>
|
|
98
|
+
</CardHeader>
|
|
99
|
+
<CardContent className="space-y-4">
|
|
100
|
+
<div className="space-y-2">
|
|
101
|
+
<Label htmlFor="underline-theme" className="text-sm">
|
|
102
|
+
Theme
|
|
103
|
+
</Label>
|
|
104
|
+
<Input
|
|
105
|
+
id="underline-theme"
|
|
106
|
+
defaultValue="Light"
|
|
107
|
+
className="h-9"
|
|
108
|
+
/>
|
|
109
|
+
</div>
|
|
110
|
+
<div className="space-y-2">
|
|
111
|
+
<Label htmlFor="underline-language" className="text-sm">
|
|
112
|
+
Language
|
|
113
|
+
</Label>
|
|
114
|
+
<Input
|
|
115
|
+
id="underline-language"
|
|
116
|
+
defaultValue="English"
|
|
117
|
+
className="h-9"
|
|
118
|
+
/>
|
|
119
|
+
</div>
|
|
120
|
+
</CardContent>
|
|
121
|
+
<CardFooter className="pt-3">
|
|
122
|
+
<Button size="sm">Save settings</Button>
|
|
123
|
+
</CardFooter>
|
|
124
|
+
</Card>
|
|
125
|
+
</TabsContent>
|
|
126
|
+
</Tabs>
|
|
127
|
+
</div>
|
|
128
|
+
)
|
|
129
|
+
}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { cva, type VariantProps } from "class-variance-authority"
|
|
2
|
+
|
|
3
|
+
import { cn } from "@/lib/utils"
|
|
4
|
+
|
|
5
|
+
const alertVariants = cva(
|
|
6
|
+
[
|
|
7
|
+
"relative w-full text-sm border has-[>svg]:grid-cols-[calc(var(--spacing)*3)_1fr] grid-cols-[0_1fr] grid gap-y-0.5 items-center [&>svg:not([class*=size-])]:size-4",
|
|
8
|
+
"has-[>[data-slot=alert-title]+[data-slot=alert-description]]:[&_[data-slot=alert-action]]:sm:row-end-3",
|
|
9
|
+
"has-[>[data-slot=alert-title]+[data-slot=alert-description]]:items-start",
|
|
10
|
+
"has-[>[data-slot=alert-title]+[data-slot=alert-description]]:[&_svg]:translate-y-0.5",
|
|
11
|
+
"rounded-lg",
|
|
12
|
+
"px-3",
|
|
13
|
+
"py-2.5",
|
|
14
|
+
"has-[>svg]:gap-x-2.5",
|
|
15
|
+
],
|
|
16
|
+
{
|
|
17
|
+
variants: {
|
|
18
|
+
variant: {
|
|
19
|
+
default: "bg-card text-card-foreground",
|
|
20
|
+
destructive:
|
|
21
|
+
"border-destructive/30 bg-destructive/4 [&>svg]:text-destructive",
|
|
22
|
+
info: "border-info/30 bg-info/4 [&>svg]:text-info",
|
|
23
|
+
success: "border-success/30 bg-success/4 [&>svg]:text-success",
|
|
24
|
+
warning: "border-warning/30 bg-warning/4 [&>svg]:text-warning",
|
|
25
|
+
invert:
|
|
26
|
+
"border-invert bg-invert text-invert-foreground [&_[data-slot=alert-description]]:text-invert-foreground/70",
|
|
27
|
+
},
|
|
28
|
+
},
|
|
29
|
+
defaultVariants: {
|
|
30
|
+
variant: "default",
|
|
31
|
+
},
|
|
32
|
+
}
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
function Alert({
|
|
36
|
+
className,
|
|
37
|
+
variant,
|
|
38
|
+
...props
|
|
39
|
+
}: React.ComponentProps<"div"> & VariantProps<typeof alertVariants>) {
|
|
40
|
+
return (
|
|
41
|
+
<div
|
|
42
|
+
data-slot="alert"
|
|
43
|
+
role="alert"
|
|
44
|
+
className={cn(alertVariants({ variant }), className)}
|
|
45
|
+
{...props}
|
|
46
|
+
/>
|
|
47
|
+
)
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function AlertTitle({ className, ...props }: React.ComponentProps<"div">) {
|
|
51
|
+
return (
|
|
52
|
+
<div
|
|
53
|
+
data-slot="alert-title"
|
|
54
|
+
className={cn(
|
|
55
|
+
"col-start-2 line-clamp-1 min-h-4 font-medium tracking-tight",
|
|
56
|
+
className
|
|
57
|
+
)}
|
|
58
|
+
{...props}
|
|
59
|
+
/>
|
|
60
|
+
)
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function AlertDescription({
|
|
64
|
+
className,
|
|
65
|
+
...props
|
|
66
|
+
}: React.ComponentProps<"div">) {
|
|
67
|
+
return (
|
|
68
|
+
<div
|
|
69
|
+
data-slot="alert-description"
|
|
70
|
+
className={cn(
|
|
71
|
+
"text-muted-foreground col-start-2 grid justify-items-start gap-1 text-sm [&_p]:leading-relaxed",
|
|
72
|
+
className
|
|
73
|
+
)}
|
|
74
|
+
{...props}
|
|
75
|
+
/>
|
|
76
|
+
)
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function AlertAction({ className, ...props }: React.ComponentProps<"div">) {
|
|
80
|
+
return (
|
|
81
|
+
<div
|
|
82
|
+
data-slot="alert-action"
|
|
83
|
+
className={cn(
|
|
84
|
+
"flex gap-1.5 max-sm:col-start-2 max-sm:mt-2 max-sm:justify-start sm:col-start-3 sm:row-start-1 sm:justify-end sm:self-center",
|
|
85
|
+
className
|
|
86
|
+
)}
|
|
87
|
+
{...props}
|
|
88
|
+
/>
|
|
89
|
+
)
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
export { Alert, AlertTitle, AlertDescription, AlertAction }
|
|
@@ -0,0 +1,343 @@
|
|
|
1
|
+
"use client"
|
|
2
|
+
|
|
3
|
+
import { Autocomplete as AutocompletePrimitive } from "@base-ui/react/autocomplete"
|
|
4
|
+
import { cva, type VariantProps } from "class-variance-authority"
|
|
5
|
+
|
|
6
|
+
import { cn } from "../../lib/utils"
|
|
7
|
+
import { ScrollArea } from "../ui/scroll-area"
|
|
8
|
+
import { XIcon, ChevronsUpDownIcon } from "lucide-react"
|
|
9
|
+
|
|
10
|
+
const inputVariants = cva(
|
|
11
|
+
"outline-none flex w-full text-foreground placeholder:text-muted-foreground disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50 [[readonly]]:bg-muted/80 [[readonly]]:cursor-not-allowed border border-input focus-visible:border-ring aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive dark:aria-invalid:border-destructive/50 rounded-lg bg-transparent dark:bg-input/30 text-sm transition-colors focus-visible:ring-ring/50 focus-visible:ring-3 aria-invalid:ring-3",
|
|
12
|
+
{
|
|
13
|
+
variants: {
|
|
14
|
+
size: {
|
|
15
|
+
sm: "h-7 px-2 [&~[data-slot=autocomplete-clear]]:end-1.5 [&~[data-slot=autocomplete-trigger]]:end-1.5",
|
|
16
|
+
default:
|
|
17
|
+
"h-8 px-2.5 [&~[data-slot=autocomplete-clear]]:end-1.75 [&~[data-slot=autocomplete-trigger]]:end-1.75",
|
|
18
|
+
lg: "h-9 px-2.5 [&~[data-slot=autocomplete-clear]]:end-2 [&~[data-slot=autocomplete-trigger]]:end-2",
|
|
19
|
+
},
|
|
20
|
+
},
|
|
21
|
+
defaultVariants: {
|
|
22
|
+
size: "default",
|
|
23
|
+
},
|
|
24
|
+
}
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
const Autocomplete = AutocompletePrimitive.Root
|
|
28
|
+
|
|
29
|
+
function AutocompleteValue({ ...props }: AutocompletePrimitive.Value.Props) {
|
|
30
|
+
return (
|
|
31
|
+
<AutocompletePrimitive.Value data-slot="autocomplete-value" {...props} />
|
|
32
|
+
)
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function AutocompleteInput({
|
|
36
|
+
className,
|
|
37
|
+
size = "default",
|
|
38
|
+
showClear = false,
|
|
39
|
+
showTrigger = false,
|
|
40
|
+
...props
|
|
41
|
+
}: Omit<AutocompletePrimitive.Input.Props, "size"> &
|
|
42
|
+
VariantProps<typeof inputVariants> & {
|
|
43
|
+
showClear?: boolean
|
|
44
|
+
showTrigger?: boolean
|
|
45
|
+
}) {
|
|
46
|
+
return (
|
|
47
|
+
<div className="relative w-full">
|
|
48
|
+
<AutocompletePrimitive.Input
|
|
49
|
+
data-slot="autocomplete-input"
|
|
50
|
+
data-size={size}
|
|
51
|
+
className={cn(inputVariants({ size }), className)}
|
|
52
|
+
{...props}
|
|
53
|
+
/>
|
|
54
|
+
{showTrigger && <AutocompleteTrigger />}
|
|
55
|
+
{showClear && <AutocompleteClear />}
|
|
56
|
+
</div>
|
|
57
|
+
)
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function AutocompleteStatus({
|
|
61
|
+
className,
|
|
62
|
+
...props
|
|
63
|
+
}: AutocompletePrimitive.Status.Props) {
|
|
64
|
+
return (
|
|
65
|
+
<AutocompletePrimitive.Status
|
|
66
|
+
data-slot="autocomplete-status"
|
|
67
|
+
className={cn(
|
|
68
|
+
"text-muted-foreground px-2 py-1.5 text-sm empty:m-0 empty:p-0",
|
|
69
|
+
className
|
|
70
|
+
)}
|
|
71
|
+
{...props}
|
|
72
|
+
/>
|
|
73
|
+
)
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function AutocompletePortal({ ...props }: AutocompletePrimitive.Portal.Props) {
|
|
77
|
+
return (
|
|
78
|
+
<AutocompletePrimitive.Portal data-slot="autocomplete-portal" {...props} />
|
|
79
|
+
)
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function AutocompleteBackdrop({
|
|
83
|
+
...props
|
|
84
|
+
}: AutocompletePrimitive.Backdrop.Props) {
|
|
85
|
+
return (
|
|
86
|
+
<AutocompletePrimitive.Backdrop
|
|
87
|
+
data-slot="autocomplete-backdrop"
|
|
88
|
+
{...props}
|
|
89
|
+
/>
|
|
90
|
+
)
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
function AutocompletePositioner({
|
|
94
|
+
className,
|
|
95
|
+
...props
|
|
96
|
+
}: AutocompletePrimitive.Positioner.Props) {
|
|
97
|
+
return (
|
|
98
|
+
<AutocompletePrimitive.Positioner
|
|
99
|
+
data-slot="autocomplete-positioner"
|
|
100
|
+
className={cn("z-50 outline-none", className)}
|
|
101
|
+
{...props}
|
|
102
|
+
/>
|
|
103
|
+
)
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
function AutocompleteList({
|
|
107
|
+
className,
|
|
108
|
+
scrollAreaClassName,
|
|
109
|
+
...props
|
|
110
|
+
}: AutocompletePrimitive.List.Props & {
|
|
111
|
+
scrollAreaClassName?: string
|
|
112
|
+
scrollFade?: boolean
|
|
113
|
+
scrollbarGutter?: boolean
|
|
114
|
+
}) {
|
|
115
|
+
return (
|
|
116
|
+
<ScrollArea
|
|
117
|
+
className={cn(
|
|
118
|
+
"size-full min-h-0 **:data-[slot=scroll-area-viewport]:h-full **:data-[slot=scroll-area-viewport]:overscroll-contain",
|
|
119
|
+
scrollAreaClassName
|
|
120
|
+
)}
|
|
121
|
+
>
|
|
122
|
+
<AutocompletePrimitive.List
|
|
123
|
+
data-slot="autocomplete-list"
|
|
124
|
+
className={cn(
|
|
125
|
+
"not-empty:px-1 not-empty:py-1 not-empty:scroll-py-1 in-data-has-overflow-y:me-3",
|
|
126
|
+
className
|
|
127
|
+
)}
|
|
128
|
+
{...props}
|
|
129
|
+
/>
|
|
130
|
+
</ScrollArea>
|
|
131
|
+
)
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
function AutocompleteCollection({
|
|
135
|
+
...props
|
|
136
|
+
}: React.ComponentProps<typeof AutocompletePrimitive.Collection>) {
|
|
137
|
+
return (
|
|
138
|
+
<AutocompletePrimitive.Collection
|
|
139
|
+
data-slot="autocomplete-collection"
|
|
140
|
+
{...props}
|
|
141
|
+
/>
|
|
142
|
+
)
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
function AutocompleteRow({
|
|
146
|
+
className,
|
|
147
|
+
...props
|
|
148
|
+
}: React.ComponentProps<typeof AutocompletePrimitive.Row>) {
|
|
149
|
+
return (
|
|
150
|
+
<AutocompletePrimitive.Row
|
|
151
|
+
data-slot="autocomplete-row"
|
|
152
|
+
className={cn("flex items-center gap-2", className)}
|
|
153
|
+
{...props}
|
|
154
|
+
/>
|
|
155
|
+
)
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
function AutocompleteItem({
|
|
159
|
+
className,
|
|
160
|
+
...props
|
|
161
|
+
}: React.ComponentProps<typeof AutocompletePrimitive.Item>) {
|
|
162
|
+
return (
|
|
163
|
+
<AutocompletePrimitive.Item
|
|
164
|
+
data-slot="autocomplete-item"
|
|
165
|
+
className={cn(
|
|
166
|
+
"text-foreground data-highlighted:text-foreground data-highlighted:before:bg-accent gap-1.5 rounded-md px-1.5 py-1 text-sm data-highlighted:before:rounded-sm [&_svg:not([class*='size-'])]:size-4 relative flex cursor-default items-center outline-hidden transition-colors select-none data-disabled:pointer-events-none data-disabled:opacity-50 data-highlighted:relative data-highlighted:z-0 data-highlighted:before:absolute data-highlighted:before:inset-x-0 data-highlighted:before:inset-y-0 data-highlighted:before:z-[-1] [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([role=img]):not([class*=text-])]:opacity-60",
|
|
167
|
+
className
|
|
168
|
+
)}
|
|
169
|
+
{...props}
|
|
170
|
+
/>
|
|
171
|
+
)
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
export interface AutocompleteContentProps extends React.ComponentProps<
|
|
175
|
+
typeof AutocompletePrimitive.Popup
|
|
176
|
+
> {
|
|
177
|
+
align?: AutocompletePrimitive.Positioner.Props["align"]
|
|
178
|
+
sideOffset?: AutocompletePrimitive.Positioner.Props["sideOffset"]
|
|
179
|
+
alignOffset?: AutocompletePrimitive.Positioner.Props["alignOffset"]
|
|
180
|
+
side?: AutocompletePrimitive.Positioner.Props["side"]
|
|
181
|
+
anchor?: AutocompletePrimitive.Positioner.Props["anchor"]
|
|
182
|
+
showBackdrop?: boolean
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
function AutocompleteContent({
|
|
186
|
+
className,
|
|
187
|
+
children,
|
|
188
|
+
showBackdrop = false,
|
|
189
|
+
align = "start",
|
|
190
|
+
sideOffset = 4,
|
|
191
|
+
alignOffset = 0,
|
|
192
|
+
side = "bottom",
|
|
193
|
+
anchor,
|
|
194
|
+
...props
|
|
195
|
+
}: AutocompleteContentProps) {
|
|
196
|
+
return (
|
|
197
|
+
<AutocompletePortal>
|
|
198
|
+
{showBackdrop && <AutocompleteBackdrop />}
|
|
199
|
+
<AutocompletePositioner
|
|
200
|
+
align={align}
|
|
201
|
+
sideOffset={sideOffset}
|
|
202
|
+
alignOffset={alignOffset}
|
|
203
|
+
side={side}
|
|
204
|
+
anchor={anchor}
|
|
205
|
+
>
|
|
206
|
+
<div className="relative flex max-h-full">
|
|
207
|
+
<AutocompletePrimitive.Popup
|
|
208
|
+
data-slot="autocomplete-popup"
|
|
209
|
+
className={cn(
|
|
210
|
+
"bg-popover text-popover-foreground rounded-lg shadow-md ring-foreground/10 flex max-h-[min(var(--available-height),24rem)] w-(--anchor-width) max-w-(--available-width) origin-(--transform-origin) scroll-pt-2 scroll-pb-2 flex-col overscroll-contain py-0.5 ring-1 transition-[scale,opacity] has-data-starting-style:scale-98 has-data-starting-style:opacity-0 has-data-[side=none]:scale-100 has-data-[side=none]:transition-none",
|
|
211
|
+
className
|
|
212
|
+
)}
|
|
213
|
+
{...props}
|
|
214
|
+
>
|
|
215
|
+
{children}
|
|
216
|
+
</AutocompletePrimitive.Popup>
|
|
217
|
+
</div>
|
|
218
|
+
</AutocompletePositioner>
|
|
219
|
+
</AutocompletePortal>
|
|
220
|
+
)
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
function AutocompleteGroup({
|
|
224
|
+
...props
|
|
225
|
+
}: React.ComponentProps<typeof AutocompletePrimitive.Group>) {
|
|
226
|
+
return (
|
|
227
|
+
<AutocompletePrimitive.Group data-slot="autocomplete-group" {...props} />
|
|
228
|
+
)
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
function AutocompleteGroupLabel({
|
|
232
|
+
className,
|
|
233
|
+
...props
|
|
234
|
+
}: React.ComponentProps<typeof AutocompletePrimitive.GroupLabel>) {
|
|
235
|
+
return (
|
|
236
|
+
<AutocompletePrimitive.GroupLabel
|
|
237
|
+
data-slot="autocomplete-group-label"
|
|
238
|
+
className={cn(
|
|
239
|
+
"text-muted-foreground px-1.5 py-1 text-xs font-medium",
|
|
240
|
+
className
|
|
241
|
+
)}
|
|
242
|
+
{...props}
|
|
243
|
+
/>
|
|
244
|
+
)
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
function AutocompleteEmpty({
|
|
248
|
+
className,
|
|
249
|
+
...props
|
|
250
|
+
}: React.ComponentProps<typeof AutocompletePrimitive.Empty>) {
|
|
251
|
+
return (
|
|
252
|
+
<AutocompletePrimitive.Empty
|
|
253
|
+
data-slot="autocomplete-empty"
|
|
254
|
+
className={cn(
|
|
255
|
+
"text-muted-foreground px-2 py-1.5 text-sm text-center empty:m-0 empty:p-0",
|
|
256
|
+
className
|
|
257
|
+
)}
|
|
258
|
+
{...props}
|
|
259
|
+
/>
|
|
260
|
+
)
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
function AutocompleteClear({
|
|
264
|
+
className,
|
|
265
|
+
...props
|
|
266
|
+
}: React.ComponentProps<typeof AutocompletePrimitive.Clear>) {
|
|
267
|
+
return (
|
|
268
|
+
<AutocompletePrimitive.Clear
|
|
269
|
+
data-slot="autocomplete-clear"
|
|
270
|
+
className={cn(
|
|
271
|
+
"ring-offset-background focus:ring-ring absolute top-1/2 -translate-y-1/2 cursor-pointer opacity-70 transition-opacity hover:opacity-100 focus:ring-2 focus:ring-offset-2 focus:outline-none disabled:pointer-events-none data-disabled:pointer-events-none",
|
|
272
|
+
className
|
|
273
|
+
)}
|
|
274
|
+
{...props}
|
|
275
|
+
>
|
|
276
|
+
<XIcon className="size-4" />
|
|
277
|
+
</AutocompletePrimitive.Clear>
|
|
278
|
+
)
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
function AutocompleteTrigger({
|
|
282
|
+
className,
|
|
283
|
+
...props
|
|
284
|
+
}: React.ComponentProps<typeof AutocompletePrimitive.Trigger>) {
|
|
285
|
+
return (
|
|
286
|
+
<AutocompletePrimitive.Trigger
|
|
287
|
+
data-slot="autocomplete-trigger"
|
|
288
|
+
className={cn(
|
|
289
|
+
"focus:ring-ring ring-offset-background absolute top-1/2 -translate-y-1/2 cursor-pointer focus:ring-2 focus:ring-offset-2 focus:outline-none disabled:pointer-events-none has-[+[data-slot=autocomplete-clear]]:hidden data-disabled:pointer-events-none",
|
|
290
|
+
className
|
|
291
|
+
)}
|
|
292
|
+
{...props}
|
|
293
|
+
>
|
|
294
|
+
<ChevronsUpDownIcon className="size-4 opacity-70" />
|
|
295
|
+
</AutocompletePrimitive.Trigger>
|
|
296
|
+
)
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
function AutocompleteArrow({
|
|
300
|
+
...props
|
|
301
|
+
}: React.ComponentProps<typeof AutocompletePrimitive.Arrow>) {
|
|
302
|
+
return (
|
|
303
|
+
<AutocompletePrimitive.Arrow data-slot="autocomplete-arrow" {...props} />
|
|
304
|
+
)
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
function AutocompleteSeparator({
|
|
308
|
+
className,
|
|
309
|
+
...props
|
|
310
|
+
}: React.ComponentProps<typeof AutocompletePrimitive.Separator>) {
|
|
311
|
+
return (
|
|
312
|
+
<AutocompletePrimitive.Separator
|
|
313
|
+
data-slot="autocomplete-separator"
|
|
314
|
+
className={cn(
|
|
315
|
+
"bg-border my-1.5 h-px",
|
|
316
|
+
className
|
|
317
|
+
)}
|
|
318
|
+
{...props}
|
|
319
|
+
/>
|
|
320
|
+
)
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
export {
|
|
324
|
+
Autocomplete,
|
|
325
|
+
AutocompleteValue,
|
|
326
|
+
AutocompleteTrigger,
|
|
327
|
+
AutocompleteInput,
|
|
328
|
+
AutocompleteStatus,
|
|
329
|
+
AutocompletePortal,
|
|
330
|
+
AutocompleteBackdrop,
|
|
331
|
+
AutocompletePositioner,
|
|
332
|
+
AutocompleteContent,
|
|
333
|
+
AutocompleteList,
|
|
334
|
+
AutocompleteCollection,
|
|
335
|
+
AutocompleteRow,
|
|
336
|
+
AutocompleteItem,
|
|
337
|
+
AutocompleteGroup,
|
|
338
|
+
AutocompleteGroupLabel,
|
|
339
|
+
AutocompleteEmpty,
|
|
340
|
+
AutocompleteClear,
|
|
341
|
+
AutocompleteArrow,
|
|
342
|
+
AutocompleteSeparator,
|
|
343
|
+
}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { cva, type VariantProps } from "class-variance-authority"
|
|
2
|
+
import { Slot } from "radix-ui"
|
|
3
|
+
|
|
4
|
+
import { cn } from "@/lib/utils"
|
|
5
|
+
|
|
6
|
+
const badgeVariants = cva(
|
|
7
|
+
"rounded-sm relative inline-flex shrink-0 items-center justify-center w-fit border border-transparent font-medium whitespace-nowrap outline-none transition-shadow focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1 focus-visible:ring-offset-background disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*=size-])]:size-3",
|
|
8
|
+
{
|
|
9
|
+
variants: {
|
|
10
|
+
variant: {
|
|
11
|
+
default: "bg-primary text-primary-foreground",
|
|
12
|
+
outline: "border-border bg-transparent dark:bg-input/32",
|
|
13
|
+
secondary: "bg-secondary text-secondary-foreground",
|
|
14
|
+
info: "bg-info text-white",
|
|
15
|
+
success: "bg-success text-white",
|
|
16
|
+
warning: "bg-warning text-white",
|
|
17
|
+
destructive: "bg-destructive text-white",
|
|
18
|
+
focus: "bg-focus text-focus-foreground",
|
|
19
|
+
invert: "bg-invert text-invert-foreground",
|
|
20
|
+
"primary-light":
|
|
21
|
+
"bg-primary/10 border-none text-primary dark:bg-primary/20",
|
|
22
|
+
"warning-light":
|
|
23
|
+
"bg-warning/10 border-none text-warning-foreground dark:bg-warning/20",
|
|
24
|
+
"success-light":
|
|
25
|
+
"bg-success/10 border-none text-success-foreground dark:bg-success/20",
|
|
26
|
+
"info-light":
|
|
27
|
+
"bg-info/10 border-none text-info-foreground dark:bg-info/20",
|
|
28
|
+
"destructive-light":
|
|
29
|
+
"bg-destructive/10 border-none text-destructive-foreground dark:bg-destructive/20",
|
|
30
|
+
"invert-light":
|
|
31
|
+
"bg-invert/10 border-none text-foreground dark:bg-invert/20",
|
|
32
|
+
"focus-light":
|
|
33
|
+
"bg-focus/10 border-none text-focus-foreground dark:bg-focus/20",
|
|
34
|
+
"primary-outline":
|
|
35
|
+
"bg-background border-border text-primary dark:bg-input/30",
|
|
36
|
+
"warning-outline":
|
|
37
|
+
"bg-background border-border text-warning-foreground dark:bg-input/30",
|
|
38
|
+
"success-outline":
|
|
39
|
+
"bg-background border-border text-success-foreground dark:bg-input/30",
|
|
40
|
+
"info-outline":
|
|
41
|
+
"bg-background border-border text-info-foreground dark:bg-input/30",
|
|
42
|
+
"destructive-outline":
|
|
43
|
+
"bg-background border-border text-destructive-foreground dark:bg-input/30",
|
|
44
|
+
"invert-outline":
|
|
45
|
+
"bg-background border-border text-invert-foreground dark:bg-input/30",
|
|
46
|
+
"focus-outline":
|
|
47
|
+
"bg-background border-border text-focus-foreground dark:bg-input/30",
|
|
48
|
+
},
|
|
49
|
+
size: {
|
|
50
|
+
xs: "px-1 py-0.25 text-[0.6rem] leading-none h-4 min-w-4 gap-1",
|
|
51
|
+
sm: "px-1 py-0.25 text-[0.625rem] leading-none h-4.5 min-w-4.5 gap-1",
|
|
52
|
+
default: "px-1.25 py-0.5 text-xs h-5 min-w-5 gap-1",
|
|
53
|
+
lg: "px-1.5 py-0.5 text-xs h-5.5 min-w-5.5 gap-1",
|
|
54
|
+
xl: "px-2 py-0.75 text-sm h-6 min-w-6 gap-1.5",
|
|
55
|
+
},
|
|
56
|
+
},
|
|
57
|
+
defaultVariants: {
|
|
58
|
+
variant: "default",
|
|
59
|
+
size: "default",
|
|
60
|
+
},
|
|
61
|
+
}
|
|
62
|
+
)
|
|
63
|
+
|
|
64
|
+
interface BadgeProps
|
|
65
|
+
extends React.ComponentProps<"span">, VariantProps<typeof badgeVariants> {
|
|
66
|
+
asChild?: boolean
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function Badge({
|
|
70
|
+
className,
|
|
71
|
+
variant,
|
|
72
|
+
size,
|
|
73
|
+
asChild = false,
|
|
74
|
+
...props
|
|
75
|
+
}: BadgeProps) {
|
|
76
|
+
const Comp = asChild ? Slot.Root : "span"
|
|
77
|
+
|
|
78
|
+
return (
|
|
79
|
+
<Comp
|
|
80
|
+
data-slot="badge"
|
|
81
|
+
className={cn(badgeVariants({ variant, size, className }))}
|
|
82
|
+
{...props}
|
|
83
|
+
/>
|
|
84
|
+
)
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
export { Badge, badgeVariants, type BadgeProps }
|