@questpie/admin 0.0.1
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/.turbo/turbo-build.log +108 -0
- package/CHANGELOG.md +10 -0
- package/README.md +556 -0
- package/STATUS.md +917 -0
- package/VALIDATION.md +602 -0
- package/components.json +24 -0
- package/dist/__tests__/setup.mjs +38 -0
- package/dist/__tests__/test-utils.mjs +45 -0
- package/dist/__tests__/vitest.d.mjs +3 -0
- package/dist/components/admin-app.mjs +69 -0
- package/dist/components/fields/array-field.mjs +190 -0
- package/dist/components/fields/checkbox-field.mjs +34 -0
- package/dist/components/fields/custom-field.mjs +32 -0
- package/dist/components/fields/date-field.mjs +41 -0
- package/dist/components/fields/datetime-field.mjs +42 -0
- package/dist/components/fields/email-field.mjs +37 -0
- package/dist/components/fields/embedded-collection.mjs +253 -0
- package/dist/components/fields/field-types.mjs +1 -0
- package/dist/components/fields/field-utils.mjs +10 -0
- package/dist/components/fields/field-wrapper.mjs +34 -0
- package/dist/components/fields/index.mjs +23 -0
- package/dist/components/fields/json-field.mjs +243 -0
- package/dist/components/fields/locale-badge.mjs +16 -0
- package/dist/components/fields/number-field.mjs +39 -0
- package/dist/components/fields/password-field.mjs +37 -0
- package/dist/components/fields/relation-field.mjs +104 -0
- package/dist/components/fields/relation-picker.mjs +229 -0
- package/dist/components/fields/relation-select.mjs +188 -0
- package/dist/components/fields/rich-text-editor/index.mjs +897 -0
- package/dist/components/fields/select-field.mjs +41 -0
- package/dist/components/fields/switch-field.mjs +34 -0
- package/dist/components/fields/text-field.mjs +38 -0
- package/dist/components/fields/textarea-field.mjs +38 -0
- package/dist/components/index.mjs +59 -0
- package/dist/components/primitives/checkbox-input.mjs +127 -0
- package/dist/components/primitives/date-input.mjs +303 -0
- package/dist/components/primitives/index.mjs +12 -0
- package/dist/components/primitives/number-input.mjs +104 -0
- package/dist/components/primitives/select-input.mjs +177 -0
- package/dist/components/primitives/tag-input.mjs +135 -0
- package/dist/components/primitives/text-input.mjs +39 -0
- package/dist/components/primitives/textarea-input.mjs +37 -0
- package/dist/components/primitives/toggle-input.mjs +31 -0
- package/dist/components/primitives/types.mjs +12 -0
- package/dist/components/ui/accordion.mjs +55 -0
- package/dist/components/ui/avatar.mjs +54 -0
- package/dist/components/ui/badge.mjs +34 -0
- package/dist/components/ui/button.mjs +48 -0
- package/dist/components/ui/card.mjs +58 -0
- package/dist/components/ui/checkbox.mjs +21 -0
- package/dist/components/ui/combobox.mjs +163 -0
- package/dist/components/ui/dialog.mjs +95 -0
- package/dist/components/ui/dropdown-menu.mjs +138 -0
- package/dist/components/ui/field.mjs +113 -0
- package/dist/components/ui/input-group.mjs +82 -0
- package/dist/components/ui/input.mjs +17 -0
- package/dist/components/ui/label.mjs +15 -0
- package/dist/components/ui/popover.mjs +56 -0
- package/dist/components/ui/scroll-area.mjs +38 -0
- package/dist/components/ui/select.mjs +100 -0
- package/dist/components/ui/separator.mjs +16 -0
- package/dist/components/ui/sheet.mjs +90 -0
- package/dist/components/ui/sidebar.mjs +387 -0
- package/dist/components/ui/skeleton.mjs +14 -0
- package/dist/components/ui/spinner.mjs +16 -0
- package/dist/components/ui/switch.mjs +22 -0
- package/dist/components/ui/table.mjs +68 -0
- package/dist/components/ui/tabs.mjs +48 -0
- package/dist/components/ui/textarea.mjs +15 -0
- package/dist/components/ui/tooltip.mjs +44 -0
- package/dist/config/component-registry.mjs +38 -0
- package/dist/config/index.mjs +129 -0
- package/dist/hooks/admin-provider.mjs +70 -0
- package/dist/hooks/index.mjs +7 -0
- package/dist/hooks/store.mjs +178 -0
- package/dist/hooks/use-auth.mjs +76 -0
- package/dist/hooks/use-collection-db.mjs +146 -0
- package/dist/hooks/use-collection.mjs +112 -0
- package/dist/hooks/use-global.mjs +46 -0
- package/dist/hooks/use-mobile.mjs +20 -0
- package/dist/lib/utils.mjs +10 -0
- package/dist/styles/index.css +336 -0
- package/dist/styles/index.mjs +1 -0
- package/dist/utils/index.mjs +9 -0
- package/dist/views/auth/auth-layout.mjs +52 -0
- package/dist/views/auth/forgot-password-form.mjs +148 -0
- package/dist/views/auth/index.mjs +6 -0
- package/dist/views/auth/login-form.mjs +156 -0
- package/dist/views/auth/reset-password-form.mjs +184 -0
- package/dist/views/collection/auto-form-fields.mjs +525 -0
- package/dist/views/collection/collection-form.mjs +91 -0
- package/dist/views/collection/collection-list.mjs +76 -0
- package/dist/views/collection/form-field.mjs +42 -0
- package/dist/views/collection/index.mjs +6 -0
- package/dist/views/common/index.mjs +4 -0
- package/dist/views/common/locale-switcher.mjs +39 -0
- package/dist/views/common/version-history.mjs +272 -0
- package/dist/views/index.mjs +9 -0
- package/dist/views/layout/admin-layout.mjs +40 -0
- package/dist/views/layout/admin-router.mjs +95 -0
- package/dist/views/layout/admin-sidebar.mjs +63 -0
- package/dist/views/layout/index.mjs +5 -0
- package/package.json +276 -0
- package/src/__tests__/setup.ts +44 -0
- package/src/__tests__/test-utils.tsx +49 -0
- package/src/__tests__/vitest.d.ts +9 -0
- package/src/components/admin-app.tsx +221 -0
- package/src/components/fields/array-field.tsx +237 -0
- package/src/components/fields/checkbox-field.tsx +47 -0
- package/src/components/fields/custom-field.tsx +50 -0
- package/src/components/fields/date-field.tsx +65 -0
- package/src/components/fields/datetime-field.tsx +67 -0
- package/src/components/fields/email-field.tsx +51 -0
- package/src/components/fields/embedded-collection.tsx +315 -0
- package/src/components/fields/field-types.ts +162 -0
- package/src/components/fields/field-utils.ts +6 -0
- package/src/components/fields/field-wrapper.tsx +52 -0
- package/src/components/fields/index.ts +66 -0
- package/src/components/fields/json-field.tsx +440 -0
- package/src/components/fields/locale-badge.tsx +15 -0
- package/src/components/fields/number-field.tsx +57 -0
- package/src/components/fields/password-field.tsx +51 -0
- package/src/components/fields/relation-field.tsx +243 -0
- package/src/components/fields/relation-picker.tsx +402 -0
- package/src/components/fields/relation-select.tsx +327 -0
- package/src/components/fields/rich-text-editor/index.tsx +1337 -0
- package/src/components/fields/select-field.tsx +61 -0
- package/src/components/fields/switch-field.tsx +47 -0
- package/src/components/fields/text-field.tsx +55 -0
- package/src/components/fields/textarea-field.tsx +55 -0
- package/src/components/index.ts +40 -0
- package/src/components/primitives/checkbox-input.tsx +193 -0
- package/src/components/primitives/date-input.tsx +401 -0
- package/src/components/primitives/index.ts +24 -0
- package/src/components/primitives/number-input.tsx +132 -0
- package/src/components/primitives/select-input.tsx +296 -0
- package/src/components/primitives/tag-input.tsx +200 -0
- package/src/components/primitives/text-input.tsx +49 -0
- package/src/components/primitives/textarea-input.tsx +46 -0
- package/src/components/primitives/toggle-input.tsx +36 -0
- package/src/components/primitives/types.ts +235 -0
- package/src/components/ui/accordion.tsx +72 -0
- package/src/components/ui/avatar.tsx +106 -0
- package/src/components/ui/badge.tsx +48 -0
- package/src/components/ui/button.tsx +53 -0
- package/src/components/ui/card.tsx +94 -0
- package/src/components/ui/checkbox.tsx +27 -0
- package/src/components/ui/combobox.tsx +290 -0
- package/src/components/ui/dialog.tsx +151 -0
- package/src/components/ui/dropdown-menu.tsx +254 -0
- package/src/components/ui/field.tsx +227 -0
- package/src/components/ui/input-group.tsx +149 -0
- package/src/components/ui/input.tsx +20 -0
- package/src/components/ui/label.tsx +18 -0
- package/src/components/ui/popover.tsx +88 -0
- package/src/components/ui/scroll-area.tsx +53 -0
- package/src/components/ui/select.tsx +192 -0
- package/src/components/ui/separator.tsx +23 -0
- package/src/components/ui/sheet.tsx +127 -0
- package/src/components/ui/sidebar.tsx +723 -0
- package/src/components/ui/skeleton.tsx +13 -0
- package/src/components/ui/spinner.tsx +10 -0
- package/src/components/ui/switch.tsx +32 -0
- package/src/components/ui/table.tsx +99 -0
- package/src/components/ui/tabs.tsx +82 -0
- package/src/components/ui/textarea.tsx +18 -0
- package/src/components/ui/tooltip.tsx +70 -0
- package/src/config/component-registry.ts +190 -0
- package/src/config/index.ts +1099 -0
- package/src/hooks/README.md +269 -0
- package/src/hooks/admin-provider.tsx +110 -0
- package/src/hooks/index.ts +41 -0
- package/src/hooks/store.ts +248 -0
- package/src/hooks/use-auth.ts +168 -0
- package/src/hooks/use-collection-db.ts +209 -0
- package/src/hooks/use-collection.ts +156 -0
- package/src/hooks/use-global.ts +69 -0
- package/src/hooks/use-mobile.ts +21 -0
- package/src/lib/utils.ts +6 -0
- package/src/styles/index.css +340 -0
- package/src/utils/index.ts +6 -0
- package/src/views/auth/auth-layout.tsx +77 -0
- package/src/views/auth/forgot-password-form.tsx +192 -0
- package/src/views/auth/index.ts +21 -0
- package/src/views/auth/login-form.tsx +229 -0
- package/src/views/auth/reset-password-form.tsx +232 -0
- package/src/views/collection/auto-form-fields.tsx +982 -0
- package/src/views/collection/collection-form.tsx +186 -0
- package/src/views/collection/collection-list.tsx +223 -0
- package/src/views/collection/form-field.tsx +52 -0
- package/src/views/collection/index.ts +15 -0
- package/src/views/common/index.ts +8 -0
- package/src/views/common/locale-switcher.tsx +45 -0
- package/src/views/common/version-history.tsx +406 -0
- package/src/views/index.ts +25 -0
- package/src/views/layout/admin-layout.tsx +117 -0
- package/src/views/layout/admin-router.tsx +206 -0
- package/src/views/layout/admin-sidebar.tsx +185 -0
- package/src/views/layout/index.ts +12 -0
- package/tsconfig.json +13 -0
- package/tsconfig.tsbuildinfo +1 -0
- package/tsdown.config.ts +13 -0
- package/vitest.config.ts +29 -0
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { cn } from "../../lib/utils"
|
|
2
|
+
|
|
3
|
+
function Skeleton({ className, ...props }: React.ComponentProps<"div">) {
|
|
4
|
+
return (
|
|
5
|
+
<div
|
|
6
|
+
data-slot="skeleton"
|
|
7
|
+
className={cn("bg-muted rounded-md animate-pulse", className)}
|
|
8
|
+
{...props}
|
|
9
|
+
/>
|
|
10
|
+
)
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export { Skeleton }
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { cn } from "../../lib/utils"
|
|
2
|
+
import { SpinnerIcon } from "@phosphor-icons/react"
|
|
3
|
+
|
|
4
|
+
function Spinner({ className, ...props }: React.ComponentProps<"svg">) {
|
|
5
|
+
return (
|
|
6
|
+
<SpinnerIcon role="status" aria-label="Loading" className={cn("size-4 animate-spin", className)} {...props} />
|
|
7
|
+
)
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export { Spinner }
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
"use client"
|
|
2
|
+
|
|
3
|
+
import { Switch as SwitchPrimitive } from "@base-ui/react/switch"
|
|
4
|
+
|
|
5
|
+
import { cn } from "../../lib/utils"
|
|
6
|
+
|
|
7
|
+
function Switch({
|
|
8
|
+
className,
|
|
9
|
+
size = "default",
|
|
10
|
+
...props
|
|
11
|
+
}: SwitchPrimitive.Root.Props & {
|
|
12
|
+
size?: "sm" | "default"
|
|
13
|
+
}) {
|
|
14
|
+
return (
|
|
15
|
+
<SwitchPrimitive.Root
|
|
16
|
+
data-slot="switch"
|
|
17
|
+
data-size={size}
|
|
18
|
+
className={cn(
|
|
19
|
+
"data-checked:bg-primary data-unchecked:bg-input focus-visible:border-ring focus-visible:ring-ring/30 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive dark:aria-invalid:border-destructive/50 dark:data-unchecked:bg-input/80 shrink-0 rounded-full border border-transparent focus-visible:ring-[2px] aria-invalid:ring-[2px] data-[size=default]:h-[16.6px] data-[size=default]:w-[28px] data-[size=sm]:h-[14px] data-[size=sm]:w-[24px] peer group/switch relative inline-flex items-center transition-all outline-none after:absolute after:-inset-x-3 after:-inset-y-2 data-disabled:cursor-not-allowed data-disabled:opacity-50",
|
|
20
|
+
className
|
|
21
|
+
)}
|
|
22
|
+
{...props}
|
|
23
|
+
>
|
|
24
|
+
<SwitchPrimitive.Thumb
|
|
25
|
+
data-slot="switch-thumb"
|
|
26
|
+
className="bg-background dark:data-unchecked:bg-foreground dark:data-checked:bg-primary-foreground rounded-full group-data-[size=default]/switch:size-3.5 group-data-[size=sm]/switch:size-3 group-data-[size=default]/switch:data-checked:translate-x-[calc(100%-2px)] group-data-[size=sm]/switch:data-checked:translate-x-[calc(100%-2px)] group-data-[size=default]/switch:data-unchecked:translate-x-0 group-data-[size=sm]/switch:data-unchecked:translate-x-0 pointer-events-none block ring-0 transition-transform"
|
|
27
|
+
/>
|
|
28
|
+
</SwitchPrimitive.Root>
|
|
29
|
+
)
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export { Switch }
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import * as React from "react"
|
|
2
|
+
|
|
3
|
+
import { cn } from "../../lib/utils"
|
|
4
|
+
|
|
5
|
+
function Table({ className, ...props }: React.ComponentProps<"table">) {
|
|
6
|
+
return (
|
|
7
|
+
<div data-slot="table-container" className="relative w-full overflow-x-auto">
|
|
8
|
+
<table
|
|
9
|
+
data-slot="table"
|
|
10
|
+
className={cn("w-full caption-bottom text-xs", className)}
|
|
11
|
+
{...props}
|
|
12
|
+
/>
|
|
13
|
+
</div>
|
|
14
|
+
)
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function TableHeader({ className, ...props }: React.ComponentProps<"thead">) {
|
|
18
|
+
return (
|
|
19
|
+
<thead
|
|
20
|
+
data-slot="table-header"
|
|
21
|
+
className={cn("[&_tr]:border-b", className)}
|
|
22
|
+
{...props}
|
|
23
|
+
/>
|
|
24
|
+
)
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function TableBody({ className, ...props }: React.ComponentProps<"tbody">) {
|
|
28
|
+
return (
|
|
29
|
+
<tbody
|
|
30
|
+
data-slot="table-body"
|
|
31
|
+
className={cn("[&_tr:last-child]:border-0", className)}
|
|
32
|
+
{...props}
|
|
33
|
+
/>
|
|
34
|
+
)
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function TableFooter({ className, ...props }: React.ComponentProps<"tfoot">) {
|
|
38
|
+
return (
|
|
39
|
+
<tfoot
|
|
40
|
+
data-slot="table-footer"
|
|
41
|
+
className={cn("bg-muted/50 border-t font-medium [&>tr]:last:border-b-0", className)}
|
|
42
|
+
{...props}
|
|
43
|
+
/>
|
|
44
|
+
)
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function TableRow({ className, ...props }: React.ComponentProps<"tr">) {
|
|
48
|
+
return (
|
|
49
|
+
<tr
|
|
50
|
+
data-slot="table-row"
|
|
51
|
+
className={cn("hover:bg-muted/50 data-[state=selected]:bg-muted border-b transition-colors", className)}
|
|
52
|
+
{...props}
|
|
53
|
+
/>
|
|
54
|
+
)
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function TableHead({ className, ...props }: React.ComponentProps<"th">) {
|
|
58
|
+
return (
|
|
59
|
+
<th
|
|
60
|
+
data-slot="table-head"
|
|
61
|
+
className={cn("text-foreground h-10 px-2 text-left align-middle font-medium whitespace-nowrap [&:has([role=checkbox])]:pr-0", className)}
|
|
62
|
+
{...props}
|
|
63
|
+
/>
|
|
64
|
+
)
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function TableCell({ className, ...props }: React.ComponentProps<"td">) {
|
|
68
|
+
return (
|
|
69
|
+
<td
|
|
70
|
+
data-slot="table-cell"
|
|
71
|
+
className={cn("p-2 align-middle whitespace-nowrap [&:has([role=checkbox])]:pr-0", className)}
|
|
72
|
+
{...props}
|
|
73
|
+
/>
|
|
74
|
+
)
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function TableCaption({
|
|
78
|
+
className,
|
|
79
|
+
...props
|
|
80
|
+
}: React.ComponentProps<"caption">) {
|
|
81
|
+
return (
|
|
82
|
+
<caption
|
|
83
|
+
data-slot="table-caption"
|
|
84
|
+
className={cn("text-muted-foreground mt-4 text-xs", className)}
|
|
85
|
+
{...props}
|
|
86
|
+
/>
|
|
87
|
+
)
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
export {
|
|
91
|
+
Table,
|
|
92
|
+
TableHeader,
|
|
93
|
+
TableBody,
|
|
94
|
+
TableFooter,
|
|
95
|
+
TableHead,
|
|
96
|
+
TableRow,
|
|
97
|
+
TableCell,
|
|
98
|
+
TableCaption,
|
|
99
|
+
}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
"use client"
|
|
2
|
+
|
|
3
|
+
import { Tabs as TabsPrimitive } from "@base-ui/react/tabs"
|
|
4
|
+
import { cva, type VariantProps } from "class-variance-authority"
|
|
5
|
+
|
|
6
|
+
import { cn } from "../../lib/utils"
|
|
7
|
+
|
|
8
|
+
function Tabs({
|
|
9
|
+
className,
|
|
10
|
+
orientation = "horizontal",
|
|
11
|
+
...props
|
|
12
|
+
}: TabsPrimitive.Root.Props) {
|
|
13
|
+
return (
|
|
14
|
+
<TabsPrimitive.Root
|
|
15
|
+
data-slot="tabs"
|
|
16
|
+
data-orientation={orientation}
|
|
17
|
+
className={cn(
|
|
18
|
+
"gap-2 group/tabs flex data-[orientation=horizontal]:flex-col",
|
|
19
|
+
className
|
|
20
|
+
)}
|
|
21
|
+
{...props}
|
|
22
|
+
/>
|
|
23
|
+
)
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const tabsListVariants = cva(
|
|
27
|
+
"rounded-lg p-[3px] group-data-horizontal/tabs:h-8 data-[variant=line]:rounded-none group/tabs-list text-muted-foreground inline-flex w-fit items-center justify-center group-data-[orientation=vertical]/tabs:h-fit group-data-[orientation=vertical]/tabs:flex-col",
|
|
28
|
+
{
|
|
29
|
+
variants: {
|
|
30
|
+
variant: {
|
|
31
|
+
default: "bg-muted",
|
|
32
|
+
line: "gap-1 bg-transparent",
|
|
33
|
+
},
|
|
34
|
+
},
|
|
35
|
+
defaultVariants: {
|
|
36
|
+
variant: "default",
|
|
37
|
+
},
|
|
38
|
+
}
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
function TabsList({
|
|
42
|
+
className,
|
|
43
|
+
variant = "default",
|
|
44
|
+
...props
|
|
45
|
+
}: TabsPrimitive.List.Props & VariantProps<typeof tabsListVariants>) {
|
|
46
|
+
return (
|
|
47
|
+
<TabsPrimitive.List
|
|
48
|
+
data-slot="tabs-list"
|
|
49
|
+
data-variant={variant}
|
|
50
|
+
className={cn(tabsListVariants({ variant }), className)}
|
|
51
|
+
{...props}
|
|
52
|
+
/>
|
|
53
|
+
)
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function TabsTrigger({ className, ...props }: TabsPrimitive.Tab.Props) {
|
|
57
|
+
return (
|
|
58
|
+
<TabsPrimitive.Tab
|
|
59
|
+
data-slot="tabs-trigger"
|
|
60
|
+
className={cn(
|
|
61
|
+
"gap-1.5 rounded-md border border-transparent px-1.5 py-0.5 text-xs font-medium group-data-vertical/tabs:py-[calc(--spacing(1.25))] [&_svg:not([class*='size-'])]:size-3.5 focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:outline-ring text-foreground/60 hover:text-foreground dark:text-muted-foreground dark:hover:text-foreground relative inline-flex h-[calc(100%-1px)] flex-1 items-center justify-center whitespace-nowrap transition-all group-data-[orientation=vertical]/tabs:w-full group-data-[orientation=vertical]/tabs:justify-start focus-visible:ring-[3px] focus-visible:outline-1 disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0",
|
|
62
|
+
"group-data-[variant=line]/tabs-list:bg-transparent group-data-[variant=line]/tabs-list:data-active:bg-transparent dark:group-data-[variant=line]/tabs-list:data-active:border-transparent dark:group-data-[variant=line]/tabs-list:data-active:bg-transparent",
|
|
63
|
+
"data-active:bg-background dark:data-active:text-foreground dark:data-active:border-input dark:data-active:bg-input/30 data-active:text-foreground",
|
|
64
|
+
"after:bg-foreground after:absolute after:opacity-0 after:transition-opacity group-data-[orientation=horizontal]/tabs:after:inset-x-0 group-data-[orientation=horizontal]/tabs:after:bottom-[-5px] group-data-[orientation=horizontal]/tabs:after:h-0.5 group-data-[orientation=vertical]/tabs:after:inset-y-0 group-data-[orientation=vertical]/tabs:after:-right-1 group-data-[orientation=vertical]/tabs:after:w-0.5 group-data-[variant=line]/tabs-list:data-active:after:opacity-100",
|
|
65
|
+
className
|
|
66
|
+
)}
|
|
67
|
+
{...props}
|
|
68
|
+
/>
|
|
69
|
+
)
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function TabsContent({ className, ...props }: TabsPrimitive.Panel.Props) {
|
|
73
|
+
return (
|
|
74
|
+
<TabsPrimitive.Panel
|
|
75
|
+
data-slot="tabs-content"
|
|
76
|
+
className={cn("text-xs/relaxed flex-1 outline-none", className)}
|
|
77
|
+
{...props}
|
|
78
|
+
/>
|
|
79
|
+
)
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
export { Tabs, TabsList, TabsTrigger, TabsContent, tabsListVariants }
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import * as React from "react"
|
|
2
|
+
|
|
3
|
+
import { cn } from "../../lib/utils"
|
|
4
|
+
|
|
5
|
+
function Textarea({ className, ...props }: React.ComponentProps<"textarea">) {
|
|
6
|
+
return (
|
|
7
|
+
<textarea
|
|
8
|
+
data-slot="textarea"
|
|
9
|
+
className={cn(
|
|
10
|
+
"border-input bg-input/20 dark:bg-input/30 focus-visible:border-ring focus-visible:ring-ring/30 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive dark:aria-invalid:border-destructive/50 resize-none rounded-md border px-2 py-2 text-sm transition-colors focus-visible:ring-[2px] aria-invalid:ring-[2px] md:text-xs/relaxed placeholder:text-muted-foreground flex field-sizing-content min-h-16 w-full outline-none disabled:cursor-not-allowed disabled:opacity-50",
|
|
11
|
+
className
|
|
12
|
+
)}
|
|
13
|
+
{...props}
|
|
14
|
+
/>
|
|
15
|
+
)
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export { Textarea }
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
"use client"
|
|
2
|
+
|
|
3
|
+
import { Tooltip as TooltipPrimitive } from "@base-ui/react/tooltip"
|
|
4
|
+
|
|
5
|
+
import { cn } from "../../lib/utils"
|
|
6
|
+
|
|
7
|
+
function TooltipProvider({
|
|
8
|
+
delay = 0,
|
|
9
|
+
...props
|
|
10
|
+
}: TooltipPrimitive.Provider.Props) {
|
|
11
|
+
return (
|
|
12
|
+
<TooltipPrimitive.Provider
|
|
13
|
+
data-slot="tooltip-provider"
|
|
14
|
+
delay={delay}
|
|
15
|
+
{...props}
|
|
16
|
+
/>
|
|
17
|
+
)
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function Tooltip({ ...props }: TooltipPrimitive.Root.Props) {
|
|
21
|
+
return (
|
|
22
|
+
<TooltipProvider>
|
|
23
|
+
<TooltipPrimitive.Root data-slot="tooltip" {...props} />
|
|
24
|
+
</TooltipProvider>
|
|
25
|
+
)
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function TooltipTrigger({ ...props }: TooltipPrimitive.Trigger.Props) {
|
|
29
|
+
return <TooltipPrimitive.Trigger data-slot="tooltip-trigger" {...props} />
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function TooltipContent({
|
|
33
|
+
className,
|
|
34
|
+
side = "top",
|
|
35
|
+
sideOffset = 4,
|
|
36
|
+
align = "center",
|
|
37
|
+
alignOffset = 0,
|
|
38
|
+
children,
|
|
39
|
+
...props
|
|
40
|
+
}: TooltipPrimitive.Popup.Props &
|
|
41
|
+
Pick<
|
|
42
|
+
TooltipPrimitive.Positioner.Props,
|
|
43
|
+
"align" | "alignOffset" | "side" | "sideOffset"
|
|
44
|
+
>) {
|
|
45
|
+
return (
|
|
46
|
+
<TooltipPrimitive.Portal>
|
|
47
|
+
<TooltipPrimitive.Positioner
|
|
48
|
+
align={align}
|
|
49
|
+
alignOffset={alignOffset}
|
|
50
|
+
side={side}
|
|
51
|
+
sideOffset={sideOffset}
|
|
52
|
+
className="isolate z-50"
|
|
53
|
+
>
|
|
54
|
+
<TooltipPrimitive.Popup
|
|
55
|
+
data-slot="tooltip-content"
|
|
56
|
+
className={cn(
|
|
57
|
+
"data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-[state=delayed-open]:animate-in data-[state=delayed-open]:fade-in-0 data-[state=delayed-open]:zoom-in-95 data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 rounded-md px-3 py-1.5 text-xs **:data-[slot=kbd]:rounded-md bg-foreground text-background z-50 w-fit max-w-xs origin-(--transform-origin)",
|
|
58
|
+
className
|
|
59
|
+
)}
|
|
60
|
+
{...props}
|
|
61
|
+
>
|
|
62
|
+
{children}
|
|
63
|
+
<TooltipPrimitive.Arrow className="size-2.5 translate-y-[calc(-50%_-_2px)] rotate-45 rounded-[2px] bg-foreground fill-foreground z-50 data-[side=bottom]:top-1 data-[side=left]:top-1/2! data-[side=left]:-right-1 data-[side=left]:-translate-y-1/2 data-[side=right]:top-1/2! data-[side=right]:-left-1 data-[side=right]:-translate-y-1/2 data-[side=top]:-bottom-2.5" />
|
|
64
|
+
</TooltipPrimitive.Popup>
|
|
65
|
+
</TooltipPrimitive.Positioner>
|
|
66
|
+
</TooltipPrimitive.Portal>
|
|
67
|
+
)
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider }
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Component Registry
|
|
3
|
+
*
|
|
4
|
+
* Centralized registry for custom field components, layouts, and UI overrides
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import type * as React from "react";
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Base props for all field components
|
|
11
|
+
*/
|
|
12
|
+
export interface FieldComponentProps<TValue = any> {
|
|
13
|
+
name: string;
|
|
14
|
+
value: TValue;
|
|
15
|
+
onChange: (value: TValue) => void;
|
|
16
|
+
onBlur?: () => void;
|
|
17
|
+
disabled?: boolean;
|
|
18
|
+
readOnly?: boolean;
|
|
19
|
+
error?: string;
|
|
20
|
+
label?: string;
|
|
21
|
+
description?: string;
|
|
22
|
+
placeholder?: string;
|
|
23
|
+
required?: boolean;
|
|
24
|
+
localized?: boolean;
|
|
25
|
+
locale?: string;
|
|
26
|
+
// Field metadata from CMS schema
|
|
27
|
+
fieldMeta?: {
|
|
28
|
+
type: string;
|
|
29
|
+
nullable?: boolean;
|
|
30
|
+
default?: any;
|
|
31
|
+
// Drizzle column config
|
|
32
|
+
column?: any;
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Relation field props
|
|
38
|
+
*/
|
|
39
|
+
export interface RelationFieldProps extends FieldComponentProps {
|
|
40
|
+
/**
|
|
41
|
+
* Target collection name
|
|
42
|
+
*/
|
|
43
|
+
targetCollection: string;
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Relation type
|
|
47
|
+
*/
|
|
48
|
+
relationType: "one" | "many";
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* How to display selected options
|
|
52
|
+
*/
|
|
53
|
+
optionLabel?: (item: any) => string;
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Custom option loader
|
|
57
|
+
*/
|
|
58
|
+
loadOptions?: () => Promise<any[]>;
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* UI mode
|
|
62
|
+
*/
|
|
63
|
+
mode?: "picker" | "inline" | "create";
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Embedded collection field props
|
|
68
|
+
*/
|
|
69
|
+
export interface EmbeddedCollectionProps extends FieldComponentProps {
|
|
70
|
+
/**
|
|
71
|
+
* Embedded collection name
|
|
72
|
+
*/
|
|
73
|
+
collection: string;
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Display mode
|
|
77
|
+
*/
|
|
78
|
+
mode?: "inline" | "modal" | "drawer";
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Can reorder items
|
|
82
|
+
*/
|
|
83
|
+
orderable?: boolean;
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Row label generator
|
|
87
|
+
*/
|
|
88
|
+
rowLabel?: (item: any) => string;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Component registry type
|
|
93
|
+
*/
|
|
94
|
+
export interface ComponentRegistry {
|
|
95
|
+
/**
|
|
96
|
+
* Field components by type
|
|
97
|
+
*/
|
|
98
|
+
fields?: {
|
|
99
|
+
// Basic types
|
|
100
|
+
text?: React.ComponentType<FieldComponentProps<string>>;
|
|
101
|
+
textarea?: React.ComponentType<FieldComponentProps<string>>;
|
|
102
|
+
number?: React.ComponentType<FieldComponentProps<number>>;
|
|
103
|
+
boolean?: React.ComponentType<FieldComponentProps<boolean>>;
|
|
104
|
+
date?: React.ComponentType<FieldComponentProps<Date>>;
|
|
105
|
+
datetime?: React.ComponentType<FieldComponentProps<Date>>;
|
|
106
|
+
array?: React.ComponentType<FieldComponentProps<any[]>>;
|
|
107
|
+
|
|
108
|
+
// Advanced types
|
|
109
|
+
richText?: React.ComponentType<FieldComponentProps<any>>;
|
|
110
|
+
markdown?: React.ComponentType<FieldComponentProps<string>>;
|
|
111
|
+
code?: React.ComponentType<FieldComponentProps<string>>;
|
|
112
|
+
json?: React.ComponentType<FieldComponentProps<any>>;
|
|
113
|
+
color?: React.ComponentType<FieldComponentProps<string>>;
|
|
114
|
+
|
|
115
|
+
// Relations
|
|
116
|
+
relation?: React.ComponentType<RelationFieldProps>;
|
|
117
|
+
relationMany?: React.ComponentType<RelationFieldProps>;
|
|
118
|
+
|
|
119
|
+
// Embedded
|
|
120
|
+
embedded?: React.ComponentType<EmbeddedCollectionProps>;
|
|
121
|
+
|
|
122
|
+
// File upload
|
|
123
|
+
file?: React.ComponentType<FieldComponentProps<string>>;
|
|
124
|
+
image?: React.ComponentType<FieldComponentProps<string>>;
|
|
125
|
+
gallery?: React.ComponentType<FieldComponentProps<string[]>>;
|
|
126
|
+
};
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* Layout components
|
|
130
|
+
*/
|
|
131
|
+
layouts?: {
|
|
132
|
+
shell?: React.ComponentType<any>;
|
|
133
|
+
sidebar?: React.ComponentType<any>;
|
|
134
|
+
header?: React.ComponentType<any>;
|
|
135
|
+
footer?: React.ComponentType<any>;
|
|
136
|
+
};
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Custom components (user-defined)
|
|
140
|
+
*/
|
|
141
|
+
custom?: Record<string, React.ComponentType<any>>;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Default component registry
|
|
146
|
+
* These are the built-in components from @questpie/admin
|
|
147
|
+
*/
|
|
148
|
+
export const defaultComponentRegistry: ComponentRegistry = {
|
|
149
|
+
fields: {
|
|
150
|
+
// Will be populated with default components
|
|
151
|
+
// text: DefaultTextInput,
|
|
152
|
+
// textarea: DefaultTextarea,
|
|
153
|
+
// etc.
|
|
154
|
+
},
|
|
155
|
+
layouts: {},
|
|
156
|
+
custom: {},
|
|
157
|
+
};
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* Merge user registry with defaults
|
|
161
|
+
*/
|
|
162
|
+
export function mergeComponentRegistry(
|
|
163
|
+
userRegistry?: Partial<ComponentRegistry>,
|
|
164
|
+
): ComponentRegistry {
|
|
165
|
+
return {
|
|
166
|
+
fields: {
|
|
167
|
+
...defaultComponentRegistry.fields,
|
|
168
|
+
...userRegistry?.fields,
|
|
169
|
+
},
|
|
170
|
+
layouts: {
|
|
171
|
+
...defaultComponentRegistry.layouts,
|
|
172
|
+
...userRegistry?.layouts,
|
|
173
|
+
},
|
|
174
|
+
custom: {
|
|
175
|
+
...defaultComponentRegistry.custom,
|
|
176
|
+
...userRegistry?.custom,
|
|
177
|
+
},
|
|
178
|
+
};
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* Get component from registry by key
|
|
183
|
+
*/
|
|
184
|
+
export function getComponent(
|
|
185
|
+
registry: ComponentRegistry,
|
|
186
|
+
type: "fields" | "layouts" | "custom",
|
|
187
|
+
key: string,
|
|
188
|
+
): React.ComponentType<any> | undefined {
|
|
189
|
+
return registry[type]?.[key as keyof typeof registry[typeof type]];
|
|
190
|
+
}
|