@questpie/admin 3.0.3 → 3.0.4

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.
Files changed (249) hide show
  1. package/README.md +34 -5
  2. package/dist/client/blocks/block-renderer.d.mts +2 -2
  3. package/dist/client/blocks/block-renderer.mjs +4 -1
  4. package/dist/client/builder/types/action-types.d.mts +31 -3
  5. package/dist/client/builder/types/collection-types.d.mts +140 -0
  6. package/dist/client/builder/types/ui-config.d.mts +16 -2
  7. package/dist/client/builder/types/views.d.mts +57 -0
  8. package/dist/client/builder/types/widget-types.d.mts +5 -0
  9. package/dist/client/components/actions/action-button.mjs +137 -199
  10. package/dist/client/components/actions/action-dialog.mjs +198 -156
  11. package/dist/client/components/actions/confirmation-dialog.mjs +2 -2
  12. package/dist/client/components/actions/header-actions.mjs +52 -53
  13. package/dist/client/components/admin-link.d.mts +2 -2
  14. package/dist/client/components/auth/auth-loading.mjs +41 -18
  15. package/dist/client/components/blocks/block-fields-renderer.mjs +64 -28
  16. package/dist/client/components/blocks/block-insert-button.mjs +4 -4
  17. package/dist/client/components/blocks/block-item.mjs +2 -2
  18. package/dist/client/components/blocks/block-library-sidebar.mjs +2 -2
  19. package/dist/client/components/component-renderer.mjs +1 -1
  20. package/dist/client/components/fields/array-field.mjs +14 -14
  21. package/dist/client/components/fields/asset-preview-field.mjs +1 -1
  22. package/dist/client/components/fields/blocks-field/blocks-field.mjs +84 -104
  23. package/dist/client/components/fields/json-field.mjs +2 -2
  24. package/dist/client/components/fields/object-array-field.mjs +22 -22
  25. package/dist/client/components/fields/object-field.mjs +5 -5
  26. package/dist/client/components/fields/relation/displays/cards-display.mjs +16 -9
  27. package/dist/client/components/fields/relation/displays/chips-display.mjs +15 -12
  28. package/dist/client/components/fields/relation/displays/grid-display.mjs +15 -11
  29. package/dist/client/components/fields/relation/displays/list-display.mjs +33 -20
  30. package/dist/client/components/fields/relation/displays/table-display.mjs +62 -93
  31. package/dist/client/components/fields/relation/relation-items-display.mjs +1 -1
  32. package/dist/client/components/fields/relation-picker.mjs +7 -6
  33. package/dist/client/components/fields/relation-select.mjs +71 -47
  34. package/dist/client/components/fields/rich-text-editor/bubble-menu.mjs +392 -82
  35. package/dist/client/components/fields/rich-text-editor/extensions.mjs +54 -23
  36. package/dist/client/components/fields/rich-text-editor/image-popover.mjs +24 -50
  37. package/dist/client/components/fields/rich-text-editor/image-upload.mjs +66 -0
  38. package/dist/client/components/fields/rich-text-editor/index.d.mts +38 -0
  39. package/dist/client/components/fields/rich-text-editor/index.mjs +637 -376
  40. package/dist/client/components/fields/rich-text-editor/link-utils.mjs +26 -0
  41. package/dist/client/components/fields/rich-text-editor/presets.d.mts +10 -0
  42. package/dist/client/components/fields/rich-text-editor/slash-commands.mjs +27 -6
  43. package/dist/client/components/fields/rich-text-editor/toolbar.mjs +464 -346
  44. package/dist/client/components/fields/rich-text-editor/types.d.mts +77 -0
  45. package/dist/client/components/fields/upload-field.mjs +45 -49
  46. package/dist/client/components/filter-builder/columns-tab.mjs +69 -62
  47. package/dist/client/components/filter-builder/filter-builder-sheet.mjs +473 -308
  48. package/dist/client/components/filter-builder/filters-tab.mjs +109 -82
  49. package/dist/client/components/filter-builder/saved-views-tab.mjs +300 -198
  50. package/dist/client/components/history-sidebar.mjs +850 -340
  51. package/dist/client/components/layout/field-layout-renderer.mjs +6 -5
  52. package/dist/client/components/locale-switcher.mjs +8 -8
  53. package/dist/client/components/media/media-grid.mjs +12 -9
  54. package/dist/client/components/media/media-picker-dialog.mjs +242 -230
  55. package/dist/client/components/preview/live-preview-mode.mjs +1 -1
  56. package/dist/client/components/primitives/asset-preview.mjs +37 -22
  57. package/dist/client/components/primitives/date-input.mjs +212 -249
  58. package/dist/client/components/primitives/dropzone.mjs +192 -159
  59. package/dist/client/components/primitives/field-select-control.mjs +93 -0
  60. package/dist/client/components/primitives/select-multi.mjs +251 -230
  61. package/dist/client/components/primitives/select-single.mjs +345 -290
  62. package/dist/client/components/primitives/time-input.mjs +2 -2
  63. package/dist/client/components/sheets/resource-sheet.mjs +2 -0
  64. package/dist/client/components/ui/accordion.mjs +4 -4
  65. package/dist/client/components/ui/alert.mjs +3 -3
  66. package/dist/client/components/ui/badge.mjs +4 -4
  67. package/dist/client/components/ui/button.mjs +47 -37
  68. package/dist/client/components/ui/card.mjs +2 -2
  69. package/dist/client/components/ui/checkbox.mjs +1 -1
  70. package/dist/client/components/ui/command.mjs +5 -5
  71. package/dist/client/components/ui/dialog.mjs +3 -3
  72. package/dist/client/components/ui/drawer.mjs +1 -1
  73. package/dist/client/components/ui/dropdown-menu.mjs +157 -15
  74. package/dist/client/components/ui/empty-state.mjs +88 -59
  75. package/dist/client/components/ui/field.mjs +2 -2
  76. package/dist/client/components/ui/input-group.mjs +3 -3
  77. package/dist/client/components/ui/input.mjs +1 -1
  78. package/dist/client/components/ui/kbd.mjs +1 -1
  79. package/dist/client/components/ui/label.mjs +1 -1
  80. package/dist/client/components/ui/popover.mjs +19 -11
  81. package/dist/client/components/ui/scroll-fade.mjs +170 -0
  82. package/dist/client/components/ui/search-input.mjs +1 -1
  83. package/dist/client/components/ui/select.mjs +129 -27
  84. package/dist/client/components/ui/sheet.mjs +54 -34
  85. package/dist/client/components/ui/sidebar.mjs +15 -14
  86. package/dist/client/components/ui/skeleton.mjs +28 -12
  87. package/dist/client/components/ui/switch.mjs +2 -2
  88. package/dist/client/components/ui/table.mjs +82 -74
  89. package/dist/client/components/ui/tabs.mjs +26 -31
  90. package/dist/client/components/ui/textarea.mjs +1 -1
  91. package/dist/client/components/ui/tooltip.mjs +1 -1
  92. package/dist/client/components/widgets/chart-widget.mjs +134 -96
  93. package/dist/client/components/widgets/progress-widget.mjs +59 -34
  94. package/dist/client/components/widgets/quick-actions-widget.mjs +184 -113
  95. package/dist/client/components/widgets/recent-items-widget.mjs +144 -102
  96. package/dist/client/components/widgets/stats-widget.mjs +91 -72
  97. package/dist/client/components/widgets/table-widget.mjs +159 -246
  98. package/dist/client/components/widgets/timeline-widget.mjs +66 -43
  99. package/dist/client/components/widgets/value-widget.mjs +261 -152
  100. package/dist/client/components/widgets/widget-empty-state.mjs +88 -0
  101. package/dist/client/components/widgets/widget-skeletons.mjs +53 -20
  102. package/dist/client/contexts/focus-context.d.mts +2 -2
  103. package/dist/client/hooks/use-action.mjs +63 -55
  104. package/dist/client/hooks/use-audit-history.mjs +1 -65
  105. package/dist/client/hooks/use-collection-validation.mjs +36 -23
  106. package/dist/client/hooks/use-collection.mjs +96 -1
  107. package/dist/client/hooks/use-saved-views.mjs +70 -49
  108. package/dist/client/hooks/use-server-actions.mjs +59 -40
  109. package/dist/client/hooks/use-server-validation.mjs +156 -41
  110. package/dist/client/hooks/use-server-widget-data.mjs +1 -1
  111. package/dist/client/hooks/use-setup-status.d.mts +3 -3
  112. package/dist/client/hooks/use-setup-status.mjs +2 -2
  113. package/dist/client/hooks/use-transition-stage.mjs +2 -10
  114. package/dist/client/hooks/use-validation-error-map.mjs +31 -13
  115. package/dist/client/hooks/use-view-state.mjs +238 -174
  116. package/dist/client/i18n/date-locale.mjs +33 -0
  117. package/dist/client/i18n/hooks.mjs +17 -1
  118. package/dist/client/lib/utils.mjs +3 -2
  119. package/dist/client/preview/block-scope-context.d.mts +2 -2
  120. package/dist/client/preview/preview-banner.d.mts +2 -2
  121. package/dist/client/preview/preview-field.d.mts +4 -4
  122. package/dist/client/preview/preview-field.mjs +2 -2
  123. package/dist/client/runtime/provider.mjs +8 -1
  124. package/dist/client/runtime/translations-provider.mjs +1 -1
  125. package/dist/client/scope/picker.d.mts +2 -2
  126. package/dist/client/scope/provider.d.mts +2 -2
  127. package/dist/client/styles/base.css +1022 -0
  128. package/dist/client/styles/index.css +3 -589
  129. package/dist/client/utils/auto-expand-fields.mjs +4 -2
  130. package/dist/client/utils/keyboard-shortcuts.mjs +26 -0
  131. package/dist/client/utils/use-lazy-component.mjs +80 -0
  132. package/dist/client/views/auth/auth-layout.d.mts +18 -11
  133. package/dist/client/views/auth/auth-layout.mjs +291 -80
  134. package/dist/client/views/auth/forgot-password-form.d.mts +2 -2
  135. package/dist/client/views/auth/forgot-password-form.mjs +2 -2
  136. package/dist/client/views/auth/login-form.d.mts +2 -2
  137. package/dist/client/views/auth/login-form.mjs +1 -1
  138. package/dist/client/views/auth/reset-password-form.d.mts +2 -2
  139. package/dist/client/views/auth/reset-password-form.mjs +2 -2
  140. package/dist/client/views/auth/setup-form.d.mts +2 -2
  141. package/dist/client/views/collection/auto-form-fields.mjs +11 -9
  142. package/dist/client/views/collection/bulk-action-toolbar.mjs +173 -138
  143. package/dist/client/views/collection/cells/complex-cells.mjs +22 -22
  144. package/dist/client/views/collection/cells/primitive-cells.mjs +1 -1
  145. package/dist/client/views/collection/cells/relation-cells.mjs +147 -129
  146. package/dist/client/views/collection/cells/shared/asset-thumbnail.mjs +224 -278
  147. package/dist/client/views/collection/cells/shared/relation-chip.mjs +64 -36
  148. package/dist/client/views/collection/cells/upload-cells.mjs +199 -9
  149. package/dist/client/views/collection/columns/build-columns.mjs +29 -9
  150. package/dist/client/views/collection/columns/column-defaults.mjs +2 -2
  151. package/dist/client/views/collection/field-renderer.mjs +50 -89
  152. package/dist/client/views/collection/form-view.mjs +237 -227
  153. package/dist/client/views/collection/table-view.mjs +1162 -229
  154. package/dist/client/views/collection/view-skeletons.mjs +222 -79
  155. package/dist/client/views/common/global-search.mjs +29 -18
  156. package/dist/client/views/dashboard/dashboard-grid.mjs +678 -501
  157. package/dist/client/views/dashboard/dashboard-widget.mjs +6 -3
  158. package/dist/client/views/dashboard/widget-card.mjs +23 -14
  159. package/dist/client/views/globals/global-form-view.mjs +634 -589
  160. package/dist/client/views/layout/admin-layout-provider.mjs +67 -70
  161. package/dist/client/views/layout/admin-layout.d.mts +3 -6
  162. package/dist/client/views/layout/admin-layout.mjs +149 -172
  163. package/dist/client/views/layout/admin-router.mjs +747 -544
  164. package/dist/client/views/layout/admin-sidebar.d.mts +38 -1
  165. package/dist/client/views/layout/admin-sidebar.mjs +751 -591
  166. package/dist/client/views/layout/admin-theme.d.mts +10 -0
  167. package/dist/client/views/layout/admin-theme.mjs +84 -0
  168. package/dist/client/views/layout/admin-view-layout.mjs +161 -0
  169. package/dist/client/views/pages/accept-invite-page.d.mts +2 -2
  170. package/dist/client/views/pages/accept-invite-page.mjs +49 -26
  171. package/dist/client/views/pages/dashboard-page.d.mts +2 -2
  172. package/dist/client/views/pages/forgot-password-page.d.mts +2 -2
  173. package/dist/client/views/pages/forgot-password-page.mjs +2 -19
  174. package/dist/client/views/pages/invite-page.d.mts +2 -2
  175. package/dist/client/views/pages/invite-page.mjs +2 -19
  176. package/dist/client/views/pages/login-page.d.mts +1 -1
  177. package/dist/client/views/pages/login-page.mjs +4 -21
  178. package/dist/client/views/pages/reset-password-page.d.mts +2 -2
  179. package/dist/client/views/pages/reset-password-page.mjs +3 -20
  180. package/dist/client/views/pages/setup-page.d.mts +2 -2
  181. package/dist/client/views/pages/setup-page.mjs +3 -20
  182. package/dist/client.d.mts +6 -2
  183. package/dist/client.mjs +2 -1
  184. package/dist/components/rich-text/rich-text-renderer.d.mts +2 -2
  185. package/dist/index.d.mts +6 -2
  186. package/dist/index.mjs +2 -1
  187. package/dist/server/augmentation/dashboard.d.mts +67 -3
  188. package/dist/server/augmentation/form-layout.d.mts +21 -0
  189. package/dist/server/augmentation/index.d.mts +1 -1
  190. package/dist/server/codegen/admin-client-template.mjs +4 -0
  191. package/dist/server/fields/blocks.d.mts +1 -1
  192. package/dist/server/fields/blocks.mjs +12 -0
  193. package/dist/server/fields/rich-text.d.mts +1 -1
  194. package/dist/server/fields/rich-text.mjs +8 -0
  195. package/dist/server/i18n/index.mjs +17 -1
  196. package/dist/server/i18n/messages/cs.mjs +23 -0
  197. package/dist/server/i18n/messages/de.mjs +23 -0
  198. package/dist/server/i18n/messages/en.mjs +64 -1
  199. package/dist/server/i18n/messages/es.mjs +23 -0
  200. package/dist/server/i18n/messages/fr.mjs +23 -0
  201. package/dist/server/i18n/messages/pl.mjs +23 -0
  202. package/dist/server/i18n/messages/pt.mjs +23 -0
  203. package/dist/server/i18n/messages/sk.mjs +83 -1
  204. package/dist/server/modules/admin/block/introspection.mjs +4 -1
  205. package/dist/server/modules/admin/block/prefetch.mjs +12 -2
  206. package/dist/server/modules/admin/collections/account.d.mts +50 -50
  207. package/dist/server/modules/admin/collections/admin-locks.d.mts +54 -54
  208. package/dist/server/modules/admin/collections/admin-preferences.d.mts +39 -39
  209. package/dist/server/modules/admin/collections/admin-saved-views.d.mts +47 -47
  210. package/dist/server/modules/admin/collections/apikey.d.mts +68 -68
  211. package/dist/server/modules/admin/collections/assets.d.mts +20 -20
  212. package/dist/server/modules/admin/collections/assets.mjs +0 -1
  213. package/dist/server/modules/admin/collections/session.d.mts +42 -42
  214. package/dist/server/modules/admin/collections/user.d.mts +12 -0
  215. package/dist/server/modules/admin/collections/user.mjs +40 -9
  216. package/dist/server/modules/admin/collections/verification.d.mts +2 -2
  217. package/dist/server/modules/admin/dto/admin-config.dto.mjs +2 -0
  218. package/dist/server/modules/admin/factories.mjs +7 -18
  219. package/dist/server/modules/admin/index.d.mts +1 -1
  220. package/dist/server/modules/admin/routes/admin-config.d.mts +2 -2
  221. package/dist/server/modules/admin/routes/admin-config.mjs +34 -16
  222. package/dist/server/modules/admin/routes/execute-action.d.mts +9 -9
  223. package/dist/server/modules/admin/routes/execute-action.mjs +33 -0
  224. package/dist/server/modules/admin/routes/locales.d.mts +2 -2
  225. package/dist/server/modules/admin/routes/preview.d.mts +11 -11
  226. package/dist/server/modules/admin/routes/reactive.d.mts +9 -9
  227. package/dist/server/modules/admin/routes/setup.d.mts +10 -10
  228. package/dist/server/modules/admin/routes/setup.mjs +7 -7
  229. package/dist/server/modules/admin/routes/translations.d.mts +4 -4
  230. package/dist/server/modules/admin/routes/translations.mjs +5 -1
  231. package/dist/server/modules/admin/routes/widget-data.d.mts +5 -5
  232. package/dist/server/modules/admin-preferences/collections/admin-preferences.mjs +1 -1
  233. package/dist/server/modules/admin-preferences/collections/saved-views.d.mts +27 -27
  234. package/dist/server/modules/audit/.generated/module.d.mts +1 -1
  235. package/dist/server/modules/audit/.generated/module.mjs +1 -1
  236. package/dist/server/modules/audit/collections/audit-log.d.mts +2 -2
  237. package/dist/server/modules/audit/collections/audit-log.mjs +1 -1
  238. package/dist/server/modules/audit/config/app.mjs +99 -42
  239. package/dist/server/modules/audit/jobs/audit-cleanup.mjs +1 -1
  240. package/dist/server/plugin.mjs +4 -2
  241. package/dist/server/proxy-factories.d.mts +4 -3
  242. package/dist/server/proxy-factories.mjs +34 -8
  243. package/dist/shared/types/saved-views.types.d.mts +2 -0
  244. package/package.json +6 -4
  245. package/dist/client/components/fields/rich-text-editor/link-popover.mjs +0 -85
  246. package/dist/client/components/ui/spinner.mjs +0 -52
  247. package/dist/client/components/ui/toolbar.mjs +0 -136
  248. package/dist/client/contexts/breadcrumb-context.mjs +0 -60
  249. package/dist/client/views/layout/admin-topbar.mjs +0 -236
@@ -1,590 +1,4 @@
1
- @import "tailwindcss";
2
- @import "tw-animate-css";
3
- @import "shadcn/tailwind.css";
4
- @import "@fontsource-variable/geist";
5
- @import "@fontsource-variable/jetbrains-mono";
1
+ /* QUESTPIE Admin — Default stylesheet
2
+ Alias for base.css. Import base.css directly for explicit intent. */
6
3
 
7
- /* ================================================================
8
- QUESTPIE ADMIN THEME — Brutalist Flat
9
- ================================================================
10
-
11
- HOW THEMING WORKS
12
- -----------------
13
- This file is the ONLY place that controls the visual appearance
14
- of the admin UI. Components use standard Tailwind utilities
15
- (bg-card, border-border, rounded-md, shadow-sm) which resolve
16
- to the values defined here.
17
-
18
- TO CREATE A CUSTOM THEME
19
- ------------------------
20
- 1. Copy this file
21
- 2. Change the variable values below
22
- 3. Import your copy instead of this one
23
- 4. That's it — zero component changes needed
24
-
25
- VARIABLE REFERENCE
26
- ------------------
27
-
28
- -- Surface Colors -----------------------------------------
29
- --background Page background (darkest/lightest surface)
30
- --foreground Primary text color on background
31
- --card Elevated surface: cards, panels, sidebar
32
- --card-foreground Text on card surfaces
33
- --popover Floating surfaces: dropdowns, tooltips, dialogs
34
- --popover-foreground Text on floating surfaces
35
- --input Form input backgrounds
36
- --muted Subtle backgrounds: hover, table headers, toggles
37
- --muted-foreground Secondary/dimmed text (helper text, placeholders)
38
- --accent Interactive hover backgrounds
39
- --accent-foreground Text on accent backgrounds
40
-
41
- -- Brand Colors -------------------------------------------
42
- --primary Brand accent: CTAs, focus rings, active states
43
- --primary-foreground Text on primary color backgrounds
44
- --secondary Secondary action backgrounds
45
- --secondary-foreground Text on secondary backgrounds
46
-
47
- -- Semantic Colors ----------------------------------------
48
- --destructive Errors, delete actions, danger states
49
- --success Confirmations, positive states
50
- --warning Caution states
51
- --info Informational emphasis
52
-
53
- -- Structure ----------------------------------------------
54
- --border Default border color (all structural borders)
55
- --ring Focus ring color (usually same as --primary)
56
-
57
- -- Sidebar ------------------------------------------------
58
- Separate tokens for sidebar to allow independent theming.
59
- --sidebar, --sidebar-foreground, --sidebar-primary,
60
- --sidebar-accent, --sidebar-border, --sidebar-ring, etc.
61
-
62
- -- Shape & Depth ------------------------------------------
63
- --radius Base border-radius
64
- 0 -> brutalist sharp corners
65
- 8px -> soft rounded corners
66
- --shadow-* Shadow scale (defined in @theme inline)
67
- none -> brutalist flat (no elevation)
68
- normal -> standard shadow depth
69
-
70
- -- Typography ---------------------------------------------
71
- --font-sans Body text, descriptions, user content
72
- --font-mono UI chrome: nav, buttons, tabs, badges, labels
73
-
74
- -- Spacing ------------------------------------------------
75
- --spacing-card Internal card/panel padding (default: 16px)
76
- --spacing-section Section gaps (default: 24px)
77
- --spacing-input Input internal padding (default: 12px)
78
-
79
- -- Grid Texture -------------------------------------------
80
- Controlled via body::before pseudo-element.
81
- Uses --primary color, 40px grid, 3% opacity.
82
- To disable: set body::before { display: none }
83
- ================================================================ */
84
-
85
- /* Light theme (default — :root)
86
- All colors use OKLCH for perceptually uniform contrast management.
87
- L = lightness (0–1), C = chroma (saturation), H = hue angle. */
88
- :root {
89
- --background: oklch(1 0 0);
90
- --foreground: oklch(0.269 0 0);
91
- --card: oklch(0.98 0 0);
92
- --card-foreground: oklch(0.269 0 0);
93
- --popover: oklch(1 0 0);
94
- --popover-foreground: oklch(0.269 0 0);
95
- --input: oklch(0.922 0 0);
96
- --muted: oklch(0.955 0 0);
97
- --muted-foreground: oklch(0.48 0 0);
98
- --accent: oklch(0.955 0 0);
99
- --accent-foreground: oklch(0.145 0 0);
100
- --secondary: oklch(0.955 0 0);
101
- --secondary-foreground: oklch(0.269 0 0);
102
- --primary: oklch(0.541 0.281 303.5);
103
- --primary-foreground: oklch(1 0 0);
104
- --destructive: oklch(0.637 0.237 25);
105
- --destructive-foreground: oklch(1 0 0);
106
- --success: oklch(0.7 0.2 155);
107
- --success-foreground: oklch(1 0 0);
108
- --warning: oklch(0.7 0.16 65);
109
- --warning-foreground: oklch(1 0 0);
110
- --info: oklch(0.6 0.16 240);
111
- --info-foreground: oklch(1 0 0);
112
- --border: oklch(0.922 0 0);
113
- --ring: oklch(0.541 0.281 303.5);
114
- --radius: 0px;
115
- --grid-opacity: 0.025;
116
-
117
- /* Chart Colors */
118
- --chart-1: oklch(0.541 0.281 303.5);
119
- --chart-2: oklch(0.7 0.2 155);
120
- --chart-3: oklch(0.6 0.16 240);
121
- --chart-4: oklch(0.7 0.16 65);
122
- --chart-5: oklch(0.637 0.237 25);
123
-
124
- /* Typography */
125
- --font-sans: "Geist Variable", "Inter", sans-serif;
126
- --font-mono: "JetBrains Mono Variable", "JetBrains Mono", ui-monospace, monospace;
127
-
128
- /* Spacing Scale */
129
- --spacing-section: 1.5rem;
130
- --spacing-card: 1rem;
131
- --spacing-input: 0.75rem;
132
-
133
- /* Sidebar */
134
- --sidebar: oklch(0.975 0 0);
135
- --sidebar-foreground: oklch(0.269 0 0);
136
- --sidebar-primary: oklch(0.541 0.281 303.5);
137
- --sidebar-primary-foreground: oklch(1 0 0);
138
- --sidebar-accent: oklch(0.955 0 0);
139
- --sidebar-accent-foreground: oklch(0.269 0 0);
140
- --sidebar-border: oklch(0.922 0 0);
141
- --sidebar-ring: oklch(0.541 0.281 303.5);
142
- }
143
-
144
- /* Dark theme (.dark class) */
145
- .dark {
146
- --background: oklch(0.145 0 0);
147
- --foreground: oklch(0.922 0 0);
148
- --card: oklch(0.205 0 0);
149
- --card-foreground: oklch(0.922 0 0);
150
- --popover: oklch(0.205 0 0);
151
- --popover-foreground: oklch(0.922 0 0);
152
- --muted: oklch(0.269 0 0);
153
- --muted-foreground: oklch(0.637 0 0);
154
- --accent: oklch(0.269 0 0);
155
- --accent-foreground: oklch(1 0 0);
156
- --secondary: oklch(0.269 0 0);
157
- --secondary-foreground: oklch(0.922 0 0);
158
- --destructive: oklch(0.637 0.237 25);
159
- --destructive-foreground: oklch(1 0 0);
160
- --border: oklch(0.371 0 0);
161
- --input: oklch(0.371 0 0);
162
- --ring: oklch(0.541 0.281 303.5);
163
- --success: oklch(0.765 0.219 155);
164
- --success-foreground: oklch(1 0 0);
165
- --warning: oklch(0.793 0.155 82);
166
- --warning-foreground: oklch(0.145 0 0);
167
- --info: oklch(0.77 0.119 222);
168
- --info-foreground: oklch(0.145 0 0);
169
- --grid-opacity: 0.06;
170
-
171
- /* Chart Colors */
172
- --chart-1: oklch(0.541 0.281 303.5);
173
- --chart-2: oklch(0.765 0.219 155);
174
- --chart-3: oklch(0.77 0.119 222);
175
- --chart-4: oklch(0.793 0.155 82);
176
- --chart-5: oklch(0.637 0.237 25);
177
-
178
- /* Sidebar */
179
- --sidebar: oklch(0.205 0 0);
180
- --sidebar-foreground: oklch(0.922 0 0);
181
- --sidebar-primary: oklch(0.541 0.281 303.5);
182
- --sidebar-primary-foreground: oklch(1 0 0);
183
- --sidebar-accent: oklch(0.269 0 0);
184
- --sidebar-accent-foreground: oklch(0.922 0 0);
185
- --sidebar-border: oklch(0.371 0 0);
186
- --sidebar-ring: oklch(0.541 0.281 303.5);
187
- }
188
-
189
- @theme inline {
190
- /* Typography */
191
- --font-sans: "Geist Variable", "Inter", sans-serif;
192
- --font-mono:
193
- "JetBrains Mono Variable", "JetBrains Mono", ui-monospace, monospace;
194
-
195
- /* Shadow scale: none for brutalist flat */
196
- --shadow-xs: none;
197
- --shadow-sm: none;
198
- --shadow: none;
199
- --shadow-md: none;
200
- --shadow-lg: none;
201
- --shadow-xl: none;
202
- --shadow-2xl: none;
203
-
204
- /* Radius: all resolve to --radius (except full for avatars/pills) */
205
- --radius-sm: var(--radius);
206
- --radius-md: var(--radius);
207
- --radius-lg: var(--radius);
208
- --radius-xl: var(--radius);
209
- --radius-2xl: var(--radius);
210
- --radius-3xl: var(--radius);
211
- --radius-4xl: var(--radius);
212
- --radius-full: 9999px;
213
-
214
- /* Color mappings */
215
- --color-sidebar-ring: var(--sidebar-ring);
216
- --color-sidebar-border: var(--sidebar-border);
217
- --color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
218
- --color-sidebar-accent: var(--sidebar-accent);
219
- --color-sidebar-primary-foreground: var(--sidebar-primary-foreground);
220
- --color-sidebar-primary: var(--sidebar-primary);
221
- --color-sidebar-foreground: var(--sidebar-foreground);
222
- --color-sidebar: var(--sidebar);
223
- --color-chart-5: var(--chart-5);
224
- --color-chart-4: var(--chart-4);
225
- --color-chart-3: var(--chart-3);
226
- --color-chart-2: var(--chart-2);
227
- --color-chart-1: var(--chart-1);
228
- --color-ring: var(--ring);
229
- --color-input: var(--input);
230
- --color-border: var(--border);
231
- --color-destructive: var(--destructive);
232
- --color-destructive-foreground: var(--destructive-foreground);
233
- --color-success: var(--success);
234
- --color-success-foreground: var(--success-foreground);
235
- --color-warning: var(--warning);
236
- --color-warning-foreground: var(--warning-foreground);
237
- --color-info: var(--info);
238
- --color-info-foreground: var(--info-foreground);
239
- --color-accent-foreground: var(--accent-foreground);
240
- --color-accent: var(--accent);
241
- --color-muted-foreground: var(--muted-foreground);
242
- --color-muted: var(--muted);
243
- --color-secondary-foreground: var(--secondary-foreground);
244
- --color-secondary: var(--secondary);
245
- --color-primary-foreground: var(--primary-foreground);
246
- --color-primary: var(--primary);
247
- --color-popover-foreground: var(--popover-foreground);
248
- --color-popover: var(--popover);
249
- --color-card-foreground: var(--card-foreground);
250
- --color-card: var(--card);
251
- --color-foreground: var(--foreground);
252
- --color-background: var(--background);
253
- }
254
-
255
- /* =============================================================================
256
- Grid Texture (matches landing page)
257
- ============================================================================= */
258
-
259
- body::before {
260
- content: "";
261
- position: fixed;
262
- inset: 0;
263
- z-index: 0;
264
- pointer-events: none;
265
- background-image:
266
- linear-gradient(var(--primary) 1px, transparent 1px),
267
- linear-gradient(90deg, var(--primary) 1px, transparent 1px);
268
- background-size: 40px 40px;
269
- opacity: var(--grid-opacity, 0.025);
270
- }
271
-
272
- /* =============================================================================
273
- Rich Text Editor Styles
274
- ============================================================================= */
275
-
276
- .qp-rich-text-editor__content {
277
- min-height: 200px;
278
- padding: 0.75rem;
279
- outline: none;
280
- }
281
-
282
- .qp-rich-text-editor__content > *:first-child {
283
- margin-top: 0;
284
- }
285
-
286
- .qp-rich-text-editor__content > *:last-child {
287
- margin-bottom: 0;
288
- }
289
-
290
- .qp-rich-text-editor__content p {
291
- margin: 0 0 0.75rem;
292
- }
293
-
294
- .qp-rich-text-editor__content h1 {
295
- font-size: 1.5rem;
296
- font-weight: 600;
297
- margin: 1rem 0 0.75rem;
298
- }
299
-
300
- .qp-rich-text-editor__content h2 {
301
- font-size: 1.25rem;
302
- font-weight: 600;
303
- margin: 1rem 0 0.75rem;
304
- }
305
-
306
- .qp-rich-text-editor__content h3 {
307
- font-size: 1.125rem;
308
- font-weight: 600;
309
- margin: 1rem 0 0.75rem;
310
- }
311
-
312
- .qp-rich-text-editor__content ul,
313
- .qp-rich-text-editor__content ol {
314
- padding-left: 1.5rem;
315
- margin: 0.75rem 0;
316
- }
317
-
318
- .qp-rich-text-editor__content blockquote {
319
- border-left: 2px solid var(--border);
320
- padding-left: 0.75rem;
321
- color: var(--muted-foreground);
322
- margin: 0.75rem 0;
323
- }
324
-
325
- .qp-rich-text-editor__content code {
326
- background: var(--muted);
327
- padding: 0.1rem 0.25rem;
328
- font-size: 0.875em;
329
- font-family: var(--font-mono);
330
- }
331
-
332
- .qp-rich-text-editor__content pre {
333
- background: var(--muted);
334
- padding: 0.75rem;
335
- overflow-x: auto;
336
- font-family: var(--font-mono);
337
- }
338
-
339
- .qp-rich-text-editor__content hr {
340
- border: none;
341
- border-top: 1px solid var(--border);
342
- margin: 1rem 0;
343
- }
344
-
345
- .qp-rich-text-editor__content table {
346
- border-collapse: collapse;
347
- margin: 1rem 0;
348
- width: 100%;
349
- }
350
-
351
- .qp-rich-text-editor__content th,
352
- .qp-rich-text-editor__content td {
353
- border: 1px solid var(--border);
354
- padding: 0.5rem;
355
- text-align: left;
356
- }
357
-
358
- .tippy-box[data-theme~="qp-rich-text-editor"] {
359
- background: var(--popover);
360
- color: var(--popover-foreground);
361
- border: 1px solid var(--border);
362
- }
363
-
364
- .qp-rich-text-editor__slash {
365
- display: flex;
366
- flex-direction: column;
367
- gap: 0.25rem;
368
- padding: 0.5rem;
369
- min-width: 220px;
370
- }
371
-
372
- .qp-rich-text-editor__slash-item {
373
- display: flex;
374
- flex-direction: column;
375
- align-items: flex-start;
376
- gap: 0.125rem;
377
- padding: 0.5rem;
378
- font-size: 0.75rem;
379
- line-height: 1.2;
380
- color: var(--foreground);
381
- }
382
-
383
- .qp-rich-text-editor__slash-item--active,
384
- .qp-rich-text-editor__slash-item:hover {
385
- background: var(--muted);
386
- }
387
-
388
- .qp-rich-text-editor__slash-title {
389
- font-weight: 600;
390
- }
391
-
392
- .qp-rich-text-editor__slash-description {
393
- color: var(--muted-foreground);
394
- }
395
-
396
- .qp-rich-text-editor__slash-empty {
397
- padding: 0.5rem;
398
- font-size: 0.75rem;
399
- color: var(--muted-foreground);
400
- }
401
-
402
- /* =============================================================================
403
- Base Styles
404
- ============================================================================= */
405
-
406
- @layer base {
407
- * {
408
- @apply border-border outline-ring/50;
409
- }
410
- body {
411
- @apply bg-background text-foreground;
412
- font-family: var(--font-sans);
413
- }
414
- }
415
-
416
- /* =============================================================================
417
- Custom Scrollbar Styles
418
- ============================================================================= */
419
-
420
- @utility scrollbar-thin {
421
- scrollbar-width: thin;
422
- scrollbar-color: color-mix(in oklch, var(--border) 50%, transparent)
423
- transparent;
424
-
425
- &::-webkit-scrollbar {
426
- width: 6px;
427
- height: 6px;
428
- }
429
-
430
- &::-webkit-scrollbar-track {
431
- background: transparent;
432
- }
433
-
434
- &::-webkit-scrollbar-thumb {
435
- background: color-mix(in oklch, var(--border) 60%, transparent);
436
- border-radius: 3px;
437
- }
438
-
439
- &::-webkit-scrollbar-thumb:hover {
440
- background: var(--border);
441
- }
442
-
443
- &::-webkit-scrollbar-corner {
444
- background: transparent;
445
- }
446
- }
447
-
448
- /* =============================================================================
449
- Field Focus Animation
450
- ============================================================================= */
451
-
452
- @keyframes field-glow {
453
- 0%,
454
- 100% {
455
- background-color: transparent;
456
- }
457
- 50% {
458
- background-color: color-mix(in oklch, var(--primary) 8%, transparent);
459
- }
460
- }
461
-
462
- .animate-field-glow {
463
- animation: field-glow 2s ease-in-out;
464
- }
465
-
466
- /* =============================================================================
467
- Realtime Highlight Animation
468
- ============================================================================= */
469
-
470
- @keyframes realtime-pulse {
471
- 0% {
472
- border-left-color: var(--primary);
473
- }
474
- 100% {
475
- border-left-color: transparent;
476
- }
477
- }
478
-
479
- .animate-realtime-pulse {
480
- border-left: 3px solid transparent;
481
- animation: realtime-pulse 1.5s ease-out;
482
- }
483
-
484
- /* Delete animation - red pulse + fade out */
485
- @keyframes realtime-delete {
486
- 0% {
487
- background-color: color-mix(in oklch, var(--destructive) 25%, transparent);
488
- opacity: 1;
489
- }
490
- 70% {
491
- background-color: color-mix(in oklch, var(--destructive) 15%, transparent);
492
- opacity: 0.7;
493
- }
494
- 100% {
495
- background-color: color-mix(in oklch, var(--destructive) 10%, transparent);
496
- opacity: 0;
497
- }
498
- }
499
-
500
- .animate-realtime-delete {
501
- animation: realtime-delete 1.5s ease-out forwards;
502
- pointer-events: none;
503
- }
504
-
505
- /* =============================================================================
506
- Reduced Motion — Respect user's motion preferences (WCAG 2.1 AA)
507
- ============================================================================= */
508
-
509
- @media (prefers-reduced-motion: reduce) {
510
- *,
511
- *::before,
512
- *::after {
513
- animation-duration: 0.01ms !important;
514
- animation-iteration-count: 1 !important;
515
- transition-duration: 0.01ms !important;
516
- scroll-behavior: auto !important;
517
- }
518
-
519
- .animate-field-glow,
520
- .animate-realtime-pulse,
521
- .animate-realtime-delete,
522
- .animate-spin {
523
- animation: none !important;
524
- }
525
- }
526
-
527
- /* =============================================================================
528
- High Contrast — Improve visibility for users needing more contrast
529
- ============================================================================= */
530
-
531
- @media (prefers-contrast: more) {
532
- :root {
533
- --muted-foreground: oklch(0.37 0 0);
534
- --border: oklch(0.66 0 0);
535
- }
536
-
537
- .dark {
538
- --muted-foreground: oklch(0.73 0 0);
539
- --border: oklch(0.56 0 0);
540
- }
541
- }
542
-
543
- /* =============================================================================
544
- Focus Visible — Enhanced focus styles for keyboard navigation
545
- ============================================================================= */
546
-
547
- @layer base {
548
- :focus-visible {
549
- outline: 2px solid var(--ring);
550
- outline-offset: 2px;
551
- }
552
-
553
- /* Skip link styles */
554
- [href="#main-content"]:focus {
555
- clip: auto;
556
- clip-path: none;
557
- height: auto;
558
- width: auto;
559
- overflow: visible;
560
- white-space: nowrap;
561
- }
562
-
563
- /* Field focus pulse animation (preview click-to-focus) */
564
- @keyframes field-focus-pulse {
565
- 0% {
566
- box-shadow: 0 0 0 0 var(--primary);
567
- }
568
- 50% {
569
- box-shadow: 0 0 0 4px color-mix(in srgb, var(--primary) 30%, transparent);
570
- }
571
- 100% {
572
- box-shadow: 0 0 0 0 transparent;
573
- }
574
- }
575
-
576
- .field-focus-pulse {
577
- animation: field-focus-pulse 0.6s ease-out;
578
- border-radius: var(--radius);
579
- }
580
- }
581
-
582
-
583
- iconify-icon {
584
- display: inline-block;
585
- }
586
-
587
- iconify-icon:not([width]) {
588
- width: 1em;
589
- height: 1em;
590
- }
4
+ @import "./base.css";
@@ -56,8 +56,10 @@ function autoExpandFields(config) {
56
56
  const fieldDef = config.fields?.[fieldName];
57
57
  if (fieldDef) {
58
58
  const fieldType = fieldDef.name;
59
- if (fieldType === "upload" || fieldType === "uploadMany") withFields[fieldName] = true;
60
- else if (fieldType === "relation") {
59
+ if (fieldType === "upload" || fieldType === "uploadMany") {
60
+ const relationName = fieldDef["~options"]?.relationName ?? fieldName;
61
+ if (relationName) withFields[relationName] = true;
62
+ } else if (fieldType === "relation") {
61
63
  const relationName = fieldDef["~options"]?.relationName ?? fieldName;
62
64
  const nestedAvatarRelation = getNestedAvatarRelation(fieldDef);
63
65
  const knownRelations = config.relations;
@@ -0,0 +1,26 @@
1
+ //#region src/client/utils/keyboard-shortcuts.ts
2
+ function isModifierShortcut(event) {
3
+ return event.metaKey || event.ctrlKey;
4
+ }
5
+ function isEditableShortcutTarget(target) {
6
+ if (!(target instanceof Element)) return false;
7
+ return Boolean(target.closest([
8
+ "input",
9
+ "textarea",
10
+ "select",
11
+ "[contenteditable='true']",
12
+ "[role='textbox']",
13
+ ".ProseMirror",
14
+ "[data-admin-rich-text-editor]"
15
+ ].join(",")));
16
+ }
17
+ function shouldHandleAdminShortcut(event, options) {
18
+ if (event.defaultPrevented) return false;
19
+ if (!isModifierShortcut(event)) return false;
20
+ if (event.key.toLowerCase() !== options.key.toLowerCase()) return false;
21
+ if (!options.allowEditableTarget && isEditableShortcutTarget(event.target)) return false;
22
+ return true;
23
+ }
24
+
25
+ //#endregion
26
+ export { isModifierShortcut, shouldHandleAdminShortcut };
@@ -0,0 +1,80 @@
1
+ import * as React from "react";
2
+
3
+ //#region src/client/utils/use-lazy-component.ts
4
+ /**
5
+ * Shared lazy component resolution helper.
6
+ *
7
+ * Handles three `MaybeLazyComponent` forms:
8
+ * - `React.ComponentType` — used directly, no async
9
+ * - `React.lazy(...)` — exotic component, used directly
10
+ * - `() => import(...)` — dynamic loader, resolved async
11
+ *
12
+ * @internal Not part of the public API.
13
+ */
14
+ function isLazyLoader(loader, allowDynamicImportLoaders) {
15
+ if (!allowDynamicImportLoaders) return false;
16
+ return typeof loader === "function" && !loader.prototype?.render && !loader.prototype?.isReactComponent && loader.length === 0 && !loader.$$typeof;
17
+ }
18
+ /**
19
+ * Resolve a MaybeLazyComponent to a concrete React component.
20
+ *
21
+ * Returns `{ Component, loading }`:
22
+ * - `loading: true` while a lazy loader is in-flight
23
+ * - `Component: null` if loader is undefined or failed to resolve
24
+ * - Falls back to null on error (callers should fall back to built-in)
25
+ */
26
+ function useLazyComponent(loader, options = {}) {
27
+ const { allowDynamicImportLoaders = true } = options;
28
+ const [state, setState] = React.useState(() => {
29
+ if (!loader) return {
30
+ Component: null,
31
+ loading: false
32
+ };
33
+ if (!isLazyLoader(loader, allowDynamicImportLoaders)) return {
34
+ Component: loader,
35
+ loading: false
36
+ };
37
+ return {
38
+ Component: null,
39
+ loading: true
40
+ };
41
+ });
42
+ React.useEffect(() => {
43
+ if (!loader) {
44
+ setState({
45
+ Component: null,
46
+ loading: false
47
+ });
48
+ return;
49
+ }
50
+ if (!isLazyLoader(loader, allowDynamicImportLoaders)) {
51
+ setState({
52
+ Component: loader,
53
+ loading: false
54
+ });
55
+ return;
56
+ }
57
+ let mounted = true;
58
+ (async () => {
59
+ try {
60
+ const result = await loader();
61
+ if (mounted) setState({
62
+ Component: result.default || result,
63
+ loading: false
64
+ });
65
+ } catch {
66
+ if (mounted) setState({
67
+ Component: null,
68
+ loading: false
69
+ });
70
+ }
71
+ })();
72
+ return () => {
73
+ mounted = false;
74
+ };
75
+ }, [allowDynamicImportLoaders, loader]);
76
+ return state;
77
+ }
78
+
79
+ //#endregion
80
+ export { useLazyComponent };