@kyro-cms/admin 0.1.2 → 0.1.3

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 (58) hide show
  1. package/package.json +17 -6
  2. package/src/components/Admin.tsx +50 -1
  3. package/src/components/LoginPage.tsx +223 -0
  4. package/src/components/layout/Sidebar.tsx +35 -0
  5. package/src/index.ts +35 -0
  6. package/src/middleware.ts +2 -0
  7. package/src/pages/api/auth/register.ts +133 -0
  8. package/src/styles/main.css +148 -0
  9. package/.astro/content.d.ts +0 -154
  10. package/.astro/settings.json +0 -5
  11. package/.astro/types.d.ts +0 -2
  12. package/astro.config.mjs +0 -28
  13. package/bun.lock +0 -1374
  14. package/dist/client/_astro/AdminLayout.DkDpng53.css +0 -1
  15. package/dist/client/_astro/AutoForm.3eJCmCJp.js +0 -1
  16. package/dist/client/_astro/client.DyczpTbx.js +0 -9
  17. package/dist/client/_astro/index.B02hbnpo.js +0 -1
  18. package/dist/client/fonts/Serotiva-Black.woff2 +0 -0
  19. package/dist/client/fonts/Serotiva-Bold.woff2 +0 -0
  20. package/dist/client/fonts/Serotiva-Medium.woff2 +0 -0
  21. package/dist/client/fonts/Serotiva-Regular.woff2 +0 -0
  22. package/dist/client/fonts/Serotiva-SemiBold.woff2 +0 -0
  23. package/dist/server/chunks/AdminLayout_D-_JeUqC.mjs +0 -26
  24. package/dist/server/chunks/_id__BzI_o0qT.mjs +0 -50
  25. package/dist/server/chunks/_id__Cd-jOuY3.mjs +0 -238
  26. package/dist/server/chunks/_id__DvbD--iR.mjs +0 -992
  27. package/dist/server/chunks/_id__vpVaEo16.mjs +0 -128
  28. package/dist/server/chunks/_virtual_astro_server-island-manifest_CQQ1F5PF.mjs +0 -7
  29. package/dist/server/chunks/_virtual_astro_session-driver_Bk3Q189E.mjs +0 -4
  30. package/dist/server/chunks/astro-component_Dbx3T2Nh.mjs +0 -37
  31. package/dist/server/chunks/audit-logs_DrnUMRvY.mjs +0 -74
  32. package/dist/server/chunks/config_CPXslElD.mjs +0 -4221
  33. package/dist/server/chunks/dataStore_Dl7cA2Qp.mjs +0 -89
  34. package/dist/server/chunks/index_CVqOkerS.mjs +0 -2960
  35. package/dist/server/chunks/index_CX8SQ4BF.mjs +0 -55
  36. package/dist/server/chunks/index_CYofDU51.mjs +0 -58
  37. package/dist/server/chunks/index_DdNRhuaM.mjs +0 -55
  38. package/dist/server/chunks/index_DupPvtIF.mjs +0 -42
  39. package/dist/server/chunks/index_YTS_M-B9.mjs +0 -263
  40. package/dist/server/chunks/index_YeCzuVps.mjs +0 -53
  41. package/dist/server/chunks/login_DLyqMRO8.mjs +0 -93
  42. package/dist/server/chunks/logout_CSbt5wea.mjs +0 -50
  43. package/dist/server/chunks/me_C04jlYhH.mjs +0 -41
  44. package/dist/server/chunks/new_BbQ9b55M.mjs +0 -92
  45. package/dist/server/chunks/node_9bvTewss.mjs +0 -1014
  46. package/dist/server/chunks/noop-entrypoint_BOlrdqWF.mjs +0 -3
  47. package/dist/server/chunks/sequence_9cl7AJy-.mjs +0 -2503
  48. package/dist/server/chunks/server_peBx9VXG.mjs +0 -8117
  49. package/dist/server/chunks/sharp_pmJ7nHES.mjs +0 -142
  50. package/dist/server/chunks/users_Dzddy_YR.mjs +0 -137
  51. package/dist/server/entry.mjs +0 -5
  52. package/dist/server/virtual_astro_middleware.mjs +0 -48
  53. package/public/fonts/Serotiva-Black.woff2 +0 -0
  54. package/public/fonts/Serotiva-Bold.woff2 +0 -0
  55. package/public/fonts/Serotiva-Medium.woff2 +0 -0
  56. package/public/fonts/Serotiva-Regular.woff2 +0 -0
  57. package/public/fonts/Serotiva-SemiBold.woff2 +0 -0
  58. package/tsconfig.json +0 -12
@@ -1,992 +0,0 @@
1
- import { c as createComponent } from './astro-component_Dbx3T2Nh.mjs';
2
- import 'piccolore';
3
- import { Q as renderTemplate, bb as defineScriptVars, a3 as addAttribute, B as maybeRenderHead } from './sequence_9cl7AJy-.mjs';
4
- import { r as renderComponent } from './server_peBx9VXG.mjs';
5
- import { $ as $$AdminLayout } from './AdminLayout_D-_JeUqC.mjs';
6
- import { c as collections } from './config_CPXslElD.mjs';
7
- import { jsx, jsxs } from 'react/jsx-runtime';
8
- import { useRef, useState, useEffect } from 'react';
9
-
10
- function AutoForm({
11
- config,
12
- data = {},
13
- errors = {},
14
- onChange,
15
- disabled
16
- }) {
17
- const handleFieldChange = (fieldName, value) => {
18
- onChange?.({
19
- ...data,
20
- [fieldName]: value
21
- });
22
- };
23
- const renderField = (field, parentData) => {
24
- if (field.admin?.hidden) return null;
25
- const value = parentData !== void 0 ? parentData[field.name] : data[field.name];
26
- const error = errors[field.name];
27
- if (field.type === "row" && "fields" in field) {
28
- return /* @__PURE__ */ jsx(
29
- "div",
30
- {
31
- className: "kyro-form-row",
32
- children: field.fields.map((f) => renderField(f, parentData))
33
- },
34
- field.name || `row-${Math.random()}`
35
- );
36
- }
37
- if (field.type === "collapsible" && "fields" in field) {
38
- return /* @__PURE__ */ jsxs(
39
- "details",
40
- {
41
- className: "kyro-form-collapsible",
42
- children: [
43
- /* @__PURE__ */ jsxs("summary", { className: "kyro-form-collapsible-header", children: [
44
- /* @__PURE__ */ jsx(
45
- "svg",
46
- {
47
- width: "16",
48
- height: "16",
49
- viewBox: "0 0 24 24",
50
- fill: "none",
51
- stroke: "currentColor",
52
- strokeWidth: "2",
53
- children: /* @__PURE__ */ jsx("path", { d: "M9 18l6-6-6-6" })
54
- }
55
- ),
56
- field.label
57
- ] }),
58
- /* @__PURE__ */ jsx("div", { className: "kyro-form-collapsible-content", children: field.fields.map(
59
- (f) => renderField(f, parentData)
60
- ) })
61
- ]
62
- },
63
- field.name || `collapsible-${Math.random()}`
64
- );
65
- }
66
- if (field.type === "tabs" && "tabs" in field) {
67
- return /* @__PURE__ */ jsx(
68
- "div",
69
- {
70
- className: "kyro-form-tabs",
71
- children: field.tabs.map((tab, index) => /* @__PURE__ */ jsxs("div", { className: "kyro-form-tab", children: [
72
- /* @__PURE__ */ jsx("h3", { className: "kyro-form-tab-title", children: tab.label }),
73
- /* @__PURE__ */ jsx("div", { className: "kyro-form-tab-content", children: tab.fields.map((f) => renderField(f, parentData)) })
74
- ] }, index))
75
- },
76
- field.name || `tabs-${Math.random()}`
77
- );
78
- }
79
- switch (field.type) {
80
- case "text":
81
- case "email":
82
- return /* @__PURE__ */ jsxs("div", { className: "kyro-form-field", children: [
83
- /* @__PURE__ */ jsxs("label", { className: "kyro-form-label", children: [
84
- field.label || field.name,
85
- field.required && /* @__PURE__ */ jsx("span", { className: "kyro-form-label-required", children: "*" })
86
- ] }),
87
- /* @__PURE__ */ jsx(
88
- "input",
89
- {
90
- type: field.type === "email" ? "email" : field.variant === "url" ? "url" : "text",
91
- className: `kyro-form-input ${error ? "kyro-form-input-error" : ""}`,
92
- value: value || "",
93
- onChange: (e) => handleFieldChange(field.name, e.target.value),
94
- disabled,
95
- placeholder: `Enter ${field.label || field.name}`,
96
- minLength: field.minLength,
97
- maxLength: field.maxLength
98
- }
99
- ),
100
- field.admin?.description && !error && /* @__PURE__ */ jsx("p", { className: "kyro-form-help", children: field.admin.description }),
101
- error && /* @__PURE__ */ jsx("p", { className: "kyro-form-error", children: error })
102
- ] }, field.name);
103
- case "password":
104
- return /* @__PURE__ */ jsxs("div", { className: "kyro-form-field", children: [
105
- /* @__PURE__ */ jsxs("label", { className: "kyro-form-label", children: [
106
- field.label || field.name,
107
- field.required && /* @__PURE__ */ jsx("span", { className: "kyro-form-label-required", children: "*" })
108
- ] }),
109
- /* @__PURE__ */ jsx(
110
- "input",
111
- {
112
- type: "password",
113
- className: `kyro-form-input ${error ? "kyro-form-input-error" : ""}`,
114
- value: value || "",
115
- onChange: (e) => handleFieldChange(field.name, e.target.value),
116
- disabled,
117
- placeholder: `Enter ${field.label || field.name}`
118
- }
119
- ),
120
- error && /* @__PURE__ */ jsx("p", { className: "kyro-form-error", children: error })
121
- ] }, field.name);
122
- case "textarea":
123
- return /* @__PURE__ */ jsxs("div", { className: "kyro-form-field", children: [
124
- /* @__PURE__ */ jsxs("label", { className: "kyro-form-label", children: [
125
- field.label || field.name,
126
- field.required && /* @__PURE__ */ jsx("span", { className: "kyro-form-label-required", children: "*" })
127
- ] }),
128
- /* @__PURE__ */ jsx(
129
- "textarea",
130
- {
131
- className: `kyro-form-input kyro-form-textarea ${error ? "kyro-form-input-error" : ""}`,
132
- value: value || "",
133
- onChange: (e) => handleFieldChange(field.name, e.target.value),
134
- disabled,
135
- rows: field.rows || 4,
136
- placeholder: `Enter ${field.label || field.name}`
137
- }
138
- ),
139
- field.admin?.description && !error && /* @__PURE__ */ jsx("p", { className: "kyro-form-help", children: field.admin.description }),
140
- error && /* @__PURE__ */ jsx("p", { className: "kyro-form-error", children: error })
141
- ] }, field.name);
142
- case "number":
143
- return /* @__PURE__ */ jsxs("div", { className: "kyro-form-field", children: [
144
- /* @__PURE__ */ jsxs("label", { className: "kyro-form-label", children: [
145
- field.label || field.name,
146
- field.required && /* @__PURE__ */ jsx("span", { className: "kyro-form-label-required", children: "*" })
147
- ] }),
148
- /* @__PURE__ */ jsx(
149
- "input",
150
- {
151
- type: "number",
152
- className: `kyro-form-input kyro-form-number ${error ? "kyro-form-input-error" : ""}`,
153
- value: value ?? "",
154
- onChange: (e) => handleFieldChange(field.name, parseFloat(e.target.value) || 0),
155
- disabled,
156
- placeholder: "0",
157
- min: field.min,
158
- max: field.max,
159
- step: field.step || "any"
160
- }
161
- ),
162
- field.admin?.description && !error && /* @__PURE__ */ jsx("p", { className: "kyro-form-help", children: field.admin.description }),
163
- error && /* @__PURE__ */ jsx("p", { className: "kyro-form-error", children: error })
164
- ] }, field.name);
165
- case "checkbox":
166
- return /* @__PURE__ */ jsxs("div", { className: "kyro-form-field", children: [
167
- /* @__PURE__ */ jsxs("label", { className: "kyro-form-checkbox", children: [
168
- /* @__PURE__ */ jsx(
169
- "input",
170
- {
171
- type: "checkbox",
172
- checked: value || false,
173
- onChange: (e) => handleFieldChange(field.name, e.target.checked),
174
- disabled
175
- }
176
- ),
177
- /* @__PURE__ */ jsx("span", { className: "kyro-form-checkbox-label", children: field.label || field.name })
178
- ] }),
179
- field.admin?.description && /* @__PURE__ */ jsx("p", { className: "kyro-form-help", children: field.admin.description })
180
- ] }, field.name);
181
- case "date":
182
- return /* @__PURE__ */ jsxs("div", { className: "kyro-form-field", children: [
183
- /* @__PURE__ */ jsxs("label", { className: "kyro-form-label", children: [
184
- field.label || field.name,
185
- field.required && /* @__PURE__ */ jsx("span", { className: "kyro-form-label-required", children: "*" })
186
- ] }),
187
- /* @__PURE__ */ jsx(
188
- "input",
189
- {
190
- type: "date",
191
- className: `kyro-form-input ${error ? "kyro-form-input-error" : ""}`,
192
- value: value ? new Date(value).toISOString().split("T")[0] : "",
193
- onChange: (e) => handleFieldChange(
194
- field.name,
195
- e.target.value ? new Date(e.target.value) : null
196
- ),
197
- disabled
198
- }
199
- ),
200
- error && /* @__PURE__ */ jsx("p", { className: "kyro-form-error", children: error })
201
- ] }, field.name);
202
- case "select":
203
- return /* @__PURE__ */ jsxs("div", { className: "kyro-form-field", children: [
204
- /* @__PURE__ */ jsxs("label", { className: "kyro-form-label", children: [
205
- field.label || field.name,
206
- field.required && /* @__PURE__ */ jsx("span", { className: "kyro-form-label-required", children: "*" })
207
- ] }),
208
- /* @__PURE__ */ jsxs(
209
- "select",
210
- {
211
- className: `kyro-form-input kyro-form-select ${error ? "kyro-form-input-error" : ""}`,
212
- value: value || "",
213
- onChange: (e) => handleFieldChange(field.name, e.target.value),
214
- disabled,
215
- children: [
216
- /* @__PURE__ */ jsxs("option", { value: "", children: [
217
- "Select ",
218
- field.label || field.name
219
- ] }),
220
- field.options?.map((opt) => /* @__PURE__ */ jsx("option", { value: opt.value || opt, children: opt.label || opt }, opt.value || opt))
221
- ]
222
- }
223
- ),
224
- field.admin?.description && !error && /* @__PURE__ */ jsx("p", { className: "kyro-form-help", children: field.admin.description }),
225
- error && /* @__PURE__ */ jsx("p", { className: "kyro-form-error", children: error })
226
- ] }, field.name);
227
- case "radio":
228
- return /* @__PURE__ */ jsxs("div", { className: "kyro-form-field", children: [
229
- /* @__PURE__ */ jsxs("label", { className: "kyro-form-label", children: [
230
- field.label || field.name,
231
- field.required && /* @__PURE__ */ jsx("span", { className: "kyro-form-label-required", children: "*" })
232
- ] }),
233
- /* @__PURE__ */ jsx("div", { className: "kyro-form-radio-group", children: field.options?.map((opt) => /* @__PURE__ */ jsxs("label", { className: "kyro-form-radio", children: [
234
- /* @__PURE__ */ jsx(
235
- "input",
236
- {
237
- type: "radio",
238
- name: field.name,
239
- value: opt.value || opt,
240
- checked: value === (opt.value || opt),
241
- onChange: (e) => handleFieldChange(field.name, e.target.value),
242
- disabled
243
- }
244
- ),
245
- /* @__PURE__ */ jsx("span", { children: opt.label || opt })
246
- ] }, opt.value || opt)) }),
247
- error && /* @__PURE__ */ jsx("p", { className: "kyro-form-error", children: error })
248
- ] }, field.name);
249
- case "color":
250
- return /* @__PURE__ */ jsxs("div", { className: "kyro-form-field", children: [
251
- /* @__PURE__ */ jsxs("label", { className: "kyro-form-label", children: [
252
- field.label || field.name,
253
- field.required && /* @__PURE__ */ jsx("span", { className: "kyro-form-label-required", children: "*" })
254
- ] }),
255
- /* @__PURE__ */ jsxs("div", { className: "kyro-form-color-wrapper", children: [
256
- /* @__PURE__ */ jsx(
257
- "input",
258
- {
259
- type: "color",
260
- className: `kyro-form-color ${error ? "kyro-form-input-error" : ""}`,
261
- value: value || "#000000",
262
- onChange: (e) => handleFieldChange(field.name, e.target.value),
263
- disabled
264
- }
265
- ),
266
- /* @__PURE__ */ jsx("span", { className: "kyro-form-color-value", children: value || "#000000" })
267
- ] }),
268
- error && /* @__PURE__ */ jsx("p", { className: "kyro-form-error", children: error })
269
- ] }, field.name);
270
- case "json":
271
- return /* @__PURE__ */ jsxs("div", { className: "kyro-form-field", children: [
272
- /* @__PURE__ */ jsxs("label", { className: "kyro-form-label", children: [
273
- field.label || field.name,
274
- field.required && /* @__PURE__ */ jsx("span", { className: "kyro-form-label-required", children: "*" })
275
- ] }),
276
- /* @__PURE__ */ jsx(
277
- "textarea",
278
- {
279
- className: `kyro-form-input kyro-form-textarea kyro-form-code ${error ? "kyro-form-input-error" : ""}`,
280
- value: typeof value === "string" ? value : JSON.stringify(value || {}, null, 2),
281
- onChange: (e) => {
282
- try {
283
- handleFieldChange(field.name, JSON.parse(e.target.value));
284
- } catch {
285
- handleFieldChange(field.name, e.target.value);
286
- }
287
- },
288
- disabled,
289
- rows: 6,
290
- placeholder: '{"key": "value"}'
291
- }
292
- ),
293
- field.admin?.description && !error && /* @__PURE__ */ jsx("p", { className: "kyro-form-help", children: field.admin.description }),
294
- error && /* @__PURE__ */ jsx("p", { className: "kyro-form-error", children: error })
295
- ] }, field.name);
296
- case "markdown":
297
- return /* @__PURE__ */ jsxs("div", { className: "kyro-form-field", children: [
298
- /* @__PURE__ */ jsxs("label", { className: "kyro-form-label", children: [
299
- field.label || field.name,
300
- field.required && /* @__PURE__ */ jsx("span", { className: "kyro-form-label-required", children: "*" })
301
- ] }),
302
- /* @__PURE__ */ jsx(
303
- "textarea",
304
- {
305
- className: `kyro-form-input kyro-form-textarea ${error ? "kyro-form-input-error" : ""}`,
306
- value: value || "",
307
- onChange: (e) => handleFieldChange(field.name, e.target.value),
308
- disabled,
309
- rows: 8,
310
- placeholder: "Enter markdown content..."
311
- }
312
- ),
313
- field.admin?.description && !error && /* @__PURE__ */ jsx("p", { className: "kyro-form-help", children: field.admin.description }),
314
- error && /* @__PURE__ */ jsx("p", { className: "kyro-form-error", children: error })
315
- ] }, field.name);
316
- case "code":
317
- return /* @__PURE__ */ jsxs("div", { className: "kyro-form-field", children: [
318
- /* @__PURE__ */ jsxs("label", { className: "kyro-form-label", children: [
319
- field.label || field.name,
320
- field.required && /* @__PURE__ */ jsx("span", { className: "kyro-form-label-required", children: "*" })
321
- ] }),
322
- /* @__PURE__ */ jsx(
323
- "textarea",
324
- {
325
- className: `kyro-form-input kyro-form-textarea kyro-form-code ${error ? "kyro-form-input-error" : ""}`,
326
- value: value || "",
327
- onChange: (e) => handleFieldChange(field.name, e.target.value),
328
- disabled,
329
- rows: 8,
330
- placeholder: "Enter code..."
331
- }
332
- ),
333
- field.admin?.description && !error && /* @__PURE__ */ jsx("p", { className: "kyro-form-help", children: field.admin.description }),
334
- error && /* @__PURE__ */ jsx("p", { className: "kyro-form-error", children: error })
335
- ] }, field.name);
336
- case "group":
337
- if ("fields" in field) {
338
- const groupData = value || {};
339
- return /* @__PURE__ */ jsxs("div", { className: "kyro-form-group", children: [
340
- /* @__PURE__ */ jsx("h3", { className: "kyro-form-group-title", children: field.label || field.name }),
341
- /* @__PURE__ */ jsx("div", { className: "kyro-form-group-fields", children: field.fields.map(
342
- (f) => renderField(f, groupData)
343
- ) })
344
- ] }, field.name);
345
- }
346
- return null;
347
- case "array":
348
- if ("fields" in field) {
349
- const items = Array.isArray(value) ? value : [];
350
- const labels = field.labels || {
351
- singular: "Item",
352
- plural: "Items"
353
- };
354
- return /* @__PURE__ */ jsxs("div", { className: "kyro-form-field", children: [
355
- /* @__PURE__ */ jsx("label", { className: "kyro-form-label", children: field.label || field.name }),
356
- /* @__PURE__ */ jsxs("div", { className: "kyro-form-array", children: [
357
- items.length === 0 ? /* @__PURE__ */ jsxs("p", { className: "kyro-form-array-empty", children: [
358
- "No ",
359
- labels.plural.toLowerCase(),
360
- " yet"
361
- ] }) : items.map((item, index) => /* @__PURE__ */ jsxs("div", { className: "kyro-form-array-item", children: [
362
- /* @__PURE__ */ jsxs("div", { className: "kyro-form-array-item-header", children: [
363
- /* @__PURE__ */ jsx("span", { className: "kyro-form-array-item-number", children: index + 1 }),
364
- /* @__PURE__ */ jsx(
365
- "button",
366
- {
367
- type: "button",
368
- className: "kyro-form-array-item-remove",
369
- onClick: () => {
370
- const newItems = items.filter(
371
- (_, i) => i !== index
372
- );
373
- handleFieldChange(field.name, newItems);
374
- },
375
- disabled,
376
- children: /* @__PURE__ */ jsx(
377
- "svg",
378
- {
379
- width: "14",
380
- height: "14",
381
- viewBox: "0 0 24 24",
382
- fill: "none",
383
- stroke: "currentColor",
384
- strokeWidth: "2",
385
- children: /* @__PURE__ */ jsx("path", { d: "M18 6L6 18M6 6l12 12" })
386
- }
387
- )
388
- }
389
- )
390
- ] }),
391
- /* @__PURE__ */ jsx("div", { className: "kyro-form-array-item-fields", children: field.fields.map((f) => {
392
- const fieldKey = f.name;
393
- const subFieldValue = item[fieldKey];
394
- const handleSubFieldChange = (newValue) => {
395
- const newItem = { ...item, [fieldKey]: newValue };
396
- const newItems = [...items];
397
- newItems[index] = newItem;
398
- handleFieldChange(field.name, newItems);
399
- };
400
- return /* @__PURE__ */ jsxs("div", { className: "kyro-form-field", children: [
401
- /* @__PURE__ */ jsx("label", { className: "kyro-form-label", children: f.label || f.name }),
402
- renderSubField(
403
- f,
404
- subFieldValue,
405
- handleSubFieldChange,
406
- disabled
407
- )
408
- ] }, fieldKey);
409
- }) })
410
- ] }, index)),
411
- /* @__PURE__ */ jsxs(
412
- "button",
413
- {
414
- type: "button",
415
- className: "kyro-btn kyro-btn-secondary kyro-btn-sm",
416
- onClick: () => {
417
- const newItem = {};
418
- field.fields.forEach((f) => {
419
- if (f.defaultValue !== void 0) {
420
- newItem[f.name] = f.defaultValue;
421
- }
422
- });
423
- handleFieldChange(field.name, [...items, newItem]);
424
- },
425
- disabled,
426
- children: [
427
- /* @__PURE__ */ jsx(
428
- "svg",
429
- {
430
- width: "14",
431
- height: "14",
432
- viewBox: "0 0 24 24",
433
- fill: "none",
434
- stroke: "currentColor",
435
- strokeWidth: "2",
436
- children: /* @__PURE__ */ jsx("path", { d: "M12 5v14M5 12h14" })
437
- }
438
- ),
439
- "Add ",
440
- labels.singular
441
- ]
442
- }
443
- )
444
- ] })
445
- ] }, field.name);
446
- }
447
- return null;
448
- case "blocks":
449
- if ("blocks" in field) {
450
- const blocks = Array.isArray(value) ? value : [];
451
- const labels = field.labels || {
452
- plural: "Blocks"
453
- };
454
- return /* @__PURE__ */ jsxs("div", { className: "kyro-form-field", children: [
455
- /* @__PURE__ */ jsx("label", { className: "kyro-form-label", children: field.label || field.name }),
456
- /* @__PURE__ */ jsxs("div", { className: "kyro-form-blocks", children: [
457
- blocks.length === 0 ? /* @__PURE__ */ jsxs("p", { className: "kyro-form-blocks-empty", children: [
458
- "No ",
459
- labels.plural.toLowerCase(),
460
- " yet"
461
- ] }) : blocks.map((block, index) => /* @__PURE__ */ jsxs("div", { className: "kyro-form-block-item", children: [
462
- /* @__PURE__ */ jsxs("div", { className: "kyro-form-block-item-header", children: [
463
- /* @__PURE__ */ jsx("span", { className: "kyro-form-block-item-type", children: field.blocks.find(
464
- (b) => b.slug === block.blockType
465
- )?.label || block.blockType }),
466
- /* @__PURE__ */ jsxs("div", { className: "kyro-form-block-item-actions", children: [
467
- /* @__PURE__ */ jsx(
468
- "button",
469
- {
470
- type: "button",
471
- className: "kyro-form-block-item-move",
472
- onClick: () => {
473
- if (index > 0) {
474
- const newBlocks = [...blocks];
475
- [newBlocks[index - 1], newBlocks[index]] = [
476
- newBlocks[index],
477
- newBlocks[index - 1]
478
- ];
479
- handleFieldChange(field.name, newBlocks);
480
- }
481
- },
482
- disabled: disabled || index === 0,
483
- children: /* @__PURE__ */ jsx(
484
- "svg",
485
- {
486
- width: "14",
487
- height: "14",
488
- viewBox: "0 0 24 24",
489
- fill: "none",
490
- stroke: "currentColor",
491
- strokeWidth: "2",
492
- children: /* @__PURE__ */ jsx("path", { d: "M18 15l-6-6-6 6" })
493
- }
494
- )
495
- }
496
- ),
497
- /* @__PURE__ */ jsx(
498
- "button",
499
- {
500
- type: "button",
501
- className: "kyro-form-block-item-remove",
502
- onClick: () => {
503
- const newBlocks = blocks.filter(
504
- (_, i) => i !== index
505
- );
506
- handleFieldChange(field.name, newBlocks);
507
- },
508
- disabled,
509
- children: /* @__PURE__ */ jsx(
510
- "svg",
511
- {
512
- width: "14",
513
- height: "14",
514
- viewBox: "0 0 24 24",
515
- fill: "none",
516
- stroke: "currentColor",
517
- strokeWidth: "2",
518
- children: /* @__PURE__ */ jsx("path", { d: "M18 6L6 18M6 6l12 12" })
519
- }
520
- )
521
- }
522
- )
523
- ] })
524
- ] }),
525
- /* @__PURE__ */ jsx("div", { className: "kyro-form-block-item-fields", children: field.blocks.find((b) => b.slug === block.blockType)?.fields?.map((f) => {
526
- if (!f.name) return null;
527
- const fieldKey = f.name;
528
- const blockData = block;
529
- const handleBlockFieldChange = (newValue) => {
530
- const newBlock = {
531
- ...blockData,
532
- [fieldKey]: newValue
533
- };
534
- const newBlocks = [...blocks];
535
- newBlocks[index] = newBlock;
536
- handleFieldChange(field.name, newBlocks);
537
- };
538
- return /* @__PURE__ */ jsxs("div", { className: "kyro-form-field", children: [
539
- /* @__PURE__ */ jsx("label", { className: "kyro-form-label", children: f.label || f.name }),
540
- renderSubField(
541
- f,
542
- block[fieldKey],
543
- handleBlockFieldChange,
544
- disabled
545
- )
546
- ] }, fieldKey);
547
- }) })
548
- ] }, index)),
549
- /* @__PURE__ */ jsxs("div", { className: "kyro-form-blocks-add", children: [
550
- /* @__PURE__ */ jsx("span", { className: "kyro-form-blocks-add-label", children: "Add block:" }),
551
- /* @__PURE__ */ jsx("div", { className: "kyro-form-blocks-add-buttons", children: field.blocks.map((block) => /* @__PURE__ */ jsx(
552
- "button",
553
- {
554
- type: "button",
555
- className: "kyro-btn kyro-btn-secondary kyro-btn-sm",
556
- onClick: () => {
557
- const newBlock = { blockType: block.slug };
558
- handleFieldChange(field.name, [...blocks, newBlock]);
559
- },
560
- disabled,
561
- children: block.label
562
- },
563
- block.slug
564
- )) })
565
- ] })
566
- ] })
567
- ] }, field.name);
568
- }
569
- return null;
570
- case "relationship":
571
- return /* @__PURE__ */ jsx(
572
- RelationshipField,
573
- {
574
- field,
575
- value,
576
- onChange: (newValue) => handleFieldChange(field.name, newValue),
577
- disabled,
578
- error
579
- },
580
- field.name
581
- );
582
- case "upload":
583
- return /* @__PURE__ */ jsx(
584
- UploadField,
585
- {
586
- field,
587
- value,
588
- onChange: (newValue) => handleFieldChange(field.name, newValue),
589
- disabled,
590
- error
591
- },
592
- field.name
593
- );
594
- case "richtext":
595
- return /* @__PURE__ */ jsxs("div", { className: "kyro-form-field", children: [
596
- /* @__PURE__ */ jsxs("label", { className: "kyro-form-label", children: [
597
- field.label || field.name,
598
- field.required && /* @__PURE__ */ jsx("span", { className: "kyro-form-label-required", children: "*" })
599
- ] }),
600
- /* @__PURE__ */ jsx(
601
- "textarea",
602
- {
603
- className: `kyro-form-input kyro-form-textarea kyro-form-richtext ${error ? "kyro-form-input-error" : ""}`,
604
- value: value || "",
605
- onChange: (e) => handleFieldChange(field.name, e.target.value),
606
- disabled,
607
- rows: 8,
608
- placeholder: "Enter rich text content..."
609
- }
610
- ),
611
- field.admin?.description && !error && /* @__PURE__ */ jsx("p", { className: "kyro-form-help", children: field.admin.description }),
612
- error && /* @__PURE__ */ jsx("p", { className: "kyro-form-error", children: error })
613
- ] }, field.name);
614
- default: {
615
- const anyField = field;
616
- return /* @__PURE__ */ jsx("div", { className: "kyro-form-field", children: /* @__PURE__ */ jsxs("span", { className: "kyro-form-unsupported", children: [
617
- "Unsupported field type: ",
618
- anyField.type
619
- ] }) }, anyField.name);
620
- }
621
- }
622
- };
623
- return /* @__PURE__ */ jsx("div", { className: "kyro-form", children: config.fields.map((field) => renderField(field)) });
624
- }
625
- function renderSubField(field, value, onChange, disabled) {
626
- switch (field.type) {
627
- case "text":
628
- case "email":
629
- case "password":
630
- return /* @__PURE__ */ jsx(
631
- "input",
632
- {
633
- type: field.type === "email" ? "email" : "text",
634
- className: "kyro-form-input",
635
- value: value || "",
636
- onChange: (e) => onChange(e.target.value),
637
- disabled
638
- }
639
- );
640
- case "number":
641
- return /* @__PURE__ */ jsx(
642
- "input",
643
- {
644
- type: "number",
645
- className: "kyro-form-input kyro-form-number",
646
- value: value ?? "",
647
- onChange: (e) => onChange(parseFloat(e.target.value) || 0),
648
- disabled
649
- }
650
- );
651
- case "checkbox":
652
- return /* @__PURE__ */ jsx(
653
- "input",
654
- {
655
- type: "checkbox",
656
- checked: value || false,
657
- onChange: (e) => onChange(e.target.checked),
658
- disabled
659
- }
660
- );
661
- case "textarea":
662
- return /* @__PURE__ */ jsx(
663
- "textarea",
664
- {
665
- className: "kyro-form-input kyro-form-textarea",
666
- value: value || "",
667
- onChange: (e) => onChange(e.target.value),
668
- disabled,
669
- rows: 3
670
- }
671
- );
672
- case "select":
673
- return /* @__PURE__ */ jsxs(
674
- "select",
675
- {
676
- className: "kyro-form-input kyro-form-select",
677
- value: value || "",
678
- onChange: (e) => onChange(e.target.value),
679
- disabled,
680
- children: [
681
- /* @__PURE__ */ jsx("option", { value: "", children: "Select..." }),
682
- field.options?.map((opt) => /* @__PURE__ */ jsx("option", { value: opt.value || opt, children: opt.label || opt }, opt.value || opt))
683
- ]
684
- }
685
- );
686
- default:
687
- return /* @__PURE__ */ jsx(
688
- "input",
689
- {
690
- type: "text",
691
- className: "kyro-form-input",
692
- value: value || "",
693
- onChange: (e) => onChange(e.target.value),
694
- disabled
695
- }
696
- );
697
- }
698
- }
699
- function UploadField({
700
- field,
701
- value,
702
- onChange,
703
- disabled,
704
- error
705
- }) {
706
- const inputRef = useRef(null);
707
- const [preview, setPreview] = useState(null);
708
- const [isDragging, setIsDragging] = useState(false);
709
- const isImage = (file) => file.type.startsWith("image/");
710
- const handleFile = (file) => {
711
- if (isImage(file)) {
712
- const reader = new FileReader();
713
- reader.onloadend = () => {
714
- setPreview(reader.result);
715
- };
716
- reader.readAsDataURL(file);
717
- }
718
- onChange({
719
- filename: file.name,
720
- size: file.size,
721
- type: file.type,
722
- url: URL.createObjectURL(file)
723
- });
724
- };
725
- const handleDrop = (e) => {
726
- e.preventDefault();
727
- setIsDragging(false);
728
- const file = e.dataTransfer.files[0];
729
- if (file) handleFile(file);
730
- };
731
- return /* @__PURE__ */ jsxs("div", { className: "kyro-form-field", children: [
732
- /* @__PURE__ */ jsxs("label", { className: "kyro-form-label", children: [
733
- field.label || field.name,
734
- field.required && /* @__PURE__ */ jsx("span", { className: "kyro-form-label-required", children: "*" })
735
- ] }),
736
- /* @__PURE__ */ jsxs(
737
- "div",
738
- {
739
- className: `kyro-form-upload ${isDragging ? "kyro-form-upload-dragging" : ""} ${error ? "kyro-form-upload-error" : ""}`,
740
- onDragOver: (e) => {
741
- e.preventDefault();
742
- setIsDragging(true);
743
- },
744
- onDragLeave: () => setIsDragging(false),
745
- onDrop: handleDrop,
746
- onClick: () => inputRef.current?.click(),
747
- children: [
748
- /* @__PURE__ */ jsx(
749
- "input",
750
- {
751
- ref: inputRef,
752
- type: "file",
753
- className: "kyro-form-upload-input",
754
- onChange: (e) => {
755
- const file = e.target.files?.[0];
756
- if (file) handleFile(file);
757
- },
758
- disabled,
759
- accept: field.mimeTypes?.join(",")
760
- }
761
- ),
762
- preview || value?.url ? /* @__PURE__ */ jsxs("div", { className: "kyro-form-upload-preview", children: [
763
- /* @__PURE__ */ jsx(
764
- "img",
765
- {
766
- src: preview || value.url,
767
- alt: "Preview",
768
- className: "kyro-form-upload-image"
769
- }
770
- ),
771
- /* @__PURE__ */ jsxs("div", { className: "kyro-form-upload-info", children: [
772
- /* @__PURE__ */ jsx("span", { className: "kyro-form-upload-filename", children: value?.filename || "Uploaded file" }),
773
- /* @__PURE__ */ jsx(
774
- "button",
775
- {
776
- type: "button",
777
- className: "kyro-form-upload-change",
778
- onClick: (e) => {
779
- e.stopPropagation();
780
- inputRef.current?.click();
781
- },
782
- children: "Change"
783
- }
784
- )
785
- ] })
786
- ] }) : /* @__PURE__ */ jsxs("div", { className: "kyro-form-upload-placeholder", children: [
787
- /* @__PURE__ */ jsxs(
788
- "svg",
789
- {
790
- width: "32",
791
- height: "32",
792
- viewBox: "0 0 24 24",
793
- fill: "none",
794
- stroke: "currentColor",
795
- strokeWidth: "1.5",
796
- children: [
797
- /* @__PURE__ */ jsx("path", { d: "M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4" }),
798
- /* @__PURE__ */ jsx("polyline", { points: "17,8 12,3 7,8" }),
799
- /* @__PURE__ */ jsx("line", { x1: "12", y1: "3", x2: "12", y2: "15" })
800
- ]
801
- }
802
- ),
803
- /* @__PURE__ */ jsx("span", { children: "Drop image here or click to upload" }),
804
- /* @__PURE__ */ jsx("span", { className: "kyro-form-upload-hint", children: "PNG, JPG, GIF up to 10MB" })
805
- ] })
806
- ]
807
- }
808
- ),
809
- field.admin?.description && !error && /* @__PURE__ */ jsx("p", { className: "kyro-form-help", children: field.admin.description }),
810
- error && /* @__PURE__ */ jsx("p", { className: "kyro-form-error", children: error })
811
- ] });
812
- }
813
- function RelationshipField({
814
- field,
815
- value,
816
- onChange,
817
- disabled,
818
- error
819
- }) {
820
- const [isOpen, setIsOpen] = useState(false);
821
- const [search, setSearch] = useState("");
822
- const [options, setOptions] = useState([]);
823
- const [loading, setLoading] = useState(false);
824
- const isMultiple = field.hasMany;
825
- const targetCollection = Array.isArray(field.relationTo) ? field.relationTo[0] : field.relationTo;
826
- useEffect(() => {
827
- if (isOpen) {
828
- setLoading(true);
829
- fetch(`/api/${targetCollection}?limit=50`).then((res) => res.json()).then((data) => {
830
- setOptions(data.docs || []);
831
- setLoading(false);
832
- }).catch((err) => {
833
- console.error("Failed to fetch relations:", err);
834
- setLoading(false);
835
- });
836
- }
837
- }, [isOpen, targetCollection]);
838
- const filteredOptions = options.filter((opt) => {
839
- const term = search.toLowerCase();
840
- const searchableFields = ["title", "name", "filename", "id", "slug"];
841
- return searchableFields.some(
842
- (key) => opt[key] && String(opt[key]).toLowerCase().includes(term)
843
- );
844
- });
845
- const getLabel = (opt) => {
846
- if (!opt) return "";
847
- return opt.title || opt.name || opt.filename || opt.slug || opt.id;
848
- };
849
- const isSelected = (optId) => {
850
- if (!value) return false;
851
- if (isMultiple) {
852
- return value.some((v) => (v.id || v) === optId);
853
- }
854
- return (value.id || value) === optId;
855
- };
856
- const toggleSelection = (opt) => {
857
- if (isMultiple) {
858
- const current = Array.isArray(value) ? value : [];
859
- if (isSelected(opt.id)) {
860
- onChange(current.filter((item) => (item.id || item) !== opt.id));
861
- } else {
862
- onChange([...current, opt.id]);
863
- }
864
- } else {
865
- if (isSelected(opt.id)) {
866
- onChange(null);
867
- } else {
868
- onChange(opt.id);
869
- setIsOpen(false);
870
- }
871
- }
872
- };
873
- return /* @__PURE__ */ jsxs("div", { className: "kyro-form-field", children: [
874
- /* @__PURE__ */ jsxs("label", { className: "kyro-form-label", children: [
875
- field.label || field.name,
876
- field.required && /* @__PURE__ */ jsx("span", { className: "kyro-form-label-required", children: "*" })
877
- ] }),
878
- /* @__PURE__ */ jsxs(
879
- "div",
880
- {
881
- className: "kyro-form-relationship",
882
- onClick: () => !disabled && setIsOpen(true),
883
- style: disabled ? { opacity: 0.5, cursor: "not-allowed" } : {},
884
- children: [
885
- /* @__PURE__ */ jsxs("div", { className: "kyro-form-relationship-header", children: [
886
- /* @__PURE__ */ jsx("span", { className: "kyro-form-relationship-type", children: targetCollection }),
887
- isMultiple && /* @__PURE__ */ jsx("span", { className: "kyro-form-relationship-badge", children: "Multiple" })
888
- ] }),
889
- /* @__PURE__ */ jsx("div", { className: "kyro-form-relationship-value", children: value ? isMultiple && Array.isArray(value) ? value.length > 0 ? `${value.length} items selected` : "None selected" : `Selected: ${getLabel(value) || value.id || value}` : /* @__PURE__ */ jsx("span", { className: "kyro-form-relationship-empty", children: "Click to search and select..." }) })
890
- ]
891
- }
892
- ),
893
- field.admin?.description && !error && /* @__PURE__ */ jsx("p", { className: "kyro-form-help", children: field.admin.description }),
894
- error && /* @__PURE__ */ jsx("p", { className: "kyro-form-error", children: error }),
895
- isOpen && /* @__PURE__ */ jsx("div", { className: "kyro-modal-overlay", onClick: () => setIsOpen(false), children: /* @__PURE__ */ jsxs(
896
- "div",
897
- {
898
- className: "kyro-relation-modal",
899
- onClick: (e) => e.stopPropagation(),
900
- children: [
901
- /* @__PURE__ */ jsxs("div", { className: "kyro-relation-modal-header", children: [
902
- /* @__PURE__ */ jsxs("h3", { children: [
903
- "Select ",
904
- field.label || field.name
905
- ] }),
906
- /* @__PURE__ */ jsx(
907
- "input",
908
- {
909
- type: "text",
910
- autoFocus: true,
911
- placeholder: `Search in ${targetCollection}...`,
912
- className: "kyro-relation-modal-search",
913
- value: search,
914
- onChange: (e) => setSearch(e.target.value)
915
- }
916
- )
917
- ] }),
918
- /* @__PURE__ */ jsx("div", { className: "kyro-relation-modal-list", children: loading ? /* @__PURE__ */ jsx("div", { className: "kyro-relation-modal-empty", children: "Loading..." }) : filteredOptions.length === 0 ? /* @__PURE__ */ jsx("div", { className: "kyro-relation-modal-empty", children: "No results found." }) : filteredOptions.map((opt) => /* @__PURE__ */ jsxs(
919
- "button",
920
- {
921
- type: "button",
922
- className: `kyro-relation-modal-item ${isSelected(opt.id) ? "selected" : ""}`,
923
- onClick: () => toggleSelection(opt),
924
- children: [
925
- /* @__PURE__ */ jsx("span", { children: getLabel(opt) }),
926
- /* @__PURE__ */ jsxs("span", { className: "kyro-relation-modal-item-id", children: [
927
- "(",
928
- opt.id.slice(0, 8),
929
- "...)"
930
- ] })
931
- ]
932
- },
933
- opt.id
934
- )) }),
935
- /* @__PURE__ */ jsx("div", { className: "kyro-relation-modal-footer", children: /* @__PURE__ */ jsx(
936
- "button",
937
- {
938
- type: "button",
939
- className: "kyro-btn kyro-btn-secondary kyro-btn-sm",
940
- onClick: () => setIsOpen(false),
941
- children: "Done"
942
- }
943
- ) })
944
- ]
945
- }
946
- ) })
947
- ] });
948
- }
949
-
950
- var __freeze = Object.freeze;
951
- var __defProp = Object.defineProperty;
952
- var __template = (cooked, raw) => __freeze(__defProp(cooked, "raw", { value: __freeze(raw || cooked.slice()) }));
953
- var _a;
954
- const $$id = createComponent(async ($$result, $$props, $$slots) => {
955
- const Astro2 = $$result.createAstro($$props, $$slots);
956
- Astro2.self = $$id;
957
- const { collection, id } = Astro2.params;
958
- if (!collection || !collections[collection]) {
959
- return Astro2.redirect("/");
960
- }
961
- const config = collections[collection];
962
- let doc = null;
963
- if (id && id !== "new") {
964
- try {
965
- const response = await fetch(`${Astro2.url.origin}/api/${collection}/${id}`);
966
- if (response.ok) {
967
- const result = await response.json();
968
- doc = result.data || null;
969
- }
970
- } catch (error) {
971
- console.error("Failed to fetch document:", error);
972
- }
973
- }
974
- const isNew = !doc;
975
- const title = isNew ? `Create ${config.singularLabel || config.label || collection}` : `Edit ${config.singularLabel || config.label || collection}`;
976
- const description = config.admin?.description || `Manage ${(config.label || collection || "").toLowerCase()} documents`;
977
- return renderTemplate`${renderComponent($$result, "AdminLayout", $$AdminLayout, { "title": title }, { "default": async ($$result2) => renderTemplate(_a || (_a = __template([" ", '<div class="flex-1 overflow-y-auto p-8 space-y-6"> <!-- Header --> <div class="surface-tile p-8 flex items-center justify-between"> <div class="flex items-center gap-4"> <a', ' class="inline-flex items-center justify-center w-10 h-10 rounded-xl border border-gray-200 text-[#64748b] hover:text-[#0b1222] hover:bg-gray-50 transition-colors"> <svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2.5" d="M15 19l-7-7 7-7"></path> </svg> </a> <div> <h1 class="text-2xl font-black tracking-tighter text-[#0b1222]">', '</h1> <p class="text-sm text-[#64748b] mt-0.5">', '</p> </div> </div> <div class="flex items-center gap-3"> <a', ' class="px-5 py-2.5 border border-gray-200 rounded-xl text-[#0b1222] font-bold text-sm hover:bg-gray-50 transition-colors">\nCancel\n</a> <button type="submit" form="doc-form" id="btn-save" class="px-6 py-2.5 bg-[#0b1222] text-white rounded-xl font-bold text-sm hover:bg-[#1a2332] transition-colors active:scale-95"> ', ` </button> </div> </div> <!-- Form Card --> <div class="surface-tile p-8"> <!-- Toast container --> <div id="toast-container" class="hidden fixed bottom-6 right-6 z-50"> <div class="flex items-center gap-3 px-5 py-4 bg-[#0b1222] text-white rounded-xl shadow-2xl"> <span id="toast-message"></span> <button onclick="document.getElementById('toast-container').classList.add('hidden')" class="text-white/50 hover:text-white ml-2"> <svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"></path></svg> </button> </div> </div> <form id="doc-form"> `, " </form> </div> <!-- Document Metadata (edit mode only) --> ", " </div> <script>(function(){", "\n function showToast(message, isError = false) {\n const container = document.getElementById('toast-container');\n const msg = document.getElementById('toast-message');\n if (container && msg) {\n msg.textContent = message;\n container.classList.remove('hidden');\n if (!isError) {\n setTimeout(() => container.classList.add('hidden'), 3000);\n }\n }\n }\n\n document.getElementById('doc-form')?.addEventListener('submit', async (e) => {\n e.preventDefault();\n \n const btn = document.getElementById('btn-save');\n const originalText = btn?.textContent || '';\n if (btn) {\n btn.textContent = 'Saving…';\n btn.setAttribute('disabled', 'true');\n }\n\n const formData = new FormData(e.target);\n const data = {};\n formData.forEach((value, key) => {\n data[key] = value;\n });\n\n const url = isNew ? `/api/${collection}` : `/api/${collection}/${id}`;\n const method = isNew ? 'POST' : 'PATCH';\n\n try {\n const response = await fetch(url, {\n method,\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(data),\n });\n\n if (response.ok) {\n showToast(isNew ? 'Document created successfully' : 'Changes saved');\n setTimeout(() => {\n window.location.href = `/${collection}`;\n }, 800);\n } else {\n const error = await response.json();\n showToast(error.error || 'An error occurred', true);\n }\n } catch (error) {\n showToast('Failed to save document', true);\n } finally {\n if (btn) {\n btn.textContent = originalText;\n btn.removeAttribute('disabled');\n }\n }\n });\n })();<\/script> "], [" ", '<div class="flex-1 overflow-y-auto p-8 space-y-6"> <!-- Header --> <div class="surface-tile p-8 flex items-center justify-between"> <div class="flex items-center gap-4"> <a', ' class="inline-flex items-center justify-center w-10 h-10 rounded-xl border border-gray-200 text-[#64748b] hover:text-[#0b1222] hover:bg-gray-50 transition-colors"> <svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2.5" d="M15 19l-7-7 7-7"></path> </svg> </a> <div> <h1 class="text-2xl font-black tracking-tighter text-[#0b1222]">', '</h1> <p class="text-sm text-[#64748b] mt-0.5">', '</p> </div> </div> <div class="flex items-center gap-3"> <a', ' class="px-5 py-2.5 border border-gray-200 rounded-xl text-[#0b1222] font-bold text-sm hover:bg-gray-50 transition-colors">\nCancel\n</a> <button type="submit" form="doc-form" id="btn-save" class="px-6 py-2.5 bg-[#0b1222] text-white rounded-xl font-bold text-sm hover:bg-[#1a2332] transition-colors active:scale-95"> ', ` </button> </div> </div> <!-- Form Card --> <div class="surface-tile p-8"> <!-- Toast container --> <div id="toast-container" class="hidden fixed bottom-6 right-6 z-50"> <div class="flex items-center gap-3 px-5 py-4 bg-[#0b1222] text-white rounded-xl shadow-2xl"> <span id="toast-message"></span> <button onclick="document.getElementById('toast-container').classList.add('hidden')" class="text-white/50 hover:text-white ml-2"> <svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"></path></svg> </button> </div> </div> <form id="doc-form"> `, " </form> </div> <!-- Document Metadata (edit mode only) --> ", " </div> <script>(function(){", "\n function showToast(message, isError = false) {\n const container = document.getElementById('toast-container');\n const msg = document.getElementById('toast-message');\n if (container && msg) {\n msg.textContent = message;\n container.classList.remove('hidden');\n if (!isError) {\n setTimeout(() => container.classList.add('hidden'), 3000);\n }\n }\n }\n\n document.getElementById('doc-form')?.addEventListener('submit', async (e) => {\n e.preventDefault();\n \n const btn = document.getElementById('btn-save');\n const originalText = btn?.textContent || '';\n if (btn) {\n btn.textContent = 'Saving…';\n btn.setAttribute('disabled', 'true');\n }\n\n const formData = new FormData(e.target);\n const data = {};\n formData.forEach((value, key) => {\n data[key] = value;\n });\n\n const url = isNew ? \\`/api/\\${collection}\\` : \\`/api/\\${collection}/\\${id}\\`;\n const method = isNew ? 'POST' : 'PATCH';\n\n try {\n const response = await fetch(url, {\n method,\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(data),\n });\n\n if (response.ok) {\n showToast(isNew ? 'Document created successfully' : 'Changes saved');\n setTimeout(() => {\n window.location.href = \\`/\\${collection}\\`;\n }, 800);\n } else {\n const error = await response.json();\n showToast(error.error || 'An error occurred', true);\n }\n } catch (error) {\n showToast('Failed to save document', true);\n } finally {\n if (btn) {\n btn.textContent = originalText;\n btn.removeAttribute('disabled');\n }\n }\n });\n })();<\/script> "])), maybeRenderHead(), addAttribute(`/${collection}`, "href"), title, description, addAttribute(`/${collection}`, "href"), isNew ? "Create" : "Save Changes", renderComponent($$result2, "AutoForm", AutoForm, { "client:load": true, "config": config, "data": doc || {}, "collectionSlug": collection, "client:component-hydration": "load", "client:component-path": "@/components/AutoForm", "client:component-export": "AutoForm" }), !isNew && doc && renderTemplate`<div class="surface-tile p-8"> <h3 class="text-xs font-bold text-[#64748b] uppercase tracking-[0.2em] mb-4">Document Info</h3> <div class="grid grid-cols-2 md:grid-cols-4 gap-6"> <div> <p class="text-[10px] font-bold text-[#9ca3af] uppercase tracking-widest mb-1">ID</p> <p class="text-sm text-[#0b1222] font-mono">${doc.id?.slice(0, 12)}…</p> </div> ${doc.createdAt && renderTemplate`<div> <p class="text-[10px] font-bold text-[#9ca3af] uppercase tracking-widest mb-1">Created</p> <p class="text-sm text-[#0b1222]">${new Date(doc.createdAt).toLocaleDateString("en-US", { month: "short", day: "numeric", year: "numeric" })}</p> </div>`} ${doc.updatedAt && renderTemplate`<div> <p class="text-[10px] font-bold text-[#9ca3af] uppercase tracking-widest mb-1">Updated</p> <p class="text-sm text-[#0b1222]">${new Date(doc.updatedAt).toLocaleDateString("en-US", { month: "short", day: "numeric", year: "numeric" })}</p> </div>`} </div> </div>`, defineScriptVars({ collection, id, isNew })) })}`;
978
- }, "/Users/macbook/Dev/Web/Astro/kyro-cms/admin/src/pages/[collection]/[id].astro", void 0);
979
-
980
- const $$file = "/Users/macbook/Dev/Web/Astro/kyro-cms/admin/src/pages/[collection]/[id].astro";
981
- const $$url = "/[collection]/[id]";
982
-
983
- const _page = /*#__PURE__*/Object.freeze(/*#__PURE__*/Object.defineProperty({
984
- __proto__: null,
985
- default: $$id,
986
- file: $$file,
987
- url: $$url
988
- }, Symbol.toStringTag, { value: 'Module' }));
989
-
990
- const page = () => _page;
991
-
992
- export { page };