astro-md-editor 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.
Files changed (87) hide show
  1. package/.output/nitro.json +17 -0
  2. package/.output/public/assets/index-Cc7yKB0o.js +19 -0
  3. package/.output/public/assets/inter-cyrillic-ext-wght-normal-BOeWTOD4.woff2 +0 -0
  4. package/.output/public/assets/inter-cyrillic-wght-normal-DqGufNeO.woff2 +0 -0
  5. package/.output/public/assets/inter-greek-ext-wght-normal-DlzME5K_.woff2 +0 -0
  6. package/.output/public/assets/inter-greek-wght-normal-CkhJZR-_.woff2 +0 -0
  7. package/.output/public/assets/inter-latin-ext-wght-normal-DO1Apj_S.woff2 +0 -0
  8. package/.output/public/assets/inter-latin-wght-normal-Dx4kXJAl.woff2 +0 -0
  9. package/.output/public/assets/inter-vietnamese-wght-normal-CBcvBZtf.woff2 +0 -0
  10. package/.output/public/assets/main-DDBjVFnt.js +17 -0
  11. package/.output/public/assets/styles-ggfdUHMo.css +1 -0
  12. package/.output/public/favicon.ico +0 -0
  13. package/.output/public/logo192.png +0 -0
  14. package/.output/public/logo512.png +0 -0
  15. package/.output/public/manifest.json +25 -0
  16. package/.output/public/robots.txt +3 -0
  17. package/.output/server/__root-C09LBXMv.mjs +40 -0
  18. package/.output/server/_chunks/ssr-renderer.mjs +21 -0
  19. package/.output/server/_libs/ajv-formats.mjs +330 -0
  20. package/.output/server/_libs/ajv.mjs +5484 -0
  21. package/.output/server/_libs/base-ui__react.mjs +8712 -0
  22. package/.output/server/_libs/base-ui__utils.mjs +980 -0
  23. package/.output/server/_libs/class-variance-authority.mjs +44 -0
  24. package/.output/server/_libs/clsx.mjs +16 -0
  25. package/.output/server/_libs/cookie-es.mjs +58 -0
  26. package/.output/server/_libs/croner.mjs +1 -0
  27. package/.output/server/_libs/crossws.mjs +1 -0
  28. package/.output/server/_libs/date-fns.mjs +1716 -0
  29. package/.output/server/_libs/date-fns__tz.mjs +217 -0
  30. package/.output/server/_libs/extend-shallow.mjs +35 -0
  31. package/.output/server/_libs/fast-deep-equal.mjs +38 -0
  32. package/.output/server/_libs/fast-uri.mjs +725 -0
  33. package/.output/server/_libs/floating-ui__core.mjs +663 -0
  34. package/.output/server/_libs/floating-ui__dom.mjs +624 -0
  35. package/.output/server/_libs/floating-ui__react-dom.mjs +279 -0
  36. package/.output/server/_libs/floating-ui__utils.mjs +322 -0
  37. package/.output/server/_libs/gray-matter.mjs +393 -0
  38. package/.output/server/_libs/h3-v2.mjs +276 -0
  39. package/.output/server/_libs/h3.mjs +400 -0
  40. package/.output/server/_libs/hookable.mjs +1 -0
  41. package/.output/server/_libs/is-extendable.mjs +13 -0
  42. package/.output/server/_libs/isbot.mjs +20 -0
  43. package/.output/server/_libs/js-yaml.mjs +2822 -0
  44. package/.output/server/_libs/json-schema-traverse.mjs +91 -0
  45. package/.output/server/_libs/kind-of.mjs +125 -0
  46. package/.output/server/_libs/lucide-react.mjs +177 -0
  47. package/.output/server/_libs/ohash.mjs +1 -0
  48. package/.output/server/_libs/react-day-picker.mjs +2216 -0
  49. package/.output/server/_libs/react-dom.mjs +10779 -0
  50. package/.output/server/_libs/react-resizable-panels.mjs +2024 -0
  51. package/.output/server/_libs/react.mjs +513 -0
  52. package/.output/server/_libs/reselect.mjs +326 -0
  53. package/.output/server/_libs/rou3.mjs +8 -0
  54. package/.output/server/_libs/section-matter.mjs +112 -0
  55. package/.output/server/_libs/seroval-plugins.mjs +58 -0
  56. package/.output/server/_libs/seroval.mjs +1765 -0
  57. package/.output/server/_libs/srvx.mjs +736 -0
  58. package/.output/server/_libs/strip-bom-string.mjs +16 -0
  59. package/.output/server/_libs/tabbable.mjs +342 -0
  60. package/.output/server/_libs/tailwind-merge.mjs +3175 -0
  61. package/.output/server/_libs/tanstack__history.mjs +217 -0
  62. package/.output/server/_libs/tanstack__react-router.mjs +1464 -0
  63. package/.output/server/_libs/tanstack__react-store.mjs +1 -0
  64. package/.output/server/_libs/tanstack__router-core.mjs +4912 -0
  65. package/.output/server/_libs/tanstack__store.mjs +1 -0
  66. package/.output/server/_libs/tiny-invariant.mjs +12 -0
  67. package/.output/server/_libs/tiny-warning.mjs +5 -0
  68. package/.output/server/_libs/ufo.mjs +54 -0
  69. package/.output/server/_libs/unctx.mjs +1 -0
  70. package/.output/server/_libs/unstorage.mjs +1 -0
  71. package/.output/server/_libs/use-sync-external-store.mjs +139 -0
  72. package/.output/server/_libs/zod.mjs +3634 -0
  73. package/.output/server/_libs/zustand.mjs +43 -0
  74. package/.output/server/_ssr/RightSidebar-RSY9M7XF.mjs +218 -0
  75. package/.output/server/_ssr/collections.server-D6U2tEsT.mjs +120 -0
  76. package/.output/server/_ssr/createServerRpc-29xaFZcb.mjs +12 -0
  77. package/.output/server/_ssr/index-BaqV4cZC.mjs +2083 -0
  78. package/.output/server/_ssr/index-sQBM6rwN.mjs +115 -0
  79. package/.output/server/_ssr/index.mjs +1448 -0
  80. package/.output/server/_ssr/router-D4G1DGr3.mjs +155 -0
  81. package/.output/server/_ssr/start-HYkvq4Ni.mjs +4 -0
  82. package/.output/server/_tanstack-start-manifest_v-CYEHh_qB.mjs +4 -0
  83. package/.output/server/index.mjs +451 -0
  84. package/README.md +118 -0
  85. package/index.mjs +21 -0
  86. package/package.json +86 -0
  87. package/scripts/bootstrap-collections.mjs +1201 -0
@@ -0,0 +1,2083 @@
1
+ import { r as reactExports, j as jsxRuntimeExports } from "../_libs/react.mjs";
2
+ import { u as useCollectionsData, R as Route, c as createSsrRpc } from "./router-D4G1DGr3.mjs";
3
+ import { c as cva } from "../_libs/class-variance-authority.mjs";
4
+ import { c as clsx } from "../_libs/clsx.mjs";
5
+ import { t as twMerge } from "../_libs/tailwind-merge.mjs";
6
+ import { U as Ut, q as qt, Z as Zt } from "../_libs/react-resizable-panels.mjs";
7
+ import { A as Ajv } from "../_libs/ajv.mjs";
8
+ import { a as addFormats } from "../_libs/ajv-formats.mjs";
9
+ import { c as createServerFn } from "./index.mjs";
10
+ import { P as PanelLeftClose, a as PanelLeftOpen, L as LoaderCircle, S as Save, b as PanelRightClose, c as PanelRightOpen, C as ChevronDown, d as Check, X, e as CalendarDays, f as Clock3, g as ChevronUp, I as Image, h as Search, i as ChevronLeft, j as ChevronRight } from "../_libs/lucide-react.mjs";
11
+ import { c as create } from "../_libs/zustand.mjs";
12
+ import { S as SelectRoot, B as Button$1, a as SelectTrigger$1, b as SelectIcon, c as SelectValue$1, d as SelectPortal, e as SelectPositioner, f as SelectPopup, g as SelectList, h as SelectGroup$1, i as SelectItem$1, j as SelectItemText, k as SelectItemIndicator, u as useRender, m as mergeProps, I as Input$1, l as SelectScrollUpArrow, n as SelectScrollDownArrow, o as SwitchRoot, p as SwitchThumb, P as PopoverRoot, q as PopoverTrigger$1, r as PopoverPortal, s as PopoverPositioner, t as PopoverPopup } from "../_libs/base-ui__react.mjs";
13
+ import { g as getDefaultClassNames, D as DayPicker } from "../_libs/react-day-picker.mjs";
14
+ import { a as arrayType, s as stringType, o as objectType, l as literalType, r as recordType, u as unknownType } from "../_libs/zod.mjs";
15
+ import "../_libs/tanstack__react-router.mjs";
16
+ import "../_libs/tanstack__router-core.mjs";
17
+ import "../_libs/cookie-es.mjs";
18
+ import "../_libs/tanstack__history.mjs";
19
+ import "../_libs/tiny-invariant.mjs";
20
+ import "../_libs/seroval.mjs";
21
+ import "../_libs/seroval-plugins.mjs";
22
+ import "node:stream/web";
23
+ import "node:stream";
24
+ import "../_libs/react-dom.mjs";
25
+ import "util";
26
+ import "crypto";
27
+ import "async_hooks";
28
+ import "stream";
29
+ import "../_libs/isbot.mjs";
30
+ import "../_libs/tiny-warning.mjs";
31
+ import "node:async_hooks";
32
+ import "../_libs/h3-v2.mjs";
33
+ import "../_libs/rou3.mjs";
34
+ import "../_libs/srvx.mjs";
35
+ import "node:http";
36
+ import "node:https";
37
+ import "node:http2";
38
+ import "../_libs/base-ui__utils.mjs";
39
+ import "../_libs/reselect.mjs";
40
+ import "../_libs/use-sync-external-store.mjs";
41
+ import "../_libs/floating-ui__utils.mjs";
42
+ import "../_libs/floating-ui__react-dom.mjs";
43
+ import "../_libs/floating-ui__dom.mjs";
44
+ import "../_libs/floating-ui__core.mjs";
45
+ import "../_libs/tabbable.mjs";
46
+ import "../_libs/fast-deep-equal.mjs";
47
+ import "../_libs/json-schema-traverse.mjs";
48
+ import "../_libs/fast-uri.mjs";
49
+ import "../_libs/date-fns.mjs";
50
+ import "../_libs/date-fns__tz.mjs";
51
+ function cn(...inputs) {
52
+ return twMerge(clsx(inputs));
53
+ }
54
+ const buttonVariants = cva(
55
+ "group/button inline-flex shrink-0 items-center justify-center rounded-lg border border-transparent bg-clip-padding text-sm font-medium whitespace-nowrap transition-all outline-none select-none focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50 disabled:pointer-events-none disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-3 aria-invalid:ring-destructive/20 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
56
+ {
57
+ variants: {
58
+ variant: {
59
+ default: "bg-primary text-primary-foreground [a]:hover:bg-primary/80",
60
+ outline: "border-border bg-background hover:bg-muted hover:text-foreground aria-expanded:bg-muted aria-expanded:text-foreground dark:border-input dark:bg-input/30 dark:hover:bg-input/50",
61
+ secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/80 aria-expanded:bg-secondary aria-expanded:text-secondary-foreground",
62
+ ghost: "hover:bg-muted hover:text-foreground aria-expanded:bg-muted aria-expanded:text-foreground dark:hover:bg-muted/50",
63
+ destructive: "bg-destructive/10 text-destructive hover:bg-destructive/20 focus-visible:border-destructive/40 focus-visible:ring-destructive/20 dark:bg-destructive/20 dark:hover:bg-destructive/30 dark:focus-visible:ring-destructive/40",
64
+ link: "text-primary underline-offset-4 hover:underline"
65
+ },
66
+ size: {
67
+ default: "h-8 gap-1.5 px-2.5 has-data-[icon=inline-end]:pr-2 has-data-[icon=inline-start]:pl-2",
68
+ xs: "h-6 gap-1 rounded-[min(var(--radius-md),10px)] px-2 text-xs in-data-[slot=button-group]:rounded-lg has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5 [&_svg:not([class*='size-'])]:size-3",
69
+ sm: "h-7 gap-1 rounded-[min(var(--radius-md),12px)] px-2.5 text-[0.8rem] in-data-[slot=button-group]:rounded-lg has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5 [&_svg:not([class*='size-'])]:size-3.5",
70
+ lg: "h-9 gap-1.5 px-2.5 has-data-[icon=inline-end]:pr-3 has-data-[icon=inline-start]:pl-3",
71
+ icon: "size-8",
72
+ "icon-xs": "size-6 rounded-[min(var(--radius-md),10px)] in-data-[slot=button-group]:rounded-lg [&_svg:not([class*='size-'])]:size-3",
73
+ "icon-sm": "size-7 rounded-[min(var(--radius-md),12px)] in-data-[slot=button-group]:rounded-lg",
74
+ "icon-lg": "size-9"
75
+ }
76
+ },
77
+ defaultVariants: {
78
+ variant: "default",
79
+ size: "default"
80
+ }
81
+ }
82
+ );
83
+ function Button({
84
+ className,
85
+ variant = "default",
86
+ size = "default",
87
+ ...props
88
+ }) {
89
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(
90
+ Button$1,
91
+ {
92
+ "data-slot": "button",
93
+ className: cn(buttonVariants({ variant, size, className })),
94
+ ...props
95
+ }
96
+ );
97
+ }
98
+ function ResizablePanelGroup({
99
+ className,
100
+ ...props
101
+ }) {
102
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(
103
+ Ut,
104
+ {
105
+ "data-slot": "resizable-panel-group",
106
+ className: cn(
107
+ "flex h-full w-full aria-[orientation=vertical]:flex-col",
108
+ className
109
+ ),
110
+ ...props
111
+ }
112
+ );
113
+ }
114
+ function ResizablePanel({ ...props }) {
115
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(qt, { "data-slot": "resizable-panel", ...props });
116
+ }
117
+ function ResizableHandle({
118
+ withHandle,
119
+ className,
120
+ ...props
121
+ }) {
122
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(
123
+ Zt,
124
+ {
125
+ "data-slot": "resizable-handle",
126
+ className: cn(
127
+ "group/resize-handle bg-border ring-offset-background focus-visible:ring-ring relative flex w-px items-center justify-center after:absolute after:inset-y-0 after:left-1/2 after:w-1 after:-translate-x-1/2 focus-visible:ring-1 focus-visible:outline-hidden aria-[orientation=horizontal]:h-px aria-[orientation=horizontal]:w-full aria-[orientation=horizontal]:after:left-0 aria-[orientation=horizontal]:after:h-1 aria-[orientation=horizontal]:after:w-full aria-[orientation=horizontal]:after:translate-x-0 aria-[orientation=horizontal]:after:-translate-y-1/2 [&[aria-orientation=horizontal]>div]:rotate-90",
128
+ className
129
+ ),
130
+ ...props,
131
+ children: withHandle && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "bg-border z-10 flex h-6 w-1 shrink-0 rounded-lg opacity-0 transition-opacity duration-150 group-hover/resize-handle:opacity-100 group-focus-visible/resize-handle:opacity-100" })
132
+ }
133
+ );
134
+ }
135
+ const badgeVariants = cva(
136
+ "group/badge inline-flex h-5 w-fit shrink-0 items-center justify-center gap-1 overflow-hidden rounded-4xl border border-transparent px-2 py-0.5 text-xs font-medium whitespace-nowrap transition-all focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5 aria-invalid:border-destructive aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 [&>svg]:pointer-events-none [&>svg]:size-3!",
137
+ {
138
+ variants: {
139
+ variant: {
140
+ default: "bg-primary text-primary-foreground [a]:hover:bg-primary/80",
141
+ secondary: "bg-secondary text-secondary-foreground [a]:hover:bg-secondary/80",
142
+ destructive: "bg-destructive/10 text-destructive focus-visible:ring-destructive/20 dark:bg-destructive/20 dark:focus-visible:ring-destructive/40 [a]:hover:bg-destructive/20",
143
+ outline: "border-border text-foreground [a]:hover:bg-muted [a]:hover:text-muted-foreground",
144
+ ghost: "hover:bg-muted hover:text-muted-foreground dark:hover:bg-muted/50",
145
+ link: "text-primary underline-offset-4 hover:underline"
146
+ }
147
+ },
148
+ defaultVariants: {
149
+ variant: "default"
150
+ }
151
+ }
152
+ );
153
+ function Badge({
154
+ className,
155
+ variant = "default",
156
+ render,
157
+ ...props
158
+ }) {
159
+ return useRender({
160
+ defaultTagName: "span",
161
+ props: mergeProps(
162
+ {
163
+ className: cn(badgeVariants({ variant }), className)
164
+ },
165
+ props
166
+ ),
167
+ render,
168
+ state: {
169
+ slot: "badge",
170
+ variant
171
+ }
172
+ });
173
+ }
174
+ const Select = SelectRoot;
175
+ function SelectGroup({ className, ...props }) {
176
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(
177
+ SelectGroup$1,
178
+ {
179
+ "data-slot": "select-group",
180
+ className: cn("scroll-my-1 p-1", className),
181
+ ...props
182
+ }
183
+ );
184
+ }
185
+ function SelectValue({ className, ...props }) {
186
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(
187
+ SelectValue$1,
188
+ {
189
+ "data-slot": "select-value",
190
+ className: cn("flex flex-1 text-left", className),
191
+ ...props
192
+ }
193
+ );
194
+ }
195
+ function SelectTrigger({
196
+ className,
197
+ size = "default",
198
+ children,
199
+ ...props
200
+ }) {
201
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs(
202
+ SelectTrigger$1,
203
+ {
204
+ "data-slot": "select-trigger",
205
+ "data-size": size,
206
+ className: cn(
207
+ "border-input focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:border-destructive aria-invalid:ring-destructive/20 data-placeholder:text-muted-foreground dark:bg-input/30 dark:hover:bg-input/50 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40 flex w-fit items-center justify-between gap-1.5 rounded-lg border bg-transparent py-2 pr-2 pl-2.5 text-sm whitespace-nowrap transition-colors outline-none select-none focus-visible:ring-3 disabled:cursor-not-allowed disabled:opacity-50 aria-invalid:ring-3 data-[size=default]:h-8 data-[size=sm]:h-7 data-[size=sm]:rounded-[min(var(--radius-md),10px)] *:data-[slot=select-value]:line-clamp-1 *:data-[slot=select-value]:flex *:data-[slot=select-value]:items-center *:data-[slot=select-value]:gap-1.5 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
208
+ className
209
+ ),
210
+ ...props,
211
+ children: [
212
+ children,
213
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
214
+ SelectIcon,
215
+ {
216
+ render: /* @__PURE__ */ jsxRuntimeExports.jsx(ChevronDown, { className: "text-muted-foreground pointer-events-none size-4" })
217
+ }
218
+ )
219
+ ]
220
+ }
221
+ );
222
+ }
223
+ function SelectContent({
224
+ className,
225
+ children,
226
+ side = "bottom",
227
+ sideOffset = 4,
228
+ align = "center",
229
+ alignOffset = 0,
230
+ alignItemWithTrigger = true,
231
+ ...props
232
+ }) {
233
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(SelectPortal, { children: /* @__PURE__ */ jsxRuntimeExports.jsx(
234
+ SelectPositioner,
235
+ {
236
+ side,
237
+ sideOffset,
238
+ align,
239
+ alignOffset,
240
+ alignItemWithTrigger,
241
+ className: "isolate z-50",
242
+ children: /* @__PURE__ */ jsxRuntimeExports.jsxs(
243
+ SelectPopup,
244
+ {
245
+ "data-slot": "select-content",
246
+ "data-align-trigger": alignItemWithTrigger,
247
+ className: cn(
248
+ "bg-popover text-popover-foreground ring-foreground/10 data-[side=bottom]:slide-in-from-top-2 data-[side=inline-end]:slide-in-from-left-2 data-[side=inline-start]:slide-in-from-right-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95 relative isolate z-50 max-h-(--available-height) w-(--anchor-width) min-w-36 origin-(--transform-origin) overflow-x-hidden overflow-y-auto rounded-lg shadow-md ring-1 duration-100 data-[align-trigger=true]:animate-none",
249
+ className
250
+ ),
251
+ ...props,
252
+ children: [
253
+ /* @__PURE__ */ jsxRuntimeExports.jsx(SelectScrollUpButton, {}),
254
+ /* @__PURE__ */ jsxRuntimeExports.jsx(SelectList, { children }),
255
+ /* @__PURE__ */ jsxRuntimeExports.jsx(SelectScrollDownButton, {})
256
+ ]
257
+ }
258
+ )
259
+ }
260
+ ) });
261
+ }
262
+ function SelectItem({
263
+ className,
264
+ children,
265
+ ...props
266
+ }) {
267
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs(
268
+ SelectItem$1,
269
+ {
270
+ "data-slot": "select-item",
271
+ className: cn(
272
+ "focus:bg-accent focus:text-accent-foreground not-data-[variant=destructive]:focus:**:text-accent-foreground relative flex w-full cursor-default items-center gap-1.5 rounded-md py-1 pr-8 pl-1.5 text-sm outline-hidden select-none data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 *:[span]:last:flex *:[span]:last:items-center *:[span]:last:gap-2",
273
+ className
274
+ ),
275
+ ...props,
276
+ children: [
277
+ /* @__PURE__ */ jsxRuntimeExports.jsx(SelectItemText, { className: "flex flex-1 shrink-0 gap-2 whitespace-nowrap", children }),
278
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
279
+ SelectItemIndicator,
280
+ {
281
+ render: /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "pointer-events-none absolute right-2 flex size-4 items-center justify-center" }),
282
+ children: /* @__PURE__ */ jsxRuntimeExports.jsx(Check, { className: "pointer-events-none" })
283
+ }
284
+ )
285
+ ]
286
+ }
287
+ );
288
+ }
289
+ function SelectScrollUpButton({
290
+ className,
291
+ ...props
292
+ }) {
293
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(
294
+ SelectScrollUpArrow,
295
+ {
296
+ "data-slot": "select-scroll-up-button",
297
+ className: cn(
298
+ "bg-popover top-0 z-10 flex w-full cursor-default items-center justify-center py-1 [&_svg:not([class*='size-'])]:size-4",
299
+ className
300
+ ),
301
+ ...props,
302
+ children: /* @__PURE__ */ jsxRuntimeExports.jsx(ChevronUp, {})
303
+ }
304
+ );
305
+ }
306
+ function SelectScrollDownButton({
307
+ className,
308
+ ...props
309
+ }) {
310
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(
311
+ SelectScrollDownArrow,
312
+ {
313
+ "data-slot": "select-scroll-down-button",
314
+ className: cn(
315
+ "bg-popover bottom-0 z-10 flex w-full cursor-default items-center justify-center py-1 [&_svg:not([class*='size-'])]:size-4",
316
+ className
317
+ ),
318
+ ...props,
319
+ children: /* @__PURE__ */ jsxRuntimeExports.jsx(ChevronDown, {})
320
+ }
321
+ );
322
+ }
323
+ function getFileName(pathLike) {
324
+ const normalized = pathLike.replaceAll("\\", "/");
325
+ const parts = normalized.split("/");
326
+ return parts[parts.length - 1] ?? pathLike;
327
+ }
328
+ function stripExtension(fileName) {
329
+ return fileName.replace(/\.[^.]+$/, "");
330
+ }
331
+ function getFileDisplayLabel(file) {
332
+ const title = file.data.title;
333
+ if (typeof title === "string" && title.trim().length > 0) {
334
+ return title.trim();
335
+ }
336
+ const fileName = getFileName(file.filePath || file.id);
337
+ return stripExtension(fileName);
338
+ }
339
+ function getSortedCollectionFiles(collection) {
340
+ if (!collection) {
341
+ return [];
342
+ }
343
+ return [...collection.files].sort((a, b) => {
344
+ const labelCompare = getFileDisplayLabel(a).localeCompare(
345
+ getFileDisplayLabel(b),
346
+ void 0,
347
+ { sensitivity: "base" }
348
+ );
349
+ if (labelCompare !== 0) {
350
+ return labelCompare;
351
+ }
352
+ return a.id.localeCompare(b.id, void 0, { sensitivity: "base" });
353
+ });
354
+ }
355
+ function areEditorSearchEqual(a, b) {
356
+ return a.collection === b.collection && a.file === b.file;
357
+ }
358
+ function resolveEditorSelection(collections, search) {
359
+ if (collections.length === 0) {
360
+ return {
361
+ selectedCollection: void 0,
362
+ selectedFile: void 0,
363
+ normalizedSearch: {}
364
+ };
365
+ }
366
+ const bySearchCollection = collections.find(
367
+ (collection) => collection.name === search.collection
368
+ );
369
+ const selectedCollection = bySearchCollection ?? collections[0];
370
+ const files = getSortedCollectionFiles(selectedCollection);
371
+ const bySearchFile = files.find((file) => file.id === search.file);
372
+ const firstFile = files.at(0);
373
+ const selectedFile = bySearchFile ?? firstFile;
374
+ return {
375
+ selectedCollection,
376
+ selectedFile,
377
+ normalizedSearch: {
378
+ collection: selectedCollection.name,
379
+ file: selectedFile ? selectedFile.id : void 0
380
+ }
381
+ };
382
+ }
383
+ function LeftSidebar({
384
+ collections,
385
+ selectedCollectionName,
386
+ selectedFileId,
387
+ onSelectCollection,
388
+ onSelectFile
389
+ }) {
390
+ const selectedCollection = collections.find(
391
+ (collection) => collection.name === selectedCollectionName
392
+ );
393
+ const files = getSortedCollectionFiles(selectedCollection);
394
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex h-full flex-col gap-3", children: [
395
+ /* @__PURE__ */ jsxRuntimeExports.jsxs(
396
+ Select,
397
+ {
398
+ value: selectedCollectionName,
399
+ onValueChange: (nextCollectionName) => {
400
+ if (!nextCollectionName) {
401
+ return;
402
+ }
403
+ onSelectCollection(nextCollectionName);
404
+ },
405
+ children: [
406
+ /* @__PURE__ */ jsxRuntimeExports.jsx(SelectTrigger, { className: "bg-muted/50 focus-visible:ring-ring/35 w-full border-transparent shadow-none focus-visible:border-transparent focus-visible:ring-2", children: /* @__PURE__ */ jsxRuntimeExports.jsx(SelectValue, { placeholder: "Select a collection" }) }),
407
+ /* @__PURE__ */ jsxRuntimeExports.jsx(SelectContent, { children: /* @__PURE__ */ jsxRuntimeExports.jsx(SelectGroup, { children: collections.map((collection) => /* @__PURE__ */ jsxRuntimeExports.jsx(SelectItem, { value: collection.name, children: collection.name }, collection.name)) }) })
408
+ ]
409
+ }
410
+ ),
411
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "bg-background/35 min-h-0 flex-1 overflow-auto rounded-md p-1", children: files.length === 0 ? /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-muted-foreground px-2 py-2 text-sm", children: "No files in this collection." }) : /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "space-y-0.5", children: files.map((file) => {
412
+ const isActive = file.id === selectedFileId;
413
+ const title = getFileDisplayLabel(file);
414
+ const slug = file.id;
415
+ const isMdxFile = /\.mdx$/i.test(file.filePath);
416
+ const isDraft = file.data.draft === true;
417
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(
418
+ Button,
419
+ {
420
+ type: "button",
421
+ variant: "ghost",
422
+ className: cn(
423
+ "h-auto w-full justify-start border-0 px-2.5 py-3 text-left shadow-none",
424
+ "hover:bg-background/70",
425
+ isActive && "bg-muted text-foreground hover:bg-muted/55"
426
+ ),
427
+ onClick: () => onSelectFile(file.id),
428
+ title: file.filePath,
429
+ children: /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "flex w-full min-w-0 flex-col items-start gap-0.5", children: [
430
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "w-full truncate text-sm font-normal", children: title }),
431
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "flex w-full min-w-0 items-center gap-1.5", children: [
432
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-muted-foreground min-w-0 flex-1 truncate text-xs", children: slug }),
433
+ isMdxFile ? /* @__PURE__ */ jsxRuntimeExports.jsx(
434
+ Badge,
435
+ {
436
+ variant: "secondary",
437
+ className: "bg-muted h-4 border-transparent px-1.5 text-[10px] leading-none",
438
+ children: "MDX"
439
+ }
440
+ ) : null,
441
+ isDraft ? /* @__PURE__ */ jsxRuntimeExports.jsx(
442
+ Badge,
443
+ {
444
+ variant: "outline",
445
+ className: "h-4 border-transparent bg-amber-100 px-1.5 text-[10px] leading-none text-amber-900 dark:bg-amber-900/40 dark:text-amber-200",
446
+ children: "Draft"
447
+ }
448
+ ) : null
449
+ ] })
450
+ ] })
451
+ },
452
+ file.id
453
+ );
454
+ }) }) })
455
+ ] });
456
+ }
457
+ function Textarea({ className, ...props }) {
458
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(
459
+ "textarea",
460
+ {
461
+ "data-slot": "textarea",
462
+ className: cn(
463
+ "border-input placeholder:text-muted-foreground focus-visible:border-ring focus-visible:ring-ring/50 disabled:bg-input/50 aria-invalid:border-destructive aria-invalid:ring-destructive/20 dark:bg-input/30 dark:disabled:bg-input/80 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40 flex field-sizing-content min-h-16 w-full rounded-lg border bg-transparent px-2.5 py-2 text-base transition-colors outline-none focus-visible:ring-3 disabled:cursor-not-allowed disabled:opacity-50 aria-invalid:ring-3 md:text-sm",
464
+ className
465
+ ),
466
+ ...props
467
+ }
468
+ );
469
+ }
470
+ function isRecord(value) {
471
+ return typeof value === "object" && value !== null && !Array.isArray(value);
472
+ }
473
+ function cloneRecord(value) {
474
+ return JSON.parse(JSON.stringify(value));
475
+ }
476
+ function isEqualValue(a, b) {
477
+ if (Object.is(a, b)) {
478
+ return true;
479
+ }
480
+ if (Array.isArray(a) && Array.isArray(b)) {
481
+ if (a.length !== b.length) {
482
+ return false;
483
+ }
484
+ for (let index = 0; index < a.length; index += 1) {
485
+ if (!isEqualValue(a[index], b[index])) {
486
+ return false;
487
+ }
488
+ }
489
+ return true;
490
+ }
491
+ if (isRecord(a) && isRecord(b)) {
492
+ const aKeys = Object.keys(a);
493
+ const bKeys = Object.keys(b);
494
+ if (aKeys.length !== bKeys.length) {
495
+ return false;
496
+ }
497
+ for (const key of aKeys) {
498
+ if (!Object.prototype.hasOwnProperty.call(b, key)) {
499
+ return false;
500
+ }
501
+ if (!isEqualValue(a[key], b[key])) {
502
+ return false;
503
+ }
504
+ }
505
+ return true;
506
+ }
507
+ return false;
508
+ }
509
+ function normalizeChip(value) {
510
+ const trimmed = value.trim();
511
+ return trimmed.length > 0 ? trimmed : void 0;
512
+ }
513
+ function asStringArray(value) {
514
+ if (!Array.isArray(value)) {
515
+ return [];
516
+ }
517
+ return value.filter((item) => typeof item === "string");
518
+ }
519
+ function buildNextDraft(currentDraft, field, value) {
520
+ const nextDraft = {
521
+ ...currentDraft
522
+ };
523
+ if (value === void 0) {
524
+ delete nextDraft[field];
525
+ } else {
526
+ nextDraft[field] = value;
527
+ }
528
+ return nextDraft;
529
+ }
530
+ function getIsDirty(params) {
531
+ if (!isEqualValue(params.draft, params.initial)) {
532
+ return true;
533
+ }
534
+ return params.contentDraft !== params.initialContent;
535
+ }
536
+ const useFrontmatterEditorStore = create(
537
+ (set) => ({
538
+ collectionName: void 0,
539
+ fileId: void 0,
540
+ draft: {},
541
+ initial: {},
542
+ contentDraft: "",
543
+ initialContent: "",
544
+ dirty: false,
545
+ touched: {},
546
+ errors: {},
547
+ chipInputs: {},
548
+ validationRequested: false,
549
+ loadSelection: ({ collectionName, fileId, data, content }) => set((state) => {
550
+ const sameSelection = state.collectionName === collectionName && state.fileId === fileId;
551
+ if (sameSelection) {
552
+ return state;
553
+ }
554
+ const normalizedData = cloneRecord(data);
555
+ return {
556
+ collectionName,
557
+ fileId,
558
+ draft: normalizedData,
559
+ initial: cloneRecord(normalizedData),
560
+ contentDraft: content,
561
+ initialContent: content,
562
+ dirty: false,
563
+ touched: {},
564
+ errors: {},
565
+ chipInputs: {},
566
+ validationRequested: false
567
+ };
568
+ }),
569
+ clearSelection: () => set({
570
+ collectionName: void 0,
571
+ fileId: void 0,
572
+ draft: {},
573
+ initial: {},
574
+ contentDraft: "",
575
+ initialContent: "",
576
+ dirty: false,
577
+ touched: {},
578
+ errors: {},
579
+ chipInputs: {},
580
+ validationRequested: false
581
+ }),
582
+ setFieldValue: (field, value) => set((state) => {
583
+ const nextDraft = buildNextDraft(state.draft, field, value);
584
+ return {
585
+ draft: nextDraft,
586
+ dirty: getIsDirty({
587
+ draft: nextDraft,
588
+ initial: state.initial,
589
+ contentDraft: state.contentDraft,
590
+ initialContent: state.initialContent
591
+ })
592
+ };
593
+ }),
594
+ setContentDraft: (content) => set((state) => ({
595
+ contentDraft: content,
596
+ dirty: getIsDirty({
597
+ draft: state.draft,
598
+ initial: state.initial,
599
+ contentDraft: content,
600
+ initialContent: state.initialContent
601
+ })
602
+ })),
603
+ commitSavedState: () => set((state) => ({
604
+ initial: cloneRecord(state.draft),
605
+ initialContent: state.contentDraft,
606
+ dirty: false,
607
+ touched: {},
608
+ errors: {},
609
+ validationRequested: false
610
+ })),
611
+ setFieldTouched: (field) => set((state) => ({
612
+ touched: {
613
+ ...state.touched,
614
+ [field]: true
615
+ }
616
+ })),
617
+ setValidationRequested: () => set({
618
+ validationRequested: true
619
+ }),
620
+ setValidationErrors: (errors) => set({
621
+ errors
622
+ }),
623
+ setChipInput: (field, value) => set((state) => ({
624
+ chipInputs: {
625
+ ...state.chipInputs,
626
+ [field]: value
627
+ }
628
+ })),
629
+ addChipValue: (field, value) => set((state) => {
630
+ const normalizedValue = normalizeChip(value);
631
+ if (!normalizedValue) {
632
+ return state;
633
+ }
634
+ const existingValues = asStringArray(state.draft[field]);
635
+ if (existingValues.includes(normalizedValue)) {
636
+ return {
637
+ chipInputs: {
638
+ ...state.chipInputs,
639
+ [field]: ""
640
+ }
641
+ };
642
+ }
643
+ const nextValues = [...existingValues, normalizedValue];
644
+ const nextDraft = buildNextDraft(state.draft, field, nextValues);
645
+ return {
646
+ draft: nextDraft,
647
+ dirty: getIsDirty({
648
+ draft: nextDraft,
649
+ initial: state.initial,
650
+ contentDraft: state.contentDraft,
651
+ initialContent: state.initialContent
652
+ }),
653
+ chipInputs: {
654
+ ...state.chipInputs,
655
+ [field]: ""
656
+ }
657
+ };
658
+ }),
659
+ removeChipValue: (field, index) => set((state) => {
660
+ const existingValues = asStringArray(state.draft[field]);
661
+ if (index < 0 || index >= existingValues.length) {
662
+ return state;
663
+ }
664
+ const nextValues = existingValues.filter((_, itemIndex) => {
665
+ return itemIndex !== index;
666
+ });
667
+ const nextDraft = buildNextDraft(
668
+ state.draft,
669
+ field,
670
+ nextValues.length > 0 ? nextValues : void 0
671
+ );
672
+ return {
673
+ draft: nextDraft,
674
+ dirty: getIsDirty({
675
+ draft: nextDraft,
676
+ initial: state.initial,
677
+ contentDraft: state.contentDraft,
678
+ initialContent: state.initialContent
679
+ })
680
+ };
681
+ }),
682
+ removeLastChipValue: (field) => set((state) => {
683
+ const existingValues = asStringArray(state.draft[field]);
684
+ if (existingValues.length === 0) {
685
+ return state;
686
+ }
687
+ const nextValues = existingValues.slice(0, -1);
688
+ const nextDraft = buildNextDraft(
689
+ state.draft,
690
+ field,
691
+ nextValues.length > 0 ? nextValues : void 0
692
+ );
693
+ return {
694
+ draft: nextDraft,
695
+ dirty: getIsDirty({
696
+ draft: nextDraft,
697
+ initial: state.initial,
698
+ contentDraft: state.contentDraft,
699
+ initialContent: state.initialContent
700
+ })
701
+ };
702
+ })
703
+ })
704
+ );
705
+ function Editor() {
706
+ const contentDraft = useFrontmatterEditorStore((state) => state.contentDraft);
707
+ const setContentDraft = useFrontmatterEditorStore(
708
+ (state) => state.setContentDraft
709
+ );
710
+ return /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex h-full min-h-0 w-full overflow-hidden", children: /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "mx-auto flex h-full min-h-0 w-full max-w-3xl flex-col overflow-hidden", children: /* @__PURE__ */ jsxRuntimeExports.jsx(
711
+ Textarea,
712
+ {
713
+ id: "editor-content",
714
+ className: "placeholder:text-muted-foreground/65 field-sizing-fixed h-full min-h-0 flex-1 resize-none overflow-auto rounded-none border-0 bg-transparent px-8 py-6 text-[16px] leading-8 shadow-none focus-visible:border-transparent focus-visible:ring-0",
715
+ value: contentDraft,
716
+ onChange: (event) => {
717
+ setContentDraft(event.target.value);
718
+ },
719
+ placeholder: "Start writing your article..."
720
+ }
721
+ ) }) });
722
+ }
723
+ function Calendar({
724
+ className,
725
+ classNames,
726
+ showOutsideDays = true,
727
+ captionLayout = "label",
728
+ buttonVariant = "ghost",
729
+ locale,
730
+ formatters,
731
+ components,
732
+ ...props
733
+ }) {
734
+ const defaultClassNames = getDefaultClassNames();
735
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(
736
+ DayPicker,
737
+ {
738
+ showOutsideDays,
739
+ className: cn(
740
+ "group/calendar bg-background p-2 [--cell-radius:var(--radius-md)] [--cell-size:--spacing(7)] in-data-[slot=card-content]:bg-transparent in-data-[slot=popover-content]:bg-transparent",
741
+ String.raw`rtl:**:[.rdp-button\_next>svg]:rotate-180`,
742
+ String.raw`rtl:**:[.rdp-button\_previous>svg]:rotate-180`,
743
+ className
744
+ ),
745
+ captionLayout,
746
+ locale,
747
+ formatters: {
748
+ formatMonthDropdown: (date) => date.toLocaleString(locale?.code, { month: "short" }),
749
+ ...formatters
750
+ },
751
+ classNames: {
752
+ root: cn("w-fit", defaultClassNames.root),
753
+ months: cn(
754
+ "relative flex flex-col gap-4 md:flex-row",
755
+ defaultClassNames.months
756
+ ),
757
+ month: cn("flex w-full flex-col gap-4", defaultClassNames.month),
758
+ nav: cn(
759
+ "absolute inset-x-0 top-0 flex w-full items-center justify-between gap-1",
760
+ defaultClassNames.nav
761
+ ),
762
+ button_previous: cn(
763
+ buttonVariants({ variant: buttonVariant }),
764
+ "size-(--cell-size) p-0 select-none aria-disabled:opacity-50",
765
+ defaultClassNames.button_previous
766
+ ),
767
+ button_next: cn(
768
+ buttonVariants({ variant: buttonVariant }),
769
+ "size-(--cell-size) p-0 select-none aria-disabled:opacity-50",
770
+ defaultClassNames.button_next
771
+ ),
772
+ month_caption: cn(
773
+ "flex h-(--cell-size) w-full items-center justify-center px-(--cell-size)",
774
+ defaultClassNames.month_caption
775
+ ),
776
+ dropdowns: cn(
777
+ "flex h-(--cell-size) w-full items-center justify-center gap-1.5 text-sm font-medium",
778
+ defaultClassNames.dropdowns
779
+ ),
780
+ dropdown_root: cn(
781
+ "relative rounded-(--cell-radius)",
782
+ defaultClassNames.dropdown_root
783
+ ),
784
+ dropdown: cn(
785
+ "absolute inset-0 bg-popover opacity-0",
786
+ defaultClassNames.dropdown
787
+ ),
788
+ caption_label: cn(
789
+ "font-medium select-none",
790
+ captionLayout === "label" ? "text-sm" : "flex items-center gap-1 rounded-(--cell-radius) text-sm [&>svg]:size-3.5 [&>svg]:text-muted-foreground",
791
+ defaultClassNames.caption_label
792
+ ),
793
+ table: "w-full border-collapse",
794
+ weekdays: cn("flex", defaultClassNames.weekdays),
795
+ weekday: cn(
796
+ "flex-1 rounded-(--cell-radius) text-[0.8rem] font-normal text-muted-foreground select-none",
797
+ defaultClassNames.weekday
798
+ ),
799
+ week: cn("mt-2 flex w-full", defaultClassNames.week),
800
+ week_number_header: cn(
801
+ "w-(--cell-size) select-none",
802
+ defaultClassNames.week_number_header
803
+ ),
804
+ week_number: cn(
805
+ "text-[0.8rem] text-muted-foreground select-none",
806
+ defaultClassNames.week_number
807
+ ),
808
+ day: cn(
809
+ "group/day relative aspect-square h-full w-full rounded-(--cell-radius) p-0 text-center select-none [&:last-child[data-selected=true]_button]:rounded-r-(--cell-radius)",
810
+ props.showWeekNumber ? "[&:nth-child(2)[data-selected=true]_button]:rounded-l-(--cell-radius)" : "[&:first-child[data-selected=true]_button]:rounded-l-(--cell-radius)",
811
+ defaultClassNames.day
812
+ ),
813
+ range_start: cn(
814
+ "relative isolate z-0 rounded-l-(--cell-radius) bg-muted after:absolute after:inset-y-0 after:right-0 after:w-4 after:bg-muted",
815
+ defaultClassNames.range_start
816
+ ),
817
+ range_middle: cn("rounded-none", defaultClassNames.range_middle),
818
+ range_end: cn(
819
+ "relative isolate z-0 rounded-r-(--cell-radius) bg-muted after:absolute after:inset-y-0 after:left-0 after:w-4 after:bg-muted",
820
+ defaultClassNames.range_end
821
+ ),
822
+ today: cn(
823
+ "rounded-(--cell-radius) bg-muted text-foreground data-[selected=true]:rounded-none",
824
+ defaultClassNames.today
825
+ ),
826
+ outside: cn(
827
+ "text-muted-foreground aria-selected:text-muted-foreground",
828
+ defaultClassNames.outside
829
+ ),
830
+ disabled: cn(
831
+ "text-muted-foreground opacity-50",
832
+ defaultClassNames.disabled
833
+ ),
834
+ hidden: cn("invisible", defaultClassNames.hidden),
835
+ ...classNames
836
+ },
837
+ components: {
838
+ Root: ({ className: className2, rootRef, ...props2 }) => {
839
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(
840
+ "div",
841
+ {
842
+ "data-slot": "calendar",
843
+ ref: rootRef,
844
+ className: cn(className2),
845
+ ...props2
846
+ }
847
+ );
848
+ },
849
+ Chevron: ({ className: className2, orientation, ...props2 }) => {
850
+ if (orientation === "left") {
851
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(ChevronLeft, { className: cn("size-4", className2), ...props2 });
852
+ }
853
+ if (orientation === "right") {
854
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(
855
+ ChevronRight,
856
+ {
857
+ className: cn("size-4", className2),
858
+ ...props2
859
+ }
860
+ );
861
+ }
862
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(ChevronDown, { className: cn("size-4", className2), ...props2 });
863
+ },
864
+ DayButton: ({ ...props2 }) => /* @__PURE__ */ jsxRuntimeExports.jsx(CalendarDayButton, { locale, ...props2 }),
865
+ WeekNumber: ({ children, ...props2 }) => {
866
+ return /* @__PURE__ */ jsxRuntimeExports.jsx("td", { ...props2, children: /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex size-(--cell-size) items-center justify-center text-center", children }) });
867
+ },
868
+ ...components
869
+ },
870
+ ...props
871
+ }
872
+ );
873
+ }
874
+ function CalendarDayButton({
875
+ className,
876
+ day,
877
+ modifiers,
878
+ locale,
879
+ ...props
880
+ }) {
881
+ const defaultClassNames = getDefaultClassNames();
882
+ const ref = reactExports.useRef(null);
883
+ reactExports.useEffect(() => {
884
+ if (modifiers.focused) ref.current?.focus();
885
+ }, [modifiers.focused]);
886
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(
887
+ Button,
888
+ {
889
+ variant: "ghost",
890
+ size: "icon",
891
+ "data-day": day.date.toLocaleDateString(locale?.code),
892
+ "data-selected-single": modifiers.selected && !modifiers.range_start && !modifiers.range_end && !modifiers.range_middle,
893
+ "data-range-start": modifiers.range_start,
894
+ "data-range-end": modifiers.range_end,
895
+ "data-range-middle": modifiers.range_middle,
896
+ className: cn(
897
+ "group-data-[focused=true]/day:border-ring group-data-[focused=true]/day:ring-ring/50 data-[range-end=true]:bg-primary data-[range-end=true]:text-primary-foreground data-[range-middle=true]:bg-muted data-[range-middle=true]:text-foreground data-[range-start=true]:bg-primary data-[range-start=true]:text-primary-foreground data-[selected-single=true]:bg-primary data-[selected-single=true]:text-primary-foreground dark:hover:text-foreground relative isolate z-10 flex aspect-square size-auto w-full min-w-(--cell-size) flex-col gap-1 border-0 leading-none font-normal group-data-[focused=true]/day:relative group-data-[focused=true]/day:z-10 group-data-[focused=true]/day:ring-[3px] data-[range-end=true]:rounded-(--cell-radius) data-[range-end=true]:rounded-r-(--cell-radius) data-[range-middle=true]:rounded-none data-[range-start=true]:rounded-(--cell-radius) data-[range-start=true]:rounded-l-(--cell-radius) [&>span]:text-xs [&>span]:opacity-70",
898
+ defaultClassNames.day,
899
+ className
900
+ ),
901
+ ...props
902
+ }
903
+ );
904
+ }
905
+ function Input({ className, type, ...props }) {
906
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(
907
+ Input$1,
908
+ {
909
+ type,
910
+ "data-slot": "input",
911
+ className: cn(
912
+ "border-input file:text-foreground placeholder:text-muted-foreground focus-visible:border-ring focus-visible:ring-ring/50 disabled:bg-input/50 aria-invalid:border-destructive aria-invalid:ring-destructive/20 dark:bg-input/30 dark:disabled:bg-input/80 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40 h-8 w-full min-w-0 rounded-lg border bg-transparent px-2.5 py-1 text-base transition-colors outline-none file:inline-flex file:h-6 file:border-0 file:bg-transparent file:text-sm file:font-medium focus-visible:ring-3 disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50 aria-invalid:ring-3 md:text-sm",
913
+ className
914
+ ),
915
+ ...props
916
+ }
917
+ );
918
+ }
919
+ function Label({ className, ...props }) {
920
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(
921
+ "label",
922
+ {
923
+ "data-slot": "label",
924
+ className: cn(
925
+ "flex items-center gap-2 text-sm leading-none font-medium select-none group-data-[disabled=true]:pointer-events-none group-data-[disabled=true]:opacity-50 peer-disabled:cursor-not-allowed peer-disabled:opacity-50",
926
+ className
927
+ ),
928
+ ...props
929
+ }
930
+ );
931
+ }
932
+ function Popover({ ...props }) {
933
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(PopoverRoot, { "data-slot": "popover", ...props });
934
+ }
935
+ function PopoverTrigger({ ...props }) {
936
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(PopoverTrigger$1, { "data-slot": "popover-trigger", ...props });
937
+ }
938
+ function PopoverContent({
939
+ className,
940
+ align = "center",
941
+ alignOffset = 0,
942
+ side = "bottom",
943
+ sideOffset = 4,
944
+ ...props
945
+ }) {
946
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(PopoverPortal, { children: /* @__PURE__ */ jsxRuntimeExports.jsx(
947
+ PopoverPositioner,
948
+ {
949
+ align,
950
+ alignOffset,
951
+ side,
952
+ sideOffset,
953
+ className: "isolate z-50",
954
+ children: /* @__PURE__ */ jsxRuntimeExports.jsx(
955
+ PopoverPopup,
956
+ {
957
+ "data-slot": "popover-content",
958
+ className: cn(
959
+ "bg-popover text-popover-foreground ring-foreground/10 data-[side=bottom]:slide-in-from-top-2 data-[side=inline-end]:slide-in-from-left-2 data-[side=inline-start]:slide-in-from-right-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95 z-50 flex w-72 origin-(--transform-origin) flex-col gap-2.5 rounded-lg p-2.5 text-sm shadow-md ring-1 outline-hidden duration-100",
960
+ className
961
+ ),
962
+ ...props
963
+ }
964
+ )
965
+ }
966
+ ) });
967
+ }
968
+ function Switch({
969
+ className,
970
+ size = "default",
971
+ ...props
972
+ }) {
973
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(
974
+ SwitchRoot,
975
+ {
976
+ "data-slot": "switch",
977
+ "data-size": size,
978
+ className: cn(
979
+ "peer group/switch focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:border-destructive aria-invalid:ring-destructive/20 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40 data-checked:bg-primary data-unchecked:bg-input dark:data-unchecked:bg-input/80 relative inline-flex shrink-0 items-center rounded-full border border-transparent transition-all outline-none after:absolute after:-inset-x-3 after:-inset-y-2 focus-visible:ring-3 aria-invalid:ring-3 data-disabled:cursor-not-allowed data-disabled:opacity-50 data-[size=default]:h-[18.4px] data-[size=default]:w-[32px] data-[size=sm]:h-[14px] data-[size=sm]:w-[24px]",
980
+ className
981
+ ),
982
+ ...props,
983
+ children: /* @__PURE__ */ jsxRuntimeExports.jsx(
984
+ SwitchThumb,
985
+ {
986
+ "data-slot": "switch-thumb",
987
+ className: "bg-background dark:data-checked:bg-primary-foreground dark:data-unchecked:bg-foreground pointer-events-none block rounded-full ring-0 transition-transform group-data-[size=default]/switch:size-4 group-data-[size=sm]/switch:size-3 group-data-[size=default]/switch:data-checked:translate-x-[calc(100%-2px)] group-data-[size=sm]/switch:data-checked:translate-x-[calc(100%-2px)] group-data-[size=default]/switch:data-unchecked:translate-x-0 group-data-[size=sm]/switch:data-unchecked:translate-x-0"
988
+ }
989
+ )
990
+ }
991
+ );
992
+ }
993
+ function padTwo$1(value) {
994
+ return value.toString().padStart(2, "0");
995
+ }
996
+ function toDateTimeLocal(date) {
997
+ const year = date.getFullYear();
998
+ const month = padTwo$1(date.getMonth() + 1);
999
+ const day = padTwo$1(date.getDate());
1000
+ const hour = padTwo$1(date.getHours());
1001
+ const minute = padTwo$1(date.getMinutes());
1002
+ return `${year}-${month}-${day}T${hour}:${minute}`;
1003
+ }
1004
+ function parseUnixTimestamp(value) {
1005
+ if (!Number.isFinite(value)) {
1006
+ return void 0;
1007
+ }
1008
+ const millis = Math.abs(value) < 1e12 ? value * 1e3 : value;
1009
+ const parsed = new Date(millis);
1010
+ if (Number.isNaN(parsed.getTime())) {
1011
+ return void 0;
1012
+ }
1013
+ return parsed;
1014
+ }
1015
+ function toDateTimeLocalValue(value) {
1016
+ if (typeof value === "string") {
1017
+ const trimmed = value.trim();
1018
+ if (trimmed.length === 0) {
1019
+ return "";
1020
+ }
1021
+ if (/^\d{4}-\d{2}-\d{2}$/.test(trimmed)) {
1022
+ return `${trimmed}T00:00`;
1023
+ }
1024
+ const parsed = new Date(trimmed);
1025
+ if (!Number.isNaN(parsed.getTime())) {
1026
+ return toDateTimeLocal(parsed);
1027
+ }
1028
+ return "";
1029
+ }
1030
+ if (typeof value === "number") {
1031
+ const parsed = parseUnixTimestamp(value);
1032
+ return parsed ? toDateTimeLocal(parsed) : "";
1033
+ }
1034
+ return "";
1035
+ }
1036
+ function fromDateTimeLocalToIso(value) {
1037
+ if (!value) {
1038
+ return void 0;
1039
+ }
1040
+ const parsed = new Date(value);
1041
+ if (Number.isNaN(parsed.getTime())) {
1042
+ return void 0;
1043
+ }
1044
+ return parsed.toISOString();
1045
+ }
1046
+ const ROOT_VALIDATION_KEY = "_root";
1047
+ const ajv = new Ajv({
1048
+ allErrors: true,
1049
+ strict: false
1050
+ });
1051
+ addFormats(ajv);
1052
+ const validatorCache = /* @__PURE__ */ new WeakMap();
1053
+ function getSchemaValidator(schema) {
1054
+ const cached = validatorCache.get(schema);
1055
+ if (cached) {
1056
+ return cached;
1057
+ }
1058
+ const validator = ajv.compile(schema);
1059
+ validatorCache.set(schema, validator);
1060
+ return validator;
1061
+ }
1062
+ function decodePointerSegment(segment) {
1063
+ return segment.replaceAll("~1", "/").replaceAll("~0", "~");
1064
+ }
1065
+ function getTopLevelErrorKey(error) {
1066
+ if (error.keyword === "required") {
1067
+ const missingProperty = typeof error.params.missingProperty === "string" ? error.params.missingProperty : void 0;
1068
+ return missingProperty ?? ROOT_VALIDATION_KEY;
1069
+ }
1070
+ const cleanedPath = error.instancePath.replace(/^\//, "");
1071
+ if (cleanedPath.length === 0) {
1072
+ return ROOT_VALIDATION_KEY;
1073
+ }
1074
+ const firstSegment = cleanedPath.split("/")[0];
1075
+ return firstSegment ? decodePointerSegment(firstSegment) : ROOT_VALIDATION_KEY;
1076
+ }
1077
+ function toErrorMessage(error) {
1078
+ const message = error.message?.trim();
1079
+ return message && message.length > 0 ? message : "invalid value";
1080
+ }
1081
+ function mapAjvErrors(errors) {
1082
+ if (!errors || errors.length === 0) {
1083
+ return {};
1084
+ }
1085
+ const mapped = {};
1086
+ for (const error of errors) {
1087
+ const key = getTopLevelErrorKey(error);
1088
+ const message = toErrorMessage(error);
1089
+ const existing = mapped[key] ?? [];
1090
+ if (!existing.includes(message)) {
1091
+ mapped[key] = [...existing, message];
1092
+ }
1093
+ }
1094
+ return mapped;
1095
+ }
1096
+ function validateFrontmatterDraft(schema, draft) {
1097
+ const validator = getSchemaValidator(schema);
1098
+ const valid = validator(draft);
1099
+ return {
1100
+ valid: Boolean(valid),
1101
+ errors: mapAjvErrors(validator.errors)
1102
+ };
1103
+ }
1104
+ const recordSchema = recordType(stringType(), unknownType());
1105
+ const jsonObjectSchema = objectType({
1106
+ type: literalType("object"),
1107
+ properties: recordSchema,
1108
+ required: arrayType(stringType()).optional()
1109
+ }).passthrough();
1110
+ const propertySchema = objectType({
1111
+ type: stringType().optional(),
1112
+ format: stringType().optional(),
1113
+ enum: arrayType(stringType()).optional(),
1114
+ anyOf: arrayType(recordSchema).optional(),
1115
+ items: recordSchema.optional()
1116
+ }).passthrough();
1117
+ const ASTRO_DEF_PREFIX = "#/definitions/";
1118
+ function asRecord(value) {
1119
+ const parsed = recordSchema.safeParse(value);
1120
+ return parsed.success ? parsed.data : void 0;
1121
+ }
1122
+ function parsePropertySchema(value) {
1123
+ const parsed = propertySchema.safeParse(value);
1124
+ return parsed.success ? parsed.data : void 0;
1125
+ }
1126
+ function asObjectSchema(value) {
1127
+ const parsed = jsonObjectSchema.safeParse(value);
1128
+ return parsed.success ? parsed.data : void 0;
1129
+ }
1130
+ function isStringArraySchema(schema) {
1131
+ if (schema.type !== "array") {
1132
+ return false;
1133
+ }
1134
+ const itemSchema = parsePropertySchema(schema.items);
1135
+ return itemSchema?.type === "string";
1136
+ }
1137
+ function isDateAnyOfSchema(schema) {
1138
+ if (!schema.anyOf || schema.anyOf.length === 0) {
1139
+ return false;
1140
+ }
1141
+ let hasDateOption = false;
1142
+ for (const option of schema.anyOf) {
1143
+ const candidate = parsePropertySchema(option);
1144
+ if (!candidate) {
1145
+ return false;
1146
+ }
1147
+ if (candidate.type === "string" && (candidate.format === "date" || candidate.format === "date-time")) {
1148
+ hasDateOption = true;
1149
+ continue;
1150
+ }
1151
+ if ((candidate.type === "integer" || candidate.type === "number") && candidate.format === "unix-time") {
1152
+ hasDateOption = true;
1153
+ continue;
1154
+ }
1155
+ if (candidate.type === "null") {
1156
+ continue;
1157
+ }
1158
+ return false;
1159
+ }
1160
+ return hasDateOption;
1161
+ }
1162
+ function resolveRequiredFields(required) {
1163
+ const parsed = arrayType(stringType()).safeParse(required);
1164
+ return new Set(parsed.success ? parsed.data : []);
1165
+ }
1166
+ function resolveCustomFieldKind(params) {
1167
+ const customKind = params.fieldUi?.[params.key];
1168
+ if (!customKind) {
1169
+ return void 0;
1170
+ }
1171
+ if (customKind.kind === "image" && params.property.type === "string") {
1172
+ return {
1173
+ kind: "image",
1174
+ key: params.key,
1175
+ required: params.required,
1176
+ sourceMode: customKind.mode
1177
+ };
1178
+ }
1179
+ if (customKind.kind === "imageArray" && isStringArraySchema(params.property)) {
1180
+ return {
1181
+ kind: "imageArray",
1182
+ key: params.key,
1183
+ required: params.required,
1184
+ sourceMode: customKind.mode
1185
+ };
1186
+ }
1187
+ if (customKind.kind === "color" && params.property.type === "string") {
1188
+ return {
1189
+ kind: "color",
1190
+ key: params.key,
1191
+ required: params.required
1192
+ };
1193
+ }
1194
+ return void 0;
1195
+ }
1196
+ function resolveAstroObjectSchema(schema) {
1197
+ if (!schema) {
1198
+ return void 0;
1199
+ }
1200
+ const direct = asObjectSchema(schema);
1201
+ if (direct) {
1202
+ return direct;
1203
+ }
1204
+ const ref = typeof schema.$ref === "string" ? schema.$ref : void 0;
1205
+ if (!ref?.startsWith(ASTRO_DEF_PREFIX)) {
1206
+ return void 0;
1207
+ }
1208
+ const definitionKey = ref.slice(ASTRO_DEF_PREFIX.length);
1209
+ const definitions = asRecord(schema.definitions);
1210
+ const definitionSchema = definitions ? definitions[definitionKey] : void 0;
1211
+ return asObjectSchema(definitionSchema);
1212
+ }
1213
+ function resolveSchemaFields(schema, fieldUi) {
1214
+ const requiredFields = resolveRequiredFields(schema.required);
1215
+ const fields = [];
1216
+ for (const [key, rawPropertySchema] of Object.entries(schema.properties)) {
1217
+ if (key === "$schema") {
1218
+ continue;
1219
+ }
1220
+ const parsedProperty = parsePropertySchema(rawPropertySchema);
1221
+ const isRequired = requiredFields.has(key);
1222
+ if (!parsedProperty) {
1223
+ fields.push({
1224
+ kind: "unsupported",
1225
+ key,
1226
+ required: isRequired,
1227
+ reason: "invalid schema node"
1228
+ });
1229
+ continue;
1230
+ }
1231
+ const customField = resolveCustomFieldKind({
1232
+ key,
1233
+ property: parsedProperty,
1234
+ required: isRequired,
1235
+ fieldUi
1236
+ });
1237
+ if (customField) {
1238
+ fields.push(customField);
1239
+ continue;
1240
+ }
1241
+ if (isDateAnyOfSchema(parsedProperty)) {
1242
+ fields.push({ kind: "dateAnyOf", key, required: isRequired });
1243
+ continue;
1244
+ }
1245
+ if (parsedProperty.type === "string" && (parsedProperty.format === "date" || parsedProperty.format === "date-time")) {
1246
+ fields.push({ kind: "dateAnyOf", key, required: isRequired });
1247
+ continue;
1248
+ }
1249
+ if ((parsedProperty.type === "number" || parsedProperty.type === "integer") && parsedProperty.format === "unix-time") {
1250
+ fields.push({ kind: "dateAnyOf", key, required: isRequired });
1251
+ continue;
1252
+ }
1253
+ const enumValues = parsedProperty.enum;
1254
+ if (enumValues && enumValues.length > 0) {
1255
+ fields.push({
1256
+ kind: "enum",
1257
+ key,
1258
+ required: isRequired,
1259
+ options: enumValues
1260
+ });
1261
+ continue;
1262
+ }
1263
+ if (parsedProperty.type === "string") {
1264
+ fields.push({ kind: "string", key, required: isRequired });
1265
+ continue;
1266
+ }
1267
+ if (parsedProperty.type === "boolean") {
1268
+ fields.push({ kind: "boolean", key, required: isRequired });
1269
+ continue;
1270
+ }
1271
+ if (parsedProperty.type === "number" || parsedProperty.type === "integer") {
1272
+ fields.push({ kind: "number", key, required: isRequired });
1273
+ continue;
1274
+ }
1275
+ if (isStringArraySchema(parsedProperty)) {
1276
+ fields.push({ kind: "stringArray", key, required: isRequired });
1277
+ continue;
1278
+ }
1279
+ if (parsedProperty.type === "array") {
1280
+ fields.push({
1281
+ kind: "unsupported",
1282
+ key,
1283
+ required: isRequired,
1284
+ reason: "array items are not string"
1285
+ });
1286
+ continue;
1287
+ }
1288
+ fields.push({
1289
+ kind: "unsupported",
1290
+ key,
1291
+ required: isRequired,
1292
+ reason: "schema type not supported"
1293
+ });
1294
+ }
1295
+ return fields;
1296
+ }
1297
+ const SUBTLE_FIELD_CLASS = "border-transparent bg-muted/50 shadow-none focus-visible:border-transparent focus-visible:ring-2 focus-visible:ring-ring/35";
1298
+ const MAX_ASSET_RESULTS = 120;
1299
+ const HEX_COLOR_REGEX = /^#[0-9a-fA-F]{6}$/;
1300
+ function isObjectRecord$1(value) {
1301
+ return typeof value === "object" && value !== null && !Array.isArray(value);
1302
+ }
1303
+ const listImageAssets = createServerFn({
1304
+ method: "POST"
1305
+ }).inputValidator((payload) => {
1306
+ if (!isObjectRecord$1(payload)) {
1307
+ throw new Error("Invalid asset list payload.");
1308
+ }
1309
+ const currentFilePath = payload.currentFilePath;
1310
+ if (typeof currentFilePath !== "string" || currentFilePath.length === 0) {
1311
+ throw new Error("Missing current file path.");
1312
+ }
1313
+ const sourceMode = payload.sourceMode;
1314
+ if (sourceMode !== "asset" && sourceMode !== "public") {
1315
+ throw new Error("Invalid image source mode.");
1316
+ }
1317
+ return {
1318
+ currentFilePath,
1319
+ sourceMode
1320
+ };
1321
+ }).handler(createSsrRpc("c39d1a9dd4bf0ef421bf4f2daf36aab12030ba358e594364ba10b3659b27b480"));
1322
+ const getImageAssetPreview = createServerFn({
1323
+ method: "POST"
1324
+ }).inputValidator((payload) => {
1325
+ if (!isObjectRecord$1(payload)) {
1326
+ throw new Error("Invalid asset preview payload.");
1327
+ }
1328
+ const assetId = payload.assetId;
1329
+ if (typeof assetId !== "string" || assetId.length === 0) {
1330
+ throw new Error("Missing asset id.");
1331
+ }
1332
+ return {
1333
+ assetId
1334
+ };
1335
+ }).handler(createSsrRpc("91a56e4138efcf4efad5b435140f056a882a5f54203e1c4d3b0f274ea2f876f5"));
1336
+ function toNormalCaseLabel(fieldName) {
1337
+ const normalized = fieldName.replace(/[_-]+/g, " ").replace(/([A-Z]+)([A-Z][a-z])/g, "$1 $2").replace(/([a-z0-9])([A-Z])/g, "$1 $2").replace(/\s+/g, " ").trim();
1338
+ if (normalized.length === 0) {
1339
+ return fieldName;
1340
+ }
1341
+ return normalized.split(" ").map((word) => {
1342
+ if (word === word.toUpperCase() && word.length > 1) {
1343
+ return word;
1344
+ }
1345
+ return word[0] ? word[0].toUpperCase() + word.slice(1).toLowerCase() : word;
1346
+ }).join(" ");
1347
+ }
1348
+ function getStringArrayValue(value) {
1349
+ if (!Array.isArray(value)) {
1350
+ return [];
1351
+ }
1352
+ return value.filter((item) => typeof item === "string");
1353
+ }
1354
+ function getDateTimeParts(value) {
1355
+ const localValue = toDateTimeLocalValue(value);
1356
+ if (!localValue) {
1357
+ return {
1358
+ date: "",
1359
+ time: "00:00"
1360
+ };
1361
+ }
1362
+ const [date = "", time = "00:00"] = localValue.split("T");
1363
+ return {
1364
+ date,
1365
+ time
1366
+ };
1367
+ }
1368
+ function padTwo(value) {
1369
+ return value.toString().padStart(2, "0");
1370
+ }
1371
+ function formatLocalDate(date) {
1372
+ const year = date.getFullYear();
1373
+ const month = padTwo(date.getMonth() + 1);
1374
+ const day = padTwo(date.getDate());
1375
+ return `${year}-${month}-${day}`;
1376
+ }
1377
+ function getIsoFromDateAndTime(dateValue, timeValue) {
1378
+ if (!dateValue) {
1379
+ return void 0;
1380
+ }
1381
+ return fromDateTimeLocalToIso(`${dateValue}T${timeValue || "00:00"}`);
1382
+ }
1383
+ function normalizeHexColor(value) {
1384
+ return value.trim().toUpperCase();
1385
+ }
1386
+ function isHexColor(value) {
1387
+ return HEX_COLOR_REGEX.test(value);
1388
+ }
1389
+ const HOUR_OPTIONS = Array.from({
1390
+ length: 24
1391
+ }, (_, index) => padTwo(index));
1392
+ const MINUTE_OPTIONS = Array.from({
1393
+ length: 60
1394
+ }, (_, index) => padTwo(index));
1395
+ function NumberField({
1396
+ fieldKey,
1397
+ value,
1398
+ onChange,
1399
+ onBlur
1400
+ }) {
1401
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(Input, { id: fieldKey, type: "number", className: SUBTLE_FIELD_CLASS, value: typeof value === "number" || typeof value === "string" ? String(value) : "", onChange: (event) => {
1402
+ const nextRaw = event.target.value;
1403
+ if (nextRaw.trim() === "") {
1404
+ onChange(void 0);
1405
+ return;
1406
+ }
1407
+ const parsed = Number(nextRaw);
1408
+ onChange(Number.isFinite(parsed) ? parsed : nextRaw);
1409
+ }, onBlur });
1410
+ }
1411
+ function BooleanField({
1412
+ fieldKey,
1413
+ value,
1414
+ onChange,
1415
+ onBlur
1416
+ }) {
1417
+ const isChecked = value === true;
1418
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "bg-muted/50 flex h-9 items-center justify-between rounded-md px-3", children: [
1419
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-muted-foreground text-sm", children: isChecked ? "Enabled" : "Disabled" }),
1420
+ /* @__PURE__ */ jsxRuntimeExports.jsx(Switch, { id: fieldKey, checked: isChecked, onCheckedChange: (checked) => onChange(checked), onBlur, "aria-label": fieldKey })
1421
+ ] });
1422
+ }
1423
+ function DateAnyOfField({
1424
+ fieldKey,
1425
+ value,
1426
+ onChange,
1427
+ onBlur
1428
+ }) {
1429
+ const {
1430
+ date,
1431
+ time
1432
+ } = getDateTimeParts(value);
1433
+ const [hour = "00", minute = "00"] = time.split(":");
1434
+ const selectedDate = date ? /* @__PURE__ */ new Date(`${date}T00:00:00`) : void 0;
1435
+ const handleDateSelect = (nextDate) => {
1436
+ if (!nextDate) {
1437
+ onChange(void 0);
1438
+ onBlur();
1439
+ return;
1440
+ }
1441
+ const nextDatePart = formatLocalDate(nextDate);
1442
+ onChange(getIsoFromDateAndTime(nextDatePart, `${hour}:${minute}`));
1443
+ onBlur();
1444
+ };
1445
+ const handleTimeSelect = (nextHour, nextMinute) => {
1446
+ onChange(getIsoFromDateAndTime(date, `${nextHour}:${nextMinute}`));
1447
+ onBlur();
1448
+ };
1449
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-2", children: [
1450
+ /* @__PURE__ */ jsxRuntimeExports.jsxs(Popover, { children: [
1451
+ /* @__PURE__ */ jsxRuntimeExports.jsxs(PopoverTrigger, { className: cn(buttonVariants({
1452
+ variant: "ghost"
1453
+ }), "bg-muted/50 hover:bg-muted/65 h-9 w-full justify-start border-0 px-3 text-sm font-normal shadow-none"), "aria-label": `${fieldKey} date`, children: [
1454
+ /* @__PURE__ */ jsxRuntimeExports.jsx(CalendarDays, { className: "text-muted-foreground size-4" }),
1455
+ selectedDate ? selectedDate.toLocaleDateString(void 0, {
1456
+ month: "short",
1457
+ day: "2-digit",
1458
+ year: "numeric"
1459
+ }) : "Pick a date"
1460
+ ] }),
1461
+ /* @__PURE__ */ jsxRuntimeExports.jsx(PopoverContent, { className: "w-auto p-0", children: /* @__PURE__ */ jsxRuntimeExports.jsx(Calendar, { mode: "single", selected: selectedDate, onSelect: handleDateSelect }) })
1462
+ ] }),
1463
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "grid grid-cols-2 gap-2", children: [
1464
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "relative", children: [
1465
+ /* @__PURE__ */ jsxRuntimeExports.jsx(Clock3, { className: "text-muted-foreground pointer-events-none absolute top-1/2 left-2.5 size-4 -translate-y-1/2" }),
1466
+ /* @__PURE__ */ jsxRuntimeExports.jsxs(Select, { value: hour, onValueChange: (nextHour) => {
1467
+ if (!nextHour) {
1468
+ return;
1469
+ }
1470
+ handleTimeSelect(nextHour, minute);
1471
+ }, disabled: !date, children: [
1472
+ /* @__PURE__ */ jsxRuntimeExports.jsx(SelectTrigger, { className: "bg-muted/50 focus-visible:ring-ring/35 w-full border-transparent pl-8 shadow-none focus-visible:border-transparent focus-visible:ring-2", children: /* @__PURE__ */ jsxRuntimeExports.jsx(SelectValue, { placeholder: "HH" }) }),
1473
+ /* @__PURE__ */ jsxRuntimeExports.jsx(SelectContent, { children: /* @__PURE__ */ jsxRuntimeExports.jsx(SelectGroup, { children: HOUR_OPTIONS.map((hourOption) => /* @__PURE__ */ jsxRuntimeExports.jsx(SelectItem, { value: hourOption, children: hourOption }, `hour-${hourOption}`)) }) })
1474
+ ] })
1475
+ ] }),
1476
+ /* @__PURE__ */ jsxRuntimeExports.jsxs(Select, { value: minute, onValueChange: (nextMinute) => {
1477
+ if (!nextMinute) {
1478
+ return;
1479
+ }
1480
+ handleTimeSelect(hour, nextMinute);
1481
+ }, disabled: !date, children: [
1482
+ /* @__PURE__ */ jsxRuntimeExports.jsx(SelectTrigger, { className: "bg-muted/50 focus-visible:ring-ring/35 w-full border-transparent shadow-none focus-visible:border-transparent focus-visible:ring-2", children: /* @__PURE__ */ jsxRuntimeExports.jsx(SelectValue, { placeholder: "MM" }) }),
1483
+ /* @__PURE__ */ jsxRuntimeExports.jsx(SelectContent, { children: /* @__PURE__ */ jsxRuntimeExports.jsx(SelectGroup, { children: MINUTE_OPTIONS.map((minuteOption) => /* @__PURE__ */ jsxRuntimeExports.jsx(SelectItem, { value: minuteOption, children: minuteOption }, `minute-${minuteOption}`)) }) })
1484
+ ] })
1485
+ ] })
1486
+ ] });
1487
+ }
1488
+ function EnumField({
1489
+ fieldKey,
1490
+ value,
1491
+ options,
1492
+ onChange
1493
+ }) {
1494
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs(Select, { value: typeof value === "string" ? value : void 0, onValueChange: (nextValue) => {
1495
+ if (!nextValue) {
1496
+ return;
1497
+ }
1498
+ onChange(nextValue);
1499
+ }, children: [
1500
+ /* @__PURE__ */ jsxRuntimeExports.jsx(SelectTrigger, { className: "bg-muted/50 focus-visible:ring-ring/35 w-full border-transparent shadow-none focus-visible:border-transparent focus-visible:ring-2", children: /* @__PURE__ */ jsxRuntimeExports.jsx(SelectValue, { placeholder: "Select a value" }) }),
1501
+ /* @__PURE__ */ jsxRuntimeExports.jsx(SelectContent, { children: /* @__PURE__ */ jsxRuntimeExports.jsx(SelectGroup, { children: options.map((option) => {
1502
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(SelectItem, { value: option, children: option }, `${fieldKey}-${option}`);
1503
+ }) }) })
1504
+ ] });
1505
+ }
1506
+ function StringArrayField({
1507
+ fieldKey,
1508
+ values,
1509
+ chipInput,
1510
+ onChipInputChange,
1511
+ onAddChip,
1512
+ onRemoveChip,
1513
+ onBackspaceEmpty,
1514
+ onBlur,
1515
+ placeholder
1516
+ }) {
1517
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-2", children: [
1518
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex flex-wrap gap-1.5", children: values.map((chip, index) => /* @__PURE__ */ jsxRuntimeExports.jsxs(Badge, { variant: "secondary", className: "bg-muted gap-1 border-transparent tracking-normal normal-case", children: [
1519
+ chip,
1520
+ /* @__PURE__ */ jsxRuntimeExports.jsx("button", { type: "button", className: "text-muted-foreground hover:bg-accent hover:text-foreground inline-flex size-4 items-center justify-center rounded-full", onClick: () => onRemoveChip(index), "aria-label": `Remove ${chip}`, children: /* @__PURE__ */ jsxRuntimeExports.jsx(X, { className: "size-3" }) })
1521
+ ] }, `${fieldKey}-${chip}-${index}`)) }),
1522
+ /* @__PURE__ */ jsxRuntimeExports.jsx(Input, { id: fieldKey, className: SUBTLE_FIELD_CLASS, value: chipInput, onChange: (event) => onChipInputChange(event.target.value), onKeyDown: (event) => {
1523
+ if (event.key === "Enter" || event.key === ",") {
1524
+ event.preventDefault();
1525
+ onAddChip();
1526
+ return;
1527
+ }
1528
+ if (event.key === "Backspace" && chipInput.trim().length === 0) {
1529
+ event.preventDefault();
1530
+ onBackspaceEmpty();
1531
+ }
1532
+ }, onBlur, placeholder: placeholder ?? "Type and press Enter" })
1533
+ ] });
1534
+ }
1535
+ function AssetThumbnail({
1536
+ assetId,
1537
+ label
1538
+ }) {
1539
+ const [previewUrl, setPreviewUrl] = reactExports.useState();
1540
+ const [hasFailed, setHasFailed] = reactExports.useState(false);
1541
+ const requestIdRef = reactExports.useRef(0);
1542
+ reactExports.useEffect(() => {
1543
+ requestIdRef.current += 1;
1544
+ const requestId = requestIdRef.current;
1545
+ let objectUrl;
1546
+ void (async () => {
1547
+ try {
1548
+ setHasFailed(false);
1549
+ const response = await getImageAssetPreview({
1550
+ data: {
1551
+ assetId
1552
+ }
1553
+ });
1554
+ if (!response.ok) {
1555
+ throw new Error(`Preview request failed (${response.status})`);
1556
+ }
1557
+ const blob = await response.blob();
1558
+ if (requestIdRef.current !== requestId) {
1559
+ return;
1560
+ }
1561
+ objectUrl = URL.createObjectURL(blob);
1562
+ setPreviewUrl(objectUrl);
1563
+ } catch {
1564
+ if (requestIdRef.current !== requestId) {
1565
+ return;
1566
+ }
1567
+ setHasFailed(true);
1568
+ setPreviewUrl(void 0);
1569
+ }
1570
+ })();
1571
+ return () => {
1572
+ requestIdRef.current += 1;
1573
+ if (objectUrl) {
1574
+ URL.revokeObjectURL(objectUrl);
1575
+ }
1576
+ };
1577
+ }, [assetId]);
1578
+ if (previewUrl) {
1579
+ return /* @__PURE__ */ jsxRuntimeExports.jsx("img", { src: previewUrl, alt: label, className: "h-24 w-full rounded-md object-cover" });
1580
+ }
1581
+ return /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "bg-muted/55 text-muted-foreground flex h-24 w-full items-center justify-center rounded-md", children: hasFailed ? /* @__PURE__ */ jsxRuntimeExports.jsx(Image, { className: "size-5" }) : /* @__PURE__ */ jsxRuntimeExports.jsx(LoaderCircle, { className: "size-5 animate-spin" }) });
1582
+ }
1583
+ function AssetPicker({
1584
+ currentFilePath,
1585
+ sourceMode,
1586
+ triggerLabel,
1587
+ onSelectPath
1588
+ }) {
1589
+ const [open, setOpen] = reactExports.useState(false);
1590
+ const [query, setQuery] = reactExports.useState("");
1591
+ const [loading, setLoading] = reactExports.useState(false);
1592
+ const [error, setError] = reactExports.useState();
1593
+ const [assets, setAssets] = reactExports.useState([]);
1594
+ const [loadedForKey, setLoadedForKey] = reactExports.useState();
1595
+ reactExports.useEffect(() => {
1596
+ const requestKey = `${currentFilePath}::${sourceMode}`;
1597
+ if (!open || loadedForKey === requestKey) {
1598
+ return;
1599
+ }
1600
+ let isCancelled = false;
1601
+ setLoading(true);
1602
+ setError(void 0);
1603
+ void listImageAssets({
1604
+ data: {
1605
+ currentFilePath,
1606
+ sourceMode
1607
+ }
1608
+ }).then((nextAssets) => {
1609
+ if (isCancelled) {
1610
+ return;
1611
+ }
1612
+ setAssets(nextAssets);
1613
+ setLoadedForKey(requestKey);
1614
+ }).catch((fetchError) => {
1615
+ if (isCancelled) {
1616
+ return;
1617
+ }
1618
+ const message = fetchError instanceof Error ? fetchError.message : String(fetchError);
1619
+ setError(message);
1620
+ }).finally(() => {
1621
+ if (!isCancelled) {
1622
+ setLoading(false);
1623
+ }
1624
+ });
1625
+ return () => {
1626
+ isCancelled = true;
1627
+ };
1628
+ }, [currentFilePath, loadedForKey, open, sourceMode]);
1629
+ const filteredAssets = reactExports.useMemo(() => {
1630
+ const normalizedQuery = query.trim().toLowerCase();
1631
+ return assets.filter((asset) => {
1632
+ if (normalizedQuery.length === 0) {
1633
+ return true;
1634
+ }
1635
+ return asset.displayPath.toLowerCase().includes(normalizedQuery) || asset.value.toLowerCase().includes(normalizedQuery);
1636
+ });
1637
+ }, [assets, query]);
1638
+ const visibleAssets = filteredAssets.slice(0, MAX_ASSET_RESULTS);
1639
+ const sourceLabel = sourceMode === "public" ? "public" : "src";
1640
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs(Popover, { open, onOpenChange: setOpen, children: [
1641
+ /* @__PURE__ */ jsxRuntimeExports.jsxs(PopoverTrigger, { className: cn(buttonVariants({
1642
+ variant: "outline"
1643
+ }), "h-8 border-dashed text-xs"), children: [
1644
+ /* @__PURE__ */ jsxRuntimeExports.jsx(Image, { className: "size-3.5" }),
1645
+ triggerLabel
1646
+ ] }),
1647
+ /* @__PURE__ */ jsxRuntimeExports.jsxs(PopoverContent, { className: "w-[34rem] max-w-[calc(100vw-2rem)] gap-2 p-3", children: [
1648
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-between gap-2", children: [
1649
+ /* @__PURE__ */ jsxRuntimeExports.jsxs(Badge, { variant: "secondary", className: "bg-muted text-foreground/75 rounded-md border-transparent text-[11px] normal-case", children: [
1650
+ "source: ",
1651
+ sourceLabel
1652
+ ] }),
1653
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "relative w-60 max-w-full", children: [
1654
+ /* @__PURE__ */ jsxRuntimeExports.jsx(Search, { className: "text-muted-foreground pointer-events-none absolute top-1/2 left-2.5 size-3.5 -translate-y-1/2" }),
1655
+ /* @__PURE__ */ jsxRuntimeExports.jsx(Input, { value: query, onChange: (event) => {
1656
+ setQuery(event.target.value);
1657
+ }, className: "bg-muted/50 focus-visible:ring-ring/35 h-8 border-transparent pl-8 text-xs shadow-none focus-visible:border-transparent focus-visible:ring-2", placeholder: "Search assets...", "aria-label": "Search assets" })
1658
+ ] })
1659
+ ] }),
1660
+ loading ? /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "text-muted-foreground flex h-32 items-center justify-center gap-2 text-sm", children: [
1661
+ /* @__PURE__ */ jsxRuntimeExports.jsx(LoaderCircle, { className: "size-4 animate-spin" }),
1662
+ "Loading assets..."
1663
+ ] }) : null,
1664
+ error ? /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-destructive rounded-md bg-red-500/10 px-3 py-2 text-xs", children: error }) : null,
1665
+ !loading && !error ? /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
1666
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "grid max-h-[22rem] grid-cols-3 gap-2 overflow-auto pr-1", children: visibleAssets.map((asset) => /* @__PURE__ */ jsxRuntimeExports.jsxs("button", { type: "button", className: "border-border/40 hover:border-ring/35 bg-muted/25 hover:bg-muted/35 space-y-1.5 rounded-lg border p-1.5 text-left transition-colors", onClick: () => {
1667
+ onSelectPath(asset.value);
1668
+ setOpen(false);
1669
+ }, title: asset.value, children: [
1670
+ /* @__PURE__ */ jsxRuntimeExports.jsx(AssetThumbnail, { assetId: asset.id, label: asset.displayPath }),
1671
+ /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-foreground/85 truncate text-[11px]", children: asset.displayPath })
1672
+ ] }, asset.id)) }),
1673
+ filteredAssets.length === 0 ? /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-muted-foreground text-xs", children: "No assets found." }) : null,
1674
+ filteredAssets.length > MAX_ASSET_RESULTS ? /* @__PURE__ */ jsxRuntimeExports.jsxs("p", { className: "text-muted-foreground text-xs", children: [
1675
+ "Showing first ",
1676
+ MAX_ASSET_RESULTS,
1677
+ " assets. Refine search for more."
1678
+ ] }) : null
1679
+ ] }) : null
1680
+ ] })
1681
+ ] });
1682
+ }
1683
+ function ImageField({
1684
+ fieldKey,
1685
+ currentFilePath,
1686
+ sourceMode,
1687
+ value,
1688
+ onChange,
1689
+ onBlur
1690
+ }) {
1691
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-2", children: [
1692
+ /* @__PURE__ */ jsxRuntimeExports.jsx(Input, { id: fieldKey, className: SUBTLE_FIELD_CLASS, value: typeof value === "string" ? value : "", onChange: (event) => {
1693
+ onChange(event.target.value || void 0);
1694
+ }, onBlur }),
1695
+ /* @__PURE__ */ jsxRuntimeExports.jsx(AssetPicker, { currentFilePath, sourceMode, triggerLabel: "Browse assets", onSelectPath: (selectedPath) => {
1696
+ onChange(selectedPath);
1697
+ onBlur();
1698
+ } })
1699
+ ] });
1700
+ }
1701
+ function ImageArrayField({
1702
+ fieldKey,
1703
+ currentFilePath,
1704
+ sourceMode,
1705
+ values,
1706
+ chipInput,
1707
+ onChipInputChange,
1708
+ onAddChip,
1709
+ onRemoveChip,
1710
+ onBackspaceEmpty,
1711
+ onBlur,
1712
+ onSelectAsset
1713
+ }) {
1714
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-2", children: [
1715
+ /* @__PURE__ */ jsxRuntimeExports.jsx(StringArrayField, { fieldKey, values, chipInput, onChipInputChange, onAddChip, onRemoveChip, onBackspaceEmpty, onBlur, placeholder: "Type path and press Enter" }),
1716
+ /* @__PURE__ */ jsxRuntimeExports.jsx(AssetPicker, { currentFilePath, sourceMode, triggerLabel: "Add from assets", onSelectPath: onSelectAsset })
1717
+ ] });
1718
+ }
1719
+ function ColorField({
1720
+ fieldKey,
1721
+ value,
1722
+ onChange,
1723
+ onBlur
1724
+ }) {
1725
+ const stringValue = typeof value === "string" ? value : "";
1726
+ const normalizedValue = normalizeHexColor(stringValue);
1727
+ const hasValue = normalizedValue.length > 0;
1728
+ const hasValidValue = hasValue && isHexColor(normalizedValue);
1729
+ const pickerValue = hasValidValue ? normalizedValue : "#000000";
1730
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-2", children: [
1731
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex gap-2", children: [
1732
+ /* @__PURE__ */ jsxRuntimeExports.jsx(Input, { id: fieldKey, className: SUBTLE_FIELD_CLASS, value: stringValue, onChange: (event) => {
1733
+ const nextRaw = event.target.value;
1734
+ onChange(nextRaw.length > 0 ? nextRaw : void 0);
1735
+ }, onBlur, placeholder: "#RRGGBB" }),
1736
+ /* @__PURE__ */ jsxRuntimeExports.jsx("input", { id: `${fieldKey}-picker`, type: "color", className: "border-border/50 h-9 w-12 cursor-pointer rounded-md border bg-transparent p-1", value: pickerValue, onChange: (event) => {
1737
+ onChange(normalizeHexColor(event.target.value));
1738
+ onBlur();
1739
+ }, "aria-label": `${fieldKey} color picker` })
1740
+ ] }),
1741
+ hasValue && !hasValidValue ? /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-destructive/85 text-xs", children: "Use a hex color in #RRGGBB format." }) : null
1742
+ ] });
1743
+ }
1744
+ function FieldErrorList({
1745
+ fieldKey,
1746
+ errors
1747
+ }) {
1748
+ if (!errors || errors.length === 0) {
1749
+ return null;
1750
+ }
1751
+ return /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "space-y-1", children: errors.map((error, index) => /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-destructive/85 text-xs", children: error }, `${fieldKey}-error-${index}`)) });
1752
+ }
1753
+ function RightSidebar({
1754
+ selectedCollection,
1755
+ selectedFile
1756
+ }) {
1757
+ const draft = useFrontmatterEditorStore((state) => state.draft);
1758
+ const errors = useFrontmatterEditorStore((state) => state.errors);
1759
+ const chipInputs = useFrontmatterEditorStore((state) => state.chipInputs);
1760
+ const setFieldValue = useFrontmatterEditorStore((state) => state.setFieldValue);
1761
+ const setFieldTouched = useFrontmatterEditorStore((state) => state.setFieldTouched);
1762
+ const setValidationErrors = useFrontmatterEditorStore((state) => state.setValidationErrors);
1763
+ const setChipInput = useFrontmatterEditorStore((state) => state.setChipInput);
1764
+ const addChipValue = useFrontmatterEditorStore((state) => state.addChipValue);
1765
+ const removeChipValue = useFrontmatterEditorStore((state) => state.removeChipValue);
1766
+ const removeLastChipValue = useFrontmatterEditorStore((state) => state.removeLastChipValue);
1767
+ const objectSchema = reactExports.useMemo(() => {
1768
+ return resolveAstroObjectSchema(selectedCollection?.schema);
1769
+ }, [selectedCollection?.schema]);
1770
+ const resolvedFields = reactExports.useMemo(() => {
1771
+ if (!objectSchema) {
1772
+ return [];
1773
+ }
1774
+ return resolveSchemaFields(objectSchema, selectedCollection?.fieldUi);
1775
+ }, [objectSchema, selectedCollection?.fieldUi]);
1776
+ const runValidation = reactExports.useCallback(() => {
1777
+ if (!selectedCollection?.schema) {
1778
+ setValidationErrors({});
1779
+ return;
1780
+ }
1781
+ const result = validateFrontmatterDraft(selectedCollection.schema, draft);
1782
+ setValidationErrors(result.errors);
1783
+ }, [selectedCollection?.schema, draft, setValidationErrors]);
1784
+ const handleFieldBlur = reactExports.useCallback((fieldKey) => {
1785
+ setFieldTouched(fieldKey);
1786
+ runValidation();
1787
+ }, [runValidation, setFieldTouched]);
1788
+ reactExports.useEffect(() => {
1789
+ runValidation();
1790
+ }, [runValidation]);
1791
+ if (!selectedCollection || !selectedFile) {
1792
+ return /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-muted-foreground flex h-full items-center justify-center text-sm", children: "Select a file to edit frontmatter." });
1793
+ }
1794
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex h-full flex-col gap-3", children: [
1795
+ /* @__PURE__ */ jsxRuntimeExports.jsx("h3", { className: "text-foreground/90 text-sm font-semibold", children: "Frontmatter" }),
1796
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "min-h-0 flex-1 space-y-3 overflow-auto pr-1", children: [
1797
+ !objectSchema ? /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "bg-muted/40 text-muted-foreground rounded-md px-3 py-2 text-sm", children: "This collection has no object schema available." }) : null,
1798
+ resolvedFields.map((field) => {
1799
+ const fieldErrors = errors[field.key];
1800
+ const label = toNormalCaseLabel(field.key);
1801
+ const value = draft[field.key];
1802
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "bg-background/45 space-y-2 rounded-lg px-2.5 py-2.5", children: [
1803
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex items-center justify-between gap-2", children: /* @__PURE__ */ jsxRuntimeExports.jsxs(Label, { htmlFor: field.key, className: "text-muted-foreground text-xs font-medium tracking-wide", children: [
1804
+ label,
1805
+ field.required ? " *" : ""
1806
+ ] }) }),
1807
+ field.kind === "string" && /* @__PURE__ */ jsxRuntimeExports.jsx(Input, { id: field.key, className: SUBTLE_FIELD_CLASS, value: typeof value === "string" ? value : "", onChange: (event) => {
1808
+ setFieldValue(field.key, event.target.value || void 0);
1809
+ }, onBlur: () => handleFieldBlur(field.key) }),
1810
+ field.kind === "image" && /* @__PURE__ */ jsxRuntimeExports.jsx(ImageField, { fieldKey: field.key, currentFilePath: selectedFile.filePath, sourceMode: field.sourceMode, value, onChange: (nextValue) => {
1811
+ setFieldValue(field.key, nextValue);
1812
+ }, onBlur: () => handleFieldBlur(field.key) }),
1813
+ field.kind === "color" && /* @__PURE__ */ jsxRuntimeExports.jsx(ColorField, { fieldKey: field.key, value, onChange: (nextValue) => {
1814
+ setFieldValue(field.key, nextValue);
1815
+ }, onBlur: () => handleFieldBlur(field.key) }),
1816
+ field.kind === "number" && /* @__PURE__ */ jsxRuntimeExports.jsx(NumberField, { fieldKey: field.key, value, onChange: (nextValue) => {
1817
+ setFieldValue(field.key, nextValue);
1818
+ }, onBlur: () => handleFieldBlur(field.key) }),
1819
+ field.kind === "boolean" && /* @__PURE__ */ jsxRuntimeExports.jsx(BooleanField, { fieldKey: field.key, value, onChange: (nextValue) => {
1820
+ setFieldValue(field.key, nextValue);
1821
+ }, onBlur: () => handleFieldBlur(field.key) }),
1822
+ field.kind === "enum" && /* @__PURE__ */ jsxRuntimeExports.jsx(EnumField, { fieldKey: field.key, value, options: field.options, onChange: (nextValue) => {
1823
+ setFieldValue(field.key, nextValue);
1824
+ handleFieldBlur(field.key);
1825
+ } }),
1826
+ field.kind === "stringArray" && /* @__PURE__ */ jsxRuntimeExports.jsx(StringArrayField, { fieldKey: field.key, values: getStringArrayValue(value), chipInput: chipInputs[field.key] ?? "", onChipInputChange: (nextValue) => {
1827
+ setChipInput(field.key, nextValue);
1828
+ }, onAddChip: () => {
1829
+ addChipValue(field.key, chipInputs[field.key] ?? "");
1830
+ handleFieldBlur(field.key);
1831
+ }, onRemoveChip: (index) => {
1832
+ removeChipValue(field.key, index);
1833
+ handleFieldBlur(field.key);
1834
+ }, onBackspaceEmpty: () => {
1835
+ removeLastChipValue(field.key);
1836
+ handleFieldBlur(field.key);
1837
+ }, onBlur: () => handleFieldBlur(field.key) }),
1838
+ field.kind === "imageArray" && /* @__PURE__ */ jsxRuntimeExports.jsx(ImageArrayField, { fieldKey: field.key, currentFilePath: selectedFile.filePath, sourceMode: field.sourceMode, values: getStringArrayValue(value), chipInput: chipInputs[field.key] ?? "", onChipInputChange: (nextValue) => {
1839
+ setChipInput(field.key, nextValue);
1840
+ }, onAddChip: () => {
1841
+ addChipValue(field.key, chipInputs[field.key] ?? "");
1842
+ handleFieldBlur(field.key);
1843
+ }, onRemoveChip: (index) => {
1844
+ removeChipValue(field.key, index);
1845
+ handleFieldBlur(field.key);
1846
+ }, onBackspaceEmpty: () => {
1847
+ removeLastChipValue(field.key);
1848
+ handleFieldBlur(field.key);
1849
+ }, onBlur: () => handleFieldBlur(field.key), onSelectAsset: (nextValue) => {
1850
+ addChipValue(field.key, nextValue);
1851
+ handleFieldBlur(field.key);
1852
+ } }),
1853
+ field.kind === "dateAnyOf" && /* @__PURE__ */ jsxRuntimeExports.jsx(DateAnyOfField, { fieldKey: field.key, value, onChange: (nextValue) => {
1854
+ setFieldValue(field.key, nextValue);
1855
+ }, onBlur: () => handleFieldBlur(field.key) }),
1856
+ field.kind === "unsupported" && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "bg-muted/40 text-muted-foreground rounded-md px-3 py-2 text-sm", children: [
1857
+ "Not yet supported: ",
1858
+ field.reason
1859
+ ] }),
1860
+ /* @__PURE__ */ jsxRuntimeExports.jsx(FieldErrorList, { fieldKey: field.key, errors: fieldErrors })
1861
+ ] }, field.key);
1862
+ }),
1863
+ errors[ROOT_VALIDATION_KEY]?.length ? /* @__PURE__ */ jsxRuntimeExports.jsx(FieldErrorList, { fieldKey: ROOT_VALIDATION_KEY, errors: errors[ROOT_VALIDATION_KEY] }) : null
1864
+ ] })
1865
+ ] });
1866
+ }
1867
+ function isObjectRecord(value) {
1868
+ return typeof value === "object" && value !== null && !Array.isArray(value);
1869
+ }
1870
+ const saveSelectionToFile = createServerFn({
1871
+ method: "POST"
1872
+ }).inputValidator((payload) => {
1873
+ if (!isObjectRecord(payload)) {
1874
+ throw new Error("Invalid save payload.");
1875
+ }
1876
+ const collectionName = payload.collectionName;
1877
+ const fileId = payload.fileId;
1878
+ const draft = payload.draft;
1879
+ const content = payload.content;
1880
+ if (typeof collectionName !== "string" || collectionName.length === 0) {
1881
+ throw new Error("Missing collection name.");
1882
+ }
1883
+ if (typeof fileId !== "string" || fileId.length === 0) {
1884
+ throw new Error("Missing file id.");
1885
+ }
1886
+ if (!isObjectRecord(draft)) {
1887
+ throw new Error("Invalid frontmatter draft.");
1888
+ }
1889
+ if (typeof content !== "string") {
1890
+ throw new Error("Invalid markdown content.");
1891
+ }
1892
+ return {
1893
+ collectionName,
1894
+ fileId,
1895
+ draft,
1896
+ content
1897
+ };
1898
+ }).handler(createSsrRpc("b1ee42a5714ab9be8f37a4c5fca02ffd6269030b4d3ef663ff002865393e2386"));
1899
+ function App() {
1900
+ const data = useCollectionsData();
1901
+ const search = Route.useSearch();
1902
+ const [leftOpen, setLeftOpen] = reactExports.useState(true);
1903
+ const [rightOpen, setRightOpen] = reactExports.useState(true);
1904
+ const [isSaving, setIsSaving] = reactExports.useState(false);
1905
+ const [saveError, setSaveError] = reactExports.useState();
1906
+ const leftPanelRef = reactExports.useRef(null);
1907
+ const rightPanelRef = reactExports.useRef(null);
1908
+ const navigate = Route.useNavigate();
1909
+ const draft = useFrontmatterEditorStore((state) => state.draft);
1910
+ const contentDraft = useFrontmatterEditorStore((state) => state.contentDraft);
1911
+ const dirty = useFrontmatterEditorStore((state) => state.dirty);
1912
+ const loadSelection = useFrontmatterEditorStore((state) => state.loadSelection);
1913
+ const clearSelection = useFrontmatterEditorStore((state) => state.clearSelection);
1914
+ const commitSavedState = useFrontmatterEditorStore((state) => state.commitSavedState);
1915
+ const {
1916
+ selectedCollection,
1917
+ selectedFile,
1918
+ normalizedSearch
1919
+ } = reactExports.useMemo(() => resolveEditorSelection(data, search), [data, search]);
1920
+ reactExports.useEffect(() => {
1921
+ if (areEditorSearchEqual(search, normalizedSearch)) {
1922
+ return;
1923
+ }
1924
+ void navigate({
1925
+ search: normalizedSearch,
1926
+ replace: true
1927
+ });
1928
+ }, [navigate, normalizedSearch, search]);
1929
+ reactExports.useEffect(() => {
1930
+ if (!selectedCollection || !selectedFile) {
1931
+ clearSelection();
1932
+ return;
1933
+ }
1934
+ loadSelection({
1935
+ collectionName: selectedCollection.name,
1936
+ fileId: selectedFile.id,
1937
+ data: selectedFile.data,
1938
+ content: selectedFile.content
1939
+ });
1940
+ }, [clearSelection, loadSelection, selectedCollection, selectedFile]);
1941
+ reactExports.useEffect(() => {
1942
+ if (!dirty) {
1943
+ return;
1944
+ }
1945
+ const handleBeforeUnload = (event) => {
1946
+ event.preventDefault();
1947
+ event.returnValue = "";
1948
+ };
1949
+ window.addEventListener("beforeunload", handleBeforeUnload);
1950
+ return () => {
1951
+ window.removeEventListener("beforeunload", handleBeforeUnload);
1952
+ };
1953
+ }, [dirty]);
1954
+ const canNavigateAway = reactExports.useCallback(() => {
1955
+ if (!dirty) {
1956
+ return true;
1957
+ }
1958
+ return window.confirm("You have unsaved changes. Discard changes and continue?");
1959
+ }, [dirty]);
1960
+ const selectCollection = reactExports.useCallback((collectionName) => {
1961
+ const nextCollection = data.find((collection) => collection.name === collectionName);
1962
+ if (!nextCollection) {
1963
+ return;
1964
+ }
1965
+ const nextFile = getSortedCollectionFiles(nextCollection).at(0);
1966
+ const nextSearch = {
1967
+ collection: nextCollection.name,
1968
+ file: nextFile?.id
1969
+ };
1970
+ if (areEditorSearchEqual(normalizedSearch, nextSearch)) {
1971
+ return;
1972
+ }
1973
+ if (!canNavigateAway()) {
1974
+ return;
1975
+ }
1976
+ void navigate({
1977
+ search: nextSearch
1978
+ });
1979
+ }, [canNavigateAway, data, navigate, normalizedSearch]);
1980
+ const selectFile = reactExports.useCallback((fileId) => {
1981
+ if (!selectedCollection) {
1982
+ return;
1983
+ }
1984
+ const nextSearch = {
1985
+ collection: selectedCollection.name,
1986
+ file: fileId
1987
+ };
1988
+ if (areEditorSearchEqual(normalizedSearch, nextSearch)) {
1989
+ return;
1990
+ }
1991
+ if (!canNavigateAway()) {
1992
+ return;
1993
+ }
1994
+ void navigate({
1995
+ search: nextSearch
1996
+ });
1997
+ }, [canNavigateAway, navigate, normalizedSearch, selectedCollection]);
1998
+ const toggleLeftSidebar = reactExports.useCallback(() => {
1999
+ const panel = leftPanelRef.current;
2000
+ if (!panel) {
2001
+ setLeftOpen((open) => !open);
2002
+ return;
2003
+ }
2004
+ if (panel.isCollapsed()) {
2005
+ panel.expand();
2006
+ setLeftOpen(true);
2007
+ return;
2008
+ }
2009
+ panel.collapse();
2010
+ setLeftOpen(false);
2011
+ }, []);
2012
+ const toggleRightSidebar = reactExports.useCallback(() => {
2013
+ const panel = rightPanelRef.current;
2014
+ if (!panel) {
2015
+ setRightOpen((open) => !open);
2016
+ return;
2017
+ }
2018
+ if (panel.isCollapsed()) {
2019
+ panel.expand();
2020
+ setRightOpen(true);
2021
+ return;
2022
+ }
2023
+ panel.collapse();
2024
+ setRightOpen(false);
2025
+ }, []);
2026
+ const syncSidebarState = reactExports.useCallback(() => {
2027
+ const nextLeftOpen = !(leftPanelRef.current?.isCollapsed() ?? false);
2028
+ const nextRightOpen = !(rightPanelRef.current?.isCollapsed() ?? false);
2029
+ setLeftOpen((current) => current === nextLeftOpen ? current : nextLeftOpen);
2030
+ setRightOpen((current) => current === nextRightOpen ? current : nextRightOpen);
2031
+ }, []);
2032
+ const handleSave = reactExports.useCallback(async () => {
2033
+ if (!selectedCollection || !selectedFile || !dirty || isSaving) {
2034
+ return;
2035
+ }
2036
+ setIsSaving(true);
2037
+ setSaveError(void 0);
2038
+ try {
2039
+ await saveSelectionToFile({
2040
+ data: {
2041
+ collectionName: selectedCollection.name,
2042
+ fileId: selectedFile.id,
2043
+ draft,
2044
+ content: contentDraft
2045
+ }
2046
+ });
2047
+ commitSavedState();
2048
+ } catch (error) {
2049
+ const message = error instanceof Error ? error.message : "Unable to save file.";
2050
+ setSaveError(message);
2051
+ } finally {
2052
+ setIsSaving(false);
2053
+ }
2054
+ }, [commitSavedState, contentDraft, dirty, draft, isSaving, selectedCollection, selectedFile]);
2055
+ reactExports.useEffect(() => {
2056
+ setSaveError(void 0);
2057
+ }, [selectedCollection?.name, selectedFile?.id]);
2058
+ const selectedFileLabel = selectedFile ? getFileDisplayLabel(selectedFile) : "No file selected";
2059
+ return /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "h-svh w-screen overflow-hidden p-2", children: /* @__PURE__ */ jsxRuntimeExports.jsxs(ResizablePanelGroup, { orientation: "horizontal", onLayoutChanged: syncSidebarState, children: [
2060
+ /* @__PURE__ */ jsxRuntimeExports.jsx(ResizablePanel, { id: "editor-left-sidebar", panelRef: leftPanelRef, collapsible: true, collapsedSize: 0, defaultSize: "18rem", minSize: "14rem", maxSize: "30rem", className: "min-w-0", children: /* @__PURE__ */ jsxRuntimeExports.jsx("aside", { className: "bg-background/55 flex h-full flex-col overflow-hidden rounded-xl px-2.5 py-3 backdrop-blur-sm", children: /* @__PURE__ */ jsxRuntimeExports.jsx(LeftSidebar, { collections: data, selectedCollectionName: selectedCollection?.name, selectedFileId: selectedFile?.id, onSelectCollection: selectCollection, onSelectFile: selectFile }) }) }),
2061
+ /* @__PURE__ */ jsxRuntimeExports.jsx(ResizableHandle, { withHandle: true, className: cn(leftOpen ? "mx-1 w-2 bg-transparent" : "mx-0 w-0", !leftOpen && "pointer-events-none opacity-0") }),
2062
+ /* @__PURE__ */ jsxRuntimeExports.jsx(ResizablePanel, { id: "editor-main-panel", minSize: "30%", className: "min-w-0", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("main", { className: "bg-background/75 flex h-full w-full min-w-0 flex-1 flex-col overflow-hidden rounded-xl px-3 py-2 backdrop-blur-sm", children: [
2063
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("header", { className: "border-border/45 flex items-center justify-between gap-3 border-b pb-2", children: [
2064
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex shrink-0 items-center gap-1.5", children: /* @__PURE__ */ jsxRuntimeExports.jsx(Button, { variant: "ghost", size: "icon", onClick: toggleLeftSidebar, "aria-label": leftOpen ? "Hide left sidebar" : "Show left sidebar", className: "text-muted-foreground hover:bg-background/65 hover:text-foreground size-8 border-0", children: leftOpen ? /* @__PURE__ */ jsxRuntimeExports.jsx(PanelLeftClose, {}) : /* @__PURE__ */ jsxRuntimeExports.jsx(PanelLeftOpen, {}) }) }),
2065
+ /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-foreground/85 min-w-0 flex-1 truncate text-center text-sm font-medium", title: selectedFile?.id, children: selectedFileLabel }),
2066
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex shrink-0 items-center justify-end gap-2", children: [
2067
+ dirty ? /* @__PURE__ */ jsxRuntimeExports.jsxs(Button, { type: "button", variant: "ghost", size: "sm", onClick: handleSave, disabled: isSaving || !selectedCollection || !selectedFile, className: "border-0", children: [
2068
+ isSaving ? /* @__PURE__ */ jsxRuntimeExports.jsx(LoaderCircle, { className: "animate-spin" }) : /* @__PURE__ */ jsxRuntimeExports.jsx(Save, {}),
2069
+ "Save"
2070
+ ] }) : null,
2071
+ /* @__PURE__ */ jsxRuntimeExports.jsx(Button, { variant: "ghost", size: "icon", onClick: toggleRightSidebar, "aria-label": rightOpen ? "Hide right sidebar" : "Show right sidebar", className: "text-muted-foreground hover:bg-background/65 hover:text-foreground size-8 border-0", children: rightOpen ? /* @__PURE__ */ jsxRuntimeExports.jsx(PanelRightClose, {}) : /* @__PURE__ */ jsxRuntimeExports.jsx(PanelRightOpen, {}) })
2072
+ ] })
2073
+ ] }),
2074
+ saveError ? /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-destructive/90 pt-2 text-xs", children: saveError }) : null,
2075
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex min-h-0 flex-1 overflow-hidden pt-1", children: /* @__PURE__ */ jsxRuntimeExports.jsx(Editor, {}) })
2076
+ ] }) }),
2077
+ /* @__PURE__ */ jsxRuntimeExports.jsx(ResizableHandle, { withHandle: true, className: cn(rightOpen ? "mx-1 w-2 bg-transparent" : "mx-0 w-0", !rightOpen && "pointer-events-none opacity-0") }),
2078
+ /* @__PURE__ */ jsxRuntimeExports.jsx(ResizablePanel, { id: "editor-right-sidebar", panelRef: rightPanelRef, collapsible: true, collapsedSize: 0, defaultSize: "18rem", minSize: "14rem", maxSize: "30rem", className: "min-w-0", children: /* @__PURE__ */ jsxRuntimeExports.jsx("aside", { className: "bg-background/55 flex h-full flex-col overflow-hidden rounded-xl px-2.5 py-3 backdrop-blur-sm", children: /* @__PURE__ */ jsxRuntimeExports.jsx(RightSidebar, { selectedCollection, selectedFile }) }) })
2079
+ ] }) });
2080
+ }
2081
+ export {
2082
+ App as component
2083
+ };