@questpie/admin 0.0.1 → 1.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.
Files changed (250) hide show
  1. package/README.md +439 -424
  2. package/dist/auth-layout-M8K8_q5R.mjs +181 -0
  3. package/dist/auth-layout-M8K8_q5R.mjs.map +1 -0
  4. package/dist/bulk-upload-dialog-D7w7W1Hl.mjs +273 -0
  5. package/dist/bulk-upload-dialog-D7w7W1Hl.mjs.map +1 -0
  6. package/dist/{components/ui/card.mjs → card-BKHjBQfw.mjs} +8 -8
  7. package/dist/card-BKHjBQfw.mjs.map +1 -0
  8. package/dist/client/styles/index.css +434 -0
  9. package/dist/client-DbpZKSgH.d.mts +13585 -0
  10. package/dist/client-DbpZKSgH.d.mts.map +1 -0
  11. package/dist/client-njX1rZmi.mjs +22612 -0
  12. package/dist/client-njX1rZmi.mjs.map +1 -0
  13. package/dist/client.d.mts +3 -0
  14. package/dist/client.mjs +13 -0
  15. package/dist/content-locales-provider-BXvuIgfg.mjs +1650 -0
  16. package/dist/content-locales-provider-BXvuIgfg.mjs.map +1 -0
  17. package/dist/dashboard-page-B4PGEdc2.mjs +2500 -0
  18. package/dist/dashboard-page-B4PGEdc2.mjs.map +1 -0
  19. package/dist/dashboard-page-mCY0pgZv.mjs +3 -0
  20. package/dist/dropzone-Do3awXKd.mjs +634 -0
  21. package/dist/dropzone-Do3awXKd.mjs.map +1 -0
  22. package/dist/{views/auth/forgot-password-form.mjs → forgot-password-page-Bcp-An4Y.mjs} +87 -14
  23. package/dist/forgot-password-page-Bcp-An4Y.mjs.map +1 -0
  24. package/dist/forgot-password-page-CEwsdLwn.mjs +3 -0
  25. package/dist/index-B9Xwk4hi.d.mts +2753 -0
  26. package/dist/index-B9Xwk4hi.d.mts.map +1 -0
  27. package/dist/index.d.mts +3 -0
  28. package/dist/index.mjs +13 -0
  29. package/dist/login-page-BUnpCbCa.mjs +3 -0
  30. package/dist/login-page-CP4gA-dl.mjs +298 -0
  31. package/dist/login-page-CP4gA-dl.mjs.map +1 -0
  32. package/dist/preview-utils-BKQ9-TMa.mjs +65 -0
  33. package/dist/preview-utils-BKQ9-TMa.mjs.map +1 -0
  34. package/dist/{views/auth/reset-password-form.mjs → reset-password-page-BqfDmLxA.mjs} +111 -14
  35. package/dist/reset-password-page-BqfDmLxA.mjs.map +1 -0
  36. package/dist/reset-password-page-CufHz3h3.mjs +3 -0
  37. package/dist/runtime-6VZM878K.mjs +69 -0
  38. package/dist/runtime-6VZM878K.mjs.map +1 -0
  39. package/dist/saved-views.types-BMsz5mCy.d.mts +42 -0
  40. package/dist/saved-views.types-BMsz5mCy.d.mts.map +1 -0
  41. package/dist/server.d.mts +250 -0
  42. package/dist/server.d.mts.map +1 -0
  43. package/dist/server.mjs +832 -0
  44. package/dist/server.mjs.map +1 -0
  45. package/dist/setup-page-BNNzt_Z6.mjs +3 -0
  46. package/dist/setup-page-YAP_fzqh.mjs +264 -0
  47. package/dist/setup-page-YAP_fzqh.mjs.map +1 -0
  48. package/dist/shared.d.mts +57 -0
  49. package/dist/shared.d.mts.map +1 -0
  50. package/dist/shared.mjs +3 -0
  51. package/dist/{hooks/use-auth.mjs → use-auth-BoLmWtmU.mjs} +42 -30
  52. package/dist/use-auth-BoLmWtmU.mjs.map +1 -0
  53. package/package.json +48 -198
  54. package/.turbo/turbo-build.log +0 -108
  55. package/CHANGELOG.md +0 -10
  56. package/STATUS.md +0 -917
  57. package/VALIDATION.md +0 -602
  58. package/components.json +0 -24
  59. package/dist/__tests__/setup.mjs +0 -38
  60. package/dist/__tests__/test-utils.mjs +0 -45
  61. package/dist/__tests__/vitest.d.mjs +0 -3
  62. package/dist/components/admin-app.mjs +0 -69
  63. package/dist/components/fields/array-field.mjs +0 -190
  64. package/dist/components/fields/checkbox-field.mjs +0 -34
  65. package/dist/components/fields/custom-field.mjs +0 -32
  66. package/dist/components/fields/date-field.mjs +0 -41
  67. package/dist/components/fields/datetime-field.mjs +0 -42
  68. package/dist/components/fields/email-field.mjs +0 -37
  69. package/dist/components/fields/embedded-collection.mjs +0 -253
  70. package/dist/components/fields/field-types.mjs +0 -1
  71. package/dist/components/fields/field-utils.mjs +0 -10
  72. package/dist/components/fields/field-wrapper.mjs +0 -34
  73. package/dist/components/fields/index.mjs +0 -23
  74. package/dist/components/fields/json-field.mjs +0 -243
  75. package/dist/components/fields/locale-badge.mjs +0 -16
  76. package/dist/components/fields/number-field.mjs +0 -39
  77. package/dist/components/fields/password-field.mjs +0 -37
  78. package/dist/components/fields/relation-field.mjs +0 -104
  79. package/dist/components/fields/relation-picker.mjs +0 -229
  80. package/dist/components/fields/relation-select.mjs +0 -188
  81. package/dist/components/fields/rich-text-editor/index.mjs +0 -897
  82. package/dist/components/fields/select-field.mjs +0 -41
  83. package/dist/components/fields/switch-field.mjs +0 -34
  84. package/dist/components/fields/text-field.mjs +0 -38
  85. package/dist/components/fields/textarea-field.mjs +0 -38
  86. package/dist/components/index.mjs +0 -59
  87. package/dist/components/primitives/checkbox-input.mjs +0 -127
  88. package/dist/components/primitives/date-input.mjs +0 -303
  89. package/dist/components/primitives/index.mjs +0 -12
  90. package/dist/components/primitives/number-input.mjs +0 -104
  91. package/dist/components/primitives/select-input.mjs +0 -177
  92. package/dist/components/primitives/tag-input.mjs +0 -135
  93. package/dist/components/primitives/text-input.mjs +0 -39
  94. package/dist/components/primitives/textarea-input.mjs +0 -37
  95. package/dist/components/primitives/toggle-input.mjs +0 -31
  96. package/dist/components/primitives/types.mjs +0 -12
  97. package/dist/components/ui/accordion.mjs +0 -55
  98. package/dist/components/ui/avatar.mjs +0 -54
  99. package/dist/components/ui/badge.mjs +0 -34
  100. package/dist/components/ui/button.mjs +0 -48
  101. package/dist/components/ui/checkbox.mjs +0 -21
  102. package/dist/components/ui/combobox.mjs +0 -163
  103. package/dist/components/ui/dialog.mjs +0 -95
  104. package/dist/components/ui/dropdown-menu.mjs +0 -138
  105. package/dist/components/ui/field.mjs +0 -113
  106. package/dist/components/ui/input-group.mjs +0 -82
  107. package/dist/components/ui/input.mjs +0 -17
  108. package/dist/components/ui/label.mjs +0 -15
  109. package/dist/components/ui/popover.mjs +0 -56
  110. package/dist/components/ui/scroll-area.mjs +0 -38
  111. package/dist/components/ui/select.mjs +0 -100
  112. package/dist/components/ui/separator.mjs +0 -16
  113. package/dist/components/ui/sheet.mjs +0 -90
  114. package/dist/components/ui/sidebar.mjs +0 -387
  115. package/dist/components/ui/skeleton.mjs +0 -14
  116. package/dist/components/ui/spinner.mjs +0 -16
  117. package/dist/components/ui/switch.mjs +0 -22
  118. package/dist/components/ui/table.mjs +0 -68
  119. package/dist/components/ui/tabs.mjs +0 -48
  120. package/dist/components/ui/textarea.mjs +0 -15
  121. package/dist/components/ui/tooltip.mjs +0 -44
  122. package/dist/config/component-registry.mjs +0 -38
  123. package/dist/config/index.mjs +0 -129
  124. package/dist/hooks/admin-provider.mjs +0 -70
  125. package/dist/hooks/index.mjs +0 -7
  126. package/dist/hooks/store.mjs +0 -178
  127. package/dist/hooks/use-collection-db.mjs +0 -146
  128. package/dist/hooks/use-collection.mjs +0 -112
  129. package/dist/hooks/use-global.mjs +0 -46
  130. package/dist/hooks/use-mobile.mjs +0 -20
  131. package/dist/lib/utils.mjs +0 -10
  132. package/dist/styles/index.css +0 -336
  133. package/dist/styles/index.mjs +0 -1
  134. package/dist/utils/index.mjs +0 -9
  135. package/dist/views/auth/auth-layout.mjs +0 -52
  136. package/dist/views/auth/index.mjs +0 -6
  137. package/dist/views/auth/login-form.mjs +0 -156
  138. package/dist/views/collection/auto-form-fields.mjs +0 -525
  139. package/dist/views/collection/collection-form.mjs +0 -91
  140. package/dist/views/collection/collection-list.mjs +0 -76
  141. package/dist/views/collection/form-field.mjs +0 -42
  142. package/dist/views/collection/index.mjs +0 -6
  143. package/dist/views/common/index.mjs +0 -4
  144. package/dist/views/common/locale-switcher.mjs +0 -39
  145. package/dist/views/common/version-history.mjs +0 -272
  146. package/dist/views/index.mjs +0 -9
  147. package/dist/views/layout/admin-layout.mjs +0 -40
  148. package/dist/views/layout/admin-router.mjs +0 -95
  149. package/dist/views/layout/admin-sidebar.mjs +0 -63
  150. package/dist/views/layout/index.mjs +0 -5
  151. package/src/__tests__/setup.ts +0 -44
  152. package/src/__tests__/test-utils.tsx +0 -49
  153. package/src/__tests__/vitest.d.ts +0 -9
  154. package/src/components/admin-app.tsx +0 -221
  155. package/src/components/fields/array-field.tsx +0 -237
  156. package/src/components/fields/checkbox-field.tsx +0 -47
  157. package/src/components/fields/custom-field.tsx +0 -50
  158. package/src/components/fields/date-field.tsx +0 -65
  159. package/src/components/fields/datetime-field.tsx +0 -67
  160. package/src/components/fields/email-field.tsx +0 -51
  161. package/src/components/fields/embedded-collection.tsx +0 -315
  162. package/src/components/fields/field-types.ts +0 -162
  163. package/src/components/fields/field-utils.ts +0 -6
  164. package/src/components/fields/field-wrapper.tsx +0 -52
  165. package/src/components/fields/index.ts +0 -66
  166. package/src/components/fields/json-field.tsx +0 -440
  167. package/src/components/fields/locale-badge.tsx +0 -15
  168. package/src/components/fields/number-field.tsx +0 -57
  169. package/src/components/fields/password-field.tsx +0 -51
  170. package/src/components/fields/relation-field.tsx +0 -243
  171. package/src/components/fields/relation-picker.tsx +0 -402
  172. package/src/components/fields/relation-select.tsx +0 -327
  173. package/src/components/fields/rich-text-editor/index.tsx +0 -1337
  174. package/src/components/fields/select-field.tsx +0 -61
  175. package/src/components/fields/switch-field.tsx +0 -47
  176. package/src/components/fields/text-field.tsx +0 -55
  177. package/src/components/fields/textarea-field.tsx +0 -55
  178. package/src/components/index.ts +0 -40
  179. package/src/components/primitives/checkbox-input.tsx +0 -193
  180. package/src/components/primitives/date-input.tsx +0 -401
  181. package/src/components/primitives/index.ts +0 -24
  182. package/src/components/primitives/number-input.tsx +0 -132
  183. package/src/components/primitives/select-input.tsx +0 -296
  184. package/src/components/primitives/tag-input.tsx +0 -200
  185. package/src/components/primitives/text-input.tsx +0 -49
  186. package/src/components/primitives/textarea-input.tsx +0 -46
  187. package/src/components/primitives/toggle-input.tsx +0 -36
  188. package/src/components/primitives/types.ts +0 -235
  189. package/src/components/ui/accordion.tsx +0 -72
  190. package/src/components/ui/avatar.tsx +0 -106
  191. package/src/components/ui/badge.tsx +0 -48
  192. package/src/components/ui/button.tsx +0 -53
  193. package/src/components/ui/card.tsx +0 -94
  194. package/src/components/ui/checkbox.tsx +0 -27
  195. package/src/components/ui/combobox.tsx +0 -290
  196. package/src/components/ui/dialog.tsx +0 -151
  197. package/src/components/ui/dropdown-menu.tsx +0 -254
  198. package/src/components/ui/field.tsx +0 -227
  199. package/src/components/ui/input-group.tsx +0 -149
  200. package/src/components/ui/input.tsx +0 -20
  201. package/src/components/ui/label.tsx +0 -18
  202. package/src/components/ui/popover.tsx +0 -88
  203. package/src/components/ui/scroll-area.tsx +0 -53
  204. package/src/components/ui/select.tsx +0 -192
  205. package/src/components/ui/separator.tsx +0 -23
  206. package/src/components/ui/sheet.tsx +0 -127
  207. package/src/components/ui/sidebar.tsx +0 -723
  208. package/src/components/ui/skeleton.tsx +0 -13
  209. package/src/components/ui/spinner.tsx +0 -10
  210. package/src/components/ui/switch.tsx +0 -32
  211. package/src/components/ui/table.tsx +0 -99
  212. package/src/components/ui/tabs.tsx +0 -82
  213. package/src/components/ui/textarea.tsx +0 -18
  214. package/src/components/ui/tooltip.tsx +0 -70
  215. package/src/config/component-registry.ts +0 -190
  216. package/src/config/index.ts +0 -1099
  217. package/src/hooks/README.md +0 -269
  218. package/src/hooks/admin-provider.tsx +0 -110
  219. package/src/hooks/index.ts +0 -41
  220. package/src/hooks/store.ts +0 -248
  221. package/src/hooks/use-auth.ts +0 -168
  222. package/src/hooks/use-collection-db.ts +0 -209
  223. package/src/hooks/use-collection.ts +0 -156
  224. package/src/hooks/use-global.ts +0 -69
  225. package/src/hooks/use-mobile.ts +0 -21
  226. package/src/lib/utils.ts +0 -6
  227. package/src/styles/index.css +0 -340
  228. package/src/utils/index.ts +0 -6
  229. package/src/views/auth/auth-layout.tsx +0 -77
  230. package/src/views/auth/forgot-password-form.tsx +0 -192
  231. package/src/views/auth/index.ts +0 -21
  232. package/src/views/auth/login-form.tsx +0 -229
  233. package/src/views/auth/reset-password-form.tsx +0 -232
  234. package/src/views/collection/auto-form-fields.tsx +0 -982
  235. package/src/views/collection/collection-form.tsx +0 -186
  236. package/src/views/collection/collection-list.tsx +0 -223
  237. package/src/views/collection/form-field.tsx +0 -52
  238. package/src/views/collection/index.ts +0 -15
  239. package/src/views/common/index.ts +0 -8
  240. package/src/views/common/locale-switcher.tsx +0 -45
  241. package/src/views/common/version-history.tsx +0 -406
  242. package/src/views/index.ts +0 -25
  243. package/src/views/layout/admin-layout.tsx +0 -117
  244. package/src/views/layout/admin-router.tsx +0 -206
  245. package/src/views/layout/admin-sidebar.tsx +0 -185
  246. package/src/views/layout/index.ts +0 -12
  247. package/tsconfig.json +0 -13
  248. package/tsconfig.tsbuildinfo +0 -1
  249. package/tsdown.config.ts +0 -13
  250. package/vitest.config.ts +0 -29
@@ -0,0 +1,634 @@
1
+ import { f as useAdminStore, g as cn, h as Button, s as selectClient } from "./content-locales-provider-BXvuIgfg.mjs";
2
+ import { CloudArrowUp, SpinnerGap, XIcon } from "@phosphor-icons/react";
3
+ import * as React$1 from "react";
4
+ import { useCallback, useState } from "react";
5
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
6
+ import { useQueryClient } from "@tanstack/react-query";
7
+ import { Dialog } from "@base-ui/react/dialog";
8
+ import { Drawer } from "vaul";
9
+
10
+ //#region src/client/hooks/use-media-query.ts
11
+ /**
12
+ * Hook to detect media query matches
13
+ *
14
+ * @example
15
+ * ```tsx
16
+ * const isMobile = useMediaQuery("(max-width: 768px)");
17
+ * const isDesktop = useMediaQuery("(min-width: 769px)");
18
+ * const prefersDark = useMediaQuery("(prefers-color-scheme: dark)");
19
+ * ```
20
+ */
21
+ function useMediaQuery(query) {
22
+ const [matches, setMatches] = React$1.useState(() => {
23
+ if (typeof window === "undefined") return false;
24
+ return window.matchMedia(query).matches;
25
+ });
26
+ React$1.useEffect(() => {
27
+ if (typeof window === "undefined") return;
28
+ const mediaQuery = window.matchMedia(query);
29
+ setMatches(mediaQuery.matches);
30
+ const listener = (event) => {
31
+ setMatches(event.matches);
32
+ };
33
+ if (mediaQuery.addEventListener) mediaQuery.addEventListener("change", listener);
34
+ else mediaQuery.addListener(listener);
35
+ return () => {
36
+ if (mediaQuery.removeEventListener) mediaQuery.removeEventListener("change", listener);
37
+ else mediaQuery.removeListener(listener);
38
+ };
39
+ }, [query]);
40
+ return matches;
41
+ }
42
+ /**
43
+ * Predefined breakpoints matching Tailwind CSS defaults
44
+ */
45
+ const breakpoints = {
46
+ sm: "(min-width: 640px)",
47
+ md: "(min-width: 768px)",
48
+ lg: "(min-width: 1024px)",
49
+ xl: "(min-width: 1280px)",
50
+ "2xl": "(min-width: 1536px)"
51
+ };
52
+ /**
53
+ * Hook to check if viewport is mobile (below md breakpoint)
54
+ */
55
+ function useIsMobile() {
56
+ return !useMediaQuery(breakpoints.md);
57
+ }
58
+ /**
59
+ * Hook to check if viewport is desktop (md breakpoint and above)
60
+ */
61
+ function useIsDesktop() {
62
+ return useMediaQuery(breakpoints.md);
63
+ }
64
+
65
+ //#endregion
66
+ //#region src/client/components/ui/dialog.tsx
67
+ function Dialog$1({ ...props }) {
68
+ return /* @__PURE__ */ jsx(Dialog.Root, {
69
+ "data-slot": "dialog",
70
+ ...props
71
+ });
72
+ }
73
+ function DialogPortal({ ...props }) {
74
+ return /* @__PURE__ */ jsx(Dialog.Portal, {
75
+ "data-slot": "dialog-portal",
76
+ ...props
77
+ });
78
+ }
79
+ function DialogOverlay({ className, ...props }) {
80
+ return /* @__PURE__ */ jsx(Dialog.Backdrop, {
81
+ "data-slot": "dialog-overlay",
82
+ className: cn("data-open:animate-in data-closed:animate-out data-closed:fade-out-0 data-open:fade-in-0 bg-black/80 duration-100 supports-backdrop-filter:backdrop-blur-xs fixed inset-0 isolate z-50", className),
83
+ ...props
84
+ });
85
+ }
86
+ function DialogContent({ className, children, showCloseButton = true, ...props }) {
87
+ return /* @__PURE__ */ jsxs(DialogPortal, { children: [/* @__PURE__ */ jsx(DialogOverlay, {}), /* @__PURE__ */ jsxs(Dialog.Popup, {
88
+ "data-slot": "dialog-content",
89
+ className: cn("bg-background data-open:animate-in data-closed:animate-out data-closed:fade-out-0 data-open:fade-in-0 data-closed:zoom-out-95 data-open:zoom-in-95 ring-foreground/10 grid max-w-[calc(100%-2rem)] gap-4 p-4 text-sm ring-1 duration-100 sm:max-w-sm fixed top-1/2 left-1/2 z-50 w-full -translate-x-1/2 -translate-y-1/2 outline-none", className),
90
+ ...props,
91
+ children: [children, showCloseButton && /* @__PURE__ */ jsxs(Dialog.Close, {
92
+ "data-slot": "dialog-close",
93
+ render: /* @__PURE__ */ jsx(Button, {
94
+ variant: "ghost",
95
+ className: "absolute top-2 right-2",
96
+ size: "icon-sm"
97
+ }),
98
+ children: [/* @__PURE__ */ jsx(XIcon, {}), /* @__PURE__ */ jsx("span", {
99
+ className: "sr-only",
100
+ children: "Close"
101
+ })]
102
+ })]
103
+ })] });
104
+ }
105
+ function DialogHeader({ className, ...props }) {
106
+ return /* @__PURE__ */ jsx("div", {
107
+ "data-slot": "dialog-header",
108
+ className: cn("gap-1 flex flex-col", className),
109
+ ...props
110
+ });
111
+ }
112
+ function DialogFooter({ className, showCloseButton = false, children, ...props }) {
113
+ return /* @__PURE__ */ jsxs("div", {
114
+ "data-slot": "dialog-footer",
115
+ className: cn("gap-2 flex flex-col-reverse gap-2 sm:flex-row sm:justify-end", className),
116
+ ...props,
117
+ children: [children, showCloseButton && /* @__PURE__ */ jsx(Dialog.Close, {
118
+ render: /* @__PURE__ */ jsx(Button, { variant: "outline" }),
119
+ children: "Close"
120
+ })]
121
+ });
122
+ }
123
+ function DialogTitle({ className, ...props }) {
124
+ return /* @__PURE__ */ jsx(Dialog.Title, {
125
+ "data-slot": "dialog-title",
126
+ className: cn("text-sm font-medium", className),
127
+ ...props
128
+ });
129
+ }
130
+ function DialogDescription({ className, ...props }) {
131
+ return /* @__PURE__ */ jsx(Dialog.Description, {
132
+ "data-slot": "dialog-description",
133
+ className: cn("text-muted-foreground *:[a]:hover:text-foreground text-xs/relaxed *:[a]:underline *:[a]:underline-offset-3", className),
134
+ ...props
135
+ });
136
+ }
137
+
138
+ //#endregion
139
+ //#region src/client/components/ui/drawer.tsx
140
+ function Drawer$1({ ...props }) {
141
+ return /* @__PURE__ */ jsx(Drawer.Root, {
142
+ "data-slot": "drawer",
143
+ ...props
144
+ });
145
+ }
146
+ function DrawerTrigger({ ...props }) {
147
+ return /* @__PURE__ */ jsx(Drawer.Trigger, {
148
+ "data-slot": "drawer-trigger",
149
+ ...props
150
+ });
151
+ }
152
+ function DrawerPortal({ ...props }) {
153
+ return /* @__PURE__ */ jsx(Drawer.Portal, {
154
+ "data-slot": "drawer-portal",
155
+ ...props
156
+ });
157
+ }
158
+ function DrawerOverlay({ className, ...props }) {
159
+ return /* @__PURE__ */ jsx(Drawer.Overlay, {
160
+ "data-slot": "drawer-overlay",
161
+ className: cn("data-open:animate-in data-closed:animate-out data-closed:fade-out-0 data-open:fade-in-0 bg-black/80 supports-backdrop-filter:backdrop-blur-xs fixed inset-0 z-50", className),
162
+ ...props
163
+ });
164
+ }
165
+ function DrawerContent({ className, children, ...props }) {
166
+ return /* @__PURE__ */ jsxs(DrawerPortal, {
167
+ "data-slot": "drawer-portal",
168
+ children: [/* @__PURE__ */ jsx(DrawerOverlay, {}), /* @__PURE__ */ jsxs(Drawer.Content, {
169
+ "data-slot": "drawer-content",
170
+ className: cn("before:bg-background px-4 pb-4 relative flex h-auto flex-col bg-transparent text-xs/relaxed before:absolute before:inset-2 before:-z-10 before:rounded-xl data-[vaul-drawer-direction=bottom]:inset-x-0 data-[vaul-drawer-direction=bottom]:bottom-0 data-[vaul-drawer-direction=bottom]:mt-24 data-[vaul-drawer-direction=bottom]:max-h-[80vh] data-[vaul-drawer-direction=left]:inset-y-0 data-[vaul-drawer-direction=left]:left-0 data-[vaul-drawer-direction=left]:w-3/4 data-[vaul-drawer-direction=right]:inset-y-0 data-[vaul-drawer-direction=right]:right-0 data-[vaul-drawer-direction=right]:w-3/4 data-[vaul-drawer-direction=top]:inset-x-0 data-[vaul-drawer-direction=top]:top-0 data-[vaul-drawer-direction=top]:mb-24 data-[vaul-drawer-direction=top]:max-h-[80vh] data-[vaul-drawer-direction=left]:sm:max-w-sm data-[vaul-drawer-direction=right]:sm:max-w-sm group/drawer-content fixed z-50", className),
171
+ ...props,
172
+ children: [/* @__PURE__ */ jsx("div", { className: "bg-muted mx-auto mt-4 hidden h-1.5 w-[100px] shrink-0 rounded-full group-data-[vaul-drawer-direction=bottom]/drawer-content:block" }), children]
173
+ })]
174
+ });
175
+ }
176
+ function DrawerHeader({ className, ...props }) {
177
+ return /* @__PURE__ */ jsx("div", {
178
+ "data-slot": "drawer-header",
179
+ className: cn("gap-1 pt-4 group-data-[vaul-drawer-direction=bottom]/drawer-content:text-center group-data-[vaul-drawer-direction=top]/drawer-content:text-center md:text-left flex flex-col", className),
180
+ ...props
181
+ });
182
+ }
183
+ function DrawerFooter({ className, ...props }) {
184
+ return /* @__PURE__ */ jsx("div", {
185
+ "data-slot": "drawer-footer",
186
+ className: cn("gap-2 py-4 mt-auto flex flex-col", className),
187
+ ...props
188
+ });
189
+ }
190
+ function DrawerTitle({ className, ...props }) {
191
+ return /* @__PURE__ */ jsx(Drawer.Title, {
192
+ "data-slot": "drawer-title",
193
+ className: cn("text-foreground text-sm font-medium", className),
194
+ ...props
195
+ });
196
+ }
197
+ function DrawerDescription({ className, ...props }) {
198
+ return /* @__PURE__ */ jsx(Drawer.Description, {
199
+ "data-slot": "drawer-description",
200
+ className: cn("text-muted-foreground text-xs/relaxed", className),
201
+ ...props
202
+ });
203
+ }
204
+
205
+ //#endregion
206
+ //#region src/client/components/ui/responsive-dialog.tsx
207
+ const ResponsiveDialogContext = React$1.createContext(null);
208
+ function useResponsiveDialog() {
209
+ const context = React$1.useContext(ResponsiveDialogContext);
210
+ if (!context) throw new Error("ResponsiveDialog components must be used within ResponsiveDialog");
211
+ return context;
212
+ }
213
+ function ResponsiveDialog({ children, open, onOpenChange }) {
214
+ const isMobile = useIsMobile();
215
+ const contextValue = React$1.useMemo(() => ({ isMobile }), [isMobile]);
216
+ if (isMobile) return /* @__PURE__ */ jsx(ResponsiveDialogContext.Provider, {
217
+ value: contextValue,
218
+ children: /* @__PURE__ */ jsx(Drawer$1, {
219
+ open,
220
+ onOpenChange,
221
+ children
222
+ })
223
+ });
224
+ return /* @__PURE__ */ jsx(ResponsiveDialogContext.Provider, {
225
+ value: contextValue,
226
+ children: /* @__PURE__ */ jsx(Dialog.Root, {
227
+ open,
228
+ onOpenChange,
229
+ children
230
+ })
231
+ });
232
+ }
233
+ function ResponsiveDialogContent({ children, className }) {
234
+ const { isMobile } = useResponsiveDialog();
235
+ if (isMobile) return /* @__PURE__ */ jsx(DrawerContent, {
236
+ className: cn("max-h-[96vh]", className),
237
+ children
238
+ });
239
+ return /* @__PURE__ */ jsx(DialogContent, {
240
+ className,
241
+ children
242
+ });
243
+ }
244
+ function ResponsiveDialogHeader({ className, ...props }) {
245
+ const { isMobile } = useResponsiveDialog();
246
+ if (isMobile) return /* @__PURE__ */ jsx(DrawerHeader, {
247
+ className,
248
+ ...props
249
+ });
250
+ return /* @__PURE__ */ jsx(DialogHeader, {
251
+ className,
252
+ ...props
253
+ });
254
+ }
255
+ function ResponsiveDialogTitle({ className, children, ...props }) {
256
+ const { isMobile } = useResponsiveDialog();
257
+ if (isMobile) return /* @__PURE__ */ jsx(DrawerTitle, {
258
+ className,
259
+ ...props,
260
+ children
261
+ });
262
+ return /* @__PURE__ */ jsx(Dialog.Title, {
263
+ "data-slot": "responsive-dialog-title",
264
+ className: cn("text-sm font-medium", className),
265
+ ...props,
266
+ children
267
+ });
268
+ }
269
+ function ResponsiveDialogDescription({ className, children, ...props }) {
270
+ const { isMobile } = useResponsiveDialog();
271
+ if (isMobile) return /* @__PURE__ */ jsx(DrawerDescription, {
272
+ className,
273
+ ...props,
274
+ children
275
+ });
276
+ return /* @__PURE__ */ jsx(Dialog.Description, {
277
+ "data-slot": "responsive-dialog-description",
278
+ className: cn("text-muted-foreground text-xs/relaxed", className),
279
+ ...props,
280
+ children
281
+ });
282
+ }
283
+ function ResponsiveDialogFooter({ className, ...props }) {
284
+ const { isMobile } = useResponsiveDialog();
285
+ if (isMobile) return /* @__PURE__ */ jsx(DrawerFooter, {
286
+ className,
287
+ ...props
288
+ });
289
+ return /* @__PURE__ */ jsx(DialogFooter, {
290
+ className,
291
+ ...props
292
+ });
293
+ }
294
+
295
+ //#endregion
296
+ //#region src/client/hooks/use-upload.ts
297
+ /**
298
+ * useUpload Hook
299
+ *
300
+ * Handles file uploads to the CMS with progress tracking.
301
+ * Uses the QuestpieClient's upload method which uses XMLHttpRequest for progress.
302
+ *
303
+ * @example
304
+ * ```tsx
305
+ * const { upload, uploadMany, isUploading, progress } = useUpload();
306
+ *
307
+ * // Single file upload
308
+ * const asset = await upload(file);
309
+ *
310
+ * // Multiple files upload
311
+ * const assets = await uploadMany(files, {
312
+ * onProgress: (p) => console.log(`${p}%`),
313
+ * });
314
+ * ```
315
+ */
316
+ /**
317
+ * Hook for uploading files to the CMS
318
+ *
319
+ * Uses the QuestpieClient's built-in upload method which provides
320
+ * progress tracking via XMLHttpRequest.
321
+ */
322
+ function useUpload() {
323
+ const client = useAdminStore(selectClient);
324
+ const queryClient = useQueryClient();
325
+ const [isUploading, setIsUploading] = useState(false);
326
+ const [progress, setProgress] = useState(0);
327
+ const [error, setError] = useState(null);
328
+ return {
329
+ upload: useCallback(async (file, options = {}) => {
330
+ const { collection = "assets", onProgress, signal } = options;
331
+ setIsUploading(true);
332
+ setProgress(0);
333
+ setError(null);
334
+ try {
335
+ const collectionApi = client.collections[collection];
336
+ if (!collectionApi?.upload) throw new Error(`Collection "${collection}" does not support uploads. Make sure .upload() is enabled on the collection.`);
337
+ const result = await collectionApi.upload(file, {
338
+ signal,
339
+ onProgress: (p) => {
340
+ setProgress(p);
341
+ onProgress?.(p);
342
+ }
343
+ });
344
+ queryClient.invalidateQueries({ queryKey: [
345
+ "questpie",
346
+ "collections",
347
+ collection
348
+ ] });
349
+ return result;
350
+ } catch (err) {
351
+ const uploadError = err instanceof Error ? err : /* @__PURE__ */ new Error("Upload failed");
352
+ setError(uploadError);
353
+ throw uploadError;
354
+ } finally {
355
+ setIsUploading(false);
356
+ }
357
+ }, [client, queryClient]),
358
+ uploadMany: useCallback(async (files, options = {}) => {
359
+ const { collection = "assets", onProgress, signal } = options;
360
+ if (files.length === 0) return [];
361
+ setIsUploading(true);
362
+ setProgress(0);
363
+ setError(null);
364
+ try {
365
+ const collectionApi = client.collections[collection];
366
+ if (!collectionApi?.uploadMany) throw new Error(`Collection "${collection}" does not support uploads. Make sure .upload() is enabled on the collection.`);
367
+ const results = await collectionApi.uploadMany(files, {
368
+ signal,
369
+ onProgress: (p, fileIndex) => {
370
+ setProgress(p);
371
+ onProgress?.(p, fileIndex);
372
+ }
373
+ });
374
+ queryClient.invalidateQueries({ queryKey: [
375
+ "questpie",
376
+ "collections",
377
+ collection
378
+ ] });
379
+ setProgress(100);
380
+ return results;
381
+ } catch (err) {
382
+ const uploadError = err instanceof Error ? err : /* @__PURE__ */ new Error("Upload failed");
383
+ setError(uploadError);
384
+ throw uploadError;
385
+ } finally {
386
+ setIsUploading(false);
387
+ }
388
+ }, [client, queryClient]),
389
+ isUploading,
390
+ progress,
391
+ error,
392
+ reset: useCallback(() => {
393
+ setIsUploading(false);
394
+ setProgress(0);
395
+ setError(null);
396
+ }, [])
397
+ };
398
+ }
399
+
400
+ //#endregion
401
+ //#region src/client/components/primitives/dropzone.tsx
402
+ /**
403
+ * Dropzone Primitive
404
+ *
405
+ * A reusable drag-and-drop area for file uploads.
406
+ * Supports file type filtering, size validation, and visual feedback.
407
+ *
408
+ * @example
409
+ * ```tsx
410
+ * <Dropzone
411
+ * onDrop={(files) => handleUpload(files)}
412
+ * accept={["image/*", "application/pdf"]}
413
+ * maxSize={5_000_000}
414
+ * />
415
+ * ```
416
+ */
417
+ /**
418
+ * Check if a file matches accepted types
419
+ */
420
+ function matchesAccept(file, accept) {
421
+ if (!accept || accept.length === 0) return true;
422
+ const mimeType = file.type.toLowerCase();
423
+ const fileName = file.name.toLowerCase();
424
+ return accept.some((pattern) => {
425
+ const normalizedPattern = pattern.toLowerCase();
426
+ if (normalizedPattern.endsWith("/*")) {
427
+ const baseType = normalizedPattern.slice(0, -2);
428
+ return mimeType.startsWith(`${baseType}/`);
429
+ }
430
+ if (normalizedPattern.startsWith(".")) return fileName.endsWith(normalizedPattern);
431
+ return mimeType === normalizedPattern;
432
+ });
433
+ }
434
+ /**
435
+ * Format file size for display
436
+ */
437
+ function formatFileSize(bytes) {
438
+ if (bytes < 1024) return `${bytes} B`;
439
+ if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
440
+ return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
441
+ }
442
+ function Dropzone({ onDrop, accept, maxSize, multiple = false, disabled = false, loading = false, progress, label = "Drop files here or click to browse", hint, error, className, children, onValidationError }) {
443
+ const [isDragging, setIsDragging] = React$1.useState(false);
444
+ const inputRef = React$1.useRef(null);
445
+ const dragCounterRef = React$1.useRef(0);
446
+ /**
447
+ * Validate files and return valid ones + errors
448
+ */
449
+ const validateFiles = React$1.useCallback((files) => {
450
+ const valid = [];
451
+ const errors = [];
452
+ for (const file of files) {
453
+ if (!matchesAccept(file, accept)) {
454
+ errors.push({
455
+ file,
456
+ type: "type",
457
+ message: `"${file.name}" is not an accepted file type`
458
+ });
459
+ continue;
460
+ }
461
+ if (maxSize && file.size > maxSize) {
462
+ errors.push({
463
+ file,
464
+ type: "size",
465
+ message: `"${file.name}" exceeds maximum size of ${formatFileSize(maxSize)}`
466
+ });
467
+ continue;
468
+ }
469
+ valid.push(file);
470
+ }
471
+ return {
472
+ valid,
473
+ errors
474
+ };
475
+ }, [accept, maxSize]);
476
+ /**
477
+ * Handle file selection
478
+ */
479
+ const handleFiles = React$1.useCallback((files) => {
480
+ if (disabled || loading) return;
481
+ const fileArray = Array.from(files);
482
+ const { valid, errors } = validateFiles(multiple ? fileArray : fileArray.slice(0, 1));
483
+ if (errors.length > 0) onValidationError?.(errors);
484
+ if (valid.length > 0) onDrop(valid);
485
+ }, [
486
+ disabled,
487
+ loading,
488
+ multiple,
489
+ validateFiles,
490
+ onDrop,
491
+ onValidationError
492
+ ]);
493
+ /**
494
+ * Handle drag events
495
+ */
496
+ const handleDragEnter = React$1.useCallback((e) => {
497
+ e.preventDefault();
498
+ e.stopPropagation();
499
+ dragCounterRef.current += 1;
500
+ if (e.dataTransfer.items.length > 0 && !disabled && !loading) setIsDragging(true);
501
+ }, [disabled, loading]);
502
+ const handleDragLeave = React$1.useCallback((e) => {
503
+ e.preventDefault();
504
+ e.stopPropagation();
505
+ dragCounterRef.current -= 1;
506
+ if (dragCounterRef.current === 0) setIsDragging(false);
507
+ }, []);
508
+ const handleDragOver = React$1.useCallback((e) => {
509
+ e.preventDefault();
510
+ e.stopPropagation();
511
+ }, []);
512
+ const handleDrop = React$1.useCallback((e) => {
513
+ e.preventDefault();
514
+ e.stopPropagation();
515
+ dragCounterRef.current = 0;
516
+ setIsDragging(false);
517
+ if (e.dataTransfer.files.length > 0) handleFiles(e.dataTransfer.files);
518
+ }, [handleFiles]);
519
+ /**
520
+ * Handle click to open file dialog
521
+ */
522
+ const handleClick = React$1.useCallback(() => {
523
+ if (disabled || loading) return;
524
+ inputRef.current?.click();
525
+ }, [disabled, loading]);
526
+ /**
527
+ * Handle file input change
528
+ */
529
+ const handleInputChange = React$1.useCallback((e) => {
530
+ if (e.target.files && e.target.files.length > 0) handleFiles(e.target.files);
531
+ e.target.value = "";
532
+ }, [handleFiles]);
533
+ /**
534
+ * Build accept string for input
535
+ */
536
+ const acceptString = accept?.join(",") || void 0;
537
+ /**
538
+ * Build hint text
539
+ */
540
+ const hintText = React$1.useMemo(() => {
541
+ if (hint) return hint;
542
+ const parts = [];
543
+ if (accept && accept.length > 0) {
544
+ const types = accept.map((t) => {
545
+ if (t.startsWith("image/")) return "Images";
546
+ if (t.startsWith("video/")) return "Videos";
547
+ if (t.startsWith("audio/")) return "Audio";
548
+ if (t === "application/pdf") return "PDF";
549
+ if (t.startsWith(".")) return t.toUpperCase();
550
+ return t;
551
+ }).filter((v, i, a) => a.indexOf(v) === i);
552
+ parts.push(types.join(", "));
553
+ }
554
+ if (maxSize) parts.push(`Max ${formatFileSize(maxSize)}`);
555
+ return parts.length > 0 ? parts.join(" • ") : void 0;
556
+ }, [
557
+ hint,
558
+ accept,
559
+ maxSize
560
+ ]);
561
+ return /* @__PURE__ */ jsxs("div", {
562
+ role: "button",
563
+ tabIndex: disabled || loading ? -1 : 0,
564
+ onClick: handleClick,
565
+ onKeyDown: (e) => {
566
+ if (e.key === "Enter" || e.key === " ") {
567
+ e.preventDefault();
568
+ handleClick();
569
+ }
570
+ },
571
+ onDragEnter: handleDragEnter,
572
+ onDragLeave: handleDragLeave,
573
+ onDragOver: handleDragOver,
574
+ onDrop: handleDrop,
575
+ className: cn("relative flex min-h-[120px] cursor-pointer flex-col items-center justify-center gap-2 rounded-lg border-2 border-dashed p-6 text-center transition-colors", "border-border/60 bg-muted/30 hover:border-border hover:bg-muted/50", isDragging && "border-primary bg-primary/5", error && "border-destructive/50 bg-destructive/5", (disabled || loading) && "pointer-events-none opacity-60", className),
576
+ "aria-disabled": disabled || loading,
577
+ "data-dragging": isDragging || void 0,
578
+ children: [
579
+ /* @__PURE__ */ jsx("input", {
580
+ ref: inputRef,
581
+ type: "file",
582
+ accept: acceptString,
583
+ multiple,
584
+ onChange: handleInputChange,
585
+ className: "sr-only",
586
+ disabled: disabled || loading,
587
+ tabIndex: -1
588
+ }),
589
+ children || /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("div", {
590
+ className: "flex items-center justify-center",
591
+ children: loading ? /* @__PURE__ */ jsxs("div", {
592
+ className: "relative",
593
+ children: [/* @__PURE__ */ jsx(SpinnerGap, {
594
+ className: "text-muted-foreground size-10 animate-spin",
595
+ weight: "regular"
596
+ }), typeof progress === "number" && /* @__PURE__ */ jsxs("span", {
597
+ className: "text-muted-foreground absolute inset-0 flex items-center justify-center text-xs font-medium",
598
+ children: [progress, "%"]
599
+ })]
600
+ }) : /* @__PURE__ */ jsx(CloudArrowUp, {
601
+ className: cn("size-10 transition-colors", isDragging ? "text-primary" : "text-muted-foreground"),
602
+ weight: "regular"
603
+ })
604
+ }), /* @__PURE__ */ jsxs("div", {
605
+ className: "space-y-1",
606
+ children: [
607
+ /* @__PURE__ */ jsx("p", {
608
+ className: cn("text-sm font-medium", isDragging ? "text-primary" : "text-foreground"),
609
+ children: loading ? "Uploading..." : label
610
+ }),
611
+ hintText && !loading && /* @__PURE__ */ jsx("p", {
612
+ className: "text-muted-foreground text-xs",
613
+ children: hintText
614
+ }),
615
+ loading && typeof progress === "number" && /* @__PURE__ */ jsx("div", {
616
+ className: "bg-muted mx-auto mt-2 h-1.5 w-32 overflow-hidden rounded-full",
617
+ children: /* @__PURE__ */ jsx("div", {
618
+ className: "bg-primary h-full rounded-full transition-all duration-300",
619
+ style: { width: `${progress}%` }
620
+ })
621
+ })
622
+ ]
623
+ })] }),
624
+ error && /* @__PURE__ */ jsx("p", {
625
+ className: "text-destructive absolute bottom-2 left-0 right-0 text-center text-xs",
626
+ children: error
627
+ })
628
+ ]
629
+ });
630
+ }
631
+
632
+ //#endregion
633
+ export { useMediaQuery as S, DialogFooter as _, ResponsiveDialogDescription as a, useIsDesktop as b, ResponsiveDialogTitle as c, DrawerHeader as d, DrawerTitle as f, DialogDescription as g, DialogContent as h, ResponsiveDialogContent as i, Drawer$1 as l, Dialog$1 as m, useUpload as n, ResponsiveDialogFooter as o, DrawerTrigger as p, ResponsiveDialog as r, ResponsiveDialogHeader as s, Dropzone as t, DrawerContent as u, DialogHeader as v, useIsMobile as x, DialogTitle as y };
634
+ //# sourceMappingURL=dropzone-Do3awXKd.mjs.map