@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,340 @@
|
|
|
1
|
+
@import "tailwindcss";
|
|
2
|
+
@import "tw-animate-css";
|
|
3
|
+
@import "shadcn/tailwind.css";
|
|
4
|
+
@import "@fontsource-variable/dm-sans";
|
|
5
|
+
@import "@fontsource-variable/jetbrains-mono";
|
|
6
|
+
|
|
7
|
+
@custom-variant dark (&:is(.dark *));
|
|
8
|
+
|
|
9
|
+
/* =============================================================================
|
|
10
|
+
QUESTPIE Design System - Cyber-Minimalist Theme
|
|
11
|
+
|
|
12
|
+
Core principles:
|
|
13
|
+
- Zero radius (sharp corners)
|
|
14
|
+
- Neon purple accents with glow effects
|
|
15
|
+
- Pitch-black foundation
|
|
16
|
+
- Backdrop blur for depth
|
|
17
|
+
============================================================================= */
|
|
18
|
+
|
|
19
|
+
:root {
|
|
20
|
+
/* Core Colors (Light mode - for completeness, but dark is primary) */
|
|
21
|
+
--background: oklch(1 0 0);
|
|
22
|
+
--foreground: oklch(0.145 0 0);
|
|
23
|
+
--card: oklch(0.98 0 0);
|
|
24
|
+
--card-foreground: oklch(0.145 0 0);
|
|
25
|
+
--popover: oklch(1 0 0);
|
|
26
|
+
--popover-foreground: oklch(0.145 0 0);
|
|
27
|
+
--primary: oklch(0.55 0.3 300);
|
|
28
|
+
--primary-foreground: oklch(1 0 0);
|
|
29
|
+
--secondary: oklch(0.96 0 0);
|
|
30
|
+
--secondary-foreground: oklch(0.55 0.3 300);
|
|
31
|
+
--muted: oklch(0.96 0 0);
|
|
32
|
+
--muted-foreground: oklch(0.5 0 0);
|
|
33
|
+
--accent: oklch(0.96 0 0);
|
|
34
|
+
--accent-foreground: oklch(0.2 0 0);
|
|
35
|
+
--destructive: oklch(0.58 0.22 27);
|
|
36
|
+
--border: oklch(0.9 0 0);
|
|
37
|
+
--input: oklch(0.9 0 0);
|
|
38
|
+
--ring: oklch(0.55 0.3 300 / 50%);
|
|
39
|
+
|
|
40
|
+
/* Chart Colors */
|
|
41
|
+
--chart-1: oklch(0.7 0.25 300);
|
|
42
|
+
--chart-2: oklch(0.65 0.28 310);
|
|
43
|
+
--chart-3: oklch(0.6 0.3 300);
|
|
44
|
+
--chart-4: oklch(0.55 0.3 300);
|
|
45
|
+
--chart-5: oklch(0.5 0.28 300);
|
|
46
|
+
|
|
47
|
+
/* QUESTPIE: Zero Radius */
|
|
48
|
+
--radius: 0px;
|
|
49
|
+
|
|
50
|
+
/* Sidebar */
|
|
51
|
+
--sidebar: oklch(0.98 0 0);
|
|
52
|
+
--sidebar-foreground: oklch(0.145 0 0);
|
|
53
|
+
--sidebar-primary: oklch(0.55 0.3 300);
|
|
54
|
+
--sidebar-primary-foreground: oklch(1 0 0);
|
|
55
|
+
--sidebar-accent: oklch(0.96 0 0);
|
|
56
|
+
--sidebar-accent-foreground: oklch(0.2 0 0);
|
|
57
|
+
--sidebar-border: oklch(0.9 0 0);
|
|
58
|
+
--sidebar-ring: oklch(0.55 0.3 300 / 50%);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/* Dark Mode - QUESTPIE Primary Theme */
|
|
62
|
+
.dark {
|
|
63
|
+
/* Depth Black Foundation */
|
|
64
|
+
--background: oklch(0.14 0 0);
|
|
65
|
+
--foreground: oklch(0.92 0.01 255);
|
|
66
|
+
|
|
67
|
+
/* Surface Black */
|
|
68
|
+
--card: oklch(0.18 0 0);
|
|
69
|
+
--card-foreground: oklch(0.92 0.01 255);
|
|
70
|
+
|
|
71
|
+
/* Popover */
|
|
72
|
+
--popover: oklch(0.18 0 0);
|
|
73
|
+
--popover-foreground: oklch(0.92 0.01 255);
|
|
74
|
+
|
|
75
|
+
/* Neon Purple Accent */
|
|
76
|
+
--primary: oklch(0.55 0.3 300);
|
|
77
|
+
--primary-foreground: oklch(1 0 0);
|
|
78
|
+
|
|
79
|
+
/* Neutral Surface */
|
|
80
|
+
--secondary: oklch(0.22 0 0);
|
|
81
|
+
--secondary-foreground: oklch(0.55 0.3 300);
|
|
82
|
+
|
|
83
|
+
/* Muted */
|
|
84
|
+
--muted: oklch(0.25 0 0);
|
|
85
|
+
--muted-foreground: oklch(0.7 0 0);
|
|
86
|
+
|
|
87
|
+
/* Accent */
|
|
88
|
+
--accent: oklch(0.25 0 0);
|
|
89
|
+
--accent-foreground: oklch(0.92 0.01 255);
|
|
90
|
+
|
|
91
|
+
/* Destructive */
|
|
92
|
+
--destructive: oklch(0.65 0.22 27);
|
|
93
|
+
|
|
94
|
+
/* Technical Border */
|
|
95
|
+
--border: oklch(0.32 0 0);
|
|
96
|
+
--input: oklch(0.28 0 0);
|
|
97
|
+
|
|
98
|
+
/* Glow Focus Ring */
|
|
99
|
+
--ring: oklch(0.55 0.3 300 / 50%);
|
|
100
|
+
|
|
101
|
+
/* Chart Colors */
|
|
102
|
+
--chart-1: oklch(0.7 0.25 300);
|
|
103
|
+
--chart-2: oklch(0.65 0.28 310);
|
|
104
|
+
--chart-3: oklch(0.6 0.3 300);
|
|
105
|
+
--chart-4: oklch(0.55 0.3 300);
|
|
106
|
+
--chart-5: oklch(0.5 0.28 300);
|
|
107
|
+
|
|
108
|
+
/* Sidebar */
|
|
109
|
+
--sidebar: oklch(0.16 0 0);
|
|
110
|
+
--sidebar-foreground: oklch(0.92 0.01 255);
|
|
111
|
+
--sidebar-primary: oklch(0.55 0.3 300);
|
|
112
|
+
--sidebar-primary-foreground: oklch(1 0 0);
|
|
113
|
+
--sidebar-accent: oklch(0.22 0 0);
|
|
114
|
+
--sidebar-accent-foreground: oklch(0.92 0.01 255);
|
|
115
|
+
--sidebar-border: oklch(0.32 0 0);
|
|
116
|
+
--sidebar-ring: oklch(0.55 0.3 300 / 50%);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
@theme inline {
|
|
120
|
+
/* Typography */
|
|
121
|
+
--font-sans: "DM Sans Variable", ui-sans-serif, system-ui, sans-serif;
|
|
122
|
+
--font-mono: "JetBrains Mono Variable", ui-monospace, monospace;
|
|
123
|
+
|
|
124
|
+
/* Color Variables */
|
|
125
|
+
--color-sidebar-ring: var(--sidebar-ring);
|
|
126
|
+
--color-sidebar-border: var(--sidebar-border);
|
|
127
|
+
--color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
|
|
128
|
+
--color-sidebar-accent: var(--sidebar-accent);
|
|
129
|
+
--color-sidebar-primary-foreground: var(--sidebar-primary-foreground);
|
|
130
|
+
--color-sidebar-primary: var(--sidebar-primary);
|
|
131
|
+
--color-sidebar-foreground: var(--sidebar-foreground);
|
|
132
|
+
--color-sidebar: var(--sidebar);
|
|
133
|
+
--color-chart-5: var(--chart-5);
|
|
134
|
+
--color-chart-4: var(--chart-4);
|
|
135
|
+
--color-chart-3: var(--chart-3);
|
|
136
|
+
--color-chart-2: var(--chart-2);
|
|
137
|
+
--color-chart-1: var(--chart-1);
|
|
138
|
+
--color-ring: var(--ring);
|
|
139
|
+
--color-input: var(--input);
|
|
140
|
+
--color-border: var(--border);
|
|
141
|
+
--color-destructive: var(--destructive);
|
|
142
|
+
--color-accent-foreground: var(--accent-foreground);
|
|
143
|
+
--color-accent: var(--accent);
|
|
144
|
+
--color-muted-foreground: var(--muted-foreground);
|
|
145
|
+
--color-muted: var(--muted);
|
|
146
|
+
--color-secondary-foreground: var(--secondary-foreground);
|
|
147
|
+
--color-secondary: var(--secondary);
|
|
148
|
+
--color-primary-foreground: var(--primary-foreground);
|
|
149
|
+
--color-primary: var(--primary);
|
|
150
|
+
--color-popover-foreground: var(--popover-foreground);
|
|
151
|
+
--color-popover: var(--popover);
|
|
152
|
+
--color-card-foreground: var(--card-foreground);
|
|
153
|
+
--color-card: var(--card);
|
|
154
|
+
--color-foreground: var(--foreground);
|
|
155
|
+
--color-background: var(--background);
|
|
156
|
+
|
|
157
|
+
/* QUESTPIE: Zero Radius */
|
|
158
|
+
--radius-sm: 0px;
|
|
159
|
+
--radius-md: 0px;
|
|
160
|
+
--radius-lg: 0px;
|
|
161
|
+
--radius-xl: 0px;
|
|
162
|
+
--radius-2xl: 0px;
|
|
163
|
+
--radius-3xl: 0px;
|
|
164
|
+
--radius-4xl: 0px;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
@layer base {
|
|
168
|
+
* {
|
|
169
|
+
@apply border-border outline-ring/50;
|
|
170
|
+
}
|
|
171
|
+
body {
|
|
172
|
+
@apply bg-background font-sans text-foreground;
|
|
173
|
+
}
|
|
174
|
+
html {
|
|
175
|
+
@apply font-sans;
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
/* =============================================================================
|
|
180
|
+
QUESTPIE Atmospheric Utilities
|
|
181
|
+
============================================================================= */
|
|
182
|
+
|
|
183
|
+
@utility bg-grid-quest {
|
|
184
|
+
background-image:
|
|
185
|
+
linear-gradient(to right, oklch(0.55 0.3 300 / 5%) 1px, transparent 1px),
|
|
186
|
+
linear-gradient(to bottom, oklch(0.55 0.3 300 / 5%) 1px, transparent 1px);
|
|
187
|
+
background-size: 24px 24px;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
@utility glow-primary {
|
|
191
|
+
box-shadow: 0 0 20px oklch(0.55 0.3 300 / 30%);
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
@utility glow-primary-sm {
|
|
195
|
+
box-shadow: 0 0 8px oklch(0.55 0.3 300 / 25%);
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
@utility glow-destructive {
|
|
199
|
+
box-shadow: 0 0 20px oklch(0.65 0.22 27 / 30%);
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
@utility ambient-beam {
|
|
203
|
+
background: radial-gradient(
|
|
204
|
+
circle,
|
|
205
|
+
oklch(0.55 0.3 300 / 15%) 0%,
|
|
206
|
+
transparent 70%
|
|
207
|
+
);
|
|
208
|
+
filter: blur(100px);
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
/* =============================================================================
|
|
212
|
+
Rich Text Editor Styles
|
|
213
|
+
============================================================================= */
|
|
214
|
+
|
|
215
|
+
.qp-rich-text-editor__content {
|
|
216
|
+
min-height: 200px;
|
|
217
|
+
padding: 0.75rem;
|
|
218
|
+
outline: none;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
.qp-rich-text-editor__content > *:first-child {
|
|
222
|
+
margin-top: 0;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
.qp-rich-text-editor__content > *:last-child {
|
|
226
|
+
margin-bottom: 0;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
.qp-rich-text-editor__content p {
|
|
230
|
+
margin: 0 0 0.75rem;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
.qp-rich-text-editor__content h1 {
|
|
234
|
+
font-size: 1.5rem;
|
|
235
|
+
font-weight: 600;
|
|
236
|
+
margin: 1rem 0 0.75rem;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
.qp-rich-text-editor__content h2 {
|
|
240
|
+
font-size: 1.25rem;
|
|
241
|
+
font-weight: 600;
|
|
242
|
+
margin: 1rem 0 0.75rem;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
.qp-rich-text-editor__content h3 {
|
|
246
|
+
font-size: 1.125rem;
|
|
247
|
+
font-weight: 600;
|
|
248
|
+
margin: 1rem 0 0.75rem;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
.qp-rich-text-editor__content ul,
|
|
252
|
+
.qp-rich-text-editor__content ol {
|
|
253
|
+
padding-left: 1.5rem;
|
|
254
|
+
margin: 0.75rem 0;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
.qp-rich-text-editor__content blockquote {
|
|
258
|
+
border-left: 2px solid var(--border);
|
|
259
|
+
padding-left: 0.75rem;
|
|
260
|
+
color: var(--muted-foreground);
|
|
261
|
+
margin: 0.75rem 0;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
.qp-rich-text-editor__content code {
|
|
265
|
+
background: var(--muted);
|
|
266
|
+
padding: 0.1rem 0.25rem;
|
|
267
|
+
font-size: 0.875em;
|
|
268
|
+
font-family: var(--font-mono);
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
.qp-rich-text-editor__content pre {
|
|
272
|
+
background: var(--muted);
|
|
273
|
+
padding: 0.75rem;
|
|
274
|
+
overflow-x: auto;
|
|
275
|
+
font-family: var(--font-mono);
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
.qp-rich-text-editor__content hr {
|
|
279
|
+
border: none;
|
|
280
|
+
border-top: 1px solid var(--border);
|
|
281
|
+
margin: 1rem 0;
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
.qp-rich-text-editor__content table {
|
|
285
|
+
border-collapse: collapse;
|
|
286
|
+
margin: 1rem 0;
|
|
287
|
+
width: 100%;
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
.qp-rich-text-editor__content th,
|
|
291
|
+
.qp-rich-text-editor__content td {
|
|
292
|
+
border: 1px solid var(--border);
|
|
293
|
+
padding: 0.5rem;
|
|
294
|
+
text-align: left;
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
.tippy-box[data-theme~="qp-rich-text-editor"] {
|
|
298
|
+
background: var(--popover);
|
|
299
|
+
color: var(--popover-foreground);
|
|
300
|
+
border: 1px solid var(--border);
|
|
301
|
+
box-shadow: 0 0 20px oklch(0 0 0 / 40%);
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
.qp-rich-text-editor__slash {
|
|
305
|
+
display: flex;
|
|
306
|
+
flex-direction: column;
|
|
307
|
+
gap: 0.25rem;
|
|
308
|
+
padding: 0.5rem;
|
|
309
|
+
min-width: 220px;
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
.qp-rich-text-editor__slash-item {
|
|
313
|
+
display: flex;
|
|
314
|
+
flex-direction: column;
|
|
315
|
+
align-items: flex-start;
|
|
316
|
+
gap: 0.125rem;
|
|
317
|
+
padding: 0.5rem;
|
|
318
|
+
font-size: 0.75rem;
|
|
319
|
+
line-height: 1.2;
|
|
320
|
+
color: var(--foreground);
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
.qp-rich-text-editor__slash-item--active,
|
|
324
|
+
.qp-rich-text-editor__slash-item:hover {
|
|
325
|
+
background: var(--muted);
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
.qp-rich-text-editor__slash-title {
|
|
329
|
+
font-weight: 600;
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
.qp-rich-text-editor__slash-description {
|
|
333
|
+
color: var(--muted-foreground);
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
.qp-rich-text-editor__slash-empty {
|
|
337
|
+
padding: 0.5rem;
|
|
338
|
+
font-size: 0.75rem;
|
|
339
|
+
color: var(--muted-foreground);
|
|
340
|
+
}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Auth Layout - centered card layout for authentication pages
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import * as React from "react";
|
|
6
|
+
import {
|
|
7
|
+
Card,
|
|
8
|
+
CardContent,
|
|
9
|
+
CardDescription,
|
|
10
|
+
CardHeader,
|
|
11
|
+
CardTitle,
|
|
12
|
+
} from "../../components/ui/card";
|
|
13
|
+
import { cn } from "../../lib/utils";
|
|
14
|
+
|
|
15
|
+
export type AuthLayoutProps = {
|
|
16
|
+
/** Page title */
|
|
17
|
+
title: string;
|
|
18
|
+
/** Page description */
|
|
19
|
+
description?: string;
|
|
20
|
+
/** Logo component or element */
|
|
21
|
+
logo?: React.ReactNode;
|
|
22
|
+
/** Footer content (e.g., links to other auth pages) */
|
|
23
|
+
footer?: React.ReactNode;
|
|
24
|
+
/** Form content */
|
|
25
|
+
children: React.ReactNode;
|
|
26
|
+
/** Additional class name for the card */
|
|
27
|
+
className?: string;
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Centered layout for authentication pages (login, register, forgot password, etc.)
|
|
32
|
+
*
|
|
33
|
+
* @example
|
|
34
|
+
* ```tsx
|
|
35
|
+
* <AuthLayout
|
|
36
|
+
* title="Sign in"
|
|
37
|
+
* description="Enter your credentials to access the admin panel"
|
|
38
|
+
* logo={<Logo />}
|
|
39
|
+
* footer={<Link to="/forgot-password">Forgot password?</Link>}
|
|
40
|
+
* >
|
|
41
|
+
* <LoginForm />
|
|
42
|
+
* </AuthLayout>
|
|
43
|
+
* ```
|
|
44
|
+
*/
|
|
45
|
+
export function AuthLayout({
|
|
46
|
+
title,
|
|
47
|
+
description,
|
|
48
|
+
logo,
|
|
49
|
+
footer,
|
|
50
|
+
children,
|
|
51
|
+
className,
|
|
52
|
+
}: AuthLayoutProps) {
|
|
53
|
+
return (
|
|
54
|
+
<div className="bg-background flex min-h-screen flex-col items-center justify-center p-4">
|
|
55
|
+
<div className="w-full max-w-sm space-y-6">
|
|
56
|
+
{/* Logo */}
|
|
57
|
+
{logo && <div className="flex justify-center">{logo}</div>}
|
|
58
|
+
|
|
59
|
+
{/* Main Card */}
|
|
60
|
+
<Card className={cn("w-full", className)}>
|
|
61
|
+
<CardHeader className="text-center">
|
|
62
|
+
<CardTitle className="text-lg">{title}</CardTitle>
|
|
63
|
+
{description && <CardDescription>{description}</CardDescription>}
|
|
64
|
+
</CardHeader>
|
|
65
|
+
<CardContent>{children}</CardContent>
|
|
66
|
+
</Card>
|
|
67
|
+
|
|
68
|
+
{/* Footer */}
|
|
69
|
+
{footer && (
|
|
70
|
+
<div className="text-muted-foreground text-center text-xs">
|
|
71
|
+
{footer}
|
|
72
|
+
</div>
|
|
73
|
+
)}
|
|
74
|
+
</div>
|
|
75
|
+
</div>
|
|
76
|
+
);
|
|
77
|
+
}
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Forgot Password Form - request password reset email
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import * as React from "react";
|
|
6
|
+
import { useForm } from "react-hook-form";
|
|
7
|
+
import { Envelope, SpinnerGap, CheckCircle } from "@phosphor-icons/react";
|
|
8
|
+
import { Button } from "../../components/ui/button";
|
|
9
|
+
import { Input } from "../../components/ui/input";
|
|
10
|
+
import {
|
|
11
|
+
Field,
|
|
12
|
+
FieldContent,
|
|
13
|
+
FieldError,
|
|
14
|
+
FieldGroup,
|
|
15
|
+
FieldLabel,
|
|
16
|
+
} from "../../components/ui/field";
|
|
17
|
+
import { cn } from "../../lib/utils";
|
|
18
|
+
|
|
19
|
+
export type ForgotPasswordFormValues = {
|
|
20
|
+
email: string;
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
export type ForgotPasswordFormProps = {
|
|
24
|
+
/** Called when form is submitted with valid data */
|
|
25
|
+
onSubmit: (values: ForgotPasswordFormValues) => Promise<void>;
|
|
26
|
+
/** Called when back to login link is clicked */
|
|
27
|
+
onBackToLoginClick?: () => void;
|
|
28
|
+
/** Default values */
|
|
29
|
+
defaultValues?: Partial<ForgotPasswordFormValues>;
|
|
30
|
+
/** Additional class name */
|
|
31
|
+
className?: string;
|
|
32
|
+
/** Error message from auth */
|
|
33
|
+
error?: string | null;
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Forgot password form with email field
|
|
38
|
+
*
|
|
39
|
+
* @example
|
|
40
|
+
* ```tsx
|
|
41
|
+
* const authClient = createAdminAuthClient<typeof cms>({ baseURL: '...' })
|
|
42
|
+
*
|
|
43
|
+
* function ForgotPasswordPage() {
|
|
44
|
+
* const [error, setError] = useState<string | null>(null)
|
|
45
|
+
*
|
|
46
|
+
* const handleSubmit = async (values: ForgotPasswordFormValues) => {
|
|
47
|
+
* const result = await authClient.forgetPassword({
|
|
48
|
+
* email: values.email,
|
|
49
|
+
* redirectTo: '/reset-password',
|
|
50
|
+
* })
|
|
51
|
+
* if (result.error) {
|
|
52
|
+
* setError(result.error.message)
|
|
53
|
+
* }
|
|
54
|
+
* }
|
|
55
|
+
*
|
|
56
|
+
* return (
|
|
57
|
+
* <AuthLayout title="Forgot password">
|
|
58
|
+
* <ForgotPasswordForm onSubmit={handleSubmit} error={error} />
|
|
59
|
+
* </AuthLayout>
|
|
60
|
+
* )
|
|
61
|
+
* }
|
|
62
|
+
* ```
|
|
63
|
+
*/
|
|
64
|
+
export function ForgotPasswordForm({
|
|
65
|
+
onSubmit,
|
|
66
|
+
onBackToLoginClick,
|
|
67
|
+
defaultValues,
|
|
68
|
+
className,
|
|
69
|
+
error,
|
|
70
|
+
}: ForgotPasswordFormProps) {
|
|
71
|
+
const [isSuccess, setIsSuccess] = React.useState(false);
|
|
72
|
+
|
|
73
|
+
const {
|
|
74
|
+
register,
|
|
75
|
+
handleSubmit,
|
|
76
|
+
formState: { errors, isSubmitting },
|
|
77
|
+
} = useForm<ForgotPasswordFormValues>({
|
|
78
|
+
defaultValues: {
|
|
79
|
+
email: "",
|
|
80
|
+
...defaultValues,
|
|
81
|
+
},
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
const handleFormSubmit = handleSubmit(async (values) => {
|
|
85
|
+
await onSubmit(values);
|
|
86
|
+
if (!error) {
|
|
87
|
+
setIsSuccess(true);
|
|
88
|
+
}
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
// Success state
|
|
92
|
+
if (isSuccess) {
|
|
93
|
+
return (
|
|
94
|
+
<div className={cn("space-y-4 text-center", className)}>
|
|
95
|
+
<div className="bg-primary/10 mx-auto flex size-12 items-center justify-center rounded-full">
|
|
96
|
+
<CheckCircle className="text-primary size-6" weight="duotone" />
|
|
97
|
+
</div>
|
|
98
|
+
<div className="space-y-2">
|
|
99
|
+
<h3 className="text-sm font-medium">Check your email</h3>
|
|
100
|
+
<p className="text-muted-foreground text-xs">
|
|
101
|
+
We've sent a password reset link to your email address. Please check
|
|
102
|
+
your inbox and follow the instructions.
|
|
103
|
+
</p>
|
|
104
|
+
</div>
|
|
105
|
+
<Button
|
|
106
|
+
type="button"
|
|
107
|
+
variant="outline"
|
|
108
|
+
className="w-full"
|
|
109
|
+
onClick={onBackToLoginClick}
|
|
110
|
+
>
|
|
111
|
+
Back to login
|
|
112
|
+
</Button>
|
|
113
|
+
</div>
|
|
114
|
+
);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
return (
|
|
118
|
+
<form onSubmit={handleFormSubmit} className={cn("space-y-4", className)}>
|
|
119
|
+
<p className="text-muted-foreground text-xs">
|
|
120
|
+
Enter your email address and we'll send you a link to reset your
|
|
121
|
+
password.
|
|
122
|
+
</p>
|
|
123
|
+
|
|
124
|
+
<FieldGroup>
|
|
125
|
+
{/* Email Field */}
|
|
126
|
+
<Field data-invalid={!!errors.email}>
|
|
127
|
+
<FieldLabel htmlFor="email">Email</FieldLabel>
|
|
128
|
+
<FieldContent>
|
|
129
|
+
<div className="relative">
|
|
130
|
+
<Envelope
|
|
131
|
+
className="text-muted-foreground absolute left-2 top-1/2 size-4 -translate-y-1/2"
|
|
132
|
+
weight="duotone"
|
|
133
|
+
/>
|
|
134
|
+
<Input
|
|
135
|
+
id="email"
|
|
136
|
+
type="email"
|
|
137
|
+
placeholder="you@example.com"
|
|
138
|
+
className="pl-8"
|
|
139
|
+
autoComplete="email"
|
|
140
|
+
aria-invalid={!!errors.email}
|
|
141
|
+
{...register("email", {
|
|
142
|
+
required: "Email is required",
|
|
143
|
+
pattern: {
|
|
144
|
+
value: /^[^\s@]+@[^\s@]+\.[^\s@]+$/,
|
|
145
|
+
message: "Invalid email address",
|
|
146
|
+
},
|
|
147
|
+
})}
|
|
148
|
+
/>
|
|
149
|
+
</div>
|
|
150
|
+
<FieldError>{errors.email?.message}</FieldError>
|
|
151
|
+
</FieldContent>
|
|
152
|
+
</Field>
|
|
153
|
+
</FieldGroup>
|
|
154
|
+
|
|
155
|
+
{/* Error Message */}
|
|
156
|
+
{error && (
|
|
157
|
+
<div className="bg-destructive/10 text-destructive rounded-md p-3 text-xs">
|
|
158
|
+
{error}
|
|
159
|
+
</div>
|
|
160
|
+
)}
|
|
161
|
+
|
|
162
|
+
{/* Submit Button */}
|
|
163
|
+
<Button
|
|
164
|
+
type="submit"
|
|
165
|
+
className="w-full"
|
|
166
|
+
size="lg"
|
|
167
|
+
disabled={isSubmitting}
|
|
168
|
+
>
|
|
169
|
+
{isSubmitting ? (
|
|
170
|
+
<>
|
|
171
|
+
<SpinnerGap className="animate-spin" weight="bold" />
|
|
172
|
+
Sending...
|
|
173
|
+
</>
|
|
174
|
+
) : (
|
|
175
|
+
"Send reset link"
|
|
176
|
+
)}
|
|
177
|
+
</Button>
|
|
178
|
+
|
|
179
|
+
{/* Back to Login Link */}
|
|
180
|
+
<p className="text-muted-foreground text-center text-xs">
|
|
181
|
+
Remember your password?{" "}
|
|
182
|
+
<button
|
|
183
|
+
type="button"
|
|
184
|
+
onClick={onBackToLoginClick}
|
|
185
|
+
className="text-primary hover:underline"
|
|
186
|
+
>
|
|
187
|
+
Back to login
|
|
188
|
+
</button>
|
|
189
|
+
</p>
|
|
190
|
+
</form>
|
|
191
|
+
);
|
|
192
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Auth views - authentication related components
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
export { AuthLayout } from "./auth-layout";
|
|
6
|
+
export type { AuthLayoutProps } from "./auth-layout";
|
|
7
|
+
|
|
8
|
+
export { LoginForm } from "./login-form";
|
|
9
|
+
export type { LoginFormProps, LoginFormValues } from "./login-form";
|
|
10
|
+
|
|
11
|
+
export { ForgotPasswordForm } from "./forgot-password-form";
|
|
12
|
+
export type {
|
|
13
|
+
ForgotPasswordFormProps,
|
|
14
|
+
ForgotPasswordFormValues,
|
|
15
|
+
} from "./forgot-password-form";
|
|
16
|
+
|
|
17
|
+
export { ResetPasswordForm } from "./reset-password-form";
|
|
18
|
+
export type {
|
|
19
|
+
ResetPasswordFormProps,
|
|
20
|
+
ResetPasswordFormValues,
|
|
21
|
+
} from "./reset-password-form";
|