@orion-studios/payload-studio 0.3.0-beta.0

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 (55) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +47 -0
  3. package/dist/OrionBlocksFieldImpl-QX5GTMQZ.mjs +904 -0
  4. package/dist/admin/client.d.mts +110 -0
  5. package/dist/admin/client.d.ts +110 -0
  6. package/dist/admin/client.js +2853 -0
  7. package/dist/admin/client.mjs +1672 -0
  8. package/dist/admin/index.d.mts +2 -0
  9. package/dist/admin/index.d.ts +2 -0
  10. package/dist/admin/index.js +324 -0
  11. package/dist/admin/index.mjs +13 -0
  12. package/dist/admin.css +327 -0
  13. package/dist/blocks/index.d.mts +3 -0
  14. package/dist/blocks/index.d.ts +3 -0
  15. package/dist/blocks/index.js +844 -0
  16. package/dist/blocks/index.mjs +35 -0
  17. package/dist/chunk-6BWS3CLP.mjs +16 -0
  18. package/dist/chunk-BVN5HKTM.mjs +299 -0
  19. package/dist/chunk-L62FYT57.mjs +829 -0
  20. package/dist/chunk-PGLMIFRY.mjs +209 -0
  21. package/dist/chunk-Q76U4Z53.mjs +249 -0
  22. package/dist/chunk-WLXZDMK3.mjs +154 -0
  23. package/dist/chunk-ZLLNO5FM.mjs +229 -0
  24. package/dist/index-B-5K41Km.d.mts +71 -0
  25. package/dist/index-B-5K41Km.d.ts +71 -0
  26. package/dist/index-BgQSKQKb.d.mts +149 -0
  27. package/dist/index-BgQSKQKb.d.ts +149 -0
  28. package/dist/index-CITGmLG_.d.mts +81 -0
  29. package/dist/index-CITGmLG_.d.ts +81 -0
  30. package/dist/index-DhH3ERbg.d.ts +39 -0
  31. package/dist/index-DtQ0tph5.d.mts +39 -0
  32. package/dist/index-FA2Ep5rj.d.mts +129 -0
  33. package/dist/index-FA2Ep5rj.d.ts +129 -0
  34. package/dist/index.d.mts +7 -0
  35. package/dist/index.d.ts +7 -0
  36. package/dist/index.js +1735 -0
  37. package/dist/index.mjs +23 -0
  38. package/dist/nextjs/index.d.mts +2 -0
  39. package/dist/nextjs/index.d.ts +2 -0
  40. package/dist/nextjs/index.js +244 -0
  41. package/dist/nextjs/index.mjs +15 -0
  42. package/dist/studio/index.d.mts +1 -0
  43. package/dist/studio/index.d.ts +1 -0
  44. package/dist/studio/index.js +169 -0
  45. package/dist/studio/index.mjs +17 -0
  46. package/dist/studio-pages/builder.css +260 -0
  47. package/dist/studio-pages/client.d.mts +23 -0
  48. package/dist/studio-pages/client.d.ts +23 -0
  49. package/dist/studio-pages/client.js +1938 -0
  50. package/dist/studio-pages/client.mjs +1909 -0
  51. package/dist/studio-pages/index.d.mts +2 -0
  52. package/dist/studio-pages/index.d.ts +2 -0
  53. package/dist/studio-pages/index.js +264 -0
  54. package/dist/studio-pages/index.mjs +19 -0
  55. package/package.json +87 -0
@@ -0,0 +1,2853 @@
1
+ 'use client';
2
+ "use strict";
3
+ "use client";
4
+ var __defProp = Object.defineProperty;
5
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
6
+ var __getOwnPropNames = Object.getOwnPropertyNames;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __esm = (fn, res) => function __init() {
9
+ return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
10
+ };
11
+ var __export = (target, all) => {
12
+ for (var name in all)
13
+ __defProp(target, name, { get: all[name], enumerable: true });
14
+ };
15
+ var __copyProps = (to, from, except, desc) => {
16
+ if (from && typeof from === "object" || typeof from === "function") {
17
+ for (let key of __getOwnPropNames(from))
18
+ if (!__hasOwnProp.call(to, key) && key !== except)
19
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
20
+ }
21
+ return to;
22
+ };
23
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
24
+
25
+ // src/admin/components/BlockPicker.tsx
26
+ function BlockPicker({
27
+ blocks,
28
+ onSelect
29
+ }) {
30
+ const [searchQuery, setSearchQuery] = (0, import_react5.useState)("");
31
+ const filtered = blocks.filter(
32
+ (b) => b.label.toLowerCase().includes(searchQuery.toLowerCase()) || b.slug.toLowerCase().includes(searchQuery.toLowerCase()) || b.description && b.description.toLowerCase().includes(searchQuery.toLowerCase())
33
+ );
34
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { style: { display: "flex", flexDirection: "column", gap: 16 }, children: [
35
+ blocks.length > 4 && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
36
+ "input",
37
+ {
38
+ type: "text",
39
+ placeholder: "Search sections...",
40
+ value: searchQuery,
41
+ onChange: (e) => setSearchQuery(e.target.value),
42
+ style: {
43
+ padding: "10px 14px",
44
+ border: "1px solid var(--admin-input-border)",
45
+ borderRadius: "var(--admin-radius-md)",
46
+ background: "var(--admin-input-bg)",
47
+ color: "var(--admin-text)",
48
+ fontSize: 14,
49
+ outline: "none",
50
+ width: "100%",
51
+ boxSizing: "border-box"
52
+ }
53
+ }
54
+ ),
55
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
56
+ "div",
57
+ {
58
+ style: {
59
+ display: "grid",
60
+ gridTemplateColumns: "repeat(auto-fill, minmax(180px, 1fr))",
61
+ gap: 12
62
+ },
63
+ children: filtered.map((block) => /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
64
+ "button",
65
+ {
66
+ type: "button",
67
+ onClick: () => onSelect(block.slug),
68
+ style: {
69
+ display: "flex",
70
+ flexDirection: "column",
71
+ alignItems: "center",
72
+ gap: 10,
73
+ padding: 16,
74
+ background: "var(--admin-card-bg)",
75
+ border: "1px solid var(--admin-card-border)",
76
+ borderRadius: "var(--admin-radius-lg)",
77
+ cursor: "pointer",
78
+ transition: "all 0.2s ease",
79
+ textAlign: "center"
80
+ },
81
+ onMouseEnter: (e) => {
82
+ e.currentTarget.style.borderColor = "var(--admin-accent)";
83
+ e.currentTarget.style.boxShadow = "var(--admin-card-shadow-hover)";
84
+ e.currentTarget.style.transform = "translateY(-2px)";
85
+ },
86
+ onMouseLeave: (e) => {
87
+ e.currentTarget.style.borderColor = "var(--admin-card-border)";
88
+ e.currentTarget.style.boxShadow = "none";
89
+ e.currentTarget.style.transform = "translateY(0)";
90
+ },
91
+ children: [
92
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
93
+ "div",
94
+ {
95
+ style: {
96
+ width: 48,
97
+ height: 48,
98
+ borderRadius: "var(--admin-radius-md)",
99
+ background: "var(--admin-accent-subtle)",
100
+ color: "var(--admin-accent)",
101
+ display: "flex",
102
+ alignItems: "center",
103
+ justifyContent: "center",
104
+ fontSize: 24,
105
+ overflow: "hidden"
106
+ },
107
+ children: block.imageURL ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
108
+ "img",
109
+ {
110
+ src: block.imageURL,
111
+ alt: block.label,
112
+ style: { width: "100%", height: "100%", objectFit: "cover" }
113
+ }
114
+ ) : block.icon ? block.icon : /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(BlockDefaultIcon, {})
115
+ }
116
+ ),
117
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
118
+ "span",
119
+ {
120
+ style: {
121
+ fontSize: 13,
122
+ fontWeight: 600,
123
+ color: "var(--admin-text)",
124
+ lineHeight: 1.3
125
+ },
126
+ children: block.label
127
+ }
128
+ ),
129
+ block.description && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
130
+ "span",
131
+ {
132
+ style: {
133
+ fontSize: 11,
134
+ color: "var(--admin-text-muted)",
135
+ lineHeight: 1.4
136
+ },
137
+ children: block.description
138
+ }
139
+ )
140
+ ]
141
+ },
142
+ block.slug
143
+ ))
144
+ }
145
+ ),
146
+ filtered.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("p", { style: { textAlign: "center", color: "var(--admin-text-muted)", fontSize: 14, padding: 20 }, children: "No sections match your search." })
147
+ ] });
148
+ }
149
+ function BlockDefaultIcon() {
150
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("svg", { width: 24, height: 24, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 1.5, strokeLinecap: "round", strokeLinejoin: "round", children: [
151
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("rect", { x: "3", y: "3", width: "7", height: "7" }),
152
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("rect", { x: "14", y: "3", width: "7", height: "7" }),
153
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("rect", { x: "14", y: "14", width: "7", height: "7" }),
154
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("rect", { x: "3", y: "14", width: "7", height: "7" })
155
+ ] });
156
+ }
157
+ var import_react5, import_jsx_runtime8;
158
+ var init_BlockPicker = __esm({
159
+ "src/admin/components/BlockPicker.tsx"() {
160
+ "use strict";
161
+ "use client";
162
+ import_react5 = require("react");
163
+ import_jsx_runtime8 = require("react/jsx-runtime");
164
+ }
165
+ });
166
+
167
+ // src/admin/components/SectionTabs.tsx
168
+ function SectionTabs({
169
+ tabs,
170
+ defaultTab = 0
171
+ }) {
172
+ const [activeTab, setActiveTab] = (0, import_react6.useState)(defaultTab);
173
+ if (tabs.length === 0) return null;
174
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
175
+ "div",
176
+ {
177
+ style: {
178
+ border: "1px solid var(--admin-border)",
179
+ borderRadius: "var(--admin-radius-lg)",
180
+ overflow: "hidden",
181
+ background: "var(--admin-card-bg)"
182
+ },
183
+ children: [
184
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
185
+ "div",
186
+ {
187
+ style: {
188
+ display: "flex",
189
+ borderBottom: "2px solid var(--admin-border)",
190
+ background: "var(--admin-surface)",
191
+ overflowX: "auto",
192
+ scrollbarWidth: "none"
193
+ },
194
+ children: tabs.map((tab, index) => {
195
+ const isActive = index === activeTab;
196
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
197
+ "button",
198
+ {
199
+ type: "button",
200
+ onClick: () => setActiveTab(index),
201
+ style: {
202
+ display: "flex",
203
+ alignItems: "center",
204
+ gap: 6,
205
+ padding: "12px 18px",
206
+ border: "none",
207
+ borderBottom: isActive ? "2px solid var(--admin-accent)" : "2px solid transparent",
208
+ marginBottom: -2,
209
+ background: "transparent",
210
+ color: isActive ? "var(--admin-accent)" : "var(--admin-text-muted)",
211
+ fontWeight: isActive ? 600 : 500,
212
+ fontSize: 13,
213
+ cursor: "pointer",
214
+ transition: "all 0.15s ease",
215
+ whiteSpace: "nowrap"
216
+ },
217
+ children: [
218
+ tab.icon && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { style: { display: "flex", opacity: isActive ? 1 : 0.6 }, children: tab.icon }),
219
+ tab.label
220
+ ]
221
+ },
222
+ index
223
+ );
224
+ })
225
+ }
226
+ ),
227
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { style: { padding: 20 }, children: tabs[activeTab]?.content })
228
+ ]
229
+ }
230
+ );
231
+ }
232
+ var import_react6, import_jsx_runtime9;
233
+ var init_SectionTabs = __esm({
234
+ "src/admin/components/SectionTabs.tsx"() {
235
+ "use strict";
236
+ "use client";
237
+ import_react6 = require("react");
238
+ import_jsx_runtime9 = require("react/jsx-runtime");
239
+ }
240
+ });
241
+
242
+ // src/admin/components/OrionBlocksDrawer.tsx
243
+ function normalizeLabel(label, i18n, fallback) {
244
+ if (typeof label === "string" && label.trim().length > 0) {
245
+ return label;
246
+ }
247
+ if (label && typeof label === "object") {
248
+ const translated = (0, import_translations.getTranslation)(label, i18n);
249
+ if (typeof translated === "string" && translated.trim().length > 0) {
250
+ return translated;
251
+ }
252
+ }
253
+ return fallback;
254
+ }
255
+ function getGroupLabel(block, i18n) {
256
+ const group = block.admin?.group;
257
+ return normalizeLabel(group, i18n, "Other");
258
+ }
259
+ function getBlockDescription(block) {
260
+ const custom = block.admin?.custom;
261
+ if (!custom || typeof custom !== "object") {
262
+ return void 0;
263
+ }
264
+ const description = custom.description;
265
+ return typeof description === "string" && description.trim().length > 0 ? description : void 0;
266
+ }
267
+ function OrionBlocksDrawer(props) {
268
+ const { addRow, addRowIndex, blocks, drawerSlug, labels } = props;
269
+ const { closeModal } = (0, import_ui.useModal)();
270
+ const { i18n, t } = (0, import_ui.useTranslation)();
271
+ const groupedBlocks = (0, import_react7.useMemo)(() => {
272
+ const groupMap = /* @__PURE__ */ new Map();
273
+ const allOptions = blocks.map((block) => ({
274
+ slug: block.slug,
275
+ label: normalizeLabel(block.labels?.singular, i18n, block.slug),
276
+ description: getBlockDescription(block),
277
+ imageURL: block.imageURL
278
+ }));
279
+ for (const block of blocks) {
280
+ const groupLabel = getGroupLabel(block, i18n);
281
+ const option = {
282
+ slug: block.slug,
283
+ label: normalizeLabel(block.labels?.singular, i18n, block.slug),
284
+ description: getBlockDescription(block),
285
+ imageURL: block.imageURL
286
+ };
287
+ const existing = groupMap.get(groupLabel);
288
+ if (existing) {
289
+ existing.push(option);
290
+ } else {
291
+ groupMap.set(groupLabel, [option]);
292
+ }
293
+ }
294
+ const groups = [{ label: "All", options: allOptions }];
295
+ const sortedGroupEntries = Array.from(groupMap.entries()).sort(([a], [b]) => a.localeCompare(b));
296
+ for (const [label, options] of sortedGroupEntries) {
297
+ groups.push({ label, options });
298
+ }
299
+ return groups;
300
+ }, [blocks, i18n]);
301
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
302
+ import_ui.Drawer,
303
+ {
304
+ slug: drawerSlug,
305
+ title: t("fields:addLabel", {
306
+ label: normalizeLabel(labels.singular, i18n, "Block")
307
+ }),
308
+ children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
309
+ SectionTabs,
310
+ {
311
+ tabs: groupedBlocks.map((group) => ({
312
+ label: group.label,
313
+ content: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
314
+ BlockPicker,
315
+ {
316
+ blocks: group.options,
317
+ onSelect: (slug) => {
318
+ addRow(addRowIndex, slug);
319
+ closeModal(drawerSlug);
320
+ }
321
+ }
322
+ )
323
+ }))
324
+ }
325
+ )
326
+ }
327
+ );
328
+ }
329
+ var import_translations, import_ui, import_react7, import_jsx_runtime10;
330
+ var init_OrionBlocksDrawer = __esm({
331
+ "src/admin/components/OrionBlocksDrawer.tsx"() {
332
+ "use strict";
333
+ "use client";
334
+ import_translations = require("@payloadcms/translations");
335
+ import_ui = require("@payloadcms/ui");
336
+ import_react7 = require("react");
337
+ init_BlockPicker();
338
+ init_SectionTabs();
339
+ import_jsx_runtime10 = require("react/jsx-runtime");
340
+ }
341
+ });
342
+
343
+ // src/admin/components/OrionBlocksFieldImpl.tsx
344
+ var OrionBlocksFieldImpl_exports = {};
345
+ __export(OrionBlocksFieldImpl_exports, {
346
+ OrionBlocksFieldImpl: () => OrionBlocksFieldImpl
347
+ });
348
+ function reduceFormStateByPath({ formState, path, rowIndex }) {
349
+ const filteredState = {};
350
+ const prefix = typeof rowIndex !== "number" ? path : `${path}.${rowIndex}`;
351
+ for (const key in formState) {
352
+ if (!key.startsWith(prefix)) {
353
+ continue;
354
+ }
355
+ const { customComponents: _customComponents, validate: _validate, ...field } = formState[key];
356
+ if (Array.isArray(field.rows)) {
357
+ field.rows = field.rows.map((row) => {
358
+ if (!row || typeof row !== "object") {
359
+ return row;
360
+ }
361
+ const { customComponents: _rowCustomComponents, ...serializableRow } = row;
362
+ return serializableRow;
363
+ });
364
+ }
365
+ filteredState[key] = field;
366
+ }
367
+ return filteredState;
368
+ }
369
+ function mergeFormStateFromClipboard({ dataFromClipboard, formState, path, rowIndex }) {
370
+ const typeFromClipboard = dataFromClipboard.type;
371
+ const clipboardFields = dataFromClipboard.data;
372
+ const pathFromClipboard = dataFromClipboard.path;
373
+ const rowIndexFromClipboard = dataFromClipboard.rowIndex;
374
+ if (!clipboardFields || !pathFromClipboard || !typeFromClipboard) {
375
+ return formState;
376
+ }
377
+ const copyFromField = typeof rowIndexFromClipboard !== "number";
378
+ const pasteIntoField = typeof rowIndex !== "number";
379
+ const fromRowToField = !copyFromField && pasteIntoField;
380
+ const isArray = typeFromClipboard === "array";
381
+ let pathToReplace;
382
+ if (copyFromField && pasteIntoField) {
383
+ pathToReplace = pathFromClipboard;
384
+ } else if (copyFromField) {
385
+ pathToReplace = `${pathFromClipboard}.${rowIndex}`;
386
+ } else {
387
+ pathToReplace = `${pathFromClipboard}.${rowIndexFromClipboard}`;
388
+ }
389
+ let targetSegment;
390
+ if (!pasteIntoField) {
391
+ targetSegment = `${path}.${rowIndex}`;
392
+ } else if (fromRowToField) {
393
+ targetSegment = `${path}.0`;
394
+ } else {
395
+ targetSegment = path;
396
+ }
397
+ if (fromRowToField) {
398
+ const lastRenderedPath = `${path}.0`;
399
+ const rowIDPath = `${pathToReplace}.id`;
400
+ const rowIDField = clipboardFields[rowIDPath];
401
+ const rowIDFromClipboard = rowIDField?.value;
402
+ const pathField = formState[path];
403
+ const existingRows = Array.isArray(pathField?.rows) ? pathField.rows : [];
404
+ formState[path] = {
405
+ ...pathField,
406
+ rows: [
407
+ {
408
+ ...existingRows.length > 0 && isArray ? existingRows[0] : {},
409
+ id: rowIDFromClipboard,
410
+ isLoading: false,
411
+ lastRenderedPath
412
+ }
413
+ ],
414
+ value: 1,
415
+ initialValue: 1,
416
+ disableFormData: true
417
+ };
418
+ for (const fieldPath in formState) {
419
+ if (fieldPath !== path && !fieldPath.startsWith(lastRenderedPath) && fieldPath.startsWith(path)) {
420
+ delete formState[fieldPath];
421
+ }
422
+ }
423
+ }
424
+ for (const clipboardPath in clipboardFields) {
425
+ if (!pasteIntoField && clipboardPath.endsWith(".id") || !clipboardPath.startsWith(pathToReplace)) {
426
+ continue;
427
+ }
428
+ const newPath = clipboardPath.replace(pathToReplace, targetSegment);
429
+ const existing = formState[newPath];
430
+ formState[newPath] = {
431
+ customComponents: isArray ? existing?.customComponents : void 0,
432
+ validate: isArray ? existing?.validate : void 0,
433
+ ...clipboardFields[clipboardPath]
434
+ };
435
+ }
436
+ return formState;
437
+ }
438
+ function clipboardCopy({ getDataToCopy, payload, t }) {
439
+ try {
440
+ const dataToWrite = {
441
+ data: getDataToCopy(),
442
+ ...payload
443
+ };
444
+ localStorage.setItem(localStorageClipboardKey, JSON.stringify(dataToWrite));
445
+ return true;
446
+ } catch {
447
+ return t("error:unableToCopy");
448
+ }
449
+ }
450
+ function clipboardPaste({ onPaste, schemaBlocks, t }) {
451
+ let dataToPaste;
452
+ try {
453
+ const jsonFromClipboard = localStorage.getItem(localStorageClipboardKey);
454
+ if (!jsonFromClipboard) {
455
+ return t("error:invalidClipboardData");
456
+ }
457
+ dataToPaste = JSON.parse(jsonFromClipboard);
458
+ } catch {
459
+ return t("error:invalidClipboardData");
460
+ }
461
+ if (!dataToPaste || dataToPaste.type !== "blocks" || !dataToPaste.path || !dataToPaste.data) {
462
+ return t("error:invalidClipboardData");
463
+ }
464
+ const allowedSlugs = new Set(schemaBlocks.map((block) => block.slug));
465
+ const clipboardBlocks = Array.isArray(dataToPaste.blocks) ? dataToPaste.blocks : [];
466
+ for (const block of clipboardBlocks) {
467
+ if (!allowedSlugs.has(block.slug)) {
468
+ return t("error:invalidClipboardData");
469
+ }
470
+ }
471
+ onPaste(dataToPaste);
472
+ return true;
473
+ }
474
+ function toggleAllRows(rows, collapsed) {
475
+ const updatedRows = rows.map((row) => ({ ...row, collapsed }));
476
+ const collapsedIDs = collapsed ? updatedRows.map((row) => row.id) : [];
477
+ return { collapsedIDs, updatedRows };
478
+ }
479
+ function extractRowsAndCollapsedIDs(rows, rowID, collapsed) {
480
+ const updatedRows = rows.map((row) => row.id === rowID ? { ...row, collapsed } : row);
481
+ const collapsedIDs = updatedRows.filter((row) => row.collapsed).map((row) => row.id);
482
+ return { collapsedIDs, updatedRows };
483
+ }
484
+ function OrionRowActions(props) {
485
+ const {
486
+ addRow,
487
+ blocks,
488
+ copyRow,
489
+ duplicateRow,
490
+ hasMaxRows,
491
+ isSortable,
492
+ labels,
493
+ moveRow,
494
+ pasteRow,
495
+ removeRow,
496
+ rowCount,
497
+ rowIndex,
498
+ drawerSlug
499
+ } = props;
500
+ const { closeModal, openModal } = (0, import_ui2.useModal)();
501
+ const [indexToAdd, setIndexToAdd] = (0, import_react8.useState)(null);
502
+ const addViaDrawer = (0, import_react8.useCallback)(
503
+ (rowToAdd, rowBlockType) => {
504
+ addRow(rowToAdd, rowBlockType);
505
+ closeModal(drawerSlug);
506
+ },
507
+ [addRow, closeModal, drawerSlug]
508
+ );
509
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_jsx_runtime11.Fragment, { children: [
510
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
511
+ OrionBlocksDrawer,
512
+ {
513
+ addRow: (_, rowBlockType) => {
514
+ addViaDrawer(indexToAdd ?? rowIndex, rowBlockType);
515
+ },
516
+ addRowIndex: indexToAdd ?? rowIndex,
517
+ blocks,
518
+ drawerSlug,
519
+ labels
520
+ }
521
+ ),
522
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
523
+ import_ArrayAction.ArrayAction,
524
+ {
525
+ addRow: (index) => {
526
+ setIndexToAdd(index);
527
+ openModal(drawerSlug);
528
+ },
529
+ copyRow,
530
+ duplicateRow,
531
+ hasMaxRows,
532
+ index: rowIndex,
533
+ isSortable,
534
+ moveRow,
535
+ pasteRow,
536
+ removeRow,
537
+ rowCount
538
+ }
539
+ )
540
+ ] });
541
+ }
542
+ function OrionBlockRow(props) {
543
+ const {
544
+ addRow,
545
+ attributes,
546
+ block,
547
+ blocks,
548
+ copyRow,
549
+ duplicateRow,
550
+ drawerSlug,
551
+ errorCount,
552
+ fields,
553
+ hasMaxRows,
554
+ isLoading: isLoadingFromProps,
555
+ isSortable,
556
+ Label,
557
+ labels,
558
+ listeners,
559
+ moveRow,
560
+ parentPath,
561
+ pasteRow,
562
+ path,
563
+ permissions,
564
+ readOnly,
565
+ removeRow,
566
+ row,
567
+ rowCount,
568
+ rowIndex,
569
+ schemaPath,
570
+ setCollapse,
571
+ setNodeRef,
572
+ transform
573
+ } = props;
574
+ const { i18n } = (0, import_Translation.useTranslation)();
575
+ const hasSubmitted = (0, import_Form.useFormSubmitted)();
576
+ const isLoading = (0, import_useThrottledValue.useThrottledValue)(Boolean(isLoadingFromProps), 500);
577
+ const fieldHasErrors = hasSubmitted && errorCount > 0;
578
+ let blockPermissions;
579
+ if (permissions === true) {
580
+ blockPermissions = true;
581
+ } else {
582
+ const permissionsBlockSpecific = permissions?.blocks?.[block.slug] ?? permissions?.blocks;
583
+ if (permissionsBlockSpecific === true) {
584
+ blockPermissions = true;
585
+ } else if (permissionsBlockSpecific && typeof permissionsBlockSpecific === "object" && "fields" in permissionsBlockSpecific) {
586
+ blockPermissions = permissionsBlockSpecific.fields;
587
+ } else if (permissions && typeof permissions === "object") {
588
+ const hasReadPermission = permissions.read === true;
589
+ const missingCreateOrUpdate = !permissions.create || !permissions.update;
590
+ const hasRestrictiveStructure = hasReadPermission && (missingCreateOrUpdate || Object.keys(permissions).length === 1 && permissions.read === true);
591
+ if (hasRestrictiveStructure) {
592
+ blockPermissions = { read: true };
593
+ }
594
+ }
595
+ }
596
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
597
+ "div",
598
+ {
599
+ id: `${parentPath.split(".").join("-")}-row-${rowIndex}`,
600
+ ref: setNodeRef,
601
+ style: { transform },
602
+ children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
603
+ import_Collapsible.Collapsible,
604
+ {
605
+ actions: !readOnly ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
606
+ OrionRowActions,
607
+ {
608
+ addRow,
609
+ blocks,
610
+ copyRow,
611
+ drawerSlug,
612
+ duplicateRow,
613
+ hasMaxRows,
614
+ isSortable,
615
+ labels,
616
+ moveRow,
617
+ pasteRow,
618
+ removeRow,
619
+ rowCount,
620
+ rowIndex
621
+ }
622
+ ) : void 0,
623
+ className: [
624
+ `${baseClass}__row`,
625
+ fieldHasErrors ? `${baseClass}__row--has-errors` : `${baseClass}__row--no-errors`
626
+ ].filter(Boolean).join(" "),
627
+ collapsibleStyle: fieldHasErrors ? "error" : "default",
628
+ dragHandleProps: isSortable ? {
629
+ id: row.id,
630
+ attributes,
631
+ listeners
632
+ } : void 0,
633
+ header: isLoading ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_ShimmerEffect.ShimmerEffect, { height: "1rem", width: "8rem" }) : /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: `${baseClass}__block-header`, children: [
634
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
635
+ import_RowLabel.RowLabel,
636
+ {
637
+ CustomComponent: Label,
638
+ label: /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_jsx_runtime11.Fragment, { children: [
639
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: `${baseClass}__block-number`, children: String(rowIndex + 1).padStart(2, "0") }),
640
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
641
+ import_Pill.Pill,
642
+ {
643
+ className: `${baseClass}__block-pill ${baseClass}__block-pill-${row.blockType}`,
644
+ pillStyle: "white",
645
+ size: "small",
646
+ children: (0, import_translations2.getTranslation)(block.labels?.singular, i18n)
647
+ }
648
+ )
649
+ ] }),
650
+ path,
651
+ rowNumber: rowIndex
652
+ }
653
+ ),
654
+ fieldHasErrors && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_ErrorPill.ErrorPill, { count: errorCount, i18n, withMessage: true })
655
+ ] }),
656
+ isCollapsed: Boolean(row.collapsed),
657
+ onToggle: (collapsed) => {
658
+ setCollapse(row.id, collapsed);
659
+ },
660
+ children: isLoading ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_ShimmerEffect.ShimmerEffect, {}) : /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
661
+ import_RenderFields.RenderFields,
662
+ {
663
+ className: `${baseClass}__fields`,
664
+ fields,
665
+ margins: "small",
666
+ parentIndexPath: "",
667
+ parentPath: path,
668
+ parentSchemaPath: schemaPath,
669
+ permissions: blockPermissions,
670
+ readOnly
671
+ }
672
+ )
673
+ }
674
+ )
675
+ }
676
+ );
677
+ }
678
+ var import_translations2, import_ui2, import_ArrayAction, import_Banner, import_Button, import_ClipboardAction, import_Collapsible, import_DraggableSortable, import_DraggableSortableItem, import_Drawer, import_ErrorPill, import_Pill, import_RenderCustomComponent, import_ShimmerEffect, import_Form, import_NullifyField, import_RenderFields, import_RowLabel, import_useField, import_withCondition, import_FieldDescription, import_FieldError, import_FieldLabel, import_useThrottledValue, import_Config, import_DocumentInfo, import_Locale, import_Translation, import_scrollToID, import_react8, import_sonner, import_jsx_runtime11, baseClass, localStorageClipboardKey, OrionBlocksFieldConnected, OrionBlocksFieldComponent, OrionBlocksFieldImpl;
679
+ var init_OrionBlocksFieldImpl = __esm({
680
+ "src/admin/components/OrionBlocksFieldImpl.tsx"() {
681
+ "use strict";
682
+ "use client";
683
+ import_translations2 = require("@payloadcms/translations");
684
+ import_ui2 = require("@payloadcms/ui");
685
+ import_ArrayAction = require("@payloadcms/ui/elements/ArrayAction");
686
+ import_Banner = require("@payloadcms/ui/elements/Banner");
687
+ import_Button = require("@payloadcms/ui/elements/Button");
688
+ import_ClipboardAction = require("@payloadcms/ui/elements/ClipboardAction");
689
+ import_Collapsible = require("@payloadcms/ui/elements/Collapsible");
690
+ import_DraggableSortable = require("@payloadcms/ui/elements/DraggableSortable");
691
+ import_DraggableSortableItem = require("@payloadcms/ui/elements/DraggableSortable/DraggableSortableItem");
692
+ import_Drawer = require("@payloadcms/ui/elements/Drawer");
693
+ import_ErrorPill = require("@payloadcms/ui/elements/ErrorPill");
694
+ import_Pill = require("@payloadcms/ui/elements/Pill");
695
+ import_RenderCustomComponent = require("@payloadcms/ui/elements/RenderCustomComponent");
696
+ import_ShimmerEffect = require("@payloadcms/ui/elements/ShimmerEffect");
697
+ import_Form = require("@payloadcms/ui/forms/Form");
698
+ import_NullifyField = require("@payloadcms/ui/forms/NullifyField");
699
+ import_RenderFields = require("@payloadcms/ui/forms/RenderFields");
700
+ import_RowLabel = require("@payloadcms/ui/forms/RowLabel");
701
+ import_useField = require("@payloadcms/ui/forms/useField");
702
+ import_withCondition = require("@payloadcms/ui/forms/withCondition");
703
+ import_FieldDescription = require("@payloadcms/ui/fields/FieldDescription");
704
+ import_FieldError = require("@payloadcms/ui/fields/FieldError");
705
+ import_FieldLabel = require("@payloadcms/ui/fields/FieldLabel");
706
+ import_useThrottledValue = require("@payloadcms/ui/hooks/useThrottledValue");
707
+ import_Config = require("@payloadcms/ui/providers/Config");
708
+ import_DocumentInfo = require("@payloadcms/ui/providers/DocumentInfo");
709
+ import_Locale = require("@payloadcms/ui/providers/Locale");
710
+ import_Translation = require("@payloadcms/ui/providers/Translation");
711
+ import_scrollToID = require("@payloadcms/ui/utilities/scrollToID");
712
+ import_react8 = require("react");
713
+ import_sonner = require("sonner");
714
+ init_OrionBlocksDrawer();
715
+ import_jsx_runtime11 = require("react/jsx-runtime");
716
+ baseClass = "blocks-field";
717
+ localStorageClipboardKey = "_payloadClipboard";
718
+ OrionBlocksFieldConnected = (props) => {
719
+ const { i18n, t } = (0, import_Translation.useTranslation)();
720
+ const fieldFromProps = props.field;
721
+ const {
722
+ name,
723
+ type,
724
+ admin: { className, description, isSortable = true, style } = {},
725
+ blockReferences,
726
+ blocks,
727
+ label,
728
+ labels: labelsFromProps,
729
+ localized,
730
+ maxRows,
731
+ minRows: minRowsProp,
732
+ required
733
+ } = fieldFromProps;
734
+ const pathFromProps = props.path;
735
+ const permissions = props.permissions;
736
+ const readOnly = Boolean(props.readOnly);
737
+ const schemaPathFromProps = props.schemaPath;
738
+ const validate = props.validate;
739
+ const schemaPath = schemaPathFromProps ?? name;
740
+ const minRows = minRowsProp ?? (required ? 1 : 0);
741
+ const { setDocFieldPreferences } = (0, import_DocumentInfo.useDocumentInfo)();
742
+ const { addFieldRow, dispatchFields, getFields, moveFieldRow, removeFieldRow, replaceState, setModified } = (0, import_Form.useForm)();
743
+ const { code: locale } = (0, import_Locale.useLocale)();
744
+ const configContext = (0, import_Config.useConfig)();
745
+ const config = configContext?.config ?? {};
746
+ const localization = config.localization;
747
+ const blocksMap = config.blocksMap ?? {};
748
+ const drawerSlug = (0, import_ui2.useDrawerSlug)("orion-blocks-drawer");
749
+ const submitted = (0, import_Form.useFormSubmitted)();
750
+ const labels = {
751
+ plural: t("fields:blocks"),
752
+ singular: t("fields:block"),
753
+ ...labelsFromProps
754
+ };
755
+ const editingDefaultLocale = (() => {
756
+ if (localization && localization.fallback) {
757
+ const defaultLocale = localization.defaultLocale;
758
+ return locale === defaultLocale;
759
+ }
760
+ return true;
761
+ })();
762
+ const memoizedValidate = (0, import_react8.useCallback)(
763
+ (value2, options) => {
764
+ if (!editingDefaultLocale && value2 === null) {
765
+ return true;
766
+ }
767
+ if (typeof validate === "function") {
768
+ return validate(value2, {
769
+ ...options,
770
+ maxRows,
771
+ minRows,
772
+ required
773
+ });
774
+ }
775
+ return true;
776
+ },
777
+ [editingDefaultLocale, maxRows, minRows, required, validate]
778
+ );
779
+ const {
780
+ blocksFilterOptions,
781
+ customComponents: {
782
+ AfterInput,
783
+ BeforeInput,
784
+ Description,
785
+ Error: Error2,
786
+ Label
787
+ } = {},
788
+ disabled,
789
+ errorPaths,
790
+ path,
791
+ rows = [],
792
+ showError,
793
+ valid,
794
+ value
795
+ } = (0, import_useField.useField)({
796
+ hasRows: true,
797
+ potentiallyStalePath: pathFromProps,
798
+ validate: memoizedValidate
799
+ });
800
+ const safePath = path ?? pathFromProps ?? name;
801
+ const { clientBlocks, clientBlocksAfterFilter } = (0, import_react8.useMemo)(() => {
802
+ const resolvedBlocks = [];
803
+ if (!blockReferences) {
804
+ resolvedBlocks.push(...blocks);
805
+ } else {
806
+ for (const blockReference of blockReferences) {
807
+ const block = typeof blockReference === "string" ? blocksMap[blockReference] : blockReference;
808
+ if (block) {
809
+ resolvedBlocks.push(block);
810
+ }
811
+ }
812
+ }
813
+ if (Array.isArray(blocksFilterOptions)) {
814
+ const filteredBlocks = resolvedBlocks.filter((block) => blocksFilterOptions.includes(block.slug));
815
+ return {
816
+ clientBlocks: resolvedBlocks,
817
+ clientBlocksAfterFilter: filteredBlocks
818
+ };
819
+ }
820
+ return {
821
+ clientBlocks: resolvedBlocks,
822
+ clientBlocksAfterFilter: resolvedBlocks
823
+ };
824
+ }, [blockReferences, blocks, blocksFilterOptions, blocksMap]);
825
+ const addRow = (0, import_react8.useCallback)(
826
+ (rowIndex, blockType) => {
827
+ addFieldRow({
828
+ blockType,
829
+ path: safePath,
830
+ rowIndex,
831
+ schemaPath
832
+ });
833
+ setTimeout(() => {
834
+ (0, import_scrollToID.scrollToID)(`${safePath}-row-${rowIndex + 1}`);
835
+ }, 0);
836
+ },
837
+ [addFieldRow, safePath, schemaPath]
838
+ );
839
+ const duplicateRow = (0, import_react8.useCallback)(
840
+ (rowIndex) => {
841
+ dispatchFields({
842
+ type: "DUPLICATE_ROW",
843
+ path: safePath,
844
+ rowIndex
845
+ });
846
+ setModified(true);
847
+ setTimeout(() => {
848
+ (0, import_scrollToID.scrollToID)(`${safePath}-row-${rowIndex + 1}`);
849
+ }, 0);
850
+ },
851
+ [dispatchFields, safePath, setModified]
852
+ );
853
+ const removeRow = (0, import_react8.useCallback)(
854
+ (rowIndex) => {
855
+ removeFieldRow({
856
+ path: safePath,
857
+ rowIndex
858
+ });
859
+ },
860
+ [removeFieldRow, safePath]
861
+ );
862
+ const moveRow = (0, import_react8.useCallback)(
863
+ (moveFromIndex, moveToIndex) => {
864
+ moveFieldRow({
865
+ moveFromIndex,
866
+ moveToIndex,
867
+ path: safePath
868
+ });
869
+ },
870
+ [moveFieldRow, safePath]
871
+ );
872
+ const toggleCollapseAll = (0, import_react8.useCallback)(
873
+ (collapsed) => {
874
+ const { collapsedIDs, updatedRows } = toggleAllRows(rows, collapsed);
875
+ dispatchFields({
876
+ type: "SET_ALL_ROWS_COLLAPSED",
877
+ path: safePath,
878
+ updatedRows
879
+ });
880
+ setDocFieldPreferences(safePath, {
881
+ collapsed: collapsedIDs
882
+ });
883
+ },
884
+ [dispatchFields, rows, safePath, setDocFieldPreferences]
885
+ );
886
+ const setCollapse = (0, import_react8.useCallback)(
887
+ (rowID, collapsed) => {
888
+ const { collapsedIDs, updatedRows } = extractRowsAndCollapsedIDs(rows, rowID, collapsed);
889
+ dispatchFields({
890
+ type: "SET_ROW_COLLAPSED",
891
+ path: safePath,
892
+ updatedRows
893
+ });
894
+ setDocFieldPreferences(safePath, {
895
+ collapsed: collapsedIDs
896
+ });
897
+ },
898
+ [dispatchFields, rows, safePath, setDocFieldPreferences]
899
+ );
900
+ const copyRow = (0, import_react8.useCallback)(
901
+ (rowIndex) => {
902
+ const result = clipboardCopy({
903
+ getDataToCopy: () => reduceFormStateByPath({
904
+ formState: getFields(),
905
+ path: safePath,
906
+ rowIndex
907
+ }),
908
+ payload: {
909
+ type,
910
+ blocks: clientBlocks,
911
+ path: safePath,
912
+ rowIndex
913
+ },
914
+ t
915
+ });
916
+ if (typeof result === "string") {
917
+ import_sonner.toast.error(result);
918
+ } else {
919
+ import_sonner.toast.success(t("general:copied"));
920
+ }
921
+ },
922
+ [clientBlocks, getFields, safePath, t, type]
923
+ );
924
+ const pasteRow = (0, import_react8.useCallback)(
925
+ (rowIndex) => {
926
+ const result = clipboardPaste({
927
+ onPaste: (dataFromClipboard) => {
928
+ const formState = getFields();
929
+ const newState = mergeFormStateFromClipboard({
930
+ dataFromClipboard,
931
+ formState,
932
+ path: safePath,
933
+ rowIndex
934
+ });
935
+ replaceState(newState);
936
+ setModified(true);
937
+ },
938
+ schemaBlocks: clientBlocks,
939
+ t
940
+ });
941
+ if (typeof result === "string") {
942
+ import_sonner.toast.error(result);
943
+ }
944
+ },
945
+ [clientBlocks, getFields, replaceState, safePath, setModified, t]
946
+ );
947
+ const pasteBlocks = (0, import_react8.useCallback)(
948
+ (dataFromClipboard) => {
949
+ const formState = getFields();
950
+ const newState = mergeFormStateFromClipboard({
951
+ dataFromClipboard,
952
+ formState,
953
+ path: safePath
954
+ });
955
+ replaceState(newState);
956
+ setModified(true);
957
+ },
958
+ [getFields, replaceState, safePath, setModified]
959
+ );
960
+ const hasMaxRows = Boolean(maxRows && rows.length >= maxRows);
961
+ const fieldErrorCount = errorPaths.length;
962
+ const fieldHasErrors = submitted && fieldErrorCount + (valid ? 0 : 1) > 0;
963
+ const showMinRows = rows.length < minRows || required && rows.length === 0;
964
+ const showRequired = readOnly && rows.length === 0;
965
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
966
+ "div",
967
+ {
968
+ className: [
969
+ import_ui2.fieldBaseClass,
970
+ baseClass,
971
+ className,
972
+ fieldHasErrors ? `${baseClass}--has-error` : `${baseClass}--has-no-error`
973
+ ].filter(Boolean).join(" "),
974
+ id: `field-${safePath.replace(/\./g, "__")}`,
975
+ style,
976
+ children: [
977
+ showError && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
978
+ import_RenderCustomComponent.RenderCustomComponent,
979
+ {
980
+ CustomComponent: Error2,
981
+ Fallback: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_FieldError.FieldError, { path: safePath, showError })
982
+ }
983
+ ),
984
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("header", { className: `${baseClass}__header`, children: [
985
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: `${baseClass}__header-wrap`, children: [
986
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: `${baseClass}__heading-with-error`, children: [
987
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("h3", { children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
988
+ import_RenderCustomComponent.RenderCustomComponent,
989
+ {
990
+ CustomComponent: Label,
991
+ Fallback: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
992
+ import_FieldLabel.FieldLabel,
993
+ {
994
+ as: "span",
995
+ label,
996
+ localized,
997
+ path: safePath,
998
+ required
999
+ }
1000
+ )
1001
+ }
1002
+ ) }),
1003
+ fieldHasErrors && fieldErrorCount > 0 && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_ErrorPill.ErrorPill, { count: fieldErrorCount, i18n, withMessage: true })
1004
+ ] }),
1005
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("ul", { className: `${baseClass}__header-actions`, children: [
1006
+ rows.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_react8.Fragment, { children: [
1007
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("li", { children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
1008
+ "button",
1009
+ {
1010
+ className: `${baseClass}__header-action`,
1011
+ onClick: () => toggleCollapseAll(true),
1012
+ type: "button",
1013
+ children: t("fields:collapseAll")
1014
+ }
1015
+ ) }),
1016
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("li", { children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
1017
+ "button",
1018
+ {
1019
+ className: `${baseClass}__header-action`,
1020
+ onClick: () => toggleCollapseAll(false),
1021
+ type: "button",
1022
+ children: t("fields:showAll")
1023
+ }
1024
+ ) })
1025
+ ] }),
1026
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("li", { children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
1027
+ import_ClipboardAction.ClipboardAction,
1028
+ {
1029
+ allowCopy: rows.length > 0,
1030
+ allowPaste: !readOnly,
1031
+ blocks: clientBlocks,
1032
+ className: `${baseClass}__header-action`,
1033
+ disabled,
1034
+ getDataToCopy: () => reduceFormStateByPath({
1035
+ formState: getFields(),
1036
+ path: safePath
1037
+ }),
1038
+ onPaste: pasteBlocks,
1039
+ path: safePath,
1040
+ type
1041
+ }
1042
+ ) })
1043
+ ] })
1044
+ ] }),
1045
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
1046
+ import_RenderCustomComponent.RenderCustomComponent,
1047
+ {
1048
+ CustomComponent: Description,
1049
+ Fallback: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_FieldDescription.FieldDescription, { description, path: safePath })
1050
+ }
1051
+ )
1052
+ ] }),
1053
+ BeforeInput,
1054
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_NullifyField.NullifyLocaleField, { fieldValue: value, localized, path: safePath, readOnly }),
1055
+ (rows.length > 0 || !valid && (showRequired || showMinRows)) && /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
1056
+ import_DraggableSortable.DraggableSortable,
1057
+ {
1058
+ className: `${baseClass}__rows`,
1059
+ ids: rows.map((row) => row.id),
1060
+ onDragEnd: ({ moveFromIndex, moveToIndex }) => moveRow(moveFromIndex, moveToIndex),
1061
+ children: [
1062
+ rows.map((row, index) => {
1063
+ const blockType = row.blockType;
1064
+ const blockConfig = blocksMap[blockType] ?? clientBlocks.find((block) => block.slug === blockType);
1065
+ if (!blockConfig) {
1066
+ return null;
1067
+ }
1068
+ const rowPath = `${safePath}.${index}`;
1069
+ const rowErrorCount = errorPaths.filter((errorPath) => errorPath.startsWith(`${rowPath}.`)).length;
1070
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_DraggableSortableItem.DraggableSortableItem, { disabled: readOnly || disabled || !isSortable, id: row.id, children: (draggableSortableItemProps) => /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
1071
+ OrionBlockRow,
1072
+ {
1073
+ ...draggableSortableItemProps,
1074
+ addRow,
1075
+ block: blockConfig,
1076
+ blocks: clientBlocks,
1077
+ copyRow,
1078
+ drawerSlug,
1079
+ duplicateRow,
1080
+ errorCount: rowErrorCount,
1081
+ fields: blockConfig.fields,
1082
+ hasMaxRows,
1083
+ isLoading: Boolean(row.isLoading),
1084
+ isSortable,
1085
+ Label: rows[index]?.customComponents?.RowLabel,
1086
+ labels,
1087
+ moveRow,
1088
+ parentPath: safePath,
1089
+ pasteRow,
1090
+ path: rowPath,
1091
+ permissions,
1092
+ readOnly: readOnly || Boolean(disabled),
1093
+ removeRow,
1094
+ row,
1095
+ rowCount: rows.length,
1096
+ rowIndex: index,
1097
+ schemaPath: schemaPath + blockConfig.slug,
1098
+ setCollapse
1099
+ }
1100
+ ) }, row.id);
1101
+ }),
1102
+ !editingDefaultLocale && /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_jsx_runtime11.Fragment, { children: [
1103
+ showMinRows && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_Banner.Banner, { type: "error", children: t("validation:requiresAtLeast", {
1104
+ count: minRows,
1105
+ label: (0, import_translations2.getTranslation)(minRows > 1 ? labels.plural : labels.singular, i18n) || t(minRows > 1 ? "general:row" : "general:rows")
1106
+ }) }),
1107
+ showRequired && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_Banner.Banner, { children: t("validation:fieldHasNo", {
1108
+ label: (0, import_translations2.getTranslation)(labels.plural, i18n)
1109
+ }) })
1110
+ ] })
1111
+ ]
1112
+ }
1113
+ ),
1114
+ !hasMaxRows && /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_react8.Fragment, { children: [
1115
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_Drawer.DrawerToggler, { className: `${baseClass}__drawer-toggler`, disabled: readOnly || disabled, slug: drawerSlug, children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
1116
+ import_Button.Button,
1117
+ {
1118
+ buttonStyle: "icon-label",
1119
+ disabled: readOnly || disabled,
1120
+ el: "span",
1121
+ icon: "plus",
1122
+ iconPosition: "left",
1123
+ iconStyle: "with-border",
1124
+ children: t("fields:addLabel", {
1125
+ label: (0, import_translations2.getTranslation)(labels.singular, i18n)
1126
+ })
1127
+ }
1128
+ ) }),
1129
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
1130
+ OrionBlocksDrawer,
1131
+ {
1132
+ addRow,
1133
+ addRowIndex: rows.length || 0,
1134
+ blocks: clientBlocksAfterFilter,
1135
+ drawerSlug,
1136
+ labels
1137
+ }
1138
+ )
1139
+ ] }),
1140
+ AfterInput
1141
+ ]
1142
+ }
1143
+ );
1144
+ };
1145
+ OrionBlocksFieldComponent = (props) => {
1146
+ const configContext = (0, import_Config.useConfig)();
1147
+ if (!configContext?.config) {
1148
+ return null;
1149
+ }
1150
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(OrionBlocksFieldConnected, { ...props });
1151
+ };
1152
+ OrionBlocksFieldImpl = (0, import_withCondition.withCondition)(OrionBlocksFieldComponent);
1153
+ }
1154
+ });
1155
+
1156
+ // src/admin/client.ts
1157
+ var client_exports = {};
1158
+ __export(client_exports, {
1159
+ AdminStudioDashboard: () => AdminStudioDashboard,
1160
+ AdminStudioGlobalsView: () => AdminStudioGlobalsView,
1161
+ AdminStudioMediaView: () => AdminStudioMediaView,
1162
+ AdminStudioNav: () => AdminStudioNav,
1163
+ AdminStudioPageEditView: () => AdminStudioPageEditView,
1164
+ AdminStudioPagesListView: () => AdminStudioPagesListView,
1165
+ AdminStudioToolsView: () => AdminStudioToolsView,
1166
+ BlockPicker: () => BlockPicker,
1167
+ Dashboard: () => Dashboard,
1168
+ EmptyState: () => EmptyState,
1169
+ HelpTooltip: () => HelpTooltip,
1170
+ Icon: () => Icon,
1171
+ Logo: () => Logo,
1172
+ OpenInStudioMenuItem: () => OpenInStudioMenuItem,
1173
+ OrionBlocksField: () => OrionBlocksField,
1174
+ PageEditRedirectToStudio: () => PageEditRedirectToStudio,
1175
+ SectionTabs: () => SectionTabs,
1176
+ StatusBadge: () => StatusBadge,
1177
+ ThemeProvider: () => ThemeProvider,
1178
+ ThemeSwitcher: () => ThemeSwitcher,
1179
+ WelcomeHeader: () => WelcomeHeader,
1180
+ useTheme: () => useTheme
1181
+ });
1182
+ module.exports = __toCommonJS(client_exports);
1183
+
1184
+ // src/admin/components/Logo.tsx
1185
+ var import_jsx_runtime = require("react/jsx-runtime");
1186
+ function Logo() {
1187
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
1188
+ "div",
1189
+ {
1190
+ style: {
1191
+ display: "flex",
1192
+ alignItems: "center",
1193
+ gap: 10,
1194
+ padding: "4px 0",
1195
+ textDecoration: "none",
1196
+ transition: "opacity 0.2s ease"
1197
+ },
1198
+ children: [
1199
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1200
+ "div",
1201
+ {
1202
+ style: {
1203
+ width: 32,
1204
+ height: 32,
1205
+ borderRadius: "var(--admin-radius-sm, 6px)",
1206
+ background: "var(--admin-accent, #3b82f6)",
1207
+ display: "flex",
1208
+ alignItems: "center",
1209
+ justifyContent: "center",
1210
+ flexShrink: 0
1211
+ },
1212
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("svg", { width: 18, height: 18, viewBox: "0 0 24 24", fill: "none", stroke: "white", strokeWidth: 2, strokeLinecap: "round", strokeLinejoin: "round", children: [
1213
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("polygon", { points: "12 2 22 8.5 22 15.5 12 22 2 15.5 2 8.5 12 2" }),
1214
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("line", { x1: "12", y1: "22", x2: "12", y2: "15.5" }),
1215
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("polyline", { points: "22 8.5 12 15.5 2 8.5" })
1216
+ ] })
1217
+ }
1218
+ ),
1219
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1220
+ "span",
1221
+ {
1222
+ style: {
1223
+ fontSize: 15,
1224
+ fontWeight: 700,
1225
+ color: "var(--admin-text, #111827)",
1226
+ letterSpacing: "-0.01em"
1227
+ },
1228
+ children: "Orion CMS"
1229
+ }
1230
+ )
1231
+ ]
1232
+ }
1233
+ );
1234
+ }
1235
+
1236
+ // src/admin/components/Icon.tsx
1237
+ var import_jsx_runtime2 = require("react/jsx-runtime");
1238
+ function Icon() {
1239
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("svg", { width: "32", height: "32", viewBox: "0 0 32 32", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: [
1240
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("rect", { width: "32", height: "32", rx: "8", fill: "var(--admin-accent, #3b82f6)" }),
1241
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("g", { transform: "translate(4, 4)", children: [
1242
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("polygon", { points: "12 2 22 8.5 22 15.5 12 22 2 15.5 2 8.5 12 2", fill: "none", stroke: "white", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" }),
1243
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("line", { x1: "12", y1: "22", x2: "12", y2: "15.5", stroke: "white", strokeWidth: "1.5" }),
1244
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("polyline", { points: "22 8.5 12 15.5 2 8.5", fill: "none", stroke: "white", strokeWidth: "1.5" })
1245
+ ] })
1246
+ ] });
1247
+ }
1248
+
1249
+ // src/admin/components/Dashboard.tsx
1250
+ var import_react4 = require("react");
1251
+
1252
+ // src/admin/components/ThemeSwitcher.tsx
1253
+ var import_react2 = require("react");
1254
+
1255
+ // src/admin/hooks/useTheme.ts
1256
+ var import_react = require("react");
1257
+ var STORAGE_KEY = "orion-admin-theme";
1258
+ function applyTheme(theme) {
1259
+ const html = document.documentElement;
1260
+ const isDark = theme === "dark" || theme === "brand-dark";
1261
+ const isBrand = theme === "brand-light" || theme === "brand-dark";
1262
+ if (isDark) {
1263
+ html.setAttribute("data-theme", "dark");
1264
+ } else {
1265
+ html.removeAttribute("data-theme");
1266
+ }
1267
+ if (isBrand) {
1268
+ html.setAttribute("data-orion-brand", "true");
1269
+ } else {
1270
+ html.removeAttribute("data-orion-brand");
1271
+ }
1272
+ }
1273
+ function getCachedTheme() {
1274
+ try {
1275
+ const stored = localStorage.getItem(STORAGE_KEY);
1276
+ if (stored && ["light", "dark", "brand-light", "brand-dark"].includes(stored)) {
1277
+ return stored;
1278
+ }
1279
+ } catch {
1280
+ }
1281
+ return null;
1282
+ }
1283
+ function cacheTheme(theme) {
1284
+ try {
1285
+ localStorage.setItem(STORAGE_KEY, theme);
1286
+ } catch {
1287
+ }
1288
+ }
1289
+ function useTheme(defaultTheme = "brand-light") {
1290
+ const [theme, setThemeState] = (0, import_react.useState)(defaultTheme);
1291
+ const [isLoading, setIsLoading] = (0, import_react.useState)(true);
1292
+ const [hasMounted, setHasMounted] = (0, import_react.useState)(false);
1293
+ const debounceRef = (0, import_react.useRef)(null);
1294
+ const userIdRef = (0, import_react.useRef)(null);
1295
+ (0, import_react.useEffect)(() => {
1296
+ setHasMounted(true);
1297
+ const cached = getCachedTheme();
1298
+ if (cached) {
1299
+ applyTheme(cached);
1300
+ setThemeState(cached);
1301
+ } else {
1302
+ applyTheme(defaultTheme);
1303
+ setThemeState(defaultTheme);
1304
+ cacheTheme(defaultTheme);
1305
+ }
1306
+ fetch("/api/users/me", { credentials: "include" }).then((res) => res.json()).then((data) => {
1307
+ const user = data?.user || data;
1308
+ if (user?.id) {
1309
+ userIdRef.current = user.id;
1310
+ }
1311
+ if (user?.themePreference) {
1312
+ const dbTheme = user.themePreference;
1313
+ setThemeState(dbTheme);
1314
+ applyTheme(dbTheme);
1315
+ cacheTheme(dbTheme);
1316
+ }
1317
+ }).catch(() => {
1318
+ }).finally(() => {
1319
+ setIsLoading(false);
1320
+ });
1321
+ }, [defaultTheme]);
1322
+ const setTheme = (0, import_react.useCallback)((newTheme) => {
1323
+ setThemeState(newTheme);
1324
+ applyTheme(newTheme);
1325
+ cacheTheme(newTheme);
1326
+ if (debounceRef.current) {
1327
+ clearTimeout(debounceRef.current);
1328
+ }
1329
+ debounceRef.current = setTimeout(() => {
1330
+ const userId = userIdRef.current;
1331
+ if (!userId) return;
1332
+ fetch(`/api/users/${userId}`, {
1333
+ method: "PATCH",
1334
+ credentials: "include",
1335
+ headers: { "Content-Type": "application/json" },
1336
+ body: JSON.stringify({ themePreference: newTheme })
1337
+ }).catch(() => {
1338
+ });
1339
+ }, 300);
1340
+ }, []);
1341
+ const isDark = theme === "dark" || theme === "brand-dark";
1342
+ const isBrand = theme === "brand-light" || theme === "brand-dark";
1343
+ const toggleDarkMode = (0, import_react.useCallback)(() => {
1344
+ if (isBrand) {
1345
+ setTheme(isDark ? "brand-light" : "brand-dark");
1346
+ } else {
1347
+ setTheme(isDark ? "light" : "dark");
1348
+ }
1349
+ }, [isDark, isBrand, setTheme]);
1350
+ const toggleBrandMode = (0, import_react.useCallback)(() => {
1351
+ if (isBrand) {
1352
+ setTheme(isDark ? "dark" : "light");
1353
+ } else {
1354
+ setTheme(isDark ? "brand-dark" : "brand-light");
1355
+ }
1356
+ }, [isDark, isBrand, setTheme]);
1357
+ return {
1358
+ theme,
1359
+ setTheme,
1360
+ isDark,
1361
+ isBrand,
1362
+ isLoading,
1363
+ hasMounted,
1364
+ toggleDarkMode,
1365
+ toggleBrandMode
1366
+ };
1367
+ }
1368
+
1369
+ // src/admin/components/ThemeSwitcher.tsx
1370
+ var import_jsx_runtime3 = require("react/jsx-runtime");
1371
+ var iconSize = 16;
1372
+ function SunIcon() {
1373
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("svg", { width: iconSize, height: iconSize, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2, strokeLinecap: "round", strokeLinejoin: "round", children: [
1374
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("circle", { cx: "12", cy: "12", r: "5" }),
1375
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("line", { x1: "12", y1: "1", x2: "12", y2: "3" }),
1376
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("line", { x1: "12", y1: "21", x2: "12", y2: "23" }),
1377
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("line", { x1: "4.22", y1: "4.22", x2: "5.64", y2: "5.64" }),
1378
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("line", { x1: "18.36", y1: "18.36", x2: "19.78", y2: "19.78" }),
1379
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("line", { x1: "1", y1: "12", x2: "3", y2: "12" }),
1380
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("line", { x1: "21", y1: "12", x2: "23", y2: "12" }),
1381
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("line", { x1: "4.22", y1: "19.78", x2: "5.64", y2: "18.36" }),
1382
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("line", { x1: "18.36", y1: "5.64", x2: "19.78", y2: "4.22" })
1383
+ ] });
1384
+ }
1385
+ function MoonIcon() {
1386
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("svg", { width: iconSize, height: iconSize, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2, strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("path", { d: "M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z" }) });
1387
+ }
1388
+ function PaletteIcon() {
1389
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("svg", { width: iconSize, height: iconSize, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2, strokeLinecap: "round", strokeLinejoin: "round", children: [
1390
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("circle", { cx: "13.5", cy: "6.5", r: "0.5", fill: "currentColor" }),
1391
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("circle", { cx: "17.5", cy: "10.5", r: "0.5", fill: "currentColor" }),
1392
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("circle", { cx: "8.5", cy: "7.5", r: "0.5", fill: "currentColor" }),
1393
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("circle", { cx: "6.5", cy: "12", r: "0.5", fill: "currentColor" }),
1394
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("path", { d: "M12 2C6.5 2 2 6.5 2 12s4.5 10 10 10c.926 0 1.648-.746 1.648-1.688 0-.437-.18-.835-.437-1.125-.29-.289-.438-.652-.438-1.125a1.64 1.64 0 0 1 1.668-1.668h1.996c3.051 0 5.555-2.503 5.555-5.554C21.965 6.012 17.461 2 12 2z" })
1395
+ ] });
1396
+ }
1397
+ var buttonBase = {
1398
+ display: "flex",
1399
+ alignItems: "center",
1400
+ justifyContent: "center",
1401
+ width: 32,
1402
+ height: 32,
1403
+ borderRadius: "var(--style-radius-s)",
1404
+ borderWidth: 1,
1405
+ borderStyle: "solid",
1406
+ borderColor: "var(--theme-elevation-150)",
1407
+ background: "var(--theme-elevation-0)",
1408
+ color: "var(--theme-elevation-450)",
1409
+ cursor: "pointer",
1410
+ transition: "all 0.2s ease",
1411
+ padding: 0
1412
+ };
1413
+ var buttonActive = {
1414
+ ...buttonBase,
1415
+ background: "var(--theme-success-50)",
1416
+ borderColor: "var(--theme-success-500)",
1417
+ color: "var(--theme-success-500)"
1418
+ };
1419
+ function ThemeSwitcher({ defaultTheme = "brand-light" }) {
1420
+ const { isDark, isBrand, hasMounted, toggleDarkMode, toggleBrandMode } = useTheme(defaultTheme);
1421
+ const showDark = hasMounted && isDark;
1422
+ const showBrand = hasMounted && isBrand;
1423
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
1424
+ "div",
1425
+ {
1426
+ style: {
1427
+ display: "flex",
1428
+ alignItems: "center",
1429
+ gap: 6,
1430
+ padding: "8px 12px"
1431
+ },
1432
+ children: [
1433
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1434
+ "button",
1435
+ {
1436
+ type: "button",
1437
+ onClick: toggleDarkMode,
1438
+ style: showDark ? buttonActive : buttonBase,
1439
+ title: showDark ? "Switch to light mode" : "Switch to dark mode",
1440
+ "aria-label": showDark ? "Switch to light mode" : "Switch to dark mode",
1441
+ children: showDark ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(MoonIcon, {}) : /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(SunIcon, {})
1442
+ }
1443
+ ),
1444
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1445
+ "button",
1446
+ {
1447
+ type: "button",
1448
+ onClick: toggleBrandMode,
1449
+ style: showBrand ? buttonActive : buttonBase,
1450
+ title: showBrand ? "Switch to standard colors" : "Switch to brand colors",
1451
+ "aria-label": showBrand ? "Switch to standard colors" : "Switch to brand colors",
1452
+ children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(PaletteIcon, {})
1453
+ }
1454
+ )
1455
+ ]
1456
+ }
1457
+ );
1458
+ }
1459
+ function ThemeProvider({ children, defaultTheme = "brand-light" }) {
1460
+ (0, import_react2.useEffect)(() => {
1461
+ try {
1462
+ const stored = localStorage.getItem("orion-admin-theme");
1463
+ const html = document.documentElement;
1464
+ const resolvedTheme = stored && ["light", "dark", "brand-light", "brand-dark"].includes(stored) ? stored : defaultTheme;
1465
+ const isDark = resolvedTheme === "dark" || resolvedTheme === "brand-dark";
1466
+ const isBrand = resolvedTheme === "brand-light" || resolvedTheme === "brand-dark";
1467
+ if (isDark) {
1468
+ html.setAttribute("data-theme", "dark");
1469
+ } else {
1470
+ html.removeAttribute("data-theme");
1471
+ }
1472
+ if (isBrand) {
1473
+ html.setAttribute("data-orion-brand", "true");
1474
+ } else {
1475
+ html.removeAttribute("data-orion-brand");
1476
+ }
1477
+ localStorage.setItem("orion-admin-theme", resolvedTheme);
1478
+ } catch {
1479
+ }
1480
+ }, [defaultTheme]);
1481
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_jsx_runtime3.Fragment, { children });
1482
+ }
1483
+
1484
+ // src/admin/components/HelpTooltip.tsx
1485
+ var import_react3 = require("react");
1486
+ var import_jsx_runtime4 = require("react/jsx-runtime");
1487
+ function HelpTooltip({
1488
+ content,
1489
+ position = "top"
1490
+ }) {
1491
+ const [isVisible, setIsVisible] = (0, import_react3.useState)(false);
1492
+ const triggerRef = (0, import_react3.useRef)(null);
1493
+ const tooltipRef = (0, import_react3.useRef)(null);
1494
+ const tooltipId = (0, import_react3.useRef)(`tooltip-${Math.random().toString(36).slice(2, 9)}`);
1495
+ const show = (0, import_react3.useCallback)(() => setIsVisible(true), []);
1496
+ const hide = (0, import_react3.useCallback)(() => setIsVisible(false), []);
1497
+ const toggle = (0, import_react3.useCallback)(() => setIsVisible((v) => !v), []);
1498
+ (0, import_react3.useEffect)(() => {
1499
+ if (!isVisible) return;
1500
+ const handleKeyDown = (e) => {
1501
+ if (e.key === "Escape") setIsVisible(false);
1502
+ };
1503
+ document.addEventListener("keydown", handleKeyDown);
1504
+ return () => document.removeEventListener("keydown", handleKeyDown);
1505
+ }, [isVisible]);
1506
+ (0, import_react3.useEffect)(() => {
1507
+ if (!isVisible) return;
1508
+ const handleClick = (e) => {
1509
+ if (triggerRef.current && !triggerRef.current.contains(e.target) && tooltipRef.current && !tooltipRef.current.contains(e.target)) {
1510
+ setIsVisible(false);
1511
+ }
1512
+ };
1513
+ document.addEventListener("mousedown", handleClick);
1514
+ return () => document.removeEventListener("mousedown", handleClick);
1515
+ }, [isVisible]);
1516
+ const positionStyles = {
1517
+ top: { bottom: "100%", left: "50%", transform: "translateX(-50%)", marginBottom: 8 },
1518
+ bottom: { top: "100%", left: "50%", transform: "translateX(-50%)", marginTop: 8 },
1519
+ left: { right: "100%", top: "50%", transform: "translateY(-50%)", marginRight: 8 },
1520
+ right: { left: "100%", top: "50%", transform: "translateY(-50%)", marginLeft: 8 }
1521
+ };
1522
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("span", { style: { position: "relative", display: "inline-flex", verticalAlign: "middle", marginLeft: 6 }, children: [
1523
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1524
+ "button",
1525
+ {
1526
+ ref: triggerRef,
1527
+ type: "button",
1528
+ onClick: toggle,
1529
+ onMouseEnter: show,
1530
+ onMouseLeave: hide,
1531
+ onFocus: show,
1532
+ onBlur: hide,
1533
+ "aria-describedby": isVisible ? tooltipId.current : void 0,
1534
+ style: {
1535
+ display: "inline-flex",
1536
+ alignItems: "center",
1537
+ justifyContent: "center",
1538
+ width: 18,
1539
+ height: 18,
1540
+ borderRadius: "50%",
1541
+ border: "1.5px solid var(--admin-text-muted)",
1542
+ background: "transparent",
1543
+ color: "var(--admin-text-muted)",
1544
+ fontSize: 11,
1545
+ fontWeight: 700,
1546
+ cursor: "help",
1547
+ padding: 0,
1548
+ lineHeight: 1,
1549
+ transition: "all 0.15s ease",
1550
+ ...isVisible ? {
1551
+ borderColor: "var(--admin-accent)",
1552
+ color: "var(--admin-accent)",
1553
+ background: "var(--admin-accent-subtle)"
1554
+ } : {}
1555
+ },
1556
+ children: "?"
1557
+ }
1558
+ ),
1559
+ isVisible && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1560
+ "div",
1561
+ {
1562
+ ref: tooltipRef,
1563
+ id: tooltipId.current,
1564
+ role: "tooltip",
1565
+ style: {
1566
+ position: "absolute",
1567
+ ...positionStyles[position],
1568
+ background: "var(--admin-tooltip-bg)",
1569
+ color: "var(--admin-tooltip-text)",
1570
+ padding: "8px 12px",
1571
+ borderRadius: "var(--admin-radius-sm)",
1572
+ fontSize: 12,
1573
+ lineHeight: 1.5,
1574
+ maxWidth: 260,
1575
+ minWidth: 160,
1576
+ whiteSpace: "normal",
1577
+ zIndex: 9999,
1578
+ boxShadow: "0 4px 12px rgba(0, 0, 0, 0.15)",
1579
+ pointerEvents: "auto",
1580
+ animation: "tooltipFadeIn 0.15s ease"
1581
+ },
1582
+ children: content
1583
+ }
1584
+ )
1585
+ ] });
1586
+ }
1587
+
1588
+ // src/admin/components/StatusBadge.tsx
1589
+ var import_jsx_runtime5 = require("react/jsx-runtime");
1590
+ var statusConfig = {
1591
+ draft: { label: "Draft" },
1592
+ published: { label: "Published" },
1593
+ changed: { label: "Changed" }
1594
+ };
1595
+ function StatusBadge({
1596
+ status,
1597
+ size = "md"
1598
+ }) {
1599
+ const config = statusConfig[status];
1600
+ const isSm = size === "sm";
1601
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
1602
+ "span",
1603
+ {
1604
+ style: {
1605
+ display: "inline-flex",
1606
+ alignItems: "center",
1607
+ gap: 4,
1608
+ padding: isSm ? "2px 8px" : "3px 10px",
1609
+ borderRadius: 20,
1610
+ fontSize: isSm ? 11 : 12,
1611
+ fontWeight: 600,
1612
+ lineHeight: 1.4,
1613
+ background: `var(--admin-badge-${status}-bg)`,
1614
+ color: `var(--admin-badge-${status}-text)`,
1615
+ whiteSpace: "nowrap"
1616
+ },
1617
+ children: [
1618
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1619
+ "span",
1620
+ {
1621
+ style: {
1622
+ width: isSm ? 5 : 6,
1623
+ height: isSm ? 5 : 6,
1624
+ borderRadius: "50%",
1625
+ background: "currentColor",
1626
+ flexShrink: 0
1627
+ }
1628
+ }
1629
+ ),
1630
+ config.label
1631
+ ]
1632
+ }
1633
+ );
1634
+ }
1635
+
1636
+ // src/admin/components/Dashboard.tsx
1637
+ var import_jsx_runtime6 = require("react/jsx-runtime");
1638
+ function PagesIcon({ size = 24 }) {
1639
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("svg", { width: size, height: size, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 1.5, strokeLinecap: "round", strokeLinejoin: "round", children: [
1640
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("path", { d: "M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z" }),
1641
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("polyline", { points: "14 2 14 8 20 8" }),
1642
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("line", { x1: "16", y1: "13", x2: "8", y2: "13" }),
1643
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("line", { x1: "16", y1: "17", x2: "8", y2: "17" }),
1644
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("polyline", { points: "10 9 9 9 8 9" })
1645
+ ] });
1646
+ }
1647
+ function MediaIcon({ size = 24 }) {
1648
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("svg", { width: size, height: size, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 1.5, strokeLinecap: "round", strokeLinejoin: "round", children: [
1649
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("rect", { x: "3", y: "3", width: "18", height: "18", rx: "2", ry: "2" }),
1650
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("circle", { cx: "8.5", cy: "8.5", r: "1.5" }),
1651
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("polyline", { points: "21 15 16 10 5 21" })
1652
+ ] });
1653
+ }
1654
+ function SettingsIcon({ size = 24 }) {
1655
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("svg", { width: size, height: size, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 1.5, strokeLinecap: "round", strokeLinejoin: "round", children: [
1656
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("circle", { cx: "12", cy: "12", r: "3" }),
1657
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("path", { d: "M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1 0 2.83 2 2 0 0 1-2.83 0l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-2 2 2 2 0 0 1-2-2v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83 0 2 2 0 0 1 0-2.83l.06-.06A1.65 1.65 0 0 0 4.68 15a1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1-2-2 2 2 0 0 1 2-2h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 0-2.83 2 2 0 0 1 2.83 0l.06.06A1.65 1.65 0 0 0 9 4.68a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 2-2 2 2 0 0 1 2 2v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 0 2 2 0 0 1 0 2.83l-.06.06A1.65 1.65 0 0 0 19.4 9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 2 2 2 2 0 0 1-2 2h-.09a1.65 1.65 0 0 0-1.51 1z" })
1658
+ ] });
1659
+ }
1660
+ function LayoutIcon({ size = 24 }) {
1661
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("svg", { width: size, height: size, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 1.5, strokeLinecap: "round", strokeLinejoin: "round", children: [
1662
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("rect", { x: "3", y: "3", width: "18", height: "18", rx: "2", ry: "2" }),
1663
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("line", { x1: "3", y1: "9", x2: "21", y2: "9" }),
1664
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("line", { x1: "3", y1: "15", x2: "21", y2: "15" })
1665
+ ] });
1666
+ }
1667
+ function PlusIcon({ size = 16 }) {
1668
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("svg", { width: size, height: size, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2.5, strokeLinecap: "round", strokeLinejoin: "round", children: [
1669
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("line", { x1: "12", y1: "5", x2: "12", y2: "19" }),
1670
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("line", { x1: "5", y1: "12", x2: "19", y2: "12" })
1671
+ ] });
1672
+ }
1673
+ function ClockIcon({ size = 14 }) {
1674
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("svg", { width: size, height: size, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2, strokeLinecap: "round", strokeLinejoin: "round", children: [
1675
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("circle", { cx: "12", cy: "12", r: "10" }),
1676
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("polyline", { points: "12 6 12 12 16 14" })
1677
+ ] });
1678
+ }
1679
+ function getGreeting() {
1680
+ const hour = (/* @__PURE__ */ new Date()).getHours();
1681
+ if (hour < 12) return "Good morning";
1682
+ if (hour < 17) return "Good afternoon";
1683
+ return "Good evening";
1684
+ }
1685
+ function formatRelativeTime(dateStr) {
1686
+ const date = new Date(dateStr);
1687
+ const now = /* @__PURE__ */ new Date();
1688
+ const diffMs = now.getTime() - date.getTime();
1689
+ const diffMins = Math.floor(diffMs / 6e4);
1690
+ const diffHours = Math.floor(diffMs / 36e5);
1691
+ const diffDays = Math.floor(diffMs / 864e5);
1692
+ if (diffMins < 1) return "Just now";
1693
+ if (diffMins < 60) return `${diffMins}m ago`;
1694
+ if (diffHours < 24) return `${diffHours}h ago`;
1695
+ if (diffDays < 7) return `${diffDays}d ago`;
1696
+ return date.toLocaleDateString();
1697
+ }
1698
+ function Dashboard() {
1699
+ const [userName, setUserName] = (0, import_react4.useState)("");
1700
+ const [recentPages, setRecentPages] = (0, import_react4.useState)([]);
1701
+ const [pageCount, setPageCount] = (0, import_react4.useState)(null);
1702
+ const [mediaCount, setMediaCount] = (0, import_react4.useState)(null);
1703
+ (0, import_react4.useEffect)(() => {
1704
+ fetch("/api/users/me", { credentials: "include" }).then((res) => res.json()).then((data) => {
1705
+ const user = data?.user || data;
1706
+ setUserName(user?.fullName || user?.email?.split("@")[0] || "");
1707
+ }).catch(() => {
1708
+ });
1709
+ fetch("/api/pages?limit=5&sort=-updatedAt", { credentials: "include" }).then((res) => res.json()).then((data) => {
1710
+ setRecentPages(data?.docs || []);
1711
+ setPageCount(data?.totalDocs ?? null);
1712
+ }).catch(() => {
1713
+ });
1714
+ fetch("/api/media?limit=0", { credentials: "include" }).then((res) => res.json()).then((data) => {
1715
+ setMediaCount(data?.totalDocs ?? null);
1716
+ }).catch(() => {
1717
+ });
1718
+ }, []);
1719
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { style: { padding: "32px", maxWidth: 1200, margin: "0 auto" }, children: [
1720
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { style: { display: "flex", alignItems: "flex-start", justifyContent: "space-between", marginBottom: 32 }, children: [
1721
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { children: [
1722
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("h1", { style: { fontSize: 28, fontWeight: 700, color: "var(--admin-text)", margin: "0 0 6px" }, children: [
1723
+ getGreeting(),
1724
+ userName ? `, ${userName}` : ""
1725
+ ] }),
1726
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { style: { fontSize: 15, color: "var(--admin-text-muted)", margin: 0 }, children: "Manage your website content and settings from here." })
1727
+ ] }),
1728
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(ThemeSwitcher, {})
1729
+ ] }),
1730
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { style: { display: "flex", gap: 10, marginBottom: 32, flexWrap: "wrap" }, children: [
1731
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(QuickAction, { href: "/admin/collections/pages/create", icon: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(PlusIcon, {}), label: "New Page" }),
1732
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(QuickAction, { href: "/admin/collections/media/create", icon: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(PlusIcon, {}), label: "Upload Media" }),
1733
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(QuickAction, { href: "/admin/globals/header", icon: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(LayoutIcon, { size: 16 }), label: "Edit Navigation" }),
1734
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(QuickAction, { href: "/admin/globals/site-settings", icon: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(SettingsIcon, { size: 16 }), label: "Website Settings" })
1735
+ ] }),
1736
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
1737
+ "div",
1738
+ {
1739
+ style: {
1740
+ display: "grid",
1741
+ gap: 20,
1742
+ gridTemplateColumns: "repeat(auto-fit, minmax(300px, 1fr))",
1743
+ marginBottom: 32
1744
+ },
1745
+ children: [
1746
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1747
+ ContentCard,
1748
+ {
1749
+ icon: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(PagesIcon, {}),
1750
+ title: "Pages",
1751
+ description: "Create and manage your website pages",
1752
+ count: pageCount,
1753
+ countLabel: "pages",
1754
+ tooltip: "Pages are the individual sections of your website. Each page has a URL and contains content sections.",
1755
+ actions: [
1756
+ { label: "View All", href: "/admin/collections/pages" },
1757
+ { label: "Create New", href: "/admin/collections/pages/create", primary: true }
1758
+ ]
1759
+ }
1760
+ ),
1761
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1762
+ ContentCard,
1763
+ {
1764
+ icon: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(MediaIcon, {}),
1765
+ title: "Media Library",
1766
+ description: "Upload and organize images and files",
1767
+ count: mediaCount,
1768
+ countLabel: "files",
1769
+ tooltip: "Your media library stores all images, documents, and files used across your website.",
1770
+ actions: [
1771
+ { label: "Browse", href: "/admin/collections/media" },
1772
+ { label: "Upload", href: "/admin/collections/media/create", primary: true }
1773
+ ]
1774
+ }
1775
+ ),
1776
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1777
+ ContentCard,
1778
+ {
1779
+ icon: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(LayoutIcon, {}),
1780
+ title: "Site Design",
1781
+ description: "Customize your header, footer, and site-wide settings",
1782
+ tooltip: "These settings apply to every page on your website \u2014 your navigation menu, footer information, and global SEO settings.",
1783
+ actions: [
1784
+ { label: "Header & Nav", href: "/admin/globals/header" },
1785
+ { label: "Footer", href: "/admin/globals/footer" },
1786
+ { label: "Settings", href: "/admin/globals/site-settings", primary: true }
1787
+ ]
1788
+ }
1789
+ )
1790
+ ]
1791
+ }
1792
+ ),
1793
+ recentPages.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
1794
+ "div",
1795
+ {
1796
+ style: {
1797
+ background: "var(--admin-card-bg)",
1798
+ border: "1px solid var(--admin-card-border)",
1799
+ borderRadius: "var(--admin-radius-lg)",
1800
+ overflow: "hidden"
1801
+ },
1802
+ children: [
1803
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
1804
+ "div",
1805
+ {
1806
+ style: {
1807
+ padding: "16px 20px",
1808
+ borderBottom: "1px solid var(--admin-border-subtle)",
1809
+ display: "flex",
1810
+ alignItems: "center",
1811
+ justifyContent: "space-between"
1812
+ },
1813
+ children: [
1814
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("h3", { style: { fontSize: 15, fontWeight: 600, color: "var(--admin-text)", margin: 0, display: "flex", alignItems: "center", gap: 6 }, children: [
1815
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(ClockIcon, {}),
1816
+ " Recently Edited"
1817
+ ] }),
1818
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1819
+ "a",
1820
+ {
1821
+ href: "/admin/collections/pages",
1822
+ style: { fontSize: 13, color: "var(--admin-accent)", textDecoration: "none", fontWeight: 500 },
1823
+ children: "View all"
1824
+ }
1825
+ )
1826
+ ]
1827
+ }
1828
+ ),
1829
+ recentPages.map((page, i) => /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
1830
+ "a",
1831
+ {
1832
+ href: `/admin/collections/pages/${page.id}`,
1833
+ style: {
1834
+ display: "flex",
1835
+ alignItems: "center",
1836
+ justifyContent: "space-between",
1837
+ padding: "12px 20px",
1838
+ textDecoration: "none",
1839
+ borderBottom: i < recentPages.length - 1 ? "1px solid var(--admin-border-subtle)" : "none",
1840
+ transition: "background-color 0.15s ease"
1841
+ },
1842
+ onMouseEnter: (e) => {
1843
+ e.currentTarget.style.backgroundColor = "var(--admin-surface)";
1844
+ },
1845
+ onMouseLeave: (e) => {
1846
+ e.currentTarget.style.backgroundColor = "transparent";
1847
+ },
1848
+ children: [
1849
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { style: { display: "flex", alignItems: "center", gap: 12, minWidth: 0 }, children: [
1850
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(PagesIcon, { size: 16 }),
1851
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { style: { fontSize: 14, fontWeight: 500, color: "var(--admin-text)", overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }, children: page.title || page.slug || "Untitled" })
1852
+ ] }),
1853
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { style: { display: "flex", alignItems: "center", gap: 12, flexShrink: 0 }, children: [
1854
+ page._status && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(StatusBadge, { status: page._status, size: "sm" }),
1855
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { style: { fontSize: 12, color: "var(--admin-text-muted)", whiteSpace: "nowrap" }, children: formatRelativeTime(page.updatedAt) })
1856
+ ] })
1857
+ ]
1858
+ },
1859
+ page.id
1860
+ ))
1861
+ ]
1862
+ }
1863
+ )
1864
+ ] });
1865
+ }
1866
+ function QuickAction({ href, icon, label }) {
1867
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
1868
+ "a",
1869
+ {
1870
+ href,
1871
+ style: {
1872
+ display: "inline-flex",
1873
+ alignItems: "center",
1874
+ gap: 6,
1875
+ padding: "8px 16px",
1876
+ background: "var(--admin-surface)",
1877
+ border: "1px solid var(--admin-border)",
1878
+ borderRadius: "var(--admin-radius-md)",
1879
+ color: "var(--admin-text)",
1880
+ textDecoration: "none",
1881
+ fontSize: 13,
1882
+ fontWeight: 500,
1883
+ transition: "all 0.2s ease",
1884
+ whiteSpace: "nowrap"
1885
+ },
1886
+ onMouseEnter: (e) => {
1887
+ e.currentTarget.style.borderColor = "var(--admin-accent)";
1888
+ e.currentTarget.style.color = "var(--admin-accent)";
1889
+ e.currentTarget.style.background = "var(--admin-accent-subtle)";
1890
+ },
1891
+ onMouseLeave: (e) => {
1892
+ e.currentTarget.style.borderColor = "var(--admin-border)";
1893
+ e.currentTarget.style.color = "var(--admin-text)";
1894
+ e.currentTarget.style.background = "var(--admin-surface)";
1895
+ },
1896
+ children: [
1897
+ icon,
1898
+ label
1899
+ ]
1900
+ }
1901
+ );
1902
+ }
1903
+ function ContentCard({
1904
+ icon,
1905
+ title,
1906
+ description,
1907
+ count,
1908
+ countLabel,
1909
+ tooltip,
1910
+ actions
1911
+ }) {
1912
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
1913
+ "div",
1914
+ {
1915
+ style: {
1916
+ background: "var(--admin-card-bg)",
1917
+ border: "1px solid var(--admin-card-border)",
1918
+ borderRadius: "var(--admin-radius-lg)",
1919
+ padding: 24,
1920
+ display: "flex",
1921
+ flexDirection: "column",
1922
+ gap: 16,
1923
+ boxShadow: "var(--admin-card-shadow)",
1924
+ transition: "all 0.2s ease"
1925
+ },
1926
+ children: [
1927
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { style: { display: "flex", alignItems: "flex-start", justifyContent: "space-between" }, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { style: { display: "flex", alignItems: "center", gap: 12 }, children: [
1928
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1929
+ "div",
1930
+ {
1931
+ style: {
1932
+ width: 40,
1933
+ height: 40,
1934
+ borderRadius: "var(--admin-radius-md)",
1935
+ background: "var(--admin-accent-subtle)",
1936
+ color: "var(--admin-accent)",
1937
+ display: "flex",
1938
+ alignItems: "center",
1939
+ justifyContent: "center"
1940
+ },
1941
+ children: icon
1942
+ }
1943
+ ),
1944
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { children: [
1945
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("h3", { style: { fontSize: 16, fontWeight: 600, color: "var(--admin-text)", margin: 0, display: "flex", alignItems: "center" }, children: [
1946
+ title,
1947
+ tooltip && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(HelpTooltip, { content: tooltip, position: "right" })
1948
+ ] }),
1949
+ count !== void 0 && count !== null && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("span", { style: { fontSize: 12, color: "var(--admin-text-muted)" }, children: [
1950
+ count,
1951
+ " ",
1952
+ countLabel
1953
+ ] })
1954
+ ] })
1955
+ ] }) }),
1956
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { style: { fontSize: 13, color: "var(--admin-text-muted)", margin: 0, lineHeight: 1.5 }, children: description }),
1957
+ actions && actions.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { style: { display: "flex", gap: 8, marginTop: "auto", flexWrap: "wrap" }, children: actions.map((action) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1958
+ "a",
1959
+ {
1960
+ href: action.href,
1961
+ style: {
1962
+ display: "inline-flex",
1963
+ alignItems: "center",
1964
+ padding: "7px 14px",
1965
+ borderRadius: "var(--admin-radius-sm)",
1966
+ fontSize: 13,
1967
+ fontWeight: 500,
1968
+ textDecoration: "none",
1969
+ transition: "all 0.15s ease",
1970
+ ...action.primary ? {
1971
+ background: "var(--admin-accent)",
1972
+ color: "var(--admin-text-inverse)"
1973
+ } : {
1974
+ background: "var(--admin-surface)",
1975
+ color: "var(--admin-text-secondary)",
1976
+ border: "1px solid var(--admin-border)"
1977
+ }
1978
+ },
1979
+ children: action.label
1980
+ },
1981
+ action.href
1982
+ )) })
1983
+ ]
1984
+ }
1985
+ );
1986
+ }
1987
+
1988
+ // src/admin/components/EmptyState.tsx
1989
+ var import_jsx_runtime7 = require("react/jsx-runtime");
1990
+ function EmptyState({
1991
+ icon,
1992
+ title,
1993
+ description,
1994
+ actionLabel,
1995
+ actionHref
1996
+ }) {
1997
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
1998
+ "div",
1999
+ {
2000
+ style: {
2001
+ display: "flex",
2002
+ flexDirection: "column",
2003
+ alignItems: "center",
2004
+ justifyContent: "center",
2005
+ padding: "48px 24px",
2006
+ textAlign: "center",
2007
+ background: "var(--admin-surface)",
2008
+ borderRadius: "var(--admin-radius-lg)",
2009
+ border: "1px dashed var(--admin-border)"
2010
+ },
2011
+ children: [
2012
+ icon && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
2013
+ "div",
2014
+ {
2015
+ style: {
2016
+ marginBottom: 16,
2017
+ color: "var(--admin-text-muted)",
2018
+ opacity: 0.6
2019
+ },
2020
+ children: icon
2021
+ }
2022
+ ),
2023
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
2024
+ "h3",
2025
+ {
2026
+ style: {
2027
+ fontSize: 18,
2028
+ fontWeight: 600,
2029
+ color: "var(--admin-text)",
2030
+ margin: "0 0 8px"
2031
+ },
2032
+ children: title
2033
+ }
2034
+ ),
2035
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
2036
+ "p",
2037
+ {
2038
+ style: {
2039
+ fontSize: 14,
2040
+ color: "var(--admin-text-muted)",
2041
+ margin: "0 0 20px",
2042
+ maxWidth: 400,
2043
+ lineHeight: 1.5
2044
+ },
2045
+ children: description
2046
+ }
2047
+ ),
2048
+ actionLabel && actionHref && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
2049
+ "a",
2050
+ {
2051
+ href: actionHref,
2052
+ style: {
2053
+ display: "inline-flex",
2054
+ alignItems: "center",
2055
+ gap: 6,
2056
+ padding: "10px 20px",
2057
+ background: "var(--admin-accent)",
2058
+ color: "var(--admin-text-inverse)",
2059
+ borderRadius: "var(--admin-radius-md)",
2060
+ textDecoration: "none",
2061
+ fontWeight: 600,
2062
+ fontSize: 14,
2063
+ transition: "all 0.2s ease"
2064
+ },
2065
+ children: actionLabel
2066
+ }
2067
+ )
2068
+ ]
2069
+ }
2070
+ );
2071
+ }
2072
+
2073
+ // src/admin/client.ts
2074
+ init_BlockPicker();
2075
+ init_SectionTabs();
2076
+
2077
+ // src/admin/components/OrionBlocksField.tsx
2078
+ var import_react9 = require("react");
2079
+ var import_jsx_runtime12 = require("react/jsx-runtime");
2080
+ var OrionBlocksFieldImpl2 = (0, import_react9.lazy)(async () => {
2081
+ const mod = await Promise.resolve().then(() => (init_OrionBlocksFieldImpl(), OrionBlocksFieldImpl_exports));
2082
+ return { default: mod.OrionBlocksFieldImpl };
2083
+ });
2084
+ function OrionBlocksField(props) {
2085
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_react9.Suspense, { fallback: null, children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(OrionBlocksFieldImpl2, { ...props }) });
2086
+ }
2087
+
2088
+ // src/admin/components/WelcomeHeader.tsx
2089
+ var import_jsx_runtime13 = require("react/jsx-runtime");
2090
+ function WelcomeHeader({
2091
+ title,
2092
+ description,
2093
+ tooltip,
2094
+ actions
2095
+ }) {
2096
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
2097
+ "div",
2098
+ {
2099
+ style: {
2100
+ display: "flex",
2101
+ alignItems: "flex-start",
2102
+ justifyContent: "space-between",
2103
+ padding: "24px 0",
2104
+ borderBottom: "1px solid var(--admin-border-subtle)",
2105
+ marginBottom: 24
2106
+ },
2107
+ children: [
2108
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { children: [
2109
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
2110
+ "h1",
2111
+ {
2112
+ style: {
2113
+ fontSize: 24,
2114
+ fontWeight: 700,
2115
+ color: "var(--admin-text)",
2116
+ margin: 0,
2117
+ display: "flex",
2118
+ alignItems: "center"
2119
+ },
2120
+ children: [
2121
+ title,
2122
+ tooltip && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(HelpTooltip, { content: tooltip, position: "right" })
2123
+ ]
2124
+ }
2125
+ ),
2126
+ description && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("p", { style: { fontSize: 14, color: "var(--admin-text-muted)", margin: "6px 0 0" }, children: description })
2127
+ ] }),
2128
+ actions && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { style: { display: "flex", gap: 8 }, children: actions })
2129
+ ]
2130
+ }
2131
+ );
2132
+ }
2133
+
2134
+ // src/admin/components/studio/AdminStudioDashboard.tsx
2135
+ var import_jsx_runtime14 = require("react/jsx-runtime");
2136
+ var cardStyle = {
2137
+ background: "var(--theme-elevation-0)",
2138
+ border: "1px solid var(--theme-elevation-150)",
2139
+ borderRadius: 16,
2140
+ color: "inherit",
2141
+ padding: "1rem",
2142
+ textDecoration: "none"
2143
+ };
2144
+ function AdminStudioDashboard() {
2145
+ return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { style: { padding: "1.2rem 1.2rem 2.5rem" }, children: [
2146
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("h1", { style: { fontSize: "1.6rem", margin: 0 }, children: "Studio" }),
2147
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("p", { style: { color: "var(--theme-elevation-600)", marginTop: "0.35rem" }, children: "Pick what you want to edit." }),
2148
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(
2149
+ "div",
2150
+ {
2151
+ style: {
2152
+ display: "grid",
2153
+ gap: "0.85rem",
2154
+ gridTemplateColumns: "repeat(auto-fit, minmax(240px, 1fr))",
2155
+ marginTop: "1.1rem"
2156
+ },
2157
+ children: [
2158
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("a", { href: "/admin/pages", style: cardStyle, children: [
2159
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { style: { fontWeight: 900 }, children: "Pages" }),
2160
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { style: { color: "var(--theme-elevation-600)", marginTop: "0.25rem" }, children: "Edit your site pages with the custom editor." })
2161
+ ] }),
2162
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("a", { href: "/admin/globals", style: cardStyle, children: [
2163
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { style: { fontWeight: 900 }, children: "Globals" }),
2164
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { style: { color: "var(--theme-elevation-600)", marginTop: "0.25rem" }, children: "Site settings, header, footer." })
2165
+ ] }),
2166
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("a", { href: "/admin/media", style: cardStyle, children: [
2167
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { style: { fontWeight: 900 }, children: "Media" }),
2168
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { style: { color: "var(--theme-elevation-600)", marginTop: "0.25rem" }, children: "Upload and manage images and files." })
2169
+ ] })
2170
+ ]
2171
+ }
2172
+ )
2173
+ ] });
2174
+ }
2175
+
2176
+ // src/admin/components/studio/AdminStudioNav.tsx
2177
+ var import_react10 = require("react");
2178
+ var import_ui3 = require("@payloadcms/ui");
2179
+ var import_jsx_runtime15 = require("react/jsx-runtime");
2180
+ var isAdmin = (user) => {
2181
+ if (!user || typeof user !== "object") return false;
2182
+ const role = user.role;
2183
+ return typeof role === "string" && role === "admin";
2184
+ };
2185
+ var getPropString = (props, key, fallback) => {
2186
+ if (!props || typeof props !== "object") return fallback;
2187
+ const direct = props[key];
2188
+ if (typeof direct === "string" && direct.length > 0) return direct;
2189
+ const clientProps = props.clientProps;
2190
+ if (clientProps && typeof clientProps === "object") {
2191
+ const nested = clientProps[key];
2192
+ if (typeof nested === "string" && nested.length > 0) return nested;
2193
+ }
2194
+ return fallback;
2195
+ };
2196
+ function AdminStudioNav(props) {
2197
+ const { user } = (0, import_ui3.useAuth)();
2198
+ const brandName = getPropString(props, "brandName", "Orion Studio");
2199
+ const [pathname, setPathname] = (0, import_react10.useState)("");
2200
+ (0, import_react10.useEffect)(() => {
2201
+ const update = () => setPathname(window.location.pathname);
2202
+ update();
2203
+ window.addEventListener("popstate", update);
2204
+ return () => window.removeEventListener("popstate", update);
2205
+ }, []);
2206
+ const links = (0, import_react10.useMemo)(
2207
+ () => [
2208
+ { href: "/admin", label: "Dashboard", matchPrefixes: ["/admin"] },
2209
+ {
2210
+ href: "/admin/pages",
2211
+ label: "Pages",
2212
+ matchPrefixes: ["/admin/pages", "/admin/collections/pages"]
2213
+ },
2214
+ { href: "/admin/globals", label: "Globals", matchPrefixes: ["/admin/globals"] },
2215
+ {
2216
+ href: "/admin/media",
2217
+ label: "Media",
2218
+ matchPrefixes: ["/admin/media", "/admin/collections/media"]
2219
+ },
2220
+ {
2221
+ href: "/admin/tools",
2222
+ label: "Admin Tools",
2223
+ matchPrefixes: ["/admin/tools"],
2224
+ adminOnly: true
2225
+ }
2226
+ ],
2227
+ []
2228
+ );
2229
+ const linkStyle = (active) => ({
2230
+ background: active ? "var(--theme-elevation-100)" : "transparent",
2231
+ borderRadius: 10,
2232
+ color: "var(--theme-elevation-900)",
2233
+ display: "block",
2234
+ fontSize: "0.95rem",
2235
+ fontWeight: active ? 800 : 650,
2236
+ padding: "0.6rem 0.75rem",
2237
+ textDecoration: "none"
2238
+ });
2239
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
2240
+ "div",
2241
+ {
2242
+ style: {
2243
+ display: "flex",
2244
+ flexDirection: "column",
2245
+ gap: "0.85rem",
2246
+ height: "100%",
2247
+ padding: "1rem 0.85rem"
2248
+ },
2249
+ children: [
2250
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { style: { padding: "0 0.35rem" }, children: [
2251
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { style: { fontSize: "1.05rem", fontWeight: 900, letterSpacing: "-0.01em" }, children: brandName }),
2252
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { style: { color: "var(--theme-elevation-600)", fontSize: "0.85rem" }, children: "Studio" })
2253
+ ] }),
2254
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("nav", { style: { display: "grid", gap: "0.25rem" }, children: links.filter((link) => !link.adminOnly || isAdmin(user)).map((link) => {
2255
+ const active = link.href === "/admin" ? pathname === "/admin" : link.matchPrefixes.some((prefix) => pathname.startsWith(prefix));
2256
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("a", { href: link.href, style: linkStyle(active), children: link.label }, link.href);
2257
+ }) }),
2258
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { style: { flex: 1 } }),
2259
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
2260
+ "div",
2261
+ {
2262
+ style: {
2263
+ borderTop: "1px solid var(--theme-elevation-150)",
2264
+ paddingTop: "0.85rem"
2265
+ },
2266
+ children: [
2267
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { style: { color: "var(--theme-elevation-700)", fontSize: "0.85rem" }, children: "Signed in as" }),
2268
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { style: { fontWeight: 800, marginBottom: "0.55rem" }, children: typeof user?.email === "string" ? user.email : "User" }),
2269
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_ui3.Logout, {})
2270
+ ]
2271
+ }
2272
+ )
2273
+ ]
2274
+ }
2275
+ );
2276
+ }
2277
+
2278
+ // src/admin/components/studio/AdminStudioPagesListView.tsx
2279
+ var import_react11 = require("react");
2280
+ var import_ui4 = require("@payloadcms/ui");
2281
+ var import_jsx_runtime16 = require("react/jsx-runtime");
2282
+ var isAdmin2 = (user) => {
2283
+ if (!user || typeof user !== "object") return false;
2284
+ const role = user.role;
2285
+ return typeof role === "string" && role === "admin";
2286
+ };
2287
+ var getPropString2 = (props, key, fallback) => {
2288
+ if (!props || typeof props !== "object") return fallback;
2289
+ const direct = props[key];
2290
+ if (typeof direct === "string" && direct.length > 0) return direct;
2291
+ const clientProps = props.clientProps;
2292
+ if (clientProps && typeof clientProps === "object") {
2293
+ const nested = clientProps[key];
2294
+ if (typeof nested === "string" && nested.length > 0) return nested;
2295
+ }
2296
+ return fallback;
2297
+ };
2298
+ function AdminStudioPagesListView(props) {
2299
+ const { user } = (0, import_ui4.useAuth)();
2300
+ const pagesCollectionSlug = getPropString2(props, "pagesCollectionSlug", "pages");
2301
+ const [loading, setLoading] = (0, import_react11.useState)(true);
2302
+ const [error, setError] = (0, import_react11.useState)(null);
2303
+ const [docs, setDocs] = (0, import_react11.useState)([]);
2304
+ const apiURL = (0, import_react11.useMemo)(() => {
2305
+ const params = new URLSearchParams({
2306
+ depth: "0",
2307
+ limit: "100",
2308
+ sort: "-updatedAt",
2309
+ draft: "true"
2310
+ });
2311
+ return `/api/${pagesCollectionSlug}?${params.toString()}`;
2312
+ }, [pagesCollectionSlug]);
2313
+ (0, import_react11.useEffect)(() => {
2314
+ let cancelled = false;
2315
+ const run = async () => {
2316
+ setLoading(true);
2317
+ setError(null);
2318
+ try {
2319
+ const res = await fetch(apiURL, { credentials: "include" });
2320
+ if (!res.ok) {
2321
+ const body = await res.text();
2322
+ throw new Error(body || "Failed to fetch pages");
2323
+ }
2324
+ const data = await res.json();
2325
+ const nextDocs = Array.isArray(data.docs) ? data.docs : [];
2326
+ if (!cancelled) setDocs(nextDocs);
2327
+ } catch (err) {
2328
+ if (!cancelled) setError(err instanceof Error ? err.message : "Failed to fetch pages");
2329
+ } finally {
2330
+ if (!cancelled) setLoading(false);
2331
+ }
2332
+ };
2333
+ void run();
2334
+ return () => {
2335
+ cancelled = true;
2336
+ };
2337
+ }, [apiURL]);
2338
+ return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { style: { padding: "1.2rem 1.2rem 2.5rem" }, children: [
2339
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { style: { alignItems: "flex-end", display: "flex", gap: "0.75rem" }, children: [
2340
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { style: { flex: 1 }, children: [
2341
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("h1", { style: { margin: 0 }, children: "Pages" }),
2342
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("p", { style: { color: "var(--theme-elevation-600)", marginTop: "0.35rem" }, children: "Open a page to edit it in the custom editor." })
2343
+ ] }),
2344
+ isAdmin2(user) ? /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
2345
+ "a",
2346
+ {
2347
+ href: `/admin/collections/${pagesCollectionSlug}/create`,
2348
+ style: {
2349
+ background: "var(--theme-elevation-900)",
2350
+ borderRadius: 12,
2351
+ color: "var(--theme-elevation-0)",
2352
+ fontWeight: 800,
2353
+ padding: "0.55rem 0.85rem",
2354
+ textDecoration: "none"
2355
+ },
2356
+ children: "New Page"
2357
+ }
2358
+ ) : null
2359
+ ] }),
2360
+ loading ? /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { style: { color: "var(--theme-elevation-600)", marginTop: "1rem" }, children: "Loading\u2026" }) : null,
2361
+ error ? /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { style: { color: "crimson", marginTop: "1rem" }, children: error }) : null,
2362
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { style: { display: "grid", gap: "0.6rem", marginTop: "1rem" }, children: [
2363
+ !loading && !error && docs.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
2364
+ "div",
2365
+ {
2366
+ style: {
2367
+ border: "1px dashed var(--theme-elevation-300)",
2368
+ borderRadius: 16,
2369
+ color: "var(--theme-elevation-700)",
2370
+ padding: "1rem"
2371
+ },
2372
+ children: "No pages found."
2373
+ }
2374
+ ) : null,
2375
+ docs.map((doc) => {
2376
+ const id = typeof doc.id === "string" || typeof doc.id === "number" ? String(doc.id) : "";
2377
+ const title = typeof doc.title === "string" ? doc.title : "Untitled Page";
2378
+ const path = typeof doc.path === "string" ? doc.path : "/";
2379
+ const status = typeof doc._status === "string" ? doc._status : "";
2380
+ if (!id) return null;
2381
+ return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(
2382
+ "a",
2383
+ {
2384
+ href: `/admin/pages/${id}`,
2385
+ style: {
2386
+ background: "var(--theme-elevation-0)",
2387
+ border: "1px solid var(--theme-elevation-150)",
2388
+ borderRadius: 16,
2389
+ color: "inherit",
2390
+ display: "flex",
2391
+ gap: "0.85rem",
2392
+ justifyContent: "space-between",
2393
+ padding: "0.85rem 1rem",
2394
+ textDecoration: "none"
2395
+ },
2396
+ children: [
2397
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { style: { minWidth: 0 }, children: [
2398
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { style: { fontWeight: 900, overflow: "hidden", textOverflow: "ellipsis" }, children: title }),
2399
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
2400
+ "div",
2401
+ {
2402
+ style: {
2403
+ color: "var(--theme-elevation-600)",
2404
+ fontSize: "0.9rem",
2405
+ overflow: "hidden",
2406
+ textOverflow: "ellipsis"
2407
+ },
2408
+ children: path
2409
+ }
2410
+ )
2411
+ ] }),
2412
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(
2413
+ "div",
2414
+ {
2415
+ style: {
2416
+ alignItems: "center",
2417
+ display: "flex",
2418
+ flexShrink: 0,
2419
+ gap: "0.5rem"
2420
+ },
2421
+ children: [
2422
+ status ? /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
2423
+ "span",
2424
+ {
2425
+ style: {
2426
+ background: status === "published" ? "rgba(16, 185, 129, 0.12)" : "rgba(245, 158, 11, 0.14)",
2427
+ borderRadius: 999,
2428
+ color: status === "published" ? "rgb(5, 122, 85)" : "rgb(180, 83, 9)",
2429
+ fontSize: "0.82rem",
2430
+ fontWeight: 900,
2431
+ padding: "0.25rem 0.55rem",
2432
+ textTransform: "capitalize"
2433
+ },
2434
+ children: status
2435
+ }
2436
+ ) : null,
2437
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { style: { color: "var(--theme-elevation-600)", fontWeight: 800 }, children: "Open" })
2438
+ ]
2439
+ }
2440
+ )
2441
+ ]
2442
+ },
2443
+ id
2444
+ );
2445
+ })
2446
+ ] })
2447
+ ] });
2448
+ }
2449
+
2450
+ // src/admin/components/studio/AdminStudioPageEditView.tsx
2451
+ var import_react12 = require("react");
2452
+ var import_ui5 = require("@payloadcms/ui");
2453
+ var import_jsx_runtime17 = require("react/jsx-runtime");
2454
+ var isAdmin3 = (user) => {
2455
+ if (!user || typeof user !== "object") return false;
2456
+ const role = user.role;
2457
+ return typeof role === "string" && role === "admin";
2458
+ };
2459
+ var isEditor = (user) => {
2460
+ if (!user || typeof user !== "object") return false;
2461
+ const role = user.role;
2462
+ return typeof role === "string" && role === "editor";
2463
+ };
2464
+ var getPropString3 = (props, key, fallback) => {
2465
+ if (!props || typeof props !== "object") return fallback;
2466
+ const direct = props[key];
2467
+ if (typeof direct === "string" && direct.length > 0) return direct;
2468
+ const clientProps = props.clientProps;
2469
+ if (clientProps && typeof clientProps === "object") {
2470
+ const nested = clientProps[key];
2471
+ if (typeof nested === "string" && nested.length > 0) return nested;
2472
+ }
2473
+ return fallback;
2474
+ };
2475
+ var getParam = (params, key) => {
2476
+ if (!params || typeof params !== "object") return null;
2477
+ if (!(key in params)) return null;
2478
+ const value = params[key];
2479
+ if (typeof value === "string") return value;
2480
+ if (Array.isArray(value) && typeof value[0] === "string") return value[0];
2481
+ return null;
2482
+ };
2483
+ var getPageIDFromPathname = (pathname) => {
2484
+ const match = pathname.match(/\/admin\/pages\/([^/]+)(?:\/|$)/);
2485
+ return match?.[1] ? decodeURIComponent(match[1]) : null;
2486
+ };
2487
+ function AdminStudioPageEditView(props) {
2488
+ const { user } = (0, import_ui5.useAuth)();
2489
+ const iframeRef = (0, import_react12.useRef)(null);
2490
+ const [saving, setSaving] = (0, import_react12.useState)(null);
2491
+ const builderBasePath = getPropString3(props, "builderBasePath", "/builder");
2492
+ const pageID = (0, import_react12.useMemo)(() => {
2493
+ const fromProps = getParam(props.params, "id");
2494
+ if (fromProps) return fromProps;
2495
+ if (typeof window !== "undefined") {
2496
+ return getPageIDFromPathname(window.location.pathname);
2497
+ }
2498
+ return null;
2499
+ }, [props.params]);
2500
+ const canPublish = isAdmin3(user) || isEditor(user);
2501
+ const requestSave = (status) => {
2502
+ const iframe = iframeRef.current;
2503
+ if (!iframe?.contentWindow) {
2504
+ import_ui5.toast.error("Editor is not ready yet. Please try again.");
2505
+ return;
2506
+ }
2507
+ setSaving(status);
2508
+ iframe.contentWindow.postMessage({ source: "payload-visual-builder-parent", type: "save", status }, "*");
2509
+ };
2510
+ (0, import_react12.useEffect)(() => {
2511
+ const onMessage = (event) => {
2512
+ const data = event.data;
2513
+ if (!data || data.source !== "payload-visual-builder-child" || data.type !== "save-result") {
2514
+ return;
2515
+ }
2516
+ setSaving(null);
2517
+ if (data.ok) {
2518
+ import_ui5.toast.success(typeof data.message === "string" ? data.message : "Saved.");
2519
+ } else {
2520
+ import_ui5.toast.error(typeof data.message === "string" ? data.message : "Save failed.");
2521
+ }
2522
+ };
2523
+ window.addEventListener("message", onMessage);
2524
+ return () => window.removeEventListener("message", onMessage);
2525
+ }, []);
2526
+ if (!pageID) {
2527
+ return /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { style: { padding: "1.2rem" }, children: [
2528
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("h1", { style: { margin: 0 }, children: "Page Editor" }),
2529
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("p", { style: { color: "var(--theme-elevation-600)" }, children: "Missing page ID." })
2530
+ ] });
2531
+ }
2532
+ return /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { style: { display: "grid", gridTemplateRows: "auto 1fr", height: "calc(100vh - 0px)" }, children: [
2533
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(
2534
+ "div",
2535
+ {
2536
+ style: {
2537
+ alignItems: "center",
2538
+ background: "var(--theme-elevation-0)",
2539
+ borderBottom: "1px solid var(--theme-elevation-150)",
2540
+ display: "flex",
2541
+ gap: "0.6rem",
2542
+ justifyContent: "space-between",
2543
+ padding: "0.65rem 0.9rem",
2544
+ position: "sticky",
2545
+ top: 0,
2546
+ zIndex: 20
2547
+ },
2548
+ children: [
2549
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { style: { minWidth: 0 }, children: [
2550
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { style: { fontWeight: 900 }, children: "Page Editor" }),
2551
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(
2552
+ "div",
2553
+ {
2554
+ style: {
2555
+ color: "var(--theme-elevation-600)",
2556
+ fontSize: "0.85rem",
2557
+ overflow: "hidden",
2558
+ textOverflow: "ellipsis"
2559
+ },
2560
+ children: [
2561
+ "Editing: ",
2562
+ pageID
2563
+ ]
2564
+ }
2565
+ )
2566
+ ] }),
2567
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { style: { alignItems: "center", display: "flex", gap: "0.5rem" }, children: [
2568
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
2569
+ "button",
2570
+ {
2571
+ disabled: saving !== null,
2572
+ onClick: () => requestSave("draft"),
2573
+ style: {
2574
+ border: "1px solid var(--theme-elevation-300)",
2575
+ borderRadius: 12,
2576
+ cursor: saving ? "not-allowed" : "pointer",
2577
+ fontWeight: 800,
2578
+ padding: "0.5rem 0.75rem"
2579
+ },
2580
+ type: "button",
2581
+ children: saving === "draft" ? "Saving\u2026" : "Save Draft"
2582
+ }
2583
+ ),
2584
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
2585
+ "button",
2586
+ {
2587
+ disabled: !canPublish || saving !== null,
2588
+ onClick: () => requestSave("published"),
2589
+ style: {
2590
+ background: canPublish ? "var(--theme-elevation-900)" : "var(--theme-elevation-300)",
2591
+ border: "none",
2592
+ borderRadius: 12,
2593
+ color: canPublish ? "var(--theme-elevation-0)" : "var(--theme-elevation-700)",
2594
+ cursor: !canPublish || saving ? "not-allowed" : "pointer",
2595
+ fontWeight: 900,
2596
+ padding: "0.5rem 0.75rem"
2597
+ },
2598
+ type: "button",
2599
+ title: !canPublish ? "You do not have publish permissions." : void 0,
2600
+ children: saving === "published" ? "Publishing\u2026" : "Publish"
2601
+ }
2602
+ )
2603
+ ] })
2604
+ ]
2605
+ }
2606
+ ),
2607
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
2608
+ "iframe",
2609
+ {
2610
+ ref: iframeRef,
2611
+ src: `${builderBasePath.replace(/\/$/, "")}/${pageID}`,
2612
+ style: { border: "none", height: "100%", width: "100%" },
2613
+ title: "Page Builder"
2614
+ }
2615
+ )
2616
+ ] });
2617
+ }
2618
+
2619
+ // src/admin/components/studio/AdminStudioGlobalsView.tsx
2620
+ var import_jsx_runtime18 = require("react/jsx-runtime");
2621
+ var getPropGlobals = (props) => {
2622
+ if (!props || typeof props !== "object") return null;
2623
+ const direct = props.globals;
2624
+ if (Array.isArray(direct)) return direct;
2625
+ const clientProps = props.clientProps;
2626
+ if (clientProps && typeof clientProps === "object") {
2627
+ const nested = clientProps.globals;
2628
+ if (Array.isArray(nested)) return nested;
2629
+ }
2630
+ return null;
2631
+ };
2632
+ function AdminStudioGlobalsView(props) {
2633
+ const globals = getPropGlobals(props) || [
2634
+ { slug: "site-settings", label: "Website Settings" },
2635
+ { slug: "header", label: "Header & Navigation" },
2636
+ { slug: "footer", label: "Footer" }
2637
+ ];
2638
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { style: { padding: "1.2rem 1.2rem 2.5rem" }, children: [
2639
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("h1", { style: { margin: 0 }, children: "Globals" }),
2640
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("p", { style: { color: "var(--theme-elevation-600)", marginTop: "0.35rem" }, children: "Site-wide settings." }),
2641
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { style: { display: "grid", gap: "0.6rem", marginTop: "1rem" }, children: globals.map((global) => /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(
2642
+ "a",
2643
+ {
2644
+ href: `/admin/globals/${global.slug}`,
2645
+ style: {
2646
+ background: "var(--theme-elevation-0)",
2647
+ border: "1px solid var(--theme-elevation-150)",
2648
+ borderRadius: 16,
2649
+ color: "inherit",
2650
+ padding: "0.85rem 1rem",
2651
+ textDecoration: "none"
2652
+ },
2653
+ children: [
2654
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { style: { fontWeight: 900 }, children: global.label }),
2655
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { style: { color: "var(--theme-elevation-600)", fontSize: "0.9rem" }, children: [
2656
+ "/admin/globals/",
2657
+ global.slug
2658
+ ] })
2659
+ ]
2660
+ },
2661
+ global.slug
2662
+ )) })
2663
+ ] });
2664
+ }
2665
+
2666
+ // src/admin/components/studio/AdminStudioMediaView.tsx
2667
+ var import_jsx_runtime19 = require("react/jsx-runtime");
2668
+ var getPropString4 = (props, key, fallback) => {
2669
+ if (!props || typeof props !== "object") return fallback;
2670
+ const direct = props[key];
2671
+ if (typeof direct === "string" && direct.length > 0) return direct;
2672
+ const clientProps = props.clientProps;
2673
+ if (clientProps && typeof clientProps === "object") {
2674
+ const nested = clientProps[key];
2675
+ if (typeof nested === "string" && nested.length > 0) return nested;
2676
+ }
2677
+ return fallback;
2678
+ };
2679
+ function AdminStudioMediaView(props) {
2680
+ const mediaCollectionSlug = getPropString4(props, "mediaCollectionSlug", "media");
2681
+ return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { style: { padding: "1.2rem 1.2rem 2.5rem" }, children: [
2682
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("h1", { style: { margin: 0 }, children: "Media" }),
2683
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("p", { style: { color: "var(--theme-elevation-600)", marginTop: "0.35rem" }, children: "Media management is currently using Payload\u2019s library." }),
2684
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { style: { display: "grid", gap: "0.6rem", marginTop: "1rem" }, children: /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(
2685
+ "a",
2686
+ {
2687
+ href: `/admin/collections/${mediaCollectionSlug}`,
2688
+ style: {
2689
+ background: "var(--theme-elevation-0)",
2690
+ border: "1px solid var(--theme-elevation-150)",
2691
+ borderRadius: 16,
2692
+ color: "inherit",
2693
+ padding: "0.85rem 1rem",
2694
+ textDecoration: "none"
2695
+ },
2696
+ children: [
2697
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { style: { fontWeight: 900 }, children: "Open Media Library" }),
2698
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { style: { color: "var(--theme-elevation-600)", fontSize: "0.9rem" }, children: [
2699
+ "/admin/collections/",
2700
+ mediaCollectionSlug
2701
+ ] })
2702
+ ]
2703
+ }
2704
+ ) })
2705
+ ] });
2706
+ }
2707
+
2708
+ // src/admin/components/studio/AdminStudioToolsView.tsx
2709
+ var import_ui6 = require("@payloadcms/ui");
2710
+ var import_jsx_runtime20 = require("react/jsx-runtime");
2711
+ var isAdmin4 = (user) => {
2712
+ if (!user || typeof user !== "object") return false;
2713
+ const role = user.role;
2714
+ return typeof role === "string" && role === "admin";
2715
+ };
2716
+ var getPropString5 = (props, key, fallback) => {
2717
+ if (!props || typeof props !== "object") return fallback;
2718
+ const direct = props[key];
2719
+ if (typeof direct === "string" && direct.length > 0) return direct;
2720
+ const clientProps = props.clientProps;
2721
+ if (clientProps && typeof clientProps === "object") {
2722
+ const nested = clientProps[key];
2723
+ if (typeof nested === "string" && nested.length > 0) return nested;
2724
+ }
2725
+ return fallback;
2726
+ };
2727
+ function AdminStudioToolsView(props) {
2728
+ const { user } = (0, import_ui6.useAuth)();
2729
+ if (!isAdmin4(user)) {
2730
+ return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { style: { padding: "1.2rem" }, children: [
2731
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("h1", { style: { margin: 0 }, children: "Admin Tools" }),
2732
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("p", { style: { color: "var(--theme-elevation-600)" }, children: "You do not have access to this page." })
2733
+ ] });
2734
+ }
2735
+ const pagesCollectionSlug = getPropString5(props, "pagesCollectionSlug", "pages");
2736
+ const mediaCollectionSlug = getPropString5(props, "mediaCollectionSlug", "media");
2737
+ const links = [
2738
+ { href: `/admin/collections/${pagesCollectionSlug}`, label: "Raw Pages Collection" },
2739
+ { href: `/admin/collections/${mediaCollectionSlug}`, label: "Raw Media Collection" },
2740
+ { href: "/admin/globals/site-settings", label: "Raw Site Settings Global" },
2741
+ { href: "/admin/globals/header", label: "Raw Header Global" },
2742
+ { href: "/admin/globals/footer", label: "Raw Footer Global" },
2743
+ { href: "/admin/collections/users", label: "Users / Roles" }
2744
+ ];
2745
+ return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { style: { padding: "1.2rem 1.2rem 2.5rem" }, children: [
2746
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("h1", { style: { margin: 0 }, children: "Admin Tools" }),
2747
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("p", { style: { color: "var(--theme-elevation-600)", marginTop: "0.35rem" }, children: "Hidden fallback links for administrators." }),
2748
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { style: { display: "grid", gap: "0.6rem", marginTop: "1rem" }, children: links.map((link) => /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(
2749
+ "a",
2750
+ {
2751
+ href: link.href,
2752
+ style: {
2753
+ background: "var(--theme-elevation-0)",
2754
+ border: "1px solid var(--theme-elevation-150)",
2755
+ borderRadius: 16,
2756
+ color: "inherit",
2757
+ padding: "0.85rem 1rem",
2758
+ textDecoration: "none"
2759
+ },
2760
+ children: [
2761
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { style: { fontWeight: 900 }, children: link.label }),
2762
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { style: { color: "var(--theme-elevation-600)", fontSize: "0.9rem" }, children: link.href })
2763
+ ]
2764
+ },
2765
+ link.href
2766
+ )) })
2767
+ ] });
2768
+ }
2769
+
2770
+ // src/admin/components/studio/OpenInStudioMenuItem.tsx
2771
+ var import_ui7 = require("@payloadcms/ui");
2772
+ var import_jsx_runtime21 = require("react/jsx-runtime");
2773
+ function OpenInStudioMenuItem({ pagesPathBase = "/admin/pages" }) {
2774
+ const documentInfo = (0, import_ui7.useDocumentInfo)();
2775
+ const id = documentInfo?.id;
2776
+ if (!id) {
2777
+ return null;
2778
+ }
2779
+ return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
2780
+ "a",
2781
+ {
2782
+ href: `${pagesPathBase}/${id}`,
2783
+ style: {
2784
+ color: "var(--theme-elevation-800)",
2785
+ display: "block",
2786
+ fontSize: "0.92rem",
2787
+ lineHeight: 1.3,
2788
+ padding: "0.45rem 0.7rem",
2789
+ textDecoration: "none",
2790
+ width: "100%"
2791
+ },
2792
+ children: "Open Editor"
2793
+ }
2794
+ );
2795
+ }
2796
+
2797
+ // src/admin/components/studio/PageEditRedirectToStudio.tsx
2798
+ var import_react13 = require("react");
2799
+ var import_ui8 = require("@payloadcms/ui");
2800
+ var import_jsx_runtime22 = require("react/jsx-runtime");
2801
+ function PageEditRedirectToStudio({ pagesPathBase = "/admin/pages" }) {
2802
+ const documentInfo = (0, import_ui8.useDocumentInfo)();
2803
+ const id = documentInfo?.id;
2804
+ (0, import_react13.useEffect)(() => {
2805
+ if (!id) {
2806
+ return;
2807
+ }
2808
+ window.location.replace(`${pagesPathBase}/${id}`);
2809
+ }, [id, pagesPathBase]);
2810
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(
2811
+ "div",
2812
+ {
2813
+ style: {
2814
+ alignItems: "center",
2815
+ display: "flex",
2816
+ flexDirection: "column",
2817
+ gap: "0.75rem",
2818
+ justifyContent: "center",
2819
+ minHeight: "50vh"
2820
+ },
2821
+ children: [
2822
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("h2", { style: { margin: 0 }, children: "Opening Editor..." }),
2823
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("p", { style: { color: "var(--theme-elevation-600)", margin: 0 }, children: "Redirecting to the custom page editor." }),
2824
+ id ? /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("a", { href: `${pagesPathBase}/${id}`, children: "Continue to Editor" }) : /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("a", { href: pagesPathBase, children: "Open Pages" })
2825
+ ]
2826
+ }
2827
+ );
2828
+ }
2829
+ // Annotate the CommonJS export names for ESM import in node:
2830
+ 0 && (module.exports = {
2831
+ AdminStudioDashboard,
2832
+ AdminStudioGlobalsView,
2833
+ AdminStudioMediaView,
2834
+ AdminStudioNav,
2835
+ AdminStudioPageEditView,
2836
+ AdminStudioPagesListView,
2837
+ AdminStudioToolsView,
2838
+ BlockPicker,
2839
+ Dashboard,
2840
+ EmptyState,
2841
+ HelpTooltip,
2842
+ Icon,
2843
+ Logo,
2844
+ OpenInStudioMenuItem,
2845
+ OrionBlocksField,
2846
+ PageEditRedirectToStudio,
2847
+ SectionTabs,
2848
+ StatusBadge,
2849
+ ThemeProvider,
2850
+ ThemeSwitcher,
2851
+ WelcomeHeader,
2852
+ useTheme
2853
+ });