@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,235 @@
|
|
|
1
|
+
import type { ReactNode } from "react";
|
|
2
|
+
|
|
3
|
+
// =============================================================================
|
|
4
|
+
// Base Props (shared by all primitives)
|
|
5
|
+
// =============================================================================
|
|
6
|
+
|
|
7
|
+
export interface BasePrimitiveProps {
|
|
8
|
+
/** Unique identifier */
|
|
9
|
+
id?: string;
|
|
10
|
+
/** Placeholder text */
|
|
11
|
+
placeholder?: string;
|
|
12
|
+
/** Disabled state */
|
|
13
|
+
disabled?: boolean;
|
|
14
|
+
/** Read-only state */
|
|
15
|
+
readOnly?: boolean;
|
|
16
|
+
/** Additional class names */
|
|
17
|
+
className?: string;
|
|
18
|
+
/** aria-invalid for error state */
|
|
19
|
+
"aria-invalid"?: boolean;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
// =============================================================================
|
|
23
|
+
// Text Inputs
|
|
24
|
+
// =============================================================================
|
|
25
|
+
|
|
26
|
+
export interface TextInputProps extends BasePrimitiveProps {
|
|
27
|
+
value: string;
|
|
28
|
+
onChange: (value: string) => void;
|
|
29
|
+
type?: "text" | "email" | "password" | "url" | "tel" | "search";
|
|
30
|
+
maxLength?: number;
|
|
31
|
+
autoComplete?: string;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export interface NumberInputProps extends BasePrimitiveProps {
|
|
35
|
+
value: number | null;
|
|
36
|
+
onChange: (value: number | null) => void;
|
|
37
|
+
min?: number;
|
|
38
|
+
max?: number;
|
|
39
|
+
step?: number;
|
|
40
|
+
/** Show increment/decrement buttons */
|
|
41
|
+
showButtons?: boolean;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export interface TextareaInputProps extends BasePrimitiveProps {
|
|
45
|
+
value: string;
|
|
46
|
+
onChange: (value: string) => void;
|
|
47
|
+
rows?: number;
|
|
48
|
+
maxLength?: number;
|
|
49
|
+
autoResize?: boolean;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// =============================================================================
|
|
53
|
+
// Select / Multi-Select
|
|
54
|
+
// =============================================================================
|
|
55
|
+
|
|
56
|
+
export interface SelectOption<TValue = string> {
|
|
57
|
+
value: TValue;
|
|
58
|
+
label: string;
|
|
59
|
+
disabled?: boolean;
|
|
60
|
+
icon?: ReactNode;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export interface SelectOptionGroup<TValue = string> {
|
|
64
|
+
label: string;
|
|
65
|
+
options: SelectOption<TValue>[];
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export type SelectOptions<TValue = string> =
|
|
69
|
+
| SelectOption<TValue>[]
|
|
70
|
+
| SelectOptionGroup<TValue>[];
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Unified Select Input props
|
|
74
|
+
* - multiple: false (default) = single select (dropdown)
|
|
75
|
+
* - multiple: true = multi-select with chips
|
|
76
|
+
*
|
|
77
|
+
* Both modes support:
|
|
78
|
+
* - Static options array
|
|
79
|
+
* - Dynamic loading via loadOptions
|
|
80
|
+
* - Search/filtering
|
|
81
|
+
*/
|
|
82
|
+
export interface SelectInputProps<TValue = string> extends BasePrimitiveProps {
|
|
83
|
+
/** Selected value(s) */
|
|
84
|
+
value: TValue | TValue[] | null;
|
|
85
|
+
/** Change handler */
|
|
86
|
+
onChange: (value: TValue | TValue[] | null) => void;
|
|
87
|
+
/** Static options */
|
|
88
|
+
options?: SelectOptions<TValue>;
|
|
89
|
+
/** Dynamic options loader */
|
|
90
|
+
loadOptions?: (search: string) => Promise<SelectOption<TValue>[]>;
|
|
91
|
+
/** Allow multiple selections */
|
|
92
|
+
multiple?: boolean;
|
|
93
|
+
/** Allow clearing selection */
|
|
94
|
+
clearable?: boolean;
|
|
95
|
+
/** Max selections (for multiple mode) */
|
|
96
|
+
maxSelections?: number;
|
|
97
|
+
/** Debounce delay for loadOptions (ms) */
|
|
98
|
+
debounceMs?: number;
|
|
99
|
+
/** Loading state */
|
|
100
|
+
loading?: boolean;
|
|
101
|
+
/** Empty state message */
|
|
102
|
+
emptyMessage?: string;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// =============================================================================
|
|
106
|
+
// Boolean Inputs
|
|
107
|
+
// =============================================================================
|
|
108
|
+
|
|
109
|
+
export interface ToggleInputProps extends BasePrimitiveProps {
|
|
110
|
+
value: boolean;
|
|
111
|
+
onChange: (value: boolean) => void;
|
|
112
|
+
/** Size variant */
|
|
113
|
+
size?: "sm" | "default" | "lg";
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
export interface CheckboxInputProps extends BasePrimitiveProps {
|
|
117
|
+
value: boolean;
|
|
118
|
+
onChange: (value: boolean) => void;
|
|
119
|
+
/** Indeterminate state */
|
|
120
|
+
indeterminate?: boolean;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
export interface CheckboxGroupProps<TValue = string>
|
|
124
|
+
extends BasePrimitiveProps {
|
|
125
|
+
value: TValue[];
|
|
126
|
+
onChange: (value: TValue[]) => void;
|
|
127
|
+
options: SelectOption<TValue>[];
|
|
128
|
+
/** Layout direction */
|
|
129
|
+
orientation?: "horizontal" | "vertical";
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
export interface RadioGroupProps<TValue = string> extends BasePrimitiveProps {
|
|
133
|
+
value: TValue | null;
|
|
134
|
+
onChange: (value: TValue) => void;
|
|
135
|
+
options: SelectOption<TValue>[];
|
|
136
|
+
orientation?: "horizontal" | "vertical";
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// =============================================================================
|
|
140
|
+
// Date/Time Inputs
|
|
141
|
+
// =============================================================================
|
|
142
|
+
|
|
143
|
+
export interface DateInputProps extends BasePrimitiveProps {
|
|
144
|
+
value: Date | null;
|
|
145
|
+
onChange: (value: Date | null) => void;
|
|
146
|
+
/** Minimum date */
|
|
147
|
+
minDate?: Date;
|
|
148
|
+
/** Maximum date */
|
|
149
|
+
maxDate?: Date;
|
|
150
|
+
/** Date format display */
|
|
151
|
+
format?: string;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
export interface DateTimeInputProps extends DateInputProps {
|
|
155
|
+
/** Time precision */
|
|
156
|
+
precision?: "minute" | "second";
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
export interface TimeInputProps extends BasePrimitiveProps {
|
|
160
|
+
value: string | null; // "HH:mm" or "HH:mm:ss"
|
|
161
|
+
onChange: (value: string | null) => void;
|
|
162
|
+
precision?: "minute" | "second";
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
export interface DateRangeInputProps extends BasePrimitiveProps {
|
|
166
|
+
value: { start: Date | null; end: Date | null };
|
|
167
|
+
onChange: (value: { start: Date | null; end: Date | null }) => void;
|
|
168
|
+
minDate?: Date;
|
|
169
|
+
maxDate?: Date;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
// =============================================================================
|
|
173
|
+
// Special Inputs
|
|
174
|
+
// =============================================================================
|
|
175
|
+
|
|
176
|
+
export interface TagInputProps extends BasePrimitiveProps {
|
|
177
|
+
value: string[];
|
|
178
|
+
onChange: (value: string[]) => void;
|
|
179
|
+
/** Suggestions for autocomplete */
|
|
180
|
+
suggestions?: string[];
|
|
181
|
+
/** Max tags */
|
|
182
|
+
maxTags?: number;
|
|
183
|
+
/** Allow duplicates */
|
|
184
|
+
allowDuplicates?: boolean;
|
|
185
|
+
/** Validation pattern */
|
|
186
|
+
pattern?: RegExp;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
export interface ColorInputProps extends BasePrimitiveProps {
|
|
190
|
+
value: string; // hex color
|
|
191
|
+
onChange: (value: string) => void;
|
|
192
|
+
/** Preset colors */
|
|
193
|
+
presets?: string[];
|
|
194
|
+
/** Allow alpha */
|
|
195
|
+
alpha?: boolean;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
export interface SliderInputProps extends BasePrimitiveProps {
|
|
199
|
+
value: number | [number, number];
|
|
200
|
+
onChange: (value: number | [number, number]) => void;
|
|
201
|
+
min: number;
|
|
202
|
+
max: number;
|
|
203
|
+
step?: number;
|
|
204
|
+
/** Show value label */
|
|
205
|
+
showValue?: boolean;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
export interface JsonEditorProps extends BasePrimitiveProps {
|
|
209
|
+
value: unknown;
|
|
210
|
+
onChange: (value: unknown) => void;
|
|
211
|
+
/** Max height */
|
|
212
|
+
maxHeight?: string;
|
|
213
|
+
/** Line numbers */
|
|
214
|
+
showLineNumbers?: boolean;
|
|
215
|
+
/** Schema for validation */
|
|
216
|
+
schema?: unknown;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
// =============================================================================
|
|
220
|
+
// Utility Types
|
|
221
|
+
// =============================================================================
|
|
222
|
+
|
|
223
|
+
/** Check if options are grouped */
|
|
224
|
+
export function isOptionGroup<T>(
|
|
225
|
+
option: SelectOption<T> | SelectOptionGroup<T>,
|
|
226
|
+
): option is SelectOptionGroup<T> {
|
|
227
|
+
return "options" in option;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
/** Flatten grouped options */
|
|
231
|
+
export function flattenOptions<T>(
|
|
232
|
+
options: SelectOptions<T>,
|
|
233
|
+
): SelectOption<T>[] {
|
|
234
|
+
return options.flatMap((opt) => (isOptionGroup(opt) ? opt.options : [opt]));
|
|
235
|
+
}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { Accordion as AccordionPrimitive } from "@base-ui/react/accordion"
|
|
2
|
+
|
|
3
|
+
import { cn } from "../../lib/utils"
|
|
4
|
+
import { CaretDownIcon, CaretUpIcon } from "@phosphor-icons/react"
|
|
5
|
+
|
|
6
|
+
function Accordion({ className, ...props }: AccordionPrimitive.Root.Props) {
|
|
7
|
+
return (
|
|
8
|
+
<AccordionPrimitive.Root
|
|
9
|
+
data-slot="accordion"
|
|
10
|
+
className={cn("overflow-hidden rounded-md border flex w-full flex-col", className)}
|
|
11
|
+
{...props}
|
|
12
|
+
/>
|
|
13
|
+
)
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
function AccordionItem({ className, ...props }: AccordionPrimitive.Item.Props) {
|
|
17
|
+
return (
|
|
18
|
+
<AccordionPrimitive.Item
|
|
19
|
+
data-slot="accordion-item"
|
|
20
|
+
className={cn("data-open:bg-muted/50 not-last:border-b", className)}
|
|
21
|
+
{...props}
|
|
22
|
+
/>
|
|
23
|
+
)
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function AccordionTrigger({
|
|
27
|
+
className,
|
|
28
|
+
children,
|
|
29
|
+
...props
|
|
30
|
+
}: AccordionPrimitive.Trigger.Props) {
|
|
31
|
+
return (
|
|
32
|
+
<AccordionPrimitive.Header className="flex">
|
|
33
|
+
<AccordionPrimitive.Trigger
|
|
34
|
+
data-slot="accordion-trigger"
|
|
35
|
+
className={cn(
|
|
36
|
+
"**:data-[slot=accordion-trigger-icon]:text-muted-foreground gap-6 p-2 text-left text-xs/relaxed font-medium hover:underline **:data-[slot=accordion-trigger-icon]:ml-auto **:data-[slot=accordion-trigger-icon]:size-4 group/accordion-trigger relative flex flex-1 items-start justify-between border border-transparent transition-all outline-none disabled:pointer-events-none disabled:opacity-50",
|
|
37
|
+
className
|
|
38
|
+
)}
|
|
39
|
+
{...props}
|
|
40
|
+
>
|
|
41
|
+
{children}
|
|
42
|
+
<CaretDownIcon data-slot="accordion-trigger-icon" className="pointer-events-none shrink-0 group-aria-expanded/accordion-trigger:hidden" />
|
|
43
|
+
<CaretUpIcon data-slot="accordion-trigger-icon" className="pointer-events-none hidden shrink-0 group-aria-expanded/accordion-trigger:inline" />
|
|
44
|
+
</AccordionPrimitive.Trigger>
|
|
45
|
+
</AccordionPrimitive.Header>
|
|
46
|
+
)
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function AccordionContent({
|
|
50
|
+
className,
|
|
51
|
+
children,
|
|
52
|
+
...props
|
|
53
|
+
}: AccordionPrimitive.Panel.Props) {
|
|
54
|
+
return (
|
|
55
|
+
<AccordionPrimitive.Panel
|
|
56
|
+
data-slot="accordion-content"
|
|
57
|
+
className="data-open:animate-accordion-down data-closed:animate-accordion-up px-2 text-xs/relaxed overflow-hidden"
|
|
58
|
+
{...props}
|
|
59
|
+
>
|
|
60
|
+
<div
|
|
61
|
+
className={cn(
|
|
62
|
+
"pt-0 pb-4 [&_a]:hover:text-foreground h-(--accordion-panel-height) data-ending-style:h-0 data-starting-style:h-0 [&_a]:underline [&_a]:underline-offset-3 [&_p:not(:last-child)]:mb-4",
|
|
63
|
+
className
|
|
64
|
+
)}
|
|
65
|
+
>
|
|
66
|
+
{children}
|
|
67
|
+
</div>
|
|
68
|
+
</AccordionPrimitive.Panel>
|
|
69
|
+
)
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export { Accordion, AccordionItem, AccordionTrigger, AccordionContent }
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
"use client"
|
|
2
|
+
|
|
3
|
+
import * as React from "react"
|
|
4
|
+
import { Avatar as AvatarPrimitive } from "@base-ui/react/avatar"
|
|
5
|
+
|
|
6
|
+
import { cn } from "../../lib/utils"
|
|
7
|
+
|
|
8
|
+
function Avatar({
|
|
9
|
+
className,
|
|
10
|
+
size = "default",
|
|
11
|
+
...props
|
|
12
|
+
}: AvatarPrimitive.Root.Props & {
|
|
13
|
+
size?: "default" | "sm" | "lg"
|
|
14
|
+
}) {
|
|
15
|
+
return (
|
|
16
|
+
<AvatarPrimitive.Root
|
|
17
|
+
data-slot="avatar"
|
|
18
|
+
data-size={size}
|
|
19
|
+
className={cn(
|
|
20
|
+
"size-8 rounded-full after:rounded-full data-[size=lg]:size-10 data-[size=sm]:size-6 after:border-border group/avatar relative flex shrink-0 select-none after:absolute after:inset-0 after:border after:mix-blend-darken dark:after:mix-blend-lighten",
|
|
21
|
+
className
|
|
22
|
+
)}
|
|
23
|
+
{...props}
|
|
24
|
+
/>
|
|
25
|
+
)
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function AvatarImage({ className, ...props }: AvatarPrimitive.Image.Props) {
|
|
29
|
+
return (
|
|
30
|
+
<AvatarPrimitive.Image
|
|
31
|
+
data-slot="avatar-image"
|
|
32
|
+
className={cn(
|
|
33
|
+
"rounded-full aspect-square size-full object-cover",
|
|
34
|
+
className
|
|
35
|
+
)}
|
|
36
|
+
{...props}
|
|
37
|
+
/>
|
|
38
|
+
)
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function AvatarFallback({
|
|
42
|
+
className,
|
|
43
|
+
...props
|
|
44
|
+
}: AvatarPrimitive.Fallback.Props) {
|
|
45
|
+
return (
|
|
46
|
+
<AvatarPrimitive.Fallback
|
|
47
|
+
data-slot="avatar-fallback"
|
|
48
|
+
className={cn(
|
|
49
|
+
"bg-muted text-muted-foreground rounded-full flex size-full items-center justify-center text-sm group-data-[size=sm]/avatar:text-xs",
|
|
50
|
+
className
|
|
51
|
+
)}
|
|
52
|
+
{...props}
|
|
53
|
+
/>
|
|
54
|
+
)
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function AvatarBadge({ className, ...props }: React.ComponentProps<"span">) {
|
|
58
|
+
return (
|
|
59
|
+
<span
|
|
60
|
+
data-slot="avatar-badge"
|
|
61
|
+
className={cn(
|
|
62
|
+
"bg-primary text-primary-foreground ring-background absolute right-0 bottom-0 z-10 inline-flex items-center justify-center rounded-full bg-blend-color ring-2 select-none",
|
|
63
|
+
"group-data-[size=sm]/avatar:size-2 group-data-[size=sm]/avatar:[&>svg]:hidden",
|
|
64
|
+
"group-data-[size=default]/avatar:size-2.5 group-data-[size=default]/avatar:[&>svg]:size-2",
|
|
65
|
+
"group-data-[size=lg]/avatar:size-3 group-data-[size=lg]/avatar:[&>svg]:size-2",
|
|
66
|
+
className
|
|
67
|
+
)}
|
|
68
|
+
{...props}
|
|
69
|
+
/>
|
|
70
|
+
)
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function AvatarGroup({ className, ...props }: React.ComponentProps<"div">) {
|
|
74
|
+
return (
|
|
75
|
+
<div
|
|
76
|
+
data-slot="avatar-group"
|
|
77
|
+
className={cn(
|
|
78
|
+
"*:data-[slot=avatar]:ring-background group/avatar-group flex -space-x-2 *:data-[slot=avatar]:ring-2",
|
|
79
|
+
className
|
|
80
|
+
)}
|
|
81
|
+
{...props}
|
|
82
|
+
/>
|
|
83
|
+
)
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
function AvatarGroupCount({
|
|
87
|
+
className,
|
|
88
|
+
...props
|
|
89
|
+
}: React.ComponentProps<"div">) {
|
|
90
|
+
return (
|
|
91
|
+
<div
|
|
92
|
+
data-slot="avatar-group-count"
|
|
93
|
+
className={cn("bg-muted text-muted-foreground size-8 rounded-full text-xs/relaxed 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 ring-background relative flex shrink-0 items-center justify-center ring-2", className)}
|
|
94
|
+
{...props}
|
|
95
|
+
/>
|
|
96
|
+
)
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
export {
|
|
100
|
+
Avatar,
|
|
101
|
+
AvatarImage,
|
|
102
|
+
AvatarFallback,
|
|
103
|
+
AvatarGroup,
|
|
104
|
+
AvatarGroupCount,
|
|
105
|
+
AvatarBadge,
|
|
106
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { mergeProps } from "@base-ui/react/merge-props"
|
|
2
|
+
import { useRender } from "@base-ui/react/use-render"
|
|
3
|
+
import { cva, type VariantProps } from "class-variance-authority"
|
|
4
|
+
|
|
5
|
+
import { cn } from "../../lib/utils"
|
|
6
|
+
|
|
7
|
+
const badgeVariants = cva(
|
|
8
|
+
"h-5 gap-1 rounded-full border border-transparent px-2 py-0.5 text-[0.625rem] font-medium transition-all has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5 [&>svg]:size-2.5! inline-flex items-center justify-center w-fit whitespace-nowrap shrink-0 [&>svg]:pointer-events-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive transition-colors overflow-hidden group/badge",
|
|
9
|
+
{
|
|
10
|
+
variants: {
|
|
11
|
+
variant: {
|
|
12
|
+
default: "bg-primary text-primary-foreground [a]:hover:bg-primary/80",
|
|
13
|
+
secondary: "bg-secondary text-secondary-foreground [a]:hover:bg-secondary/80",
|
|
14
|
+
destructive: "bg-destructive/10 [a]:hover:bg-destructive/20 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 text-destructive dark:bg-destructive/20",
|
|
15
|
+
outline: "border-border text-foreground [a]:hover:bg-muted [a]:hover:text-muted-foreground bg-input/20 dark:bg-input/30",
|
|
16
|
+
ghost: "hover:bg-muted hover:text-muted-foreground dark:hover:bg-muted/50",
|
|
17
|
+
link: "text-primary underline-offset-4 hover:underline",
|
|
18
|
+
},
|
|
19
|
+
},
|
|
20
|
+
defaultVariants: {
|
|
21
|
+
variant: "default",
|
|
22
|
+
},
|
|
23
|
+
}
|
|
24
|
+
)
|
|
25
|
+
|
|
26
|
+
function Badge({
|
|
27
|
+
className,
|
|
28
|
+
variant = "default",
|
|
29
|
+
render,
|
|
30
|
+
...props
|
|
31
|
+
}: useRender.ComponentProps<"span"> & VariantProps<typeof badgeVariants>) {
|
|
32
|
+
return useRender({
|
|
33
|
+
defaultTagName: "span",
|
|
34
|
+
props: mergeProps<"span">(
|
|
35
|
+
{
|
|
36
|
+
className: cn(badgeVariants({ className, variant })),
|
|
37
|
+
},
|
|
38
|
+
props
|
|
39
|
+
),
|
|
40
|
+
render,
|
|
41
|
+
state: {
|
|
42
|
+
slot: "badge",
|
|
43
|
+
variant,
|
|
44
|
+
},
|
|
45
|
+
})
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export { Badge, badgeVariants }
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
"use client"
|
|
2
|
+
|
|
3
|
+
import { Button as ButtonPrimitive } from "@base-ui/react/button"
|
|
4
|
+
import { cva, type VariantProps } from "class-variance-authority"
|
|
5
|
+
|
|
6
|
+
import { cn } from "../../lib/utils"
|
|
7
|
+
|
|
8
|
+
const buttonVariants = cva(
|
|
9
|
+
"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 rounded-md border border-transparent bg-clip-padding text-xs/relaxed font-medium focus-visible:ring-[2px] aria-invalid:ring-[2px] [&_svg:not([class*='size-'])]:size-4 inline-flex items-center justify-center whitespace-nowrap transition-all disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none shrink-0 [&_svg]:shrink-0 outline-none group/button select-none",
|
|
10
|
+
{
|
|
11
|
+
variants: {
|
|
12
|
+
variant: {
|
|
13
|
+
default: "bg-primary text-primary-foreground hover:bg-primary/80",
|
|
14
|
+
outline: "border-border dark:bg-input/30 hover:bg-input/50 hover:text-foreground aria-expanded:bg-muted aria-expanded:text-foreground",
|
|
15
|
+
secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/80 aria-expanded:bg-secondary aria-expanded:text-secondary-foreground",
|
|
16
|
+
ghost: "hover:bg-muted hover:text-foreground dark:hover:bg-muted/50 aria-expanded:bg-muted aria-expanded:text-foreground",
|
|
17
|
+
destructive: "bg-destructive/10 hover:bg-destructive/20 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/20 text-destructive focus-visible:border-destructive/40 dark:hover:bg-destructive/30",
|
|
18
|
+
link: "text-primary underline-offset-4 hover:underline",
|
|
19
|
+
},
|
|
20
|
+
size: {
|
|
21
|
+
default: "h-7 gap-1 px-2 text-xs/relaxed has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5 [&_svg:not([class*='size-'])]:size-3.5",
|
|
22
|
+
xs: "h-5 gap-1 rounded-sm px-2 text-[0.625rem] has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5 [&_svg:not([class*='size-'])]:size-2.5",
|
|
23
|
+
sm: "h-6 gap-1 px-2 text-xs/relaxed has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5 [&_svg:not([class*='size-'])]:size-3",
|
|
24
|
+
lg: "h-8 gap-1 px-2.5 text-xs/relaxed has-data-[icon=inline-end]:pr-2 has-data-[icon=inline-start]:pl-2 [&_svg:not([class*='size-'])]:size-4",
|
|
25
|
+
icon: "size-7 [&_svg:not([class*='size-'])]:size-3.5",
|
|
26
|
+
"icon-xs": "size-5 rounded-sm [&_svg:not([class*='size-'])]:size-2.5",
|
|
27
|
+
"icon-sm": "size-6 [&_svg:not([class*='size-'])]:size-3",
|
|
28
|
+
"icon-lg": "size-8 [&_svg:not([class*='size-'])]:size-4",
|
|
29
|
+
},
|
|
30
|
+
},
|
|
31
|
+
defaultVariants: {
|
|
32
|
+
variant: "default",
|
|
33
|
+
size: "default",
|
|
34
|
+
},
|
|
35
|
+
}
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
function Button({
|
|
39
|
+
className,
|
|
40
|
+
variant = "default",
|
|
41
|
+
size = "default",
|
|
42
|
+
...props
|
|
43
|
+
}: ButtonPrimitive.Props & VariantProps<typeof buttonVariants>) {
|
|
44
|
+
return (
|
|
45
|
+
<ButtonPrimitive
|
|
46
|
+
data-slot="button"
|
|
47
|
+
className={cn(buttonVariants({ variant, size, className }))}
|
|
48
|
+
{...props}
|
|
49
|
+
/>
|
|
50
|
+
)
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export { Button, buttonVariants }
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import * as React from "react"
|
|
2
|
+
|
|
3
|
+
import { cn } from "../../lib/utils"
|
|
4
|
+
|
|
5
|
+
function Card({
|
|
6
|
+
className,
|
|
7
|
+
size = "default",
|
|
8
|
+
...props
|
|
9
|
+
}: React.ComponentProps<"div"> & { size?: "default" | "sm" }) {
|
|
10
|
+
return (
|
|
11
|
+
<div
|
|
12
|
+
data-slot="card"
|
|
13
|
+
data-size={size}
|
|
14
|
+
className={cn("ring-foreground/10 bg-card text-card-foreground gap-4 overflow-hidden rounded-lg py-4 text-xs/relaxed ring-1 has-[>img:first-child]:pt-0 data-[size=sm]:gap-3 data-[size=sm]:py-3 *:[img:first-child]:rounded-t-lg *:[img:last-child]:rounded-b-lg group/card flex flex-col", className)}
|
|
15
|
+
{...props}
|
|
16
|
+
/>
|
|
17
|
+
)
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function CardHeader({ className, ...props }: React.ComponentProps<"div">) {
|
|
21
|
+
return (
|
|
22
|
+
<div
|
|
23
|
+
data-slot="card-header"
|
|
24
|
+
className={cn(
|
|
25
|
+
"gap-1 rounded-t-lg px-4 group-data-[size=sm]/card:px-3 [.border-b]:pb-4 group-data-[size=sm]/card:[.border-b]:pb-3 group/card-header @container/card-header grid auto-rows-min items-start has-data-[slot=card-action]:grid-cols-[1fr_auto] has-data-[slot=card-description]:grid-rows-[auto_auto]",
|
|
26
|
+
className
|
|
27
|
+
)}
|
|
28
|
+
{...props}
|
|
29
|
+
/>
|
|
30
|
+
)
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function CardTitle({ className, ...props }: React.ComponentProps<"div">) {
|
|
34
|
+
return (
|
|
35
|
+
<div
|
|
36
|
+
data-slot="card-title"
|
|
37
|
+
className={cn("text-sm font-medium", className)}
|
|
38
|
+
{...props}
|
|
39
|
+
/>
|
|
40
|
+
)
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function CardDescription({ className, ...props }: React.ComponentProps<"div">) {
|
|
44
|
+
return (
|
|
45
|
+
<div
|
|
46
|
+
data-slot="card-description"
|
|
47
|
+
className={cn("text-muted-foreground text-xs/relaxed", className)}
|
|
48
|
+
{...props}
|
|
49
|
+
/>
|
|
50
|
+
)
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function CardAction({ className, ...props }: React.ComponentProps<"div">) {
|
|
54
|
+
return (
|
|
55
|
+
<div
|
|
56
|
+
data-slot="card-action"
|
|
57
|
+
className={cn(
|
|
58
|
+
"col-start-2 row-span-2 row-start-1 self-start justify-self-end",
|
|
59
|
+
className
|
|
60
|
+
)}
|
|
61
|
+
{...props}
|
|
62
|
+
/>
|
|
63
|
+
)
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function CardContent({ className, ...props }: React.ComponentProps<"div">) {
|
|
67
|
+
return (
|
|
68
|
+
<div
|
|
69
|
+
data-slot="card-content"
|
|
70
|
+
className={cn("px-4 group-data-[size=sm]/card:px-3", className)}
|
|
71
|
+
{...props}
|
|
72
|
+
/>
|
|
73
|
+
)
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function CardFooter({ className, ...props }: React.ComponentProps<"div">) {
|
|
77
|
+
return (
|
|
78
|
+
<div
|
|
79
|
+
data-slot="card-footer"
|
|
80
|
+
className={cn("rounded-b-lg px-4 group-data-[size=sm]/card:px-3 [.border-t]:pt-4 group-data-[size=sm]/card:[.border-t]:pt-3 flex items-center", className)}
|
|
81
|
+
{...props}
|
|
82
|
+
/>
|
|
83
|
+
)
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
export {
|
|
87
|
+
Card,
|
|
88
|
+
CardHeader,
|
|
89
|
+
CardFooter,
|
|
90
|
+
CardTitle,
|
|
91
|
+
CardAction,
|
|
92
|
+
CardDescription,
|
|
93
|
+
CardContent,
|
|
94
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { Checkbox as CheckboxPrimitive } from "@base-ui/react/checkbox"
|
|
2
|
+
|
|
3
|
+
import { cn } from "../../lib/utils"
|
|
4
|
+
import { CheckIcon } from "@phosphor-icons/react"
|
|
5
|
+
|
|
6
|
+
function Checkbox({ className, ...props }: CheckboxPrimitive.Root.Props) {
|
|
7
|
+
return (
|
|
8
|
+
<CheckboxPrimitive.Root
|
|
9
|
+
data-slot="checkbox"
|
|
10
|
+
className={cn(
|
|
11
|
+
"border-input dark:bg-input/30 data-checked:bg-primary data-checked:text-primary-foreground dark:data-checked:bg-primary data-checked:border-primary aria-invalid:aria-checked:border-primary aria-invalid:border-destructive dark:aria-invalid:border-destructive/50 focus-visible:border-ring focus-visible:ring-ring/30 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 flex size-4 items-center justify-center rounded-[4px] border transition-shadow group-has-disabled/field:opacity-50 focus-visible:ring-[2px] aria-invalid:ring-[2px] peer relative shrink-0 outline-none after:absolute after:-inset-x-3 after:-inset-y-2 disabled:cursor-not-allowed disabled:opacity-50",
|
|
12
|
+
className
|
|
13
|
+
)}
|
|
14
|
+
{...props}
|
|
15
|
+
>
|
|
16
|
+
<CheckboxPrimitive.Indicator
|
|
17
|
+
data-slot="checkbox-indicator"
|
|
18
|
+
className="[&>svg]:size-3.5 grid place-content-center text-current transition-none"
|
|
19
|
+
>
|
|
20
|
+
<CheckIcon
|
|
21
|
+
/>
|
|
22
|
+
</CheckboxPrimitive.Indicator>
|
|
23
|
+
</CheckboxPrimitive.Root>
|
|
24
|
+
)
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export { Checkbox }
|