@orion-studios/payload-studio 0.6.0-beta.4 → 0.6.0-beta.41
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.
- package/dist/admin/client.d.mts +1 -0
- package/dist/admin/client.d.ts +1 -0
- package/dist/admin/client.js +3924 -1355
- package/dist/admin/client.mjs +4090 -1533
- package/dist/admin/index.d.mts +2 -3
- package/dist/admin/index.d.ts +2 -3
- package/dist/admin/index.js +141 -1522
- package/dist/admin/index.mjs +2 -4
- package/dist/admin-app/client.js +11 -4
- package/dist/admin-app/client.mjs +1 -1
- package/dist/admin-app/index.d.mts +2 -2
- package/dist/admin-app/index.d.ts +2 -2
- package/dist/admin-app/index.mjs +4 -4
- package/dist/admin-app/styles.css +343 -41
- package/dist/admin.css +18 -2
- package/dist/{chunk-KPIX7OSV.mjs → chunk-2XH7X34N.mjs} +11 -4
- package/dist/{chunk-PF3EBZXF.mjs → chunk-7ZMXZRBP.mjs} +39 -3
- package/dist/chunk-JC3UV74N.mjs +1033 -0
- package/dist/{chunk-XKUTZ7IU.mjs → chunk-OL53KHTB.mjs} +46 -2
- package/dist/{chunk-EHUE4LCT.mjs → chunk-RKTIFEUY.mjs} +33 -3
- package/dist/chunk-W2UOCJDX.mjs +32 -0
- package/dist/{chunk-OTHERBGX.mjs → chunk-ZADL33R6.mjs} +1 -1
- package/dist/{index-bbA3HSxa.d.ts → index-BV0vEGl6.d.ts} +6 -9
- package/dist/{index-Cv-6qnrw.d.mts → index-D5zrOdyv.d.mts} +3 -1
- package/dist/{index-52HdVLQq.d.ts → index-DAdN56fM.d.ts} +1 -1
- package/dist/{index-DEkV-sMs.d.mts → index-DLfPOqYA.d.mts} +6 -9
- package/dist/{index-Crx_MtPw.d.ts → index-Dv-Alx4h.d.ts} +3 -1
- package/dist/{index-DEQC3Dwj.d.mts → index-G_uTNffQ.d.mts} +1 -1
- package/dist/index.d.mts +5 -5
- package/dist/index.d.ts +5 -5
- package/dist/index.js +287 -1542
- package/dist/index.mjs +6 -6
- package/dist/nextjs/index.js +39 -3
- package/dist/nextjs/index.mjs +2 -2
- package/dist/{sitePreviewTypes-BkHCWxNW.d.mts → sitePreviewTypes-BrJwGzJj.d.mts} +1 -1
- package/dist/{sitePreviewTypes-BkHCWxNW.d.ts → sitePreviewTypes-BrJwGzJj.d.ts} +1 -1
- package/dist/studio-pages/builder.css +24 -5
- package/dist/studio-pages/client.js +529 -63
- package/dist/studio-pages/client.mjs +529 -63
- package/dist/studio-pages/index.d.mts +1 -1
- package/dist/studio-pages/index.d.ts +1 -1
- package/dist/studio-pages/index.js +84 -4
- package/dist/studio-pages/index.mjs +2 -2
- package/package.json +1 -1
- package/dist/chunk-DYXSAVUQ.mjs +0 -2372
- package/dist/chunk-Z6L5K5MH.mjs +0 -64
package/dist/index.js
CHANGED
|
@@ -42,7 +42,6 @@ module.exports = __toCommonJS(index_exports);
|
|
|
42
42
|
// src/admin/index.ts
|
|
43
43
|
var admin_exports = {};
|
|
44
44
|
__export(admin_exports, {
|
|
45
|
-
AdminStudioDashboard: () => AdminStudioDashboard,
|
|
46
45
|
SOCIAL_MEDIA_DEFAULT_ICON_BY_PLATFORM: () => SOCIAL_MEDIA_DEFAULT_ICON_BY_PLATFORM,
|
|
47
46
|
SOCIAL_MEDIA_ICON_OPTIONS: () => SOCIAL_MEDIA_ICON_OPTIONS,
|
|
48
47
|
SOCIAL_MEDIA_PLATFORMS: () => SOCIAL_MEDIA_PLATFORMS,
|
|
@@ -108,9 +107,8 @@ var navItemIsActive = (pathname, item) => {
|
|
|
108
107
|
};
|
|
109
108
|
|
|
110
109
|
// src/shared/studioSections.ts
|
|
111
|
-
var studioRoles = /* @__PURE__ */ new Set(["admin", "editor", "client"]);
|
|
110
|
+
var studioRoles = /* @__PURE__ */ new Set(["admin", "developer", "editor", "client"]);
|
|
112
111
|
var studioIcons = new Set(adminNavIcons);
|
|
113
|
-
var dashboardSpans = /* @__PURE__ */ new Set(["full", "half"]);
|
|
114
112
|
var isRecord = (value) => Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
115
113
|
var isAbsoluteExternalURL = (value) => /^[a-zA-Z][a-zA-Z\d+\-.]*:/.test(value) || value.startsWith("//");
|
|
116
114
|
var normalizePathLikeValue = (value) => {
|
|
@@ -152,22 +150,6 @@ var normalizeCard = (value) => {
|
|
|
152
150
|
};
|
|
153
151
|
};
|
|
154
152
|
var normalizeIcon = (value) => typeof value === "string" && studioIcons.has(value) ? value : void 0;
|
|
155
|
-
var normalizeComponent = (value) => {
|
|
156
|
-
if (!isRecord(value)) {
|
|
157
|
-
return void 0;
|
|
158
|
-
}
|
|
159
|
-
const componentPath = typeof value.path === "string" ? value.path.trim() : "";
|
|
160
|
-
const exportName = typeof value.exportName === "string" ? value.exportName.trim() : "";
|
|
161
|
-
if (!componentPath || !exportName) {
|
|
162
|
-
return void 0;
|
|
163
|
-
}
|
|
164
|
-
return {
|
|
165
|
-
exportName,
|
|
166
|
-
path: componentPath,
|
|
167
|
-
...isRecord(value.clientProps) ? { clientProps: value.clientProps } : {}
|
|
168
|
-
};
|
|
169
|
-
};
|
|
170
|
-
var normalizeDashboardSpan = (value) => typeof value === "string" && dashboardSpans.has(value) ? value : "half";
|
|
171
153
|
var resolveStudioSections = (value) => {
|
|
172
154
|
if (!Array.isArray(value)) {
|
|
173
155
|
return [];
|
|
@@ -233,38 +215,6 @@ var resolveStudioSectionViews = (value) => {
|
|
|
233
215
|
}
|
|
234
216
|
return views;
|
|
235
217
|
};
|
|
236
|
-
var resolveStudioSectionDashboards = (value) => {
|
|
237
|
-
if (!Array.isArray(value)) {
|
|
238
|
-
return [];
|
|
239
|
-
}
|
|
240
|
-
const panels = [];
|
|
241
|
-
const seen = /* @__PURE__ */ new Set();
|
|
242
|
-
for (const entry of value) {
|
|
243
|
-
if (!isRecord(entry) || typeof entry.id !== "string" || typeof entry.label !== "string") {
|
|
244
|
-
continue;
|
|
245
|
-
}
|
|
246
|
-
const id = entry.id.trim();
|
|
247
|
-
const label = entry.label.trim();
|
|
248
|
-
const dashboard = isRecord(entry.dashboard) ? entry.dashboard : null;
|
|
249
|
-
const component = dashboard ? normalizeComponent(dashboard.Component) : void 0;
|
|
250
|
-
const href = typeof entry.href === "string" && entry.href.trim().length > 0 ? normalizePathLikeValue(entry.href) : isRecord(entry.view) && typeof entry.view.path === "string" ? normalizePathLikeValue(entry.view.path) : "";
|
|
251
|
-
if (!id || !label || !dashboard || !component || !href || seen.has(id)) {
|
|
252
|
-
continue;
|
|
253
|
-
}
|
|
254
|
-
const priority = typeof dashboard.priority === "number" && Number.isFinite(dashboard.priority) ? dashboard.priority : 100;
|
|
255
|
-
panels.push({
|
|
256
|
-
Component: component,
|
|
257
|
-
href,
|
|
258
|
-
id,
|
|
259
|
-
label,
|
|
260
|
-
priority,
|
|
261
|
-
...normalizeRoles(dashboard.roles ?? entry.roles) ? { roles: normalizeRoles(dashboard.roles ?? entry.roles) } : {},
|
|
262
|
-
span: normalizeDashboardSpan(dashboard.span)
|
|
263
|
-
});
|
|
264
|
-
seen.add(id);
|
|
265
|
-
}
|
|
266
|
-
return panels.sort((a, b) => a.priority === b.priority ? a.label.localeCompare(b.label) : a.priority - b.priority);
|
|
267
|
-
};
|
|
268
218
|
|
|
269
219
|
// src/admin/helpers/configureAdmin.ts
|
|
270
220
|
var import_meta = {};
|
|
@@ -291,8 +241,10 @@ function configureAdmin(config) {
|
|
|
291
241
|
brandPrimary = "#3b82f6",
|
|
292
242
|
brandSecondary = "#8b5cf6",
|
|
293
243
|
defaultTheme = "brand-light",
|
|
244
|
+
logoOnDarkUrl,
|
|
294
245
|
logoUrl,
|
|
295
|
-
allowThemePreference = false
|
|
246
|
+
allowThemePreference = false,
|
|
247
|
+
userSessionDurationSeconds = 60 * 60 * 24
|
|
296
248
|
} = config;
|
|
297
249
|
const studioEnabled = config.studio?.enabled ?? true;
|
|
298
250
|
const formsEnabled = config.studio?.forms?.enabled ?? false;
|
|
@@ -324,7 +276,6 @@ function configureAdmin(config) {
|
|
|
324
276
|
};
|
|
325
277
|
});
|
|
326
278
|
const studioSections = resolveStudioSections(config.studio?.sections || []);
|
|
327
|
-
const studioDashboardPanels = resolveStudioSectionDashboards(config.studio?.sections || []);
|
|
328
279
|
const studioSectionViews = resolveStudioSectionViews(config.studio?.sections || []);
|
|
329
280
|
const sitePreview = config.studio?.sitePreview;
|
|
330
281
|
let cssPath;
|
|
@@ -354,7 +305,6 @@ function configureAdmin(config) {
|
|
|
354
305
|
cssPath = genPath;
|
|
355
306
|
}
|
|
356
307
|
const clientPath = "@orion-studios/payload-studio/admin/client";
|
|
357
|
-
const adminPath = "@orion-studios/payload-studio/admin";
|
|
358
308
|
const studioNavClientProps = {
|
|
359
309
|
brandName,
|
|
360
310
|
formSubmissionsCollectionSlug,
|
|
@@ -366,14 +316,8 @@ function configureAdmin(config) {
|
|
|
366
316
|
logoUrl,
|
|
367
317
|
mediaCollectionSlug,
|
|
368
318
|
pagesCollectionSlug,
|
|
369
|
-
dashboardPanels: studioDashboardPanels,
|
|
370
319
|
sections: studioSections
|
|
371
320
|
};
|
|
372
|
-
const dashboardImportMapGenerator = studioDashboardPanels.length > 0 ? ({ addToImportMap }) => {
|
|
373
|
-
addToImportMap(
|
|
374
|
-
studioDashboardPanels.map((panel) => panel.Component)
|
|
375
|
-
);
|
|
376
|
-
} : void 0;
|
|
377
321
|
const studioBackBreadcrumbComponent = {
|
|
378
322
|
exportName: "StudioBackBreadcrumb",
|
|
379
323
|
path: clientPath
|
|
@@ -405,14 +349,52 @@ function configureAdmin(config) {
|
|
|
405
349
|
}
|
|
406
350
|
};
|
|
407
351
|
};
|
|
352
|
+
const attachStudioEditRedirectToCollection = (collection, options) => {
|
|
353
|
+
if (!studioEnabled) {
|
|
354
|
+
return collection;
|
|
355
|
+
}
|
|
356
|
+
const collectionWithBreadcrumb = attachStudioBackBreadcrumbToCollection(collection);
|
|
357
|
+
const existingViews = collectionWithBreadcrumb.admin?.components?.views;
|
|
358
|
+
const existingEditViews = existingViews?.edit;
|
|
359
|
+
const hasCustomEditView = Boolean(
|
|
360
|
+
existingEditViews?.root || existingEditViews?.default && typeof existingEditViews.default === "object" && existingEditViews.default.Component
|
|
361
|
+
);
|
|
362
|
+
if (hasCustomEditView) {
|
|
363
|
+
return collectionWithBreadcrumb;
|
|
364
|
+
}
|
|
365
|
+
return {
|
|
366
|
+
...collectionWithBreadcrumb,
|
|
367
|
+
admin: {
|
|
368
|
+
...collectionWithBreadcrumb.admin,
|
|
369
|
+
components: {
|
|
370
|
+
...collectionWithBreadcrumb.admin?.components,
|
|
371
|
+
views: {
|
|
372
|
+
...existingViews,
|
|
373
|
+
edit: {
|
|
374
|
+
...existingEditViews,
|
|
375
|
+
default: {
|
|
376
|
+
...typeof existingEditViews?.default === "object" ? existingEditViews.default : {},
|
|
377
|
+
Component: {
|
|
378
|
+
exportName: "StudioDocumentRedirect",
|
|
379
|
+
path: clientPath,
|
|
380
|
+
clientProps: {
|
|
381
|
+
description: options.description,
|
|
382
|
+
...options.emptyHref ? { emptyHref: options.emptyHref } : {},
|
|
383
|
+
...options.emptyLabel ? { emptyLabel: options.emptyLabel } : {},
|
|
384
|
+
pathBase: options.pathBase,
|
|
385
|
+
title: options.title
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
};
|
|
394
|
+
};
|
|
408
395
|
return {
|
|
409
396
|
admin: {
|
|
410
397
|
css: cssPath,
|
|
411
|
-
...dashboardImportMapGenerator ? {
|
|
412
|
-
importMap: {
|
|
413
|
-
generators: [dashboardImportMapGenerator]
|
|
414
|
-
}
|
|
415
|
-
} : {},
|
|
416
398
|
components: {
|
|
417
399
|
...studioEnabled ? {
|
|
418
400
|
Nav: {
|
|
@@ -427,6 +409,7 @@ function configureAdmin(config) {
|
|
|
427
409
|
path: clientPath,
|
|
428
410
|
clientProps: {
|
|
429
411
|
brandName,
|
|
412
|
+
logoOnDarkUrl,
|
|
430
413
|
logoUrl
|
|
431
414
|
}
|
|
432
415
|
},
|
|
@@ -435,6 +418,7 @@ function configureAdmin(config) {
|
|
|
435
418
|
path: clientPath,
|
|
436
419
|
clientProps: {
|
|
437
420
|
brandName,
|
|
421
|
+
logoOnDarkUrl,
|
|
438
422
|
logoUrl
|
|
439
423
|
}
|
|
440
424
|
}
|
|
@@ -443,12 +427,13 @@ function configureAdmin(config) {
|
|
|
443
427
|
dashboard: {
|
|
444
428
|
Component: {
|
|
445
429
|
exportName: studioEnabled ? "AdminStudioDashboard" : "Dashboard",
|
|
446
|
-
path:
|
|
430
|
+
path: clientPath,
|
|
447
431
|
clientProps: studioNavClientProps
|
|
448
432
|
}
|
|
449
433
|
},
|
|
450
434
|
...studioEnabled ? {
|
|
451
435
|
studioGlobals: {
|
|
436
|
+
exact: true,
|
|
452
437
|
path: globalsBasePath,
|
|
453
438
|
Component: {
|
|
454
439
|
exportName: "AdminStudioGlobalsView",
|
|
@@ -460,10 +445,11 @@ function configureAdmin(config) {
|
|
|
460
445
|
}
|
|
461
446
|
}
|
|
462
447
|
},
|
|
463
|
-
|
|
464
|
-
|
|
448
|
+
studioPageNew: {
|
|
449
|
+
exact: true,
|
|
450
|
+
path: `${pagesBasePath}/new`,
|
|
465
451
|
Component: {
|
|
466
|
-
exportName: "
|
|
452
|
+
exportName: "AdminStudioNewPageView",
|
|
467
453
|
path: clientPath,
|
|
468
454
|
clientProps: {
|
|
469
455
|
...studioNavClientProps,
|
|
@@ -472,6 +458,7 @@ function configureAdmin(config) {
|
|
|
472
458
|
}
|
|
473
459
|
},
|
|
474
460
|
studioPageEditor: {
|
|
461
|
+
exact: true,
|
|
475
462
|
path: `${pagesBasePath}/:id`,
|
|
476
463
|
Component: {
|
|
477
464
|
exportName: "AdminStudioPageEditView",
|
|
@@ -482,10 +469,11 @@ function configureAdmin(config) {
|
|
|
482
469
|
}
|
|
483
470
|
}
|
|
484
471
|
},
|
|
485
|
-
|
|
486
|
-
|
|
472
|
+
studioPages: {
|
|
473
|
+
exact: true,
|
|
474
|
+
path: pagesBasePath,
|
|
487
475
|
Component: {
|
|
488
|
-
exportName: "
|
|
476
|
+
exportName: "AdminStudioPagesListView",
|
|
489
477
|
path: clientPath,
|
|
490
478
|
clientProps: {
|
|
491
479
|
...studioNavClientProps,
|
|
@@ -494,6 +482,7 @@ function configureAdmin(config) {
|
|
|
494
482
|
}
|
|
495
483
|
},
|
|
496
484
|
studioContactForm: {
|
|
485
|
+
exact: true,
|
|
497
486
|
path: contactFormStudioPath,
|
|
498
487
|
Component: {
|
|
499
488
|
exportName: "AdminStudioContactFormView",
|
|
@@ -506,7 +495,47 @@ function configureAdmin(config) {
|
|
|
506
495
|
}
|
|
507
496
|
},
|
|
508
497
|
...formsEnabled ? {
|
|
498
|
+
studioFormSubmission: {
|
|
499
|
+
exact: true,
|
|
500
|
+
path: `${formsBasePath}/submissions/:id`,
|
|
501
|
+
Component: {
|
|
502
|
+
exportName: "AdminStudioFormSubmissionView",
|
|
503
|
+
path: clientPath,
|
|
504
|
+
clientProps: {
|
|
505
|
+
...studioNavClientProps,
|
|
506
|
+
formsCollectionSlug,
|
|
507
|
+
formSubmissionsCollectionSlug,
|
|
508
|
+
formUploadsCollectionSlug
|
|
509
|
+
}
|
|
510
|
+
}
|
|
511
|
+
},
|
|
512
|
+
studioFormUpload: {
|
|
513
|
+
exact: true,
|
|
514
|
+
path: `${formsBasePath}/uploads/:id`,
|
|
515
|
+
Component: {
|
|
516
|
+
exportName: "AdminStudioFormUploadView",
|
|
517
|
+
path: clientPath,
|
|
518
|
+
clientProps: {
|
|
519
|
+
...studioNavClientProps,
|
|
520
|
+
formUploadsCollectionSlug
|
|
521
|
+
}
|
|
522
|
+
}
|
|
523
|
+
},
|
|
524
|
+
studioFormDetail: {
|
|
525
|
+
exact: true,
|
|
526
|
+
path: `${formsBasePath}/:id`,
|
|
527
|
+
Component: {
|
|
528
|
+
exportName: "AdminStudioFormDetailView",
|
|
529
|
+
path: clientPath,
|
|
530
|
+
clientProps: {
|
|
531
|
+
...studioNavClientProps,
|
|
532
|
+
formsCollectionSlug,
|
|
533
|
+
formSubmissionsCollectionSlug
|
|
534
|
+
}
|
|
535
|
+
}
|
|
536
|
+
},
|
|
509
537
|
studioForms: {
|
|
538
|
+
exact: true,
|
|
510
539
|
path: formsBasePath,
|
|
511
540
|
Component: {
|
|
512
541
|
exportName: "AdminStudioFormsView",
|
|
@@ -520,10 +549,11 @@ function configureAdmin(config) {
|
|
|
520
549
|
}
|
|
521
550
|
}
|
|
522
551
|
} : {},
|
|
523
|
-
|
|
524
|
-
|
|
552
|
+
studioMediaItem: {
|
|
553
|
+
exact: true,
|
|
554
|
+
path: `${mediaBasePath}/:id`,
|
|
525
555
|
Component: {
|
|
526
|
-
exportName: "
|
|
556
|
+
exportName: "AdminStudioMediaItemView",
|
|
527
557
|
path: clientPath,
|
|
528
558
|
clientProps: {
|
|
529
559
|
...studioNavClientProps,
|
|
@@ -531,10 +561,11 @@ function configureAdmin(config) {
|
|
|
531
561
|
}
|
|
532
562
|
}
|
|
533
563
|
},
|
|
534
|
-
|
|
535
|
-
|
|
564
|
+
studioMedia: {
|
|
565
|
+
exact: true,
|
|
566
|
+
path: mediaBasePath,
|
|
536
567
|
Component: {
|
|
537
|
-
exportName: "
|
|
568
|
+
exportName: "AdminStudioMediaView",
|
|
538
569
|
path: clientPath,
|
|
539
570
|
clientProps: {
|
|
540
571
|
...studioNavClientProps,
|
|
@@ -543,6 +574,7 @@ function configureAdmin(config) {
|
|
|
543
574
|
}
|
|
544
575
|
},
|
|
545
576
|
studioTools: {
|
|
577
|
+
exact: true,
|
|
546
578
|
path: toolsBasePath,
|
|
547
579
|
Component: {
|
|
548
580
|
exportName: "AdminStudioToolsView",
|
|
@@ -587,6 +619,7 @@ function configureAdmin(config) {
|
|
|
587
619
|
path: clientPath,
|
|
588
620
|
clientProps: {
|
|
589
621
|
brandName,
|
|
622
|
+
logoOnDarkUrl,
|
|
590
623
|
logoUrl
|
|
591
624
|
}
|
|
592
625
|
}
|
|
@@ -623,8 +656,17 @@ function configureAdmin(config) {
|
|
|
623
656
|
const hasThemePreference = existingFields.some(
|
|
624
657
|
(field) => typeof field === "object" && field !== null && "name" in field && field.name === "themePreference"
|
|
625
658
|
);
|
|
659
|
+
const normalizedAuth = usersCollection.auth === true ? {
|
|
660
|
+
tokenExpiration: userSessionDurationSeconds,
|
|
661
|
+
useSessions: true
|
|
662
|
+
} : usersCollection.auth && typeof usersCollection.auth === "object" ? {
|
|
663
|
+
...usersCollection.auth,
|
|
664
|
+
tokenExpiration: usersCollection.auth.tokenExpiration ?? userSessionDurationSeconds,
|
|
665
|
+
useSessions: usersCollection.auth.useSessions ?? true
|
|
666
|
+
} : usersCollection.auth;
|
|
626
667
|
const nextCollection = {
|
|
627
668
|
...usersCollection,
|
|
669
|
+
auth: normalizedAuth,
|
|
628
670
|
fields: !allowThemePreference || hasThemePreference ? existingFields : [...existingFields, createThemePreferenceField(defaultTheme)]
|
|
629
671
|
};
|
|
630
672
|
return attachStudioBackBreadcrumbToCollection(nextCollection);
|
|
@@ -686,13 +728,31 @@ function configureAdmin(config) {
|
|
|
686
728
|
return attachStudioBackBreadcrumbToCollection(mediaCollection);
|
|
687
729
|
},
|
|
688
730
|
wrapFormsCollection(formsCollection) {
|
|
689
|
-
return
|
|
731
|
+
return attachStudioEditRedirectToCollection(formsCollection, {
|
|
732
|
+
description: "Redirecting to the Studio form workspace.",
|
|
733
|
+
emptyHref: formsBasePath,
|
|
734
|
+
emptyLabel: "Open Forms",
|
|
735
|
+
pathBase: formsBasePath,
|
|
736
|
+
title: "Opening Form..."
|
|
737
|
+
});
|
|
690
738
|
},
|
|
691
739
|
wrapFormSubmissionsCollection(formSubmissionsCollection) {
|
|
692
|
-
return
|
|
740
|
+
return attachStudioEditRedirectToCollection(formSubmissionsCollection, {
|
|
741
|
+
description: "Redirecting to the Studio submission workspace.",
|
|
742
|
+
emptyHref: formsBasePath,
|
|
743
|
+
emptyLabel: "Open Forms",
|
|
744
|
+
pathBase: `${formsBasePath}/submissions`,
|
|
745
|
+
title: "Opening Submission..."
|
|
746
|
+
});
|
|
693
747
|
},
|
|
694
748
|
wrapFormUploadsCollection(formUploadsCollection) {
|
|
695
|
-
return
|
|
749
|
+
return attachStudioEditRedirectToCollection(formUploadsCollection, {
|
|
750
|
+
description: "Redirecting to the Studio upload workspace.",
|
|
751
|
+
emptyHref: formsBasePath,
|
|
752
|
+
emptyLabel: "Open Forms",
|
|
753
|
+
pathBase: `${formsBasePath}/uploads`,
|
|
754
|
+
title: "Opening Upload..."
|
|
755
|
+
});
|
|
696
756
|
},
|
|
697
757
|
wrapGlobals(globals2) {
|
|
698
758
|
const labelMap = {
|
|
@@ -839,1431 +899,6 @@ function configureAdmin(config) {
|
|
|
839
899
|
};
|
|
840
900
|
}
|
|
841
901
|
|
|
842
|
-
// src/admin/components/studio/AdminStudioDashboard.tsx
|
|
843
|
-
var import_RenderServerComponent = require("@payloadcms/ui/elements/RenderServerComponent");
|
|
844
|
-
|
|
845
|
-
// src/admin-app/components/AdminBreadcrumbs.tsx
|
|
846
|
-
var import_jsx_runtime = require("react/jsx-runtime");
|
|
847
|
-
function AdminBreadcrumbs({ items }) {
|
|
848
|
-
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("nav", { "aria-label": "Breadcrumb", className: "orion-admin-breadcrumbs", children: items.map((item, index) => {
|
|
849
|
-
const isLast = index === items.length - 1;
|
|
850
|
-
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { children: [
|
|
851
|
-
item.href && !isLast ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("a", { href: item.href, children: item.label }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: item.label }),
|
|
852
|
-
!isLast ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "orion-admin-breadcrumb-sep", children: "/" }) : null
|
|
853
|
-
] }, `${item.label}-${index}`);
|
|
854
|
-
}) });
|
|
855
|
-
}
|
|
856
|
-
|
|
857
|
-
// src/admin-app/components/AdminPage.tsx
|
|
858
|
-
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
859
|
-
function AdminPage({ title, description, breadcrumbs, actions, children }) {
|
|
860
|
-
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "orion-admin-page", children: [
|
|
861
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "orion-admin-page-header", children: [
|
|
862
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(AdminBreadcrumbs, { items: breadcrumbs }),
|
|
863
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "orion-admin-page-title-row", children: [
|
|
864
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { children: [
|
|
865
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("h1", { children: title }),
|
|
866
|
-
description ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { children: description }) : null
|
|
867
|
-
] }),
|
|
868
|
-
actions ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "orion-admin-page-actions", children: actions }) : null
|
|
869
|
-
] })
|
|
870
|
-
] }),
|
|
871
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "orion-admin-page-content", children })
|
|
872
|
-
] });
|
|
873
|
-
}
|
|
874
|
-
|
|
875
|
-
// src/admin/components/studio/AdminStudioDashboardClient.tsx
|
|
876
|
-
var import_react = require("react");
|
|
877
|
-
var import_link = __toESM(require("next/link"));
|
|
878
|
-
var import_jsx_runtime3 = require("react/jsx-runtime");
|
|
879
|
-
var SEVEN_DAYS_MS = 7 * 24 * 60 * 60 * 1e3;
|
|
880
|
-
var isRole = (value) => value === "admin" || value === "editor" || value === "client";
|
|
881
|
-
var canReviewForms = (role) => role === "admin" || role === "editor";
|
|
882
|
-
var canCreatePages = (role) => role === "admin" || role === "editor";
|
|
883
|
-
var canAccess = (role, roles) => {
|
|
884
|
-
if (!roles || roles.length === 0) {
|
|
885
|
-
return true;
|
|
886
|
-
}
|
|
887
|
-
if (!role) {
|
|
888
|
-
return false;
|
|
889
|
-
}
|
|
890
|
-
return roles.includes(role);
|
|
891
|
-
};
|
|
892
|
-
var asText = (value, fallback) => typeof value === "string" && value.trim().length > 0 ? value.trim() : fallback;
|
|
893
|
-
var asID = (value) => {
|
|
894
|
-
if (typeof value === "string" || typeof value === "number") return String(value);
|
|
895
|
-
return "";
|
|
896
|
-
};
|
|
897
|
-
var toTimestamp = (value) => {
|
|
898
|
-
if (typeof value !== "string" || value.length === 0) {
|
|
899
|
-
return Number.NaN;
|
|
900
|
-
}
|
|
901
|
-
const timestamp = Date.parse(value);
|
|
902
|
-
return Number.isFinite(timestamp) ? timestamp : Number.NaN;
|
|
903
|
-
};
|
|
904
|
-
var isRecent = (value) => {
|
|
905
|
-
const timestamp = toTimestamp(value);
|
|
906
|
-
return Number.isFinite(timestamp) && Date.now() - timestamp <= SEVEN_DAYS_MS;
|
|
907
|
-
};
|
|
908
|
-
var formatDateTime = (value) => {
|
|
909
|
-
if (typeof value !== "string" || value.length === 0) {
|
|
910
|
-
return "Unknown time";
|
|
911
|
-
}
|
|
912
|
-
const date = new Date(value);
|
|
913
|
-
if (Number.isNaN(date.getTime())) {
|
|
914
|
-
return value;
|
|
915
|
-
}
|
|
916
|
-
return new Intl.DateTimeFormat(void 0, {
|
|
917
|
-
dateStyle: "medium",
|
|
918
|
-
timeStyle: "short"
|
|
919
|
-
}).format(date);
|
|
920
|
-
};
|
|
921
|
-
var formatRelativeTime = (timestamp) => {
|
|
922
|
-
if (!Number.isFinite(timestamp)) {
|
|
923
|
-
return "Unknown time";
|
|
924
|
-
}
|
|
925
|
-
const diffMs = timestamp - Date.now();
|
|
926
|
-
const diffMinutes = Math.round(diffMs / (60 * 1e3));
|
|
927
|
-
const rtf = new Intl.RelativeTimeFormat(void 0, { numeric: "auto" });
|
|
928
|
-
if (Math.abs(diffMinutes) < 60) {
|
|
929
|
-
return rtf.format(diffMinutes, "minute");
|
|
930
|
-
}
|
|
931
|
-
const diffHours = Math.round(diffMinutes / 60);
|
|
932
|
-
if (Math.abs(diffHours) < 24) {
|
|
933
|
-
return rtf.format(diffHours, "hour");
|
|
934
|
-
}
|
|
935
|
-
const diffDays = Math.round(diffHours / 24);
|
|
936
|
-
return rtf.format(diffDays, "day");
|
|
937
|
-
};
|
|
938
|
-
var readSubmissionIdentity = (value) => {
|
|
939
|
-
if (!value || typeof value !== "object") {
|
|
940
|
-
return "New submission";
|
|
941
|
-
}
|
|
942
|
-
const data = value;
|
|
943
|
-
const firstName = typeof data.firstName === "string" ? data.firstName.trim() : "";
|
|
944
|
-
const lastName = typeof data.lastName === "string" ? data.lastName.trim() : "";
|
|
945
|
-
const name = typeof data.name === "string" ? data.name.trim() : "";
|
|
946
|
-
const email = typeof data.email === "string" ? data.email.trim() : typeof data.contactEmail === "string" ? data.contactEmail.trim() : "";
|
|
947
|
-
const fullName = [firstName, lastName].filter(Boolean).join(" ").trim();
|
|
948
|
-
return fullName || name || email || "New submission";
|
|
949
|
-
};
|
|
950
|
-
var getFormID = (value) => {
|
|
951
|
-
if (typeof value === "string" || typeof value === "number") return String(value);
|
|
952
|
-
if (value && typeof value === "object") {
|
|
953
|
-
const nestedID = value.id;
|
|
954
|
-
if (typeof nestedID === "string" || typeof nestedID === "number") return String(nestedID);
|
|
955
|
-
}
|
|
956
|
-
return "";
|
|
957
|
-
};
|
|
958
|
-
var getFormTitle = (value) => {
|
|
959
|
-
if (!value || typeof value !== "object") {
|
|
960
|
-
return "";
|
|
961
|
-
}
|
|
962
|
-
const title = value.title;
|
|
963
|
-
if (typeof title === "string" && title.trim().length > 0) {
|
|
964
|
-
return title.trim();
|
|
965
|
-
}
|
|
966
|
-
const slug = value.slug;
|
|
967
|
-
return typeof slug === "string" && slug.trim().length > 0 ? slug.trim() : "";
|
|
968
|
-
};
|
|
969
|
-
var buildSearchParams = (params) => new URLSearchParams(
|
|
970
|
-
Object.entries(params).filter(([, value]) => typeof value === "string" && value.length > 0)
|
|
971
|
-
).toString();
|
|
972
|
-
async function loadCollection(path2) {
|
|
973
|
-
const response = await fetch(path2, {
|
|
974
|
-
cache: "no-store",
|
|
975
|
-
credentials: "include"
|
|
976
|
-
});
|
|
977
|
-
if (!response.ok) {
|
|
978
|
-
const body = await response.text();
|
|
979
|
-
throw new Error(body || `Request failed: ${response.status}`);
|
|
980
|
-
}
|
|
981
|
-
return await response.json();
|
|
982
|
-
}
|
|
983
|
-
async function loadPages(collectionSlug) {
|
|
984
|
-
const params = buildSearchParams({
|
|
985
|
-
depth: "0",
|
|
986
|
-
draft: "true",
|
|
987
|
-
limit: "200",
|
|
988
|
-
sort: "-updatedAt"
|
|
989
|
-
});
|
|
990
|
-
const result = await loadCollection(`/api/${collectionSlug}?${params}`);
|
|
991
|
-
const docs = Array.isArray(result.docs) ? result.docs : [];
|
|
992
|
-
return {
|
|
993
|
-
draftCount: docs.filter((doc) => doc._status === "draft").length,
|
|
994
|
-
recent: docs.slice(0, 8),
|
|
995
|
-
total: typeof result.totalDocs === "number" ? result.totalDocs : docs.length,
|
|
996
|
-
updatedThisWeek: docs.filter((doc) => isRecent(doc.updatedAt)).length
|
|
997
|
-
};
|
|
998
|
-
}
|
|
999
|
-
async function loadForms(formsCollectionSlug, submissionsCollectionSlug) {
|
|
1000
|
-
const [formsResult, submissionsResult] = await Promise.all([
|
|
1001
|
-
loadCollection(
|
|
1002
|
-
`/api/${formsCollectionSlug}?${buildSearchParams({
|
|
1003
|
-
depth: "0",
|
|
1004
|
-
draft: "true",
|
|
1005
|
-
limit: "80",
|
|
1006
|
-
sort: "-updatedAt"
|
|
1007
|
-
})}`
|
|
1008
|
-
),
|
|
1009
|
-
loadCollection(
|
|
1010
|
-
`/api/${submissionsCollectionSlug}?${buildSearchParams({
|
|
1011
|
-
depth: "1",
|
|
1012
|
-
limit: "40",
|
|
1013
|
-
sort: "-submittedAt"
|
|
1014
|
-
})}`
|
|
1015
|
-
)
|
|
1016
|
-
]);
|
|
1017
|
-
const forms = Array.isArray(formsResult.docs) ? formsResult.docs : [];
|
|
1018
|
-
const recentSubmissions = Array.isArray(submissionsResult.docs) ? submissionsResult.docs : [];
|
|
1019
|
-
const submissionsByForm = /* @__PURE__ */ new Map();
|
|
1020
|
-
for (const submission of recentSubmissions) {
|
|
1021
|
-
const formID = getFormID(submission.form);
|
|
1022
|
-
if (!formID) continue;
|
|
1023
|
-
submissionsByForm.set(formID, (submissionsByForm.get(formID) || 0) + 1);
|
|
1024
|
-
}
|
|
1025
|
-
let busiestFormTitle = null;
|
|
1026
|
-
let busiestFormCount = 0;
|
|
1027
|
-
for (const form of forms) {
|
|
1028
|
-
const formID = asID(form.id);
|
|
1029
|
-
if (!formID) continue;
|
|
1030
|
-
const submissionCount = submissionsByForm.get(formID) || 0;
|
|
1031
|
-
if (submissionCount > busiestFormCount) {
|
|
1032
|
-
busiestFormCount = submissionCount;
|
|
1033
|
-
busiestFormTitle = asText(form.title, "Untitled form");
|
|
1034
|
-
}
|
|
1035
|
-
}
|
|
1036
|
-
return {
|
|
1037
|
-
busiestFormTitle,
|
|
1038
|
-
forms,
|
|
1039
|
-
recentSubmissions,
|
|
1040
|
-
submissionsThisWeek: recentSubmissions.filter((submission) => isRecent(submission.submittedAt)).length,
|
|
1041
|
-
totalForms: typeof formsResult.totalDocs === "number" ? formsResult.totalDocs : forms.length
|
|
1042
|
-
};
|
|
1043
|
-
}
|
|
1044
|
-
async function loadMedia(collectionSlug) {
|
|
1045
|
-
const params = buildSearchParams({
|
|
1046
|
-
depth: "0",
|
|
1047
|
-
limit: "24",
|
|
1048
|
-
sort: "-updatedAt"
|
|
1049
|
-
});
|
|
1050
|
-
const result = await loadCollection(`/api/${collectionSlug}?${params}`);
|
|
1051
|
-
const docs = Array.isArray(result.docs) ? result.docs : [];
|
|
1052
|
-
return {
|
|
1053
|
-
recent: docs.slice(0, 8),
|
|
1054
|
-
total: typeof result.totalDocs === "number" ? result.totalDocs : docs.length,
|
|
1055
|
-
uploadsThisWeek: docs.filter((doc) => isRecent(doc.updatedAt)).length
|
|
1056
|
-
};
|
|
1057
|
-
}
|
|
1058
|
-
var loadingState = {
|
|
1059
|
-
forms: null,
|
|
1060
|
-
media: { status: "loading" },
|
|
1061
|
-
pages: { status: "loading" }
|
|
1062
|
-
};
|
|
1063
|
-
function ModuleStatus({ message }) {
|
|
1064
|
-
return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "orion-dashboard-inline-note", children: message });
|
|
1065
|
-
}
|
|
1066
|
-
function EmptyState({
|
|
1067
|
-
body,
|
|
1068
|
-
title
|
|
1069
|
-
}) {
|
|
1070
|
-
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "orion-dashboard-empty-state", children: [
|
|
1071
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("strong", { children: title }),
|
|
1072
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { children: body })
|
|
1073
|
-
] });
|
|
1074
|
-
}
|
|
1075
|
-
function SnapshotMetric({ card }) {
|
|
1076
|
-
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("article", { className: "orion-dashboard-snapshot-card", children: [
|
|
1077
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "orion-dashboard-snapshot-kicker", children: card.kicker }),
|
|
1078
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("strong", { children: card.value }),
|
|
1079
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { children: card.detail })
|
|
1080
|
-
] });
|
|
1081
|
-
}
|
|
1082
|
-
function AdminStudioDashboardClient({
|
|
1083
|
-
extensionPanels = [],
|
|
1084
|
-
formSubmissionsCollectionSlug,
|
|
1085
|
-
formsCollectionSlug,
|
|
1086
|
-
formsEnabled,
|
|
1087
|
-
formsPath,
|
|
1088
|
-
globalsBasePath,
|
|
1089
|
-
mediaCollectionSlug,
|
|
1090
|
-
mediaPath,
|
|
1091
|
-
pagesCollectionSlug,
|
|
1092
|
-
pagesPath,
|
|
1093
|
-
sectionLinks,
|
|
1094
|
-
toolsPath,
|
|
1095
|
-
userRole
|
|
1096
|
-
}) {
|
|
1097
|
-
const role = isRole(userRole) ? userRole : void 0;
|
|
1098
|
-
const [state, setState] = (0, import_react.useState)(
|
|
1099
|
-
() => formsEnabled && canReviewForms(role) ? {
|
|
1100
|
-
forms: { status: "loading" },
|
|
1101
|
-
media: { status: "loading" },
|
|
1102
|
-
pages: { status: "loading" }
|
|
1103
|
-
} : loadingState
|
|
1104
|
-
);
|
|
1105
|
-
(0, import_react.useEffect)(() => {
|
|
1106
|
-
let cancelled = false;
|
|
1107
|
-
const run = async () => {
|
|
1108
|
-
const includeForms = formsEnabled && canReviewForms(role);
|
|
1109
|
-
(0, import_react.startTransition)(() => {
|
|
1110
|
-
setState({
|
|
1111
|
-
forms: includeForms ? { status: "loading" } : null,
|
|
1112
|
-
media: { status: "loading" },
|
|
1113
|
-
pages: { status: "loading" }
|
|
1114
|
-
});
|
|
1115
|
-
});
|
|
1116
|
-
const [pagesResult, formsResult, mediaResult] = await Promise.allSettled([
|
|
1117
|
-
loadPages(pagesCollectionSlug),
|
|
1118
|
-
includeForms ? loadForms(formsCollectionSlug, formSubmissionsCollectionSlug) : Promise.resolve(null),
|
|
1119
|
-
loadMedia(mediaCollectionSlug)
|
|
1120
|
-
]);
|
|
1121
|
-
if (cancelled) return;
|
|
1122
|
-
(0, import_react.startTransition)(() => {
|
|
1123
|
-
setState({
|
|
1124
|
-
forms: includeForms && formsResult.status === "rejected" ? {
|
|
1125
|
-
error: formsResult.reason instanceof Error ? formsResult.reason.message : "Unable to load form activity.",
|
|
1126
|
-
status: "error"
|
|
1127
|
-
} : includeForms && formsResult.status === "fulfilled" && formsResult.value ? {
|
|
1128
|
-
data: formsResult.value,
|
|
1129
|
-
status: "success"
|
|
1130
|
-
} : null,
|
|
1131
|
-
media: mediaResult.status === "rejected" ? {
|
|
1132
|
-
error: mediaResult.reason instanceof Error ? mediaResult.reason.message : "Unable to load media activity.",
|
|
1133
|
-
status: "error"
|
|
1134
|
-
} : {
|
|
1135
|
-
data: mediaResult.value,
|
|
1136
|
-
status: "success"
|
|
1137
|
-
},
|
|
1138
|
-
pages: pagesResult.status === "rejected" ? {
|
|
1139
|
-
error: pagesResult.reason instanceof Error ? pagesResult.reason.message : "Unable to load page activity.",
|
|
1140
|
-
status: "error"
|
|
1141
|
-
} : {
|
|
1142
|
-
data: pagesResult.value,
|
|
1143
|
-
status: "success"
|
|
1144
|
-
}
|
|
1145
|
-
});
|
|
1146
|
-
});
|
|
1147
|
-
};
|
|
1148
|
-
void run();
|
|
1149
|
-
return () => {
|
|
1150
|
-
cancelled = true;
|
|
1151
|
-
};
|
|
1152
|
-
}, [
|
|
1153
|
-
formSubmissionsCollectionSlug,
|
|
1154
|
-
formsCollectionSlug,
|
|
1155
|
-
formsEnabled,
|
|
1156
|
-
mediaCollectionSlug,
|
|
1157
|
-
pagesCollectionSlug,
|
|
1158
|
-
role
|
|
1159
|
-
]);
|
|
1160
|
-
const visibleWorkspaceLinks = (0, import_react.useMemo)(
|
|
1161
|
-
() => sectionLinks.filter((section) => canAccess(role, section.roles)),
|
|
1162
|
-
[role, sectionLinks]
|
|
1163
|
-
);
|
|
1164
|
-
const activityItems = (0, import_react.useMemo)(() => {
|
|
1165
|
-
const items = [];
|
|
1166
|
-
if (state.pages.status === "success") {
|
|
1167
|
-
for (const doc of state.pages.data.recent) {
|
|
1168
|
-
const id = asID(doc.id);
|
|
1169
|
-
if (!id) continue;
|
|
1170
|
-
const timestamp = toTimestamp(doc.updatedAt);
|
|
1171
|
-
items.push({
|
|
1172
|
-
href: `${pagesPath}/${id}`,
|
|
1173
|
-
id: `page-${id}`,
|
|
1174
|
-
kind: "page",
|
|
1175
|
-
label: typeof doc._status === "string" ? doc._status : "page",
|
|
1176
|
-
meta: Number.isFinite(timestamp) ? formatDateTime(doc.updatedAt) : "Update time unavailable",
|
|
1177
|
-
timestamp,
|
|
1178
|
-
title: asText(doc.title, "Untitled page")
|
|
1179
|
-
});
|
|
1180
|
-
}
|
|
1181
|
-
}
|
|
1182
|
-
if (state.forms?.status === "success") {
|
|
1183
|
-
for (const submission of state.forms.data.recentSubmissions) {
|
|
1184
|
-
const id = asID(submission.id);
|
|
1185
|
-
const formID = getFormID(submission.form);
|
|
1186
|
-
if (!id || !formID) continue;
|
|
1187
|
-
const timestamp = toTimestamp(submission.submittedAt);
|
|
1188
|
-
const formTitle = getFormTitle(submission.form) || "Form response";
|
|
1189
|
-
items.push({
|
|
1190
|
-
href: `${formsPath}?form=${encodeURIComponent(formID)}`,
|
|
1191
|
-
id: `submission-${id}`,
|
|
1192
|
-
kind: "submission",
|
|
1193
|
-
label: formTitle,
|
|
1194
|
-
meta: Number.isFinite(timestamp) ? `${readSubmissionIdentity(submission.data)} \xB7 ${formatDateTime(submission.submittedAt)}` : readSubmissionIdentity(submission.data),
|
|
1195
|
-
timestamp,
|
|
1196
|
-
title: "New submission"
|
|
1197
|
-
});
|
|
1198
|
-
}
|
|
1199
|
-
}
|
|
1200
|
-
if (state.media.status === "success") {
|
|
1201
|
-
for (const doc of state.media.data.recent) {
|
|
1202
|
-
const id = asID(doc.id);
|
|
1203
|
-
if (!id) continue;
|
|
1204
|
-
const timestamp = toTimestamp(doc.updatedAt);
|
|
1205
|
-
items.push({
|
|
1206
|
-
href: `${mediaPath}/${id}`,
|
|
1207
|
-
id: `media-${id}`,
|
|
1208
|
-
kind: "media",
|
|
1209
|
-
label: asText(doc.mimeType, "Media asset"),
|
|
1210
|
-
meta: Number.isFinite(timestamp) ? formatDateTime(doc.updatedAt) : "Update time unavailable",
|
|
1211
|
-
timestamp,
|
|
1212
|
-
title: asText(doc.filename, "Untitled asset")
|
|
1213
|
-
});
|
|
1214
|
-
}
|
|
1215
|
-
}
|
|
1216
|
-
return items.filter((item) => Number.isFinite(item.timestamp)).sort((a, b) => b.timestamp - a.timestamp).slice(0, 10);
|
|
1217
|
-
}, [formsPath, mediaPath, pagesPath, state.forms, state.media, state.pages]);
|
|
1218
|
-
const attentionItems = (0, import_react.useMemo)(() => {
|
|
1219
|
-
if (role === "client") {
|
|
1220
|
-
const items2 = [];
|
|
1221
|
-
if (state.pages.status === "success" && state.pages.data.updatedThisWeek > 0) {
|
|
1222
|
-
items2.push({
|
|
1223
|
-
href: pagesPath,
|
|
1224
|
-
id: "pages-updated",
|
|
1225
|
-
label: `${state.pages.data.updatedThisWeek} page${state.pages.data.updatedThisWeek === 1 ? "" : "s"} changed in the last 7 days.`
|
|
1226
|
-
});
|
|
1227
|
-
}
|
|
1228
|
-
if (state.media.status === "success" && state.media.data.uploadsThisWeek > 0) {
|
|
1229
|
-
items2.push({
|
|
1230
|
-
href: mediaPath,
|
|
1231
|
-
id: "media-updated",
|
|
1232
|
-
label: `${state.media.data.uploadsThisWeek} new media asset${state.media.data.uploadsThisWeek === 1 ? "" : "s"} landed this week.`
|
|
1233
|
-
});
|
|
1234
|
-
}
|
|
1235
|
-
return items2;
|
|
1236
|
-
}
|
|
1237
|
-
const items = [];
|
|
1238
|
-
if (state.pages.status === "success" && state.pages.data.draftCount > 0) {
|
|
1239
|
-
items.push({
|
|
1240
|
-
href: pagesPath,
|
|
1241
|
-
id: "draft-pages",
|
|
1242
|
-
label: `${state.pages.data.draftCount} page${state.pages.data.draftCount === 1 ? "" : "s"} still need publishing review.`,
|
|
1243
|
-
tone: "accent"
|
|
1244
|
-
});
|
|
1245
|
-
}
|
|
1246
|
-
if (state.forms?.status === "success" && state.forms.data.submissionsThisWeek > 0) {
|
|
1247
|
-
items.push({
|
|
1248
|
-
href: formsPath,
|
|
1249
|
-
id: "recent-submissions",
|
|
1250
|
-
label: `${state.forms.data.submissionsThisWeek} form submission${state.forms.data.submissionsThisWeek === 1 ? "" : "s"} arrived in the last 7 days.`,
|
|
1251
|
-
tone: "accent"
|
|
1252
|
-
});
|
|
1253
|
-
}
|
|
1254
|
-
if (state.media.status === "success" && state.media.data.total === 0) {
|
|
1255
|
-
items.push({
|
|
1256
|
-
href: mediaPath,
|
|
1257
|
-
id: "empty-media",
|
|
1258
|
-
label: "The media library is still empty. Add brand assets before content expands."
|
|
1259
|
-
});
|
|
1260
|
-
}
|
|
1261
|
-
if (state.pages.status === "error") {
|
|
1262
|
-
items.push({
|
|
1263
|
-
href: pagesPath,
|
|
1264
|
-
id: "pages-error",
|
|
1265
|
-
label: "Page activity could not be loaded for the dashboard.",
|
|
1266
|
-
tone: "muted"
|
|
1267
|
-
});
|
|
1268
|
-
}
|
|
1269
|
-
if (state.forms?.status === "error") {
|
|
1270
|
-
items.push({
|
|
1271
|
-
href: formsPath,
|
|
1272
|
-
id: "forms-error",
|
|
1273
|
-
label: "Form activity could not be loaded for the dashboard.",
|
|
1274
|
-
tone: "muted"
|
|
1275
|
-
});
|
|
1276
|
-
}
|
|
1277
|
-
if (state.media.status === "error") {
|
|
1278
|
-
items.push({
|
|
1279
|
-
href: mediaPath,
|
|
1280
|
-
id: "media-error",
|
|
1281
|
-
label: "Media activity could not be loaded for the dashboard.",
|
|
1282
|
-
tone: "muted"
|
|
1283
|
-
});
|
|
1284
|
-
}
|
|
1285
|
-
return items;
|
|
1286
|
-
}, [formsPath, mediaPath, pagesPath, role, state.forms, state.media, state.pages]);
|
|
1287
|
-
const snapshotCards = (0, import_react.useMemo)(() => {
|
|
1288
|
-
const cards = [];
|
|
1289
|
-
if (state.pages.status === "success") {
|
|
1290
|
-
cards.push(
|
|
1291
|
-
role === "client" ? {
|
|
1292
|
-
detail: `${state.pages.data.updatedThisWeek} updated this week`,
|
|
1293
|
-
kicker: "Pages",
|
|
1294
|
-
value: `${state.pages.data.total}`
|
|
1295
|
-
} : {
|
|
1296
|
-
detail: `${state.pages.data.draftCount} draft${state.pages.data.draftCount === 1 ? "" : "s"} waiting`,
|
|
1297
|
-
kicker: "Pages",
|
|
1298
|
-
value: `${state.pages.data.total}`
|
|
1299
|
-
}
|
|
1300
|
-
);
|
|
1301
|
-
}
|
|
1302
|
-
if (state.forms?.status === "success") {
|
|
1303
|
-
cards.push({
|
|
1304
|
-
detail: state.forms.data.busiestFormTitle ? `Most active: ${state.forms.data.busiestFormTitle}` : "Waiting on the first submission",
|
|
1305
|
-
kicker: "Forms",
|
|
1306
|
-
value: `${state.forms.data.submissionsThisWeek}`
|
|
1307
|
-
});
|
|
1308
|
-
}
|
|
1309
|
-
if (state.media.status === "success") {
|
|
1310
|
-
cards.push({
|
|
1311
|
-
detail: `${state.media.data.uploadsThisWeek} uploaded this week`,
|
|
1312
|
-
kicker: "Media",
|
|
1313
|
-
value: `${state.media.data.total}`
|
|
1314
|
-
});
|
|
1315
|
-
}
|
|
1316
|
-
cards.push({
|
|
1317
|
-
detail: `${visibleWorkspaceLinks.length} section${visibleWorkspaceLinks.length === 1 ? "" : "s"} available`,
|
|
1318
|
-
kicker: "Workspace",
|
|
1319
|
-
value: role ? role.toUpperCase() : "CMS"
|
|
1320
|
-
});
|
|
1321
|
-
return cards.slice(0, 4);
|
|
1322
|
-
}, [role, state.forms, state.media, state.pages, visibleWorkspaceLinks.length]);
|
|
1323
|
-
const primaryActions = (0, import_react.useMemo)(() => {
|
|
1324
|
-
const actions = [];
|
|
1325
|
-
if (canCreatePages(role)) {
|
|
1326
|
-
actions.push({
|
|
1327
|
-
description: "Create or revise content in the visual builder.",
|
|
1328
|
-
href: `${pagesPath}/new`,
|
|
1329
|
-
label: "New Page"
|
|
1330
|
-
});
|
|
1331
|
-
}
|
|
1332
|
-
actions.push({
|
|
1333
|
-
description: "Review live pages and recent edits.",
|
|
1334
|
-
href: pagesPath,
|
|
1335
|
-
label: "Open Pages",
|
|
1336
|
-
tone: "ghost"
|
|
1337
|
-
});
|
|
1338
|
-
if (formsEnabled && canReviewForms(role)) {
|
|
1339
|
-
actions.push({
|
|
1340
|
-
description: "Check submissions and form performance.",
|
|
1341
|
-
href: formsPath,
|
|
1342
|
-
label: "Review Forms",
|
|
1343
|
-
tone: "soft"
|
|
1344
|
-
});
|
|
1345
|
-
}
|
|
1346
|
-
actions.push({
|
|
1347
|
-
description: "Update site settings, navigation, and footer content.",
|
|
1348
|
-
href: globalsBasePath,
|
|
1349
|
-
label: "Open Globals",
|
|
1350
|
-
tone: "ghost"
|
|
1351
|
-
});
|
|
1352
|
-
actions.push({
|
|
1353
|
-
description: "Upload or organize brand and campaign assets.",
|
|
1354
|
-
href: mediaPath,
|
|
1355
|
-
label: "Manage Media",
|
|
1356
|
-
tone: "ghost"
|
|
1357
|
-
});
|
|
1358
|
-
if (role === "admin") {
|
|
1359
|
-
actions.push({
|
|
1360
|
-
description: "Manage users, roles, and fallback tools.",
|
|
1361
|
-
href: toolsPath,
|
|
1362
|
-
label: "Admin Tools",
|
|
1363
|
-
tone: "ghost"
|
|
1364
|
-
});
|
|
1365
|
-
}
|
|
1366
|
-
return actions;
|
|
1367
|
-
}, [formsEnabled, formsPath, globalsBasePath, mediaPath, pagesPath, role, toolsPath]);
|
|
1368
|
-
const attentionTitle = role === "client" ? "What Changed" : "Needs Attention";
|
|
1369
|
-
const attentionDescription = role === "client" ? "A quick read on recent content and asset changes." : "The highest-signal items that still need review.";
|
|
1370
|
-
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "orion-dashboard-layout", children: [
|
|
1371
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("section", { className: "orion-dashboard-panel orion-dashboard-panel--attention", children: [
|
|
1372
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "orion-dashboard-panel-header", children: [
|
|
1373
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { children: [
|
|
1374
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "orion-dashboard-panel-kicker", children: attentionTitle }),
|
|
1375
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("h2", { children: attentionDescription })
|
|
1376
|
-
] }),
|
|
1377
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "orion-dashboard-panel-meta", children: "Last 7 days" })
|
|
1378
|
-
] }),
|
|
1379
|
-
attentionItems.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "orion-dashboard-attention-list", children: attentionItems.map(
|
|
1380
|
-
(item) => item.href ? /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
|
|
1381
|
-
import_link.default,
|
|
1382
|
-
{
|
|
1383
|
-
className: ["orion-dashboard-attention-item", item.tone ? `is-${item.tone}` : ""].filter(Boolean).join(" "),
|
|
1384
|
-
href: item.href,
|
|
1385
|
-
children: [
|
|
1386
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("strong", { children: item.label }),
|
|
1387
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { children: "Open" })
|
|
1388
|
-
]
|
|
1389
|
-
},
|
|
1390
|
-
item.id
|
|
1391
|
-
) : /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
1392
|
-
"div",
|
|
1393
|
-
{
|
|
1394
|
-
className: ["orion-dashboard-attention-item", item.tone ? `is-${item.tone}` : ""].filter(Boolean).join(" "),
|
|
1395
|
-
children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("strong", { children: item.label })
|
|
1396
|
-
},
|
|
1397
|
-
item.id
|
|
1398
|
-
)
|
|
1399
|
-
) }) : state.pages.status === "loading" || state.media.status === "loading" ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(ModuleStatus, { message: "Loading attention items..." }) : /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
1400
|
-
EmptyState,
|
|
1401
|
-
{
|
|
1402
|
-
body: role === "client" ? "No major changes landed during the current review window." : "No urgent follow-up surfaced from content, forms, or media activity.",
|
|
1403
|
-
title: "Everything looks steady"
|
|
1404
|
-
}
|
|
1405
|
-
)
|
|
1406
|
-
] }),
|
|
1407
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("section", { className: "orion-dashboard-panel orion-dashboard-panel--actions", children: [
|
|
1408
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "orion-dashboard-panel-header", children: [
|
|
1409
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { children: [
|
|
1410
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "orion-dashboard-panel-kicker", children: "Quick Actions" }),
|
|
1411
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("h2", { children: "Jump into the work that matters most." })
|
|
1412
|
-
] }),
|
|
1413
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("span", { className: "orion-dashboard-panel-meta", children: [
|
|
1414
|
-
role || "studio",
|
|
1415
|
-
" mode"
|
|
1416
|
-
] })
|
|
1417
|
-
] }),
|
|
1418
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "orion-dashboard-action-list", children: primaryActions.map((action) => /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
|
|
1419
|
-
import_link.default,
|
|
1420
|
-
{
|
|
1421
|
-
className: [
|
|
1422
|
-
"orion-dashboard-action",
|
|
1423
|
-
action.tone === "ghost" ? "is-ghost" : action.tone === "soft" ? "is-soft" : ""
|
|
1424
|
-
].filter(Boolean).join(" "),
|
|
1425
|
-
href: action.href,
|
|
1426
|
-
children: [
|
|
1427
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("strong", { children: action.label }),
|
|
1428
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { children: action.description })
|
|
1429
|
-
]
|
|
1430
|
-
},
|
|
1431
|
-
action.label
|
|
1432
|
-
)) }),
|
|
1433
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "orion-dashboard-workspace-strip", children: [
|
|
1434
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "orion-dashboard-workspace-label", children: "Workspace" }),
|
|
1435
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "orion-dashboard-workspace-pills", children: visibleWorkspaceLinks.map((section) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_link.default, { className: "orion-dashboard-workspace-pill", href: section.href, children: section.label }, section.id)) })
|
|
1436
|
-
] })
|
|
1437
|
-
] }),
|
|
1438
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("section", { className: "orion-dashboard-panel orion-dashboard-panel--activity", children: [
|
|
1439
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "orion-dashboard-panel-header", children: [
|
|
1440
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { children: [
|
|
1441
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "orion-dashboard-panel-kicker", children: "Recent Activity" }),
|
|
1442
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("h2", { children: "The freshest edits, responses, and uploads across the studio." })
|
|
1443
|
-
] }),
|
|
1444
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("span", { className: "orion-dashboard-panel-meta", children: [
|
|
1445
|
-
activityItems.length,
|
|
1446
|
-
" items"
|
|
1447
|
-
] })
|
|
1448
|
-
] }),
|
|
1449
|
-
activityItems.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "orion-dashboard-activity-list", children: activityItems.map((item) => /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_link.default, { className: `orion-dashboard-activity-item is-${item.kind}`, href: item.href, children: [
|
|
1450
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "orion-dashboard-activity-copy", children: [
|
|
1451
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "orion-dashboard-activity-topline", children: [
|
|
1452
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("strong", { children: item.title }),
|
|
1453
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { children: formatRelativeTime(item.timestamp) })
|
|
1454
|
-
] }),
|
|
1455
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { children: item.meta })
|
|
1456
|
-
] }),
|
|
1457
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "orion-dashboard-activity-pill", children: item.label })
|
|
1458
|
-
] }, item.id)) }) : state.pages.status === "loading" || state.media.status === "loading" ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(ModuleStatus, { message: "Loading activity feed..." }) : /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
1459
|
-
EmptyState,
|
|
1460
|
-
{
|
|
1461
|
-
body: "Recent page edits, submissions, and uploads will start stacking here as soon as the team gets moving.",
|
|
1462
|
-
title: "No recent activity yet"
|
|
1463
|
-
}
|
|
1464
|
-
)
|
|
1465
|
-
] }),
|
|
1466
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("section", { className: "orion-dashboard-panel orion-dashboard-panel--snapshot", children: [
|
|
1467
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "orion-dashboard-panel-header", children: [
|
|
1468
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { children: [
|
|
1469
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "orion-dashboard-panel-kicker", children: "Business Snapshot" }),
|
|
1470
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("h2", { children: "A compact read on content momentum and performance." })
|
|
1471
|
-
] }),
|
|
1472
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "orion-dashboard-panel-meta", children: "30-day lens" })
|
|
1473
|
-
] }),
|
|
1474
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "orion-dashboard-snapshot-grid", children: [
|
|
1475
|
-
snapshotCards.map((card) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(SnapshotMetric, { card }, card.kicker)),
|
|
1476
|
-
extensionPanels.map((panel) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
1477
|
-
"div",
|
|
1478
|
-
{
|
|
1479
|
-
className: [
|
|
1480
|
-
"orion-dashboard-extension-panel",
|
|
1481
|
-
panel.span === "full" ? "is-full" : "is-half"
|
|
1482
|
-
].filter(Boolean).join(" "),
|
|
1483
|
-
children: panel.node
|
|
1484
|
-
},
|
|
1485
|
-
panel.id
|
|
1486
|
-
))
|
|
1487
|
-
] }),
|
|
1488
|
-
state.pages.status === "error" || state.media.status === "error" ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "orion-dashboard-inline-note", children: "Some dashboard modules could not be loaded. The rest of the workspace remains available." }) : null
|
|
1489
|
-
] })
|
|
1490
|
-
] });
|
|
1491
|
-
}
|
|
1492
|
-
|
|
1493
|
-
// src/admin/components/studio/StudioSectionLayout.tsx
|
|
1494
|
-
var import_react5 = require("react");
|
|
1495
|
-
var import_navigation = require("next/navigation");
|
|
1496
|
-
var import_ui = require("@payloadcms/ui");
|
|
1497
|
-
|
|
1498
|
-
// src/admin-app/components/AdminShellClient.tsx
|
|
1499
|
-
var import_react2 = require("react");
|
|
1500
|
-
var import_jsx_runtime4 = require("react/jsx-runtime");
|
|
1501
|
-
var iconSize = 20;
|
|
1502
|
-
var iconStyle = { display: "block", flexShrink: 0 };
|
|
1503
|
-
function NavIcon({ name }) {
|
|
1504
|
-
const props = { width: iconSize, height: iconSize, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2, strokeLinecap: "round", strokeLinejoin: "round", style: iconStyle };
|
|
1505
|
-
switch (name) {
|
|
1506
|
-
case "dashboard":
|
|
1507
|
-
return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("svg", { ...props, children: [
|
|
1508
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("rect", { x: "3", y: "3", width: "7", height: "9", rx: "1" }),
|
|
1509
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("rect", { x: "14", y: "3", width: "7", height: "5", rx: "1" }),
|
|
1510
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("rect", { x: "14", y: "12", width: "7", height: "9", rx: "1" }),
|
|
1511
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("rect", { x: "3", y: "16", width: "7", height: "5", rx: "1" })
|
|
1512
|
-
] });
|
|
1513
|
-
case "pages":
|
|
1514
|
-
return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("svg", { ...props, children: [
|
|
1515
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("path", { d: "M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8Z" }),
|
|
1516
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("polyline", { points: "14 2 14 8 20 8" }),
|
|
1517
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("line", { x1: "8", y1: "13", x2: "16", y2: "13" }),
|
|
1518
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("line", { x1: "8", y1: "17", x2: "12", y2: "17" })
|
|
1519
|
-
] });
|
|
1520
|
-
case "forms":
|
|
1521
|
-
return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("svg", { ...props, children: [
|
|
1522
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("path", { d: "M9 3h6" }),
|
|
1523
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("path", { d: "M12 3v18" }),
|
|
1524
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("path", { d: "M5 7h14a2 2 0 0 1 2 2v8a4 4 0 0 1-4 4H7a4 4 0 0 1-4-4V9a2 2 0 0 1 2-2Z" }),
|
|
1525
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("path", { d: "M7 11h10" }),
|
|
1526
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("path", { d: "M7 15h6" })
|
|
1527
|
-
] });
|
|
1528
|
-
case "globals":
|
|
1529
|
-
return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("svg", { ...props, children: [
|
|
1530
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("circle", { cx: "12", cy: "12", r: "3" }),
|
|
1531
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("path", { d: "M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1-2.83 2.83l-.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-4 0v-.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-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 0-4h.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 2.83-2.83l.06.06A1.65 1.65 0 0 0 9 4.68a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 4 0v.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 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 0 4h-.09a1.65 1.65 0 0 0-1.51 1Z" })
|
|
1532
|
-
] });
|
|
1533
|
-
case "media":
|
|
1534
|
-
return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("svg", { ...props, children: [
|
|
1535
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("rect", { x: "3", y: "3", width: "18", height: "18", rx: "2", ry: "2" }),
|
|
1536
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("circle", { cx: "8.5", cy: "8.5", r: "1.5" }),
|
|
1537
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("polyline", { points: "21 15 16 10 5 21" })
|
|
1538
|
-
] });
|
|
1539
|
-
case "tools":
|
|
1540
|
-
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("svg", { ...props, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("path", { d: "M14.7 6.3a1 1 0 0 0 0 1.4l1.6 1.6a1 1 0 0 0 1.4 0l3.77-3.77a6 6 0 0 1-7.94 7.94l-6.91 6.91a2.12 2.12 0 0 1-3-3l6.91-6.91a6 6 0 0 1 7.94-7.94l-3.76 3.76Z" }) });
|
|
1541
|
-
case "analytics":
|
|
1542
|
-
return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("svg", { ...props, children: [
|
|
1543
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("path", { d: "M4 19V5" }),
|
|
1544
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("path", { d: "M10 19V10" }),
|
|
1545
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("path", { d: "M16 19v-6" }),
|
|
1546
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("path", { d: "M22 19V3" })
|
|
1547
|
-
] });
|
|
1548
|
-
case "account":
|
|
1549
|
-
return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("svg", { ...props, children: [
|
|
1550
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("path", { d: "M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2" }),
|
|
1551
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("circle", { cx: "12", cy: "7", r: "4" })
|
|
1552
|
-
] });
|
|
1553
|
-
default:
|
|
1554
|
-
return null;
|
|
1555
|
-
}
|
|
1556
|
-
}
|
|
1557
|
-
function AdminShellClient({
|
|
1558
|
-
children,
|
|
1559
|
-
brandName,
|
|
1560
|
-
logoUrl,
|
|
1561
|
-
userEmail,
|
|
1562
|
-
userRole,
|
|
1563
|
-
pathname,
|
|
1564
|
-
navItems,
|
|
1565
|
-
onLogout,
|
|
1566
|
-
storageKey = "orion-admin-shell-collapsed"
|
|
1567
|
-
}) {
|
|
1568
|
-
const [collapsed, setCollapsed] = (0, import_react2.useState)(false);
|
|
1569
|
-
const [loggingOut, setLoggingOut] = (0, import_react2.useState)(false);
|
|
1570
|
-
(0, import_react2.useEffect)(() => {
|
|
1571
|
-
try {
|
|
1572
|
-
const stored = window.localStorage.getItem(storageKey);
|
|
1573
|
-
if (stored === "1") {
|
|
1574
|
-
setCollapsed(true);
|
|
1575
|
-
}
|
|
1576
|
-
} catch {
|
|
1577
|
-
}
|
|
1578
|
-
}, [storageKey]);
|
|
1579
|
-
const toggleSidebar = () => {
|
|
1580
|
-
setCollapsed((current) => {
|
|
1581
|
-
const next = !current;
|
|
1582
|
-
try {
|
|
1583
|
-
window.localStorage.setItem(storageKey, next ? "1" : "0");
|
|
1584
|
-
} catch {
|
|
1585
|
-
}
|
|
1586
|
-
return next;
|
|
1587
|
-
});
|
|
1588
|
-
};
|
|
1589
|
-
const handleLogout = async () => {
|
|
1590
|
-
setLoggingOut(true);
|
|
1591
|
-
try {
|
|
1592
|
-
await onLogout();
|
|
1593
|
-
} finally {
|
|
1594
|
-
setLoggingOut(false);
|
|
1595
|
-
}
|
|
1596
|
-
};
|
|
1597
|
-
return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: `orion-admin-shell ${collapsed ? "is-collapsed" : ""}`, children: [
|
|
1598
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("aside", { className: "orion-admin-sidebar", children: [
|
|
1599
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
1600
|
-
"button",
|
|
1601
|
-
{
|
|
1602
|
-
"aria-label": collapsed ? "Expand sidebar" : "Collapse sidebar",
|
|
1603
|
-
className: "orion-admin-sidebar-toggle",
|
|
1604
|
-
onClick: toggleSidebar,
|
|
1605
|
-
type: "button",
|
|
1606
|
-
children: collapsed ? ">" : "<"
|
|
1607
|
-
}
|
|
1608
|
-
),
|
|
1609
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "orion-admin-brand-wrap", children: [
|
|
1610
|
-
logoUrl ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "orion-admin-brand-logo", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("img", { alt: `${brandName} logo`, src: logoUrl }) }) : null,
|
|
1611
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "orion-admin-brand-text", children: [
|
|
1612
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "orion-admin-brand-name", title: brandName, children: collapsed ? brandName.slice(0, 1).toUpperCase() : brandName }),
|
|
1613
|
-
!collapsed ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "orion-admin-brand-subtitle", children: "Studio" }) : null
|
|
1614
|
-
] })
|
|
1615
|
-
] }),
|
|
1616
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("nav", { className: "orion-admin-nav", children: navItems.filter((item) => roleCanAccessNav(userRole, item)).map((item) => {
|
|
1617
|
-
const active = navItemIsActive(pathname, item);
|
|
1618
|
-
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
1619
|
-
"a",
|
|
1620
|
-
{
|
|
1621
|
-
className: `orion-admin-nav-link ${active ? "is-active" : ""}`,
|
|
1622
|
-
href: item.href,
|
|
1623
|
-
title: item.label,
|
|
1624
|
-
children: item.icon ? collapsed ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(NavIcon, { name: item.icon }) : /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("span", { style: { alignItems: "center", display: "flex", gap: "0.6rem" }, children: [
|
|
1625
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(NavIcon, { name: item.icon }),
|
|
1626
|
-
item.label
|
|
1627
|
-
] }) : collapsed ? item.label.slice(0, 1) : item.label
|
|
1628
|
-
},
|
|
1629
|
-
item.href
|
|
1630
|
-
);
|
|
1631
|
-
}) }),
|
|
1632
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "orion-admin-sidebar-footer", children: [
|
|
1633
|
-
!collapsed ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_jsx_runtime4.Fragment, { children: [
|
|
1634
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "orion-admin-user-label", children: "Signed in as" }),
|
|
1635
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "orion-admin-user-email", children: userEmail })
|
|
1636
|
-
] }) : null,
|
|
1637
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("button", { className: "orion-admin-logout", disabled: loggingOut, onClick: handleLogout, type: "button", children: loggingOut ? "..." : "Log out" })
|
|
1638
|
-
] })
|
|
1639
|
-
] }),
|
|
1640
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("main", { className: "orion-admin-main", children })
|
|
1641
|
-
] });
|
|
1642
|
-
}
|
|
1643
|
-
|
|
1644
|
-
// src/admin/hooks/useSiteBranding.ts
|
|
1645
|
-
var import_react3 = require("react");
|
|
1646
|
-
var asRecord = (value) => {
|
|
1647
|
-
if (!value || typeof value !== "object" || Array.isArray(value)) return null;
|
|
1648
|
-
return value;
|
|
1649
|
-
};
|
|
1650
|
-
var pickString = (value) => {
|
|
1651
|
-
if (typeof value !== "string") return null;
|
|
1652
|
-
const next = value.trim();
|
|
1653
|
-
return next.length > 0 ? next : null;
|
|
1654
|
-
};
|
|
1655
|
-
var resolveUploadUrl = (value) => {
|
|
1656
|
-
const direct = pickString(value);
|
|
1657
|
-
if (direct) return direct;
|
|
1658
|
-
const record = asRecord(value);
|
|
1659
|
-
if (!record) return null;
|
|
1660
|
-
const fromUrl = pickString(record.url);
|
|
1661
|
-
if (fromUrl) return fromUrl;
|
|
1662
|
-
const fromFilename = pickString(record.filename);
|
|
1663
|
-
if (fromFilename) return `/api/media/file/${fromFilename}`;
|
|
1664
|
-
return null;
|
|
1665
|
-
};
|
|
1666
|
-
var resolveLogoUrl = (settings) => {
|
|
1667
|
-
return resolveUploadUrl(settings.logo) || resolveUploadUrl(settings.adminLogo) || resolveUploadUrl(settings.brandLogo) || null;
|
|
1668
|
-
};
|
|
1669
|
-
var cachedBranding = null;
|
|
1670
|
-
function useSiteBranding(defaultName, defaultLogoUrl) {
|
|
1671
|
-
const [branding, setBranding] = (0, import_react3.useState)(() => {
|
|
1672
|
-
if (cachedBranding) {
|
|
1673
|
-
return {
|
|
1674
|
-
logoUrl: cachedBranding.logoUrl || defaultLogoUrl || null,
|
|
1675
|
-
siteName: cachedBranding.siteName || defaultName || null
|
|
1676
|
-
};
|
|
1677
|
-
}
|
|
1678
|
-
return {
|
|
1679
|
-
logoUrl: defaultLogoUrl || null,
|
|
1680
|
-
siteName: defaultName || null
|
|
1681
|
-
};
|
|
1682
|
-
});
|
|
1683
|
-
(0, import_react3.useEffect)(() => {
|
|
1684
|
-
let cancelled = false;
|
|
1685
|
-
const run = async () => {
|
|
1686
|
-
try {
|
|
1687
|
-
const res = await fetch("/api/globals/site-settings?depth=1&draft=true", {
|
|
1688
|
-
credentials: "include"
|
|
1689
|
-
});
|
|
1690
|
-
if (!res.ok) return;
|
|
1691
|
-
const data = await res.json();
|
|
1692
|
-
const record = asRecord(data);
|
|
1693
|
-
if (!record) return;
|
|
1694
|
-
const siteName = pickString(record.siteName);
|
|
1695
|
-
const logoUrl = resolveLogoUrl(record);
|
|
1696
|
-
cachedBranding = { logoUrl, siteName };
|
|
1697
|
-
if (!cancelled) {
|
|
1698
|
-
setBranding({
|
|
1699
|
-
logoUrl: logoUrl || defaultLogoUrl || null,
|
|
1700
|
-
siteName: siteName || defaultName || null
|
|
1701
|
-
});
|
|
1702
|
-
}
|
|
1703
|
-
} catch {
|
|
1704
|
-
}
|
|
1705
|
-
};
|
|
1706
|
-
void run();
|
|
1707
|
-
return () => {
|
|
1708
|
-
cancelled = true;
|
|
1709
|
-
};
|
|
1710
|
-
}, [defaultLogoUrl, defaultName]);
|
|
1711
|
-
return branding;
|
|
1712
|
-
}
|
|
1713
|
-
|
|
1714
|
-
// src/admin/components/studio/adminPathUtils.ts
|
|
1715
|
-
var import_react4 = require("react");
|
|
1716
|
-
var DEFAULT_ADMIN_BASE_PATH = "/admin";
|
|
1717
|
-
var normalizePath = (value) => {
|
|
1718
|
-
if (!value || value === "/") return "/";
|
|
1719
|
-
const withLeadingSlash = value.startsWith("/") ? value : `/${value}`;
|
|
1720
|
-
const trimmed = withLeadingSlash.replace(/\/+$/, "");
|
|
1721
|
-
return trimmed.length > 0 ? trimmed : "/";
|
|
1722
|
-
};
|
|
1723
|
-
var normalizeAdminBasePath = (value) => {
|
|
1724
|
-
const normalized = normalizePath(value);
|
|
1725
|
-
return normalized === "/" ? DEFAULT_ADMIN_BASE_PATH : normalized;
|
|
1726
|
-
};
|
|
1727
|
-
var detectAdminBasePath = (pathname, fallback = DEFAULT_ADMIN_BASE_PATH) => {
|
|
1728
|
-
const normalizedPathname = normalizePath(pathname);
|
|
1729
|
-
const normalizedFallback = normalizeAdminBasePath(fallback);
|
|
1730
|
-
const markers = [
|
|
1731
|
-
"/contact-form",
|
|
1732
|
-
"/collections/",
|
|
1733
|
-
"/globals/",
|
|
1734
|
-
"/forms",
|
|
1735
|
-
"/pages/",
|
|
1736
|
-
"/tools",
|
|
1737
|
-
"/media",
|
|
1738
|
-
"/logout",
|
|
1739
|
-
"/login"
|
|
1740
|
-
];
|
|
1741
|
-
for (const marker of markers) {
|
|
1742
|
-
const index = normalizedPathname.indexOf(marker);
|
|
1743
|
-
if (index > 0) {
|
|
1744
|
-
return normalizeAdminBasePath(normalizedPathname.slice(0, index));
|
|
1745
|
-
}
|
|
1746
|
-
}
|
|
1747
|
-
if (normalizedPathname === normalizedFallback || normalizedPathname.startsWith(`${normalizedFallback}/`)) {
|
|
1748
|
-
return normalizedFallback;
|
|
1749
|
-
}
|
|
1750
|
-
const segments = normalizedPathname.split("/").filter(Boolean);
|
|
1751
|
-
if (segments.length > 0) {
|
|
1752
|
-
return normalizeAdminBasePath(`/${segments[0]}`);
|
|
1753
|
-
}
|
|
1754
|
-
return normalizedFallback;
|
|
1755
|
-
};
|
|
1756
|
-
var isAbsoluteExternalURL2 = (value) => /^[a-zA-Z][a-zA-Z\d+\-.]*:/.test(value) || value.startsWith("//");
|
|
1757
|
-
var resolveAdminPath = (adminBasePath, targetPath) => {
|
|
1758
|
-
if (!targetPath) return adminBasePath;
|
|
1759
|
-
if (isAbsoluteExternalURL2(targetPath)) return targetPath;
|
|
1760
|
-
const normalizedBasePath = normalizeAdminBasePath(adminBasePath);
|
|
1761
|
-
const normalizedTargetPath = normalizePath(targetPath);
|
|
1762
|
-
if (normalizedTargetPath === "/admin") {
|
|
1763
|
-
return normalizedBasePath;
|
|
1764
|
-
}
|
|
1765
|
-
if (normalizedTargetPath.startsWith("/admin/")) {
|
|
1766
|
-
return `${normalizedBasePath}${normalizedTargetPath.slice("/admin".length)}`;
|
|
1767
|
-
}
|
|
1768
|
-
if (normalizedTargetPath === normalizedBasePath || normalizedTargetPath.startsWith(`${normalizedBasePath}/`)) {
|
|
1769
|
-
return normalizedTargetPath;
|
|
1770
|
-
}
|
|
1771
|
-
if (normalizedTargetPath === "/") {
|
|
1772
|
-
return normalizedBasePath;
|
|
1773
|
-
}
|
|
1774
|
-
return `${normalizedBasePath}${normalizedTargetPath}`;
|
|
1775
|
-
};
|
|
1776
|
-
var useAdminBasePath = (fallback = DEFAULT_ADMIN_BASE_PATH) => {
|
|
1777
|
-
const [adminBasePath, setAdminBasePath] = (0, import_react4.useState)(normalizeAdminBasePath(fallback));
|
|
1778
|
-
(0, import_react4.useEffect)(() => {
|
|
1779
|
-
const update = () => {
|
|
1780
|
-
setAdminBasePath(detectAdminBasePath(window.location.pathname, fallback));
|
|
1781
|
-
};
|
|
1782
|
-
update();
|
|
1783
|
-
window.addEventListener("popstate", update);
|
|
1784
|
-
return () => window.removeEventListener("popstate", update);
|
|
1785
|
-
}, [fallback]);
|
|
1786
|
-
return adminBasePath;
|
|
1787
|
-
};
|
|
1788
|
-
|
|
1789
|
-
// src/admin/components/studio/studioNavModel.ts
|
|
1790
|
-
var getPropString = (props, key, fallback) => {
|
|
1791
|
-
if (!props || typeof props !== "object") return fallback;
|
|
1792
|
-
const direct = props[key];
|
|
1793
|
-
if (typeof direct === "string" && direct.length > 0) return direct;
|
|
1794
|
-
const clientProps = props.clientProps;
|
|
1795
|
-
if (clientProps && typeof clientProps === "object") {
|
|
1796
|
-
const nested = clientProps[key];
|
|
1797
|
-
if (typeof nested === "string" && nested.length > 0) return nested;
|
|
1798
|
-
}
|
|
1799
|
-
return fallback;
|
|
1800
|
-
};
|
|
1801
|
-
var getPropBoolean = (props, key, fallback) => {
|
|
1802
|
-
if (!props || typeof props !== "object") return fallback;
|
|
1803
|
-
const direct = props[key];
|
|
1804
|
-
if (typeof direct === "boolean") return direct;
|
|
1805
|
-
const clientProps = props.clientProps;
|
|
1806
|
-
if (clientProps && typeof clientProps === "object") {
|
|
1807
|
-
const nested = clientProps[key];
|
|
1808
|
-
if (typeof nested === "boolean") return nested;
|
|
1809
|
-
}
|
|
1810
|
-
return fallback;
|
|
1811
|
-
};
|
|
1812
|
-
var getPropStringArray = (props, key, fallback) => {
|
|
1813
|
-
if (!props || typeof props !== "object") return fallback;
|
|
1814
|
-
const read = (candidate) => Array.isArray(candidate) ? candidate.filter((value) => typeof value === "string" && value.length > 0) : null;
|
|
1815
|
-
const direct = read(props[key]);
|
|
1816
|
-
if (direct) return direct;
|
|
1817
|
-
const clientProps = props.clientProps;
|
|
1818
|
-
if (clientProps && typeof clientProps === "object") {
|
|
1819
|
-
const nested = read(clientProps[key]);
|
|
1820
|
-
if (nested) return nested;
|
|
1821
|
-
}
|
|
1822
|
-
return fallback;
|
|
1823
|
-
};
|
|
1824
|
-
var getPropSections = (props) => {
|
|
1825
|
-
if (!props || typeof props !== "object") return [];
|
|
1826
|
-
const direct = resolveStudioSections(props.sections);
|
|
1827
|
-
if (direct.length > 0) return direct;
|
|
1828
|
-
const clientProps = props.clientProps;
|
|
1829
|
-
if (clientProps && typeof clientProps === "object") {
|
|
1830
|
-
return resolveStudioSections(clientProps.sections);
|
|
1831
|
-
}
|
|
1832
|
-
return [];
|
|
1833
|
-
};
|
|
1834
|
-
var readUserRole = (user) => {
|
|
1835
|
-
if (!user || typeof user !== "object") {
|
|
1836
|
-
return void 0;
|
|
1837
|
-
}
|
|
1838
|
-
const role = user.role;
|
|
1839
|
-
return typeof role === "string" ? role : void 0;
|
|
1840
|
-
};
|
|
1841
|
-
var buildStudioNavItems = (props, adminBasePath) => {
|
|
1842
|
-
const formsEnabled = getPropBoolean(props, "formsEnabled", false);
|
|
1843
|
-
const formsCollectionSlug = getPropString(props, "formsCollectionSlug", "forms");
|
|
1844
|
-
const formSubmissionsCollectionSlug = getPropString(
|
|
1845
|
-
props,
|
|
1846
|
-
"formSubmissionsCollectionSlug",
|
|
1847
|
-
"form-submissions"
|
|
1848
|
-
);
|
|
1849
|
-
const formUploadsCollectionSlug = getPropString(props, "formUploadsCollectionSlug", "form-uploads");
|
|
1850
|
-
const mediaCollectionSlug = getPropString(props, "mediaCollectionSlug", "media");
|
|
1851
|
-
const globalsBasePath = getPropString(props, "globalsBasePath", "/globals");
|
|
1852
|
-
const globalsExtraMatchPrefixes = getPropStringArray(props, "globalsExtraMatchPrefixes", []);
|
|
1853
|
-
const sections = getPropSections(props);
|
|
1854
|
-
const pagesPath = resolveAdminPath(adminBasePath, "/pages");
|
|
1855
|
-
const formsPath = resolveAdminPath(adminBasePath, "/forms");
|
|
1856
|
-
const mediaPath = resolveAdminPath(adminBasePath, "/media");
|
|
1857
|
-
const toolsPath = resolveAdminPath(adminBasePath, "/tools");
|
|
1858
|
-
const resolvedGlobalsBasePath = resolveAdminPath(adminBasePath, globalsBasePath);
|
|
1859
|
-
const resolvedGlobalsExtraMatchPrefixes = globalsExtraMatchPrefixes.map(
|
|
1860
|
-
(prefix) => resolveAdminPath(adminBasePath, prefix)
|
|
1861
|
-
);
|
|
1862
|
-
const baseItemsBeforeTools = [
|
|
1863
|
-
{
|
|
1864
|
-
href: adminBasePath,
|
|
1865
|
-
icon: "dashboard",
|
|
1866
|
-
label: "Dashboard",
|
|
1867
|
-
matchPrefixes: [adminBasePath]
|
|
1868
|
-
},
|
|
1869
|
-
{
|
|
1870
|
-
href: pagesPath,
|
|
1871
|
-
icon: "pages",
|
|
1872
|
-
label: "Pages",
|
|
1873
|
-
matchPrefixes: [pagesPath]
|
|
1874
|
-
},
|
|
1875
|
-
...formsEnabled ? [
|
|
1876
|
-
{
|
|
1877
|
-
href: formsPath,
|
|
1878
|
-
icon: "forms",
|
|
1879
|
-
label: "Forms",
|
|
1880
|
-
matchPrefixes: [
|
|
1881
|
-
formsPath,
|
|
1882
|
-
resolveAdminPath(adminBasePath, `/collections/${formsCollectionSlug}`),
|
|
1883
|
-
resolveAdminPath(adminBasePath, `/collections/${formSubmissionsCollectionSlug}`),
|
|
1884
|
-
resolveAdminPath(adminBasePath, `/collections/${formUploadsCollectionSlug}`)
|
|
1885
|
-
]
|
|
1886
|
-
}
|
|
1887
|
-
] : [],
|
|
1888
|
-
{
|
|
1889
|
-
href: resolvedGlobalsBasePath,
|
|
1890
|
-
icon: "globals",
|
|
1891
|
-
label: "Globals",
|
|
1892
|
-
matchPrefixes: [
|
|
1893
|
-
resolvedGlobalsBasePath,
|
|
1894
|
-
resolveAdminPath(adminBasePath, "/globals"),
|
|
1895
|
-
...resolvedGlobalsExtraMatchPrefixes
|
|
1896
|
-
]
|
|
1897
|
-
},
|
|
1898
|
-
{
|
|
1899
|
-
href: mediaPath,
|
|
1900
|
-
icon: "media",
|
|
1901
|
-
label: "Media",
|
|
1902
|
-
matchPrefixes: [mediaPath, resolveAdminPath(adminBasePath, `/collections/${mediaCollectionSlug}`)]
|
|
1903
|
-
}
|
|
1904
|
-
];
|
|
1905
|
-
const adminToolsItem = {
|
|
1906
|
-
href: toolsPath,
|
|
1907
|
-
icon: "tools",
|
|
1908
|
-
label: "Admin Tools",
|
|
1909
|
-
matchPrefixes: [toolsPath, resolveAdminPath(adminBasePath, "/collections/users")],
|
|
1910
|
-
roles: ["admin"]
|
|
1911
|
-
};
|
|
1912
|
-
const extensionItems = sections.map((section) => ({
|
|
1913
|
-
href: resolveAdminPath(adminBasePath, section.href),
|
|
1914
|
-
...section.icon ? { icon: section.icon } : {},
|
|
1915
|
-
label: section.label,
|
|
1916
|
-
matchPrefixes: section.matchPrefixes.map((prefix) => resolveAdminPath(adminBasePath, prefix)),
|
|
1917
|
-
roles: section.roles
|
|
1918
|
-
}));
|
|
1919
|
-
return [...baseItemsBeforeTools, ...extensionItems, adminToolsItem];
|
|
1920
|
-
};
|
|
1921
|
-
|
|
1922
|
-
// src/admin/components/studio/StudioSectionLayout.tsx
|
|
1923
|
-
var import_jsx_runtime5 = require("react/jsx-runtime");
|
|
1924
|
-
function StudioSectionLayout({ children, navProps }) {
|
|
1925
|
-
const { user } = (0, import_ui.useAuth)();
|
|
1926
|
-
const pathname = (0, import_navigation.usePathname)() || "";
|
|
1927
|
-
const router = (0, import_navigation.useRouter)();
|
|
1928
|
-
const adminBasePath = useAdminBasePath();
|
|
1929
|
-
const defaultBrandName = getPropString(navProps, "brandName", "Orion Studio");
|
|
1930
|
-
const defaultLogoUrl = getPropString(navProps, "logoUrl", "");
|
|
1931
|
-
const navItems = (0, import_react5.useMemo)(
|
|
1932
|
-
() => buildStudioNavItems(navProps, adminBasePath),
|
|
1933
|
-
[adminBasePath, navProps]
|
|
1934
|
-
);
|
|
1935
|
-
const branding = useSiteBranding(defaultBrandName, defaultLogoUrl || void 0);
|
|
1936
|
-
(0, import_react5.useLayoutEffect)(() => {
|
|
1937
|
-
document.body.classList.add("orion-studio-shell-active");
|
|
1938
|
-
return () => {
|
|
1939
|
-
document.body.classList.remove("orion-studio-shell-active");
|
|
1940
|
-
};
|
|
1941
|
-
}, []);
|
|
1942
|
-
const logout = (0, import_react5.useMemo)(
|
|
1943
|
-
() => async () => {
|
|
1944
|
-
await fetch("/api/users/logout", {
|
|
1945
|
-
credentials: "include",
|
|
1946
|
-
method: "POST"
|
|
1947
|
-
});
|
|
1948
|
-
router.push(resolveAdminPath(adminBasePath, "/login"));
|
|
1949
|
-
router.refresh();
|
|
1950
|
-
},
|
|
1951
|
-
[adminBasePath, router]
|
|
1952
|
-
);
|
|
1953
|
-
return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
1954
|
-
AdminShellClient,
|
|
1955
|
-
{
|
|
1956
|
-
brandName: branding.siteName || defaultBrandName,
|
|
1957
|
-
logoUrl: branding.logoUrl || defaultLogoUrl || void 0,
|
|
1958
|
-
navItems,
|
|
1959
|
-
onLogout: logout,
|
|
1960
|
-
pathname,
|
|
1961
|
-
storageKey: "orion-admin-sidebar-collapsed-v1",
|
|
1962
|
-
userEmail: typeof user?.email === "string" ? user.email : "user",
|
|
1963
|
-
userRole: readUserRole(user),
|
|
1964
|
-
children
|
|
1965
|
-
}
|
|
1966
|
-
);
|
|
1967
|
-
}
|
|
1968
|
-
|
|
1969
|
-
// src/admin/components/studio/AdminStudioDashboard.tsx
|
|
1970
|
-
var import_jsx_runtime6 = require("react/jsx-runtime");
|
|
1971
|
-
var DEFAULT_ADMIN_BASE_PATH2 = "/admin";
|
|
1972
|
-
var normalizePath2 = (value) => {
|
|
1973
|
-
if (!value || value === "/") return "/";
|
|
1974
|
-
const withLeadingSlash = value.startsWith("/") ? value : `/${value}`;
|
|
1975
|
-
const trimmed = withLeadingSlash.replace(/\/+$/, "");
|
|
1976
|
-
return trimmed.length > 0 ? trimmed : "/";
|
|
1977
|
-
};
|
|
1978
|
-
var normalizeAdminBasePath2 = (value) => {
|
|
1979
|
-
const normalized = normalizePath2(value);
|
|
1980
|
-
return normalized === "/" ? DEFAULT_ADMIN_BASE_PATH2 : normalized;
|
|
1981
|
-
};
|
|
1982
|
-
var isAbsoluteExternalURL3 = (value) => /^[a-zA-Z][a-zA-Z\d+\-.]*:/.test(value) || value.startsWith("//");
|
|
1983
|
-
var resolveAdminPath2 = (adminBasePath, targetPath) => {
|
|
1984
|
-
if (!targetPath) return adminBasePath;
|
|
1985
|
-
if (isAbsoluteExternalURL3(targetPath)) return targetPath;
|
|
1986
|
-
const normalizedBasePath = normalizeAdminBasePath2(adminBasePath);
|
|
1987
|
-
const normalizedTargetPath = normalizePath2(targetPath);
|
|
1988
|
-
if (normalizedTargetPath === "/admin") {
|
|
1989
|
-
return normalizedBasePath;
|
|
1990
|
-
}
|
|
1991
|
-
if (normalizedTargetPath.startsWith("/admin/")) {
|
|
1992
|
-
return `${normalizedBasePath}${normalizedTargetPath.slice("/admin".length)}`;
|
|
1993
|
-
}
|
|
1994
|
-
if (normalizedTargetPath === normalizedBasePath || normalizedTargetPath.startsWith(`${normalizedBasePath}/`)) {
|
|
1995
|
-
return normalizedTargetPath;
|
|
1996
|
-
}
|
|
1997
|
-
if (normalizedTargetPath === "/") {
|
|
1998
|
-
return normalizedBasePath;
|
|
1999
|
-
}
|
|
2000
|
-
return `${normalizedBasePath}${normalizedTargetPath}`;
|
|
2001
|
-
};
|
|
2002
|
-
var getPropString2 = (props, key, fallback) => {
|
|
2003
|
-
if (!props || typeof props !== "object") return fallback;
|
|
2004
|
-
const direct = props[key];
|
|
2005
|
-
if (typeof direct === "string" && direct.length > 0) return direct;
|
|
2006
|
-
const clientProps = props.clientProps;
|
|
2007
|
-
if (clientProps && typeof clientProps === "object") {
|
|
2008
|
-
const nested = clientProps[key];
|
|
2009
|
-
if (typeof nested === "string" && nested.length > 0) return nested;
|
|
2010
|
-
}
|
|
2011
|
-
return fallback;
|
|
2012
|
-
};
|
|
2013
|
-
var getPropBoolean2 = (props, key, fallback) => {
|
|
2014
|
-
if (!props || typeof props !== "object") return fallback;
|
|
2015
|
-
const direct = props[key];
|
|
2016
|
-
if (typeof direct === "boolean") return direct;
|
|
2017
|
-
const clientProps = props.clientProps;
|
|
2018
|
-
if (clientProps && typeof clientProps === "object") {
|
|
2019
|
-
const nested = clientProps[key];
|
|
2020
|
-
if (typeof nested === "boolean") return nested;
|
|
2021
|
-
}
|
|
2022
|
-
return fallback;
|
|
2023
|
-
};
|
|
2024
|
-
var getPropSections2 = (props) => {
|
|
2025
|
-
if (!props || typeof props !== "object") return [];
|
|
2026
|
-
const direct = resolveStudioSections(props.sections);
|
|
2027
|
-
if (direct.length > 0) return direct;
|
|
2028
|
-
const clientProps = props.clientProps;
|
|
2029
|
-
if (clientProps && typeof clientProps === "object") {
|
|
2030
|
-
return resolveStudioSections(clientProps.sections);
|
|
2031
|
-
}
|
|
2032
|
-
return [];
|
|
2033
|
-
};
|
|
2034
|
-
var getPropDashboardPanels = (props) => {
|
|
2035
|
-
if (!props || typeof props !== "object") return [];
|
|
2036
|
-
const direct = resolveStudioSectionDashboards(props.dashboardPanels);
|
|
2037
|
-
if (direct.length > 0) return direct;
|
|
2038
|
-
const clientProps = props.clientProps;
|
|
2039
|
-
if (clientProps && typeof clientProps === "object") {
|
|
2040
|
-
return resolveStudioSectionDashboards(clientProps.dashboardPanels);
|
|
2041
|
-
}
|
|
2042
|
-
return [];
|
|
2043
|
-
};
|
|
2044
|
-
var readImportMap = (props) => {
|
|
2045
|
-
if (!props || typeof props !== "object") return void 0;
|
|
2046
|
-
const direct = props.importMap;
|
|
2047
|
-
if (direct && typeof direct === "object") {
|
|
2048
|
-
return direct;
|
|
2049
|
-
}
|
|
2050
|
-
const payloadLike = props.payload;
|
|
2051
|
-
if (payloadLike && typeof payloadLike === "object") {
|
|
2052
|
-
const nested = payloadLike.importMap;
|
|
2053
|
-
if (nested && typeof nested === "object") {
|
|
2054
|
-
return nested;
|
|
2055
|
-
}
|
|
2056
|
-
}
|
|
2057
|
-
const initPageResult = props.initPageResult;
|
|
2058
|
-
if (initPageResult && typeof initPageResult === "object") {
|
|
2059
|
-
const req = initPageResult.req;
|
|
2060
|
-
if (req && typeof req === "object") {
|
|
2061
|
-
const payload = req.payload;
|
|
2062
|
-
if (payload && typeof payload === "object") {
|
|
2063
|
-
const nested = payload.importMap;
|
|
2064
|
-
if (nested && typeof nested === "object") {
|
|
2065
|
-
return nested;
|
|
2066
|
-
}
|
|
2067
|
-
}
|
|
2068
|
-
}
|
|
2069
|
-
}
|
|
2070
|
-
return void 0;
|
|
2071
|
-
};
|
|
2072
|
-
var readUserRole2 = (props) => {
|
|
2073
|
-
if (!props || typeof props !== "object") return void 0;
|
|
2074
|
-
const user = props.user;
|
|
2075
|
-
if (user && typeof user === "object") {
|
|
2076
|
-
const role = user.role;
|
|
2077
|
-
if (typeof role === "string") {
|
|
2078
|
-
return role;
|
|
2079
|
-
}
|
|
2080
|
-
}
|
|
2081
|
-
const initPageResult = props.initPageResult;
|
|
2082
|
-
if (initPageResult && typeof initPageResult === "object") {
|
|
2083
|
-
const req = initPageResult.req;
|
|
2084
|
-
if (req && typeof req === "object") {
|
|
2085
|
-
const nestedUser = req.user;
|
|
2086
|
-
if (nestedUser && typeof nestedUser === "object") {
|
|
2087
|
-
const role = nestedUser.role;
|
|
2088
|
-
if (typeof role === "string") {
|
|
2089
|
-
return role;
|
|
2090
|
-
}
|
|
2091
|
-
}
|
|
2092
|
-
}
|
|
2093
|
-
}
|
|
2094
|
-
return void 0;
|
|
2095
|
-
};
|
|
2096
|
-
var readAdminBasePath = (props) => {
|
|
2097
|
-
if (!props || typeof props !== "object") {
|
|
2098
|
-
return DEFAULT_ADMIN_BASE_PATH2;
|
|
2099
|
-
}
|
|
2100
|
-
const payloadLike = props.payload;
|
|
2101
|
-
if (payloadLike && typeof payloadLike === "object") {
|
|
2102
|
-
const config = payloadLike.config;
|
|
2103
|
-
const routes = config && typeof config === "object" ? config.routes : null;
|
|
2104
|
-
const admin = routes && typeof routes === "object" ? routes.admin : null;
|
|
2105
|
-
if (typeof admin === "string" && admin.length > 0) {
|
|
2106
|
-
return normalizeAdminBasePath2(admin);
|
|
2107
|
-
}
|
|
2108
|
-
}
|
|
2109
|
-
const initPageResult = props.initPageResult;
|
|
2110
|
-
if (initPageResult && typeof initPageResult === "object") {
|
|
2111
|
-
const req = initPageResult.req;
|
|
2112
|
-
if (req && typeof req === "object") {
|
|
2113
|
-
const nestedPayload = req.payload;
|
|
2114
|
-
if (nestedPayload && typeof nestedPayload === "object") {
|
|
2115
|
-
const config = nestedPayload.config;
|
|
2116
|
-
const routes = config && typeof config === "object" ? config.routes : null;
|
|
2117
|
-
const admin = routes && typeof routes === "object" ? routes.admin : null;
|
|
2118
|
-
if (typeof admin === "string" && admin.length > 0) {
|
|
2119
|
-
return normalizeAdminBasePath2(admin);
|
|
2120
|
-
}
|
|
2121
|
-
}
|
|
2122
|
-
}
|
|
2123
|
-
}
|
|
2124
|
-
return DEFAULT_ADMIN_BASE_PATH2;
|
|
2125
|
-
};
|
|
2126
|
-
var canAccess2 = (role, roles) => {
|
|
2127
|
-
if (!roles || roles.length === 0) {
|
|
2128
|
-
return true;
|
|
2129
|
-
}
|
|
2130
|
-
if (!role) {
|
|
2131
|
-
return false;
|
|
2132
|
-
}
|
|
2133
|
-
return roles.includes(role);
|
|
2134
|
-
};
|
|
2135
|
-
var buildSectionLinks = (adminBasePath, sections, formsEnabled, globalsBasePath) => {
|
|
2136
|
-
const links = [
|
|
2137
|
-
{
|
|
2138
|
-
href: resolveAdminPath2(adminBasePath, "/pages"),
|
|
2139
|
-
id: "pages",
|
|
2140
|
-
label: "Pages"
|
|
2141
|
-
},
|
|
2142
|
-
...formsEnabled ? [
|
|
2143
|
-
{
|
|
2144
|
-
href: resolveAdminPath2(adminBasePath, "/forms"),
|
|
2145
|
-
id: "forms",
|
|
2146
|
-
label: "Forms",
|
|
2147
|
-
roles: ["admin", "editor"]
|
|
2148
|
-
}
|
|
2149
|
-
] : [],
|
|
2150
|
-
{
|
|
2151
|
-
href: resolveAdminPath2(adminBasePath, globalsBasePath),
|
|
2152
|
-
id: "globals",
|
|
2153
|
-
label: "Globals"
|
|
2154
|
-
},
|
|
2155
|
-
{
|
|
2156
|
-
href: resolveAdminPath2(adminBasePath, "/media"),
|
|
2157
|
-
id: "media",
|
|
2158
|
-
label: "Media"
|
|
2159
|
-
},
|
|
2160
|
-
...sections.map((section) => ({
|
|
2161
|
-
href: resolveAdminPath2(adminBasePath, section.href),
|
|
2162
|
-
id: section.id,
|
|
2163
|
-
label: section.label,
|
|
2164
|
-
...section.roles ? { roles: section.roles } : {}
|
|
2165
|
-
})),
|
|
2166
|
-
{
|
|
2167
|
-
href: resolveAdminPath2(adminBasePath, "/tools"),
|
|
2168
|
-
id: "admin-tools",
|
|
2169
|
-
label: "Admin Tools",
|
|
2170
|
-
roles: ["admin"]
|
|
2171
|
-
}
|
|
2172
|
-
];
|
|
2173
|
-
const seen = /* @__PURE__ */ new Set();
|
|
2174
|
-
return links.filter((link) => {
|
|
2175
|
-
if (seen.has(link.id)) {
|
|
2176
|
-
return false;
|
|
2177
|
-
}
|
|
2178
|
-
seen.add(link.id);
|
|
2179
|
-
return true;
|
|
2180
|
-
});
|
|
2181
|
-
};
|
|
2182
|
-
function DashboardPanelFallback({ label }) {
|
|
2183
|
-
return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "orion-dashboard-extension-fallback", children: [
|
|
2184
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "orion-dashboard-panel-kicker", children: "Extension Unavailable" }),
|
|
2185
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("strong", { children: label }),
|
|
2186
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { children: "This dashboard panel could not be rendered, but the rest of the dashboard is still available." })
|
|
2187
|
-
] });
|
|
2188
|
-
}
|
|
2189
|
-
function buildExtensionPanels(adminBasePath, importMap, panels, userRole) {
|
|
2190
|
-
const visiblePanels = panels.filter((panel) => canAccess2(userRole, panel.roles));
|
|
2191
|
-
return visiblePanels.map((panel) => {
|
|
2192
|
-
const href = resolveAdminPath2(adminBasePath, panel.href);
|
|
2193
|
-
return {
|
|
2194
|
-
id: panel.id,
|
|
2195
|
-
node: importMap ? (0, import_RenderServerComponent.RenderServerComponent)({
|
|
2196
|
-
Component: panel.Component,
|
|
2197
|
-
Fallback: () => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(DashboardPanelFallback, { label: panel.label }),
|
|
2198
|
-
importMap,
|
|
2199
|
-
serverProps: {
|
|
2200
|
-
adminBasePath,
|
|
2201
|
-
href,
|
|
2202
|
-
label: panel.label
|
|
2203
|
-
}
|
|
2204
|
-
}) : /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(DashboardPanelFallback, { label: panel.label }),
|
|
2205
|
-
span: panel.span
|
|
2206
|
-
};
|
|
2207
|
-
});
|
|
2208
|
-
}
|
|
2209
|
-
function AdminStudioDashboard(rawProps) {
|
|
2210
|
-
const props = rawProps || {};
|
|
2211
|
-
const formsEnabled = getPropBoolean2(props, "formsEnabled", false);
|
|
2212
|
-
const globalsBasePath = getPropString2(props, "globalsBasePath", "/globals");
|
|
2213
|
-
const sections = getPropSections2(props);
|
|
2214
|
-
const dashboardPanels = getPropDashboardPanels(props);
|
|
2215
|
-
const pagesCollectionSlug = getPropString2(props, "pagesCollectionSlug", "pages");
|
|
2216
|
-
const formsCollectionSlug = getPropString2(props, "formsCollectionSlug", "forms");
|
|
2217
|
-
const formSubmissionsCollectionSlug = getPropString2(
|
|
2218
|
-
props,
|
|
2219
|
-
"formSubmissionsCollectionSlug",
|
|
2220
|
-
"form-submissions"
|
|
2221
|
-
);
|
|
2222
|
-
const mediaCollectionSlug = getPropString2(props, "mediaCollectionSlug", "media");
|
|
2223
|
-
const adminBasePath = readAdminBasePath(props);
|
|
2224
|
-
const importMap = readImportMap(props);
|
|
2225
|
-
const userRole = readUserRole2(props);
|
|
2226
|
-
const navProps = {
|
|
2227
|
-
brandName: getPropString2(props, "brandName", "Orion Studio"),
|
|
2228
|
-
dashboardPanels,
|
|
2229
|
-
formSubmissionsCollectionSlug,
|
|
2230
|
-
formsCollectionSlug,
|
|
2231
|
-
formsEnabled,
|
|
2232
|
-
globalsBasePath,
|
|
2233
|
-
logoUrl: getPropString2(props, "logoUrl", ""),
|
|
2234
|
-
mediaCollectionSlug,
|
|
2235
|
-
pagesCollectionSlug,
|
|
2236
|
-
sections
|
|
2237
|
-
};
|
|
2238
|
-
const extensionPanels = buildExtensionPanels(adminBasePath, importMap, dashboardPanels, userRole);
|
|
2239
|
-
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(StudioSectionLayout, { navProps, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
2240
|
-
AdminPage,
|
|
2241
|
-
{
|
|
2242
|
-
breadcrumbs: [{ label: "Dashboard" }],
|
|
2243
|
-
description: "What needs attention, what changed recently, and how the site is performing.",
|
|
2244
|
-
title: "Studio",
|
|
2245
|
-
children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
2246
|
-
AdminStudioDashboardClient,
|
|
2247
|
-
{
|
|
2248
|
-
extensionPanels,
|
|
2249
|
-
formSubmissionsCollectionSlug,
|
|
2250
|
-
formsCollectionSlug,
|
|
2251
|
-
formsEnabled,
|
|
2252
|
-
formsPath: resolveAdminPath2(adminBasePath, "/forms"),
|
|
2253
|
-
globalsBasePath: resolveAdminPath2(adminBasePath, globalsBasePath),
|
|
2254
|
-
mediaCollectionSlug,
|
|
2255
|
-
mediaPath: resolveAdminPath2(adminBasePath, "/media"),
|
|
2256
|
-
pagesCollectionSlug,
|
|
2257
|
-
pagesPath: resolveAdminPath2(adminBasePath, "/pages"),
|
|
2258
|
-
sectionLinks: buildSectionLinks(adminBasePath, sections, formsEnabled, globalsBasePath),
|
|
2259
|
-
toolsPath: resolveAdminPath2(adminBasePath, "/tools"),
|
|
2260
|
-
userRole
|
|
2261
|
-
}
|
|
2262
|
-
)
|
|
2263
|
-
}
|
|
2264
|
-
) });
|
|
2265
|
-
}
|
|
2266
|
-
|
|
2267
902
|
// src/admin/helpers/withTooltips.ts
|
|
2268
903
|
var defaultTooltips = {
|
|
2269
904
|
title: "The main title displayed on this page.",
|
|
@@ -2534,6 +1169,36 @@ __export(admin_app_exports, {
|
|
|
2534
1169
|
roleCanAccessNav: () => roleCanAccessNav
|
|
2535
1170
|
});
|
|
2536
1171
|
|
|
1172
|
+
// src/admin-app/components/AdminBreadcrumbs.tsx
|
|
1173
|
+
var import_jsx_runtime = require("react/jsx-runtime");
|
|
1174
|
+
function AdminBreadcrumbs({ items }) {
|
|
1175
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("nav", { "aria-label": "Breadcrumb", className: "orion-admin-breadcrumbs", children: items.map((item, index) => {
|
|
1176
|
+
const isLast = index === items.length - 1;
|
|
1177
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { children: [
|
|
1178
|
+
item.href && !isLast ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("a", { href: item.href, children: item.label }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: item.label }),
|
|
1179
|
+
!isLast ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "orion-admin-breadcrumb-sep", children: "/" }) : null
|
|
1180
|
+
] }, `${item.label}-${index}`);
|
|
1181
|
+
}) });
|
|
1182
|
+
}
|
|
1183
|
+
|
|
1184
|
+
// src/admin-app/components/AdminPage.tsx
|
|
1185
|
+
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
1186
|
+
function AdminPage({ title, description, breadcrumbs, actions, children }) {
|
|
1187
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "orion-admin-page", children: [
|
|
1188
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "orion-admin-page-header", children: [
|
|
1189
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(AdminBreadcrumbs, { items: breadcrumbs }),
|
|
1190
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "orion-admin-page-title-row", children: [
|
|
1191
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { children: [
|
|
1192
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("h1", { children: title }),
|
|
1193
|
+
description ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { children: description }) : null
|
|
1194
|
+
] }),
|
|
1195
|
+
actions ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "orion-admin-page-actions", children: actions }) : null
|
|
1196
|
+
] })
|
|
1197
|
+
] }),
|
|
1198
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "orion-admin-page-content", children })
|
|
1199
|
+
] });
|
|
1200
|
+
}
|
|
1201
|
+
|
|
2537
1202
|
// src/admin-app/nestedNavigation.ts
|
|
2538
1203
|
var normalizeNestedNavItems = (items) => {
|
|
2539
1204
|
const deduped = [];
|
|
@@ -4330,7 +2995,7 @@ var TestimonialsBlock = {
|
|
|
4330
2995
|
};
|
|
4331
2996
|
|
|
4332
2997
|
// src/blocks/components/BuilderBlockLabel.tsx
|
|
4333
|
-
var
|
|
2998
|
+
var import_jsx_runtime3 = require("react/jsx-runtime");
|
|
4334
2999
|
var blockTitles = {
|
|
4335
3000
|
bookingEmbed: "Booking Embed",
|
|
4336
3001
|
cta: "Call to Action",
|
|
@@ -4357,8 +3022,8 @@ function BuilderBlockLabel({ blockType, rowLabel, rowNumber }) {
|
|
|
4357
3022
|
const fallbackTitle = blockTitles[blockType] || blockType;
|
|
4358
3023
|
const title = rowLabel && rowLabel.trim().length > 0 ? rowLabel : fallbackTitle;
|
|
4359
3024
|
const tag = blockEmojis[blockType] || "Section";
|
|
4360
|
-
return /* @__PURE__ */ (0,
|
|
4361
|
-
/* @__PURE__ */ (0,
|
|
3025
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { style: { alignItems: "center", display: "flex", gap: 8 }, children: [
|
|
3026
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
4362
3027
|
"span",
|
|
4363
3028
|
{
|
|
4364
3029
|
style: {
|
|
@@ -4373,7 +3038,7 @@ function BuilderBlockLabel({ blockType, rowLabel, rowNumber }) {
|
|
|
4373
3038
|
children: tag
|
|
4374
3039
|
}
|
|
4375
3040
|
),
|
|
4376
|
-
/* @__PURE__ */ (0,
|
|
3041
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("span", { style: { fontWeight: 700 }, children: [
|
|
4377
3042
|
typeof rowNumber === "number" ? `${rowNumber + 1}. ` : "",
|
|
4378
3043
|
title
|
|
4379
3044
|
] })
|
|
@@ -4920,18 +3585,18 @@ function createStudioRegistry(modules) {
|
|
|
4920
3585
|
listNodeTypes: () => [...nodeTypes]
|
|
4921
3586
|
};
|
|
4922
3587
|
}
|
|
4923
|
-
function validateStudioDocument(
|
|
3588
|
+
function validateStudioDocument(document, modules) {
|
|
4924
3589
|
const issues = [];
|
|
4925
|
-
if (
|
|
3590
|
+
if (document.schemaVersion !== 1) {
|
|
4926
3591
|
issues.push(makeIssue("Unsupported schema version", "schemaVersion", "studio.schemaVersion"));
|
|
4927
3592
|
}
|
|
4928
|
-
if (!Array.isArray(
|
|
3593
|
+
if (!Array.isArray(document.nodes)) {
|
|
4929
3594
|
issues.push(makeIssue("Nodes must be an array", "nodes", "studio.nodes"));
|
|
4930
3595
|
return issues;
|
|
4931
3596
|
}
|
|
4932
3597
|
const registry = createStudioRegistry(modules);
|
|
4933
3598
|
const nodeIDs = /* @__PURE__ */ new Set();
|
|
4934
|
-
|
|
3599
|
+
document.nodes.forEach((node, index) => {
|
|
4935
3600
|
if (!node.id) {
|
|
4936
3601
|
issues.push(makeIssue("Node id is required", `nodes.${index}.id`, "studio.node.id"));
|
|
4937
3602
|
}
|
|
@@ -4945,15 +3610,15 @@ function validateStudioDocument(document2, modules) {
|
|
|
4945
3610
|
});
|
|
4946
3611
|
for (const module2 of modules) {
|
|
4947
3612
|
for (const validate of module2.validators) {
|
|
4948
|
-
issues.push(...validate(
|
|
3613
|
+
issues.push(...validate(document));
|
|
4949
3614
|
}
|
|
4950
3615
|
}
|
|
4951
3616
|
return issues;
|
|
4952
3617
|
}
|
|
4953
|
-
function compileStudioDocument(
|
|
4954
|
-
const issues = validateStudioDocument(
|
|
3618
|
+
function compileStudioDocument(document, modules) {
|
|
3619
|
+
const issues = validateStudioDocument(document, modules);
|
|
4955
3620
|
const compilerEntries = modules.filter((mod) => typeof mod.compiler?.compileNode === "function").map((mod) => mod.compiler?.compileNode);
|
|
4956
|
-
const layout =
|
|
3621
|
+
const layout = document.nodes.map((node) => {
|
|
4957
3622
|
for (const compileNode of compilerEntries) {
|
|
4958
3623
|
if (!compileNode) {
|
|
4959
3624
|
continue;
|
|
@@ -5028,7 +3693,9 @@ var defaultBuilderBlockSettingsV2 = {
|
|
|
5028
3693
|
},
|
|
5029
3694
|
typography: {
|
|
5030
3695
|
bodyAlign: "left",
|
|
3696
|
+
bodySizePt: null,
|
|
5031
3697
|
headingAlign: "left",
|
|
3698
|
+
headingSizePt: null,
|
|
5032
3699
|
letterSpacingPreset: "normal",
|
|
5033
3700
|
lineHeightPreset: "normal",
|
|
5034
3701
|
maxTextWidth: "auto"
|
|
@@ -5057,7 +3724,9 @@ var defaultBuilderItemSettingsV2 = {
|
|
|
5057
3724
|
},
|
|
5058
3725
|
typography: {
|
|
5059
3726
|
bodyAlign: "left",
|
|
3727
|
+
bodySizePt: null,
|
|
5060
3728
|
headingAlign: "left",
|
|
3729
|
+
headingSizePt: null,
|
|
5061
3730
|
letterSpacingPreset: "normal",
|
|
5062
3731
|
lineHeightPreset: "normal",
|
|
5063
3732
|
maxTextWidth: "auto"
|
|
@@ -5087,6 +3756,7 @@ var defaultBuilderThemeTokens = {
|
|
|
5087
3756
|
|
|
5088
3757
|
// src/studio-pages/builder/adapters/settingsV2.ts
|
|
5089
3758
|
var isRecord3 = (value) => Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
3759
|
+
var isTextAlign = (value) => value === "left" || value === "center" || value === "right" || value === "justify";
|
|
5090
3760
|
var parsePercent = (value) => {
|
|
5091
3761
|
if (typeof value === "number" && Number.isFinite(value)) {
|
|
5092
3762
|
return Math.max(0, Math.min(100, value));
|
|
@@ -5111,6 +3781,18 @@ var parsePixel = (value) => {
|
|
|
5111
3781
|
}
|
|
5112
3782
|
return null;
|
|
5113
3783
|
};
|
|
3784
|
+
var parsePoint = (value) => {
|
|
3785
|
+
if (typeof value === "number" && Number.isFinite(value)) {
|
|
3786
|
+
return Math.max(6, Math.min(120, Math.round(value)));
|
|
3787
|
+
}
|
|
3788
|
+
if (typeof value === "string" && value.trim().length > 0) {
|
|
3789
|
+
const parsed = Number(value);
|
|
3790
|
+
if (Number.isFinite(parsed)) {
|
|
3791
|
+
return Math.max(6, Math.min(120, Math.round(parsed)));
|
|
3792
|
+
}
|
|
3793
|
+
}
|
|
3794
|
+
return null;
|
|
3795
|
+
};
|
|
5114
3796
|
var mergeSettings = (defaults, input) => {
|
|
5115
3797
|
if (!isRecord3(input)) {
|
|
5116
3798
|
return structuredClone(defaults);
|
|
@@ -5129,6 +3811,10 @@ var mergeSettings = (defaults, input) => {
|
|
|
5129
3811
|
};
|
|
5130
3812
|
var legacyBlockToV2Settings = (block) => {
|
|
5131
3813
|
const current = structuredClone(defaultBuilderBlockSettingsV2);
|
|
3814
|
+
if (block.blockType === "hero" && block.variant === "centered") {
|
|
3815
|
+
current.typography.headingAlign = "center";
|
|
3816
|
+
current.typography.bodyAlign = "center";
|
|
3817
|
+
}
|
|
5132
3818
|
current.layout.contentWidth = block.contentWidth === "narrow" || block.contentWidth === "content" || block.contentWidth === "wide" || block.contentWidth === "full" || block.contentWidth === "inherit" ? block.contentWidth : current.layout.contentWidth;
|
|
5133
3819
|
current.layout.sectionPaddingX = block.sectionPaddingX === "none" || block.sectionPaddingX === "sm" || block.sectionPaddingX === "md" || block.sectionPaddingX === "lg" || block.sectionPaddingX === "inherit" ? block.sectionPaddingX : current.layout.sectionPaddingX;
|
|
5134
3820
|
current.layout.sectionPaddingY = block.sectionPaddingY === "none" || block.sectionPaddingY === "sm" || block.sectionPaddingY === "lg" ? block.sectionPaddingY : current.layout.sectionPaddingY;
|
|
@@ -5165,15 +3851,28 @@ var legacyBlockToV2Settings = (block) => {
|
|
|
5165
3851
|
current.media.positionX = parsePercent(block.imagePositionX ?? block.backgroundImagePositionX);
|
|
5166
3852
|
current.media.positionY = parsePercent(block.imagePositionY ?? block.backgroundImagePositionY);
|
|
5167
3853
|
current.media.height = parsePixel(block.imageHeight);
|
|
5168
|
-
current.typography.headingAlign = block.textHeadingAlign
|
|
5169
|
-
current.typography.bodyAlign = block.textBodyAlign
|
|
3854
|
+
current.typography.headingAlign = isTextAlign(block.textHeadingAlign) ? block.textHeadingAlign : current.typography.headingAlign;
|
|
3855
|
+
current.typography.bodyAlign = isTextAlign(block.textBodyAlign) ? block.textBodyAlign : current.typography.bodyAlign;
|
|
3856
|
+
current.typography.headingSizePt = parsePoint(block.textHeadingSizePt);
|
|
3857
|
+
current.typography.bodySizePt = parsePoint(block.textBodySizePt);
|
|
5170
3858
|
current.typography.maxTextWidth = block.textMaxWidth === "auto" || block.textMaxWidth === "sm" || block.textMaxWidth === "md" || block.textMaxWidth === "lg" || block.textMaxWidth === "full" ? block.textMaxWidth : current.typography.maxTextWidth;
|
|
5171
3859
|
current.typography.lineHeightPreset = block.textLineHeightPreset === "tight" || block.textLineHeightPreset === "normal" || block.textLineHeightPreset === "relaxed" ? block.textLineHeightPreset : current.typography.lineHeightPreset;
|
|
5172
3860
|
current.typography.letterSpacingPreset = block.textLetterSpacingPreset === "tight" || block.textLetterSpacingPreset === "normal" || block.textLetterSpacingPreset === "relaxed" ? block.textLetterSpacingPreset : current.typography.letterSpacingPreset;
|
|
5173
3861
|
current.advanced.editCopyInPanel = Boolean(block.editCopyInPanel ?? current.advanced.editCopyInPanel);
|
|
5174
3862
|
current.advanced.customClassName = typeof block.customClassName === "string" ? block.customClassName : current.advanced.customClassName;
|
|
5175
3863
|
current.advanced.hideOnMobile = Boolean(block.hideOnMobile ?? current.advanced.hideOnMobile);
|
|
5176
|
-
|
|
3864
|
+
const settings = mergeSettings(current, block.settings);
|
|
3865
|
+
if (block.blockType === "hero") {
|
|
3866
|
+
const top = settings.layout.paddingTopPt;
|
|
3867
|
+
const bottom = settings.layout.paddingBottomPt;
|
|
3868
|
+
const hasLegacyLinkedHeroPadding = settings.layout.linkVerticalPadding !== false && (top === null || typeof top === "undefined" || top === 30) && (bottom === null || typeof bottom === "undefined" || bottom === 30 || bottom === 20);
|
|
3869
|
+
if (hasLegacyLinkedHeroPadding) {
|
|
3870
|
+
settings.layout.linkVerticalPadding = false;
|
|
3871
|
+
settings.layout.paddingTopPt = 30;
|
|
3872
|
+
settings.layout.paddingBottomPt = 20;
|
|
3873
|
+
}
|
|
3874
|
+
}
|
|
3875
|
+
return settings;
|
|
5177
3876
|
};
|
|
5178
3877
|
var v2SettingsToLegacyBlock = (blockWithSettings) => {
|
|
5179
3878
|
const settings = legacyBlockToV2Settings(blockWithSettings);
|
|
@@ -5199,6 +3898,8 @@ var v2SettingsToLegacyBlock = (blockWithSettings) => {
|
|
|
5199
3898
|
next.contentGradientAngle = settings.appearance.contentGradientAngle;
|
|
5200
3899
|
next.textHeadingAlign = settings.typography.headingAlign;
|
|
5201
3900
|
next.textBodyAlign = settings.typography.bodyAlign;
|
|
3901
|
+
next.textHeadingSizePt = settings.typography.headingSizePt;
|
|
3902
|
+
next.textBodySizePt = settings.typography.bodySizePt;
|
|
5202
3903
|
next.textMaxWidth = settings.typography.maxTextWidth;
|
|
5203
3904
|
next.textLineHeightPreset = settings.typography.lineHeightPreset;
|
|
5204
3905
|
next.textLetterSpacingPreset = settings.typography.letterSpacingPreset;
|
|
@@ -5290,7 +3991,7 @@ var layoutToStudioDocument = (layout, title, metadata) => {
|
|
|
5290
3991
|
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
5291
3992
|
};
|
|
5292
3993
|
};
|
|
5293
|
-
var studioDocumentToLayout = (
|
|
3994
|
+
var studioDocumentToLayout = (document) => document.nodes.map(
|
|
5294
3995
|
(node) => migrateBlockToSettingsV2({
|
|
5295
3996
|
id: node.id,
|
|
5296
3997
|
blockType: node.type,
|
|
@@ -5324,7 +4025,7 @@ function withStudioDocumentLayout(page) {
|
|
|
5324
4025
|
}
|
|
5325
4026
|
return page;
|
|
5326
4027
|
}
|
|
5327
|
-
function
|
|
4028
|
+
function normalizePath(segments) {
|
|
5328
4029
|
if (!segments || segments.length === 0) {
|
|
5329
4030
|
return "/";
|
|
5330
4031
|
}
|
|
@@ -5381,7 +4082,7 @@ function createPageQueries(getPayloadClient, contentTag = "website-content") {
|
|
|
5381
4082
|
{ tags: [contentTag] }
|
|
5382
4083
|
);
|
|
5383
4084
|
async function getPageBySegments(segments, draft = false) {
|
|
5384
|
-
const path2 =
|
|
4085
|
+
const path2 = normalizePath(segments);
|
|
5385
4086
|
const payload = await getPayloadClient();
|
|
5386
4087
|
if (draft) {
|
|
5387
4088
|
return queryPageByPath(payload, path2, true);
|
|
@@ -5622,8 +4323,52 @@ var alignOptions = [
|
|
|
5622
4323
|
{ label: "Right", value: "right" },
|
|
5623
4324
|
{ label: "Justify", value: "justify" }
|
|
5624
4325
|
];
|
|
5625
|
-
var layoutFieldSet = [
|
|
4326
|
+
var layoutFieldSet = [
|
|
4327
|
+
{
|
|
4328
|
+
group: "layout",
|
|
4329
|
+
key: "settings.layout.linkVerticalPadding",
|
|
4330
|
+
label: "Link Top/Bottom Padding",
|
|
4331
|
+
tags: ["spacing", "padding", "vertical"],
|
|
4332
|
+
type: "checkbox"
|
|
4333
|
+
},
|
|
4334
|
+
{
|
|
4335
|
+
group: "layout",
|
|
4336
|
+
key: "settings.layout.paddingTopPt",
|
|
4337
|
+
label: "Top Padding (pt)",
|
|
4338
|
+
max: 240,
|
|
4339
|
+
min: 0,
|
|
4340
|
+
tags: ["spacing", "padding", "top"],
|
|
4341
|
+
type: "number"
|
|
4342
|
+
},
|
|
4343
|
+
{
|
|
4344
|
+
group: "layout",
|
|
4345
|
+
key: "settings.layout.paddingBottomPt",
|
|
4346
|
+
label: "Bottom Padding (pt)",
|
|
4347
|
+
max: 240,
|
|
4348
|
+
min: 0,
|
|
4349
|
+
tags: ["spacing", "padding", "bottom"],
|
|
4350
|
+
type: "number"
|
|
4351
|
+
}
|
|
4352
|
+
];
|
|
5626
4353
|
var typographyFieldSet = [
|
|
4354
|
+
{
|
|
4355
|
+
group: "typography",
|
|
4356
|
+
key: "settings.typography.headingSizePt",
|
|
4357
|
+
label: "Heading Text Size (pt)",
|
|
4358
|
+
max: 120,
|
|
4359
|
+
min: 6,
|
|
4360
|
+
tags: ["text", "size", "heading", "font"],
|
|
4361
|
+
type: "number"
|
|
4362
|
+
},
|
|
4363
|
+
{
|
|
4364
|
+
group: "typography",
|
|
4365
|
+
key: "settings.typography.bodySizePt",
|
|
4366
|
+
label: "Body Text Size (pt)",
|
|
4367
|
+
max: 72,
|
|
4368
|
+
min: 6,
|
|
4369
|
+
tags: ["text", "size", "body", "paragraph", "font"],
|
|
4370
|
+
type: "number"
|
|
4371
|
+
},
|
|
5627
4372
|
{
|
|
5628
4373
|
group: "typography",
|
|
5629
4374
|
key: "settings.typography.headingAlign",
|
|
@@ -5993,8 +4738,8 @@ var hydrateRelationship = (valueFromStudio, valueFromLayout) => {
|
|
|
5993
4738
|
}
|
|
5994
4739
|
return valueFromLayout;
|
|
5995
4740
|
};
|
|
5996
|
-
var hydrateDocumentWithLayoutRelations = (
|
|
5997
|
-
const nextNodes =
|
|
4741
|
+
var hydrateDocumentWithLayoutRelations = (document, layout) => {
|
|
4742
|
+
const nextNodes = document.nodes.map((node, index) => {
|
|
5998
4743
|
const layoutBlock = layout[index];
|
|
5999
4744
|
if (!isRecord5(layoutBlock)) {
|
|
6000
4745
|
return node;
|
|
@@ -6033,17 +4778,17 @@ var hydrateDocumentWithLayoutRelations = (document2, layout) => {
|
|
|
6033
4778
|
};
|
|
6034
4779
|
});
|
|
6035
4780
|
return {
|
|
6036
|
-
...
|
|
4781
|
+
...document,
|
|
6037
4782
|
nodes: nextNodes
|
|
6038
4783
|
};
|
|
6039
4784
|
};
|
|
6040
|
-
var normalizeDocument = (
|
|
6041
|
-
...
|
|
4785
|
+
var normalizeDocument = (document) => ({
|
|
4786
|
+
...document,
|
|
6042
4787
|
schemaVersion: 1,
|
|
6043
4788
|
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
6044
4789
|
});
|
|
6045
|
-
var normalizeLegacyHeroDefaults = (
|
|
6046
|
-
const nodes =
|
|
4790
|
+
var normalizeLegacyHeroDefaults = (document) => {
|
|
4791
|
+
const nodes = document.nodes.map((node) => {
|
|
6047
4792
|
if (node.type !== "hero" || !isRecord5(node.data)) {
|
|
6048
4793
|
return node;
|
|
6049
4794
|
}
|
|
@@ -6061,7 +4806,7 @@ var normalizeLegacyHeroDefaults = (document2) => {
|
|
|
6061
4806
|
};
|
|
6062
4807
|
});
|
|
6063
4808
|
return {
|
|
6064
|
-
...
|
|
4809
|
+
...document,
|
|
6065
4810
|
nodes
|
|
6066
4811
|
};
|
|
6067
4812
|
};
|
|
@@ -6110,9 +4855,9 @@ var createStudioPageService = ({
|
|
|
6110
4855
|
title: typeof page.title === "string" ? page.title : "Untitled Page"
|
|
6111
4856
|
};
|
|
6112
4857
|
},
|
|
6113
|
-
validateStudioDocument: (
|
|
6114
|
-
saveDraft: async (pageID,
|
|
6115
|
-
const normalizedDocument = normalizeLegacyHeroDefaults(normalizeDocument(
|
|
4858
|
+
validateStudioDocument: (document) => validateStudioDocument(document, modules),
|
|
4859
|
+
saveDraft: async (pageID, document, _metadata) => {
|
|
4860
|
+
const normalizedDocument = normalizeLegacyHeroDefaults(normalizeDocument(document));
|
|
6116
4861
|
const compileResult = compileStudioDocument(normalizedDocument, modules);
|
|
6117
4862
|
await payload.update({
|
|
6118
4863
|
collection: collectionSlug,
|
|
@@ -6132,8 +4877,8 @@ var createStudioPageService = ({
|
|
|
6132
4877
|
status: "draft"
|
|
6133
4878
|
};
|
|
6134
4879
|
},
|
|
6135
|
-
publish: async (pageID,
|
|
6136
|
-
const normalizedDocument = normalizeLegacyHeroDefaults(normalizeDocument(
|
|
4880
|
+
publish: async (pageID, document, _metadata) => {
|
|
4881
|
+
const normalizedDocument = normalizeLegacyHeroDefaults(normalizeDocument(document));
|
|
6137
4882
|
const compileResult = compileStudioDocument(normalizedDocument, modules);
|
|
6138
4883
|
assertCanPublish(compileResult.issues);
|
|
6139
4884
|
await payload.update({
|
|
@@ -6413,9 +5158,9 @@ var pageNodeTypes = Object.keys(defaultNodeData).map((type) => ({
|
|
|
6413
5158
|
return data;
|
|
6414
5159
|
}
|
|
6415
5160
|
}));
|
|
6416
|
-
var validatePageDocument = (
|
|
5161
|
+
var validatePageDocument = (document) => {
|
|
6417
5162
|
const issues = [];
|
|
6418
|
-
if (!
|
|
5163
|
+
if (!document.title || document.title.trim().length === 0) {
|
|
6419
5164
|
issues.push({
|
|
6420
5165
|
code: "pages.title.required",
|
|
6421
5166
|
message: "Page title is required before publishing.",
|
|
@@ -6423,7 +5168,7 @@ var validatePageDocument = (document2) => {
|
|
|
6423
5168
|
severity: "error"
|
|
6424
5169
|
});
|
|
6425
5170
|
}
|
|
6426
|
-
if (
|
|
5171
|
+
if (document.nodes.length === 0) {
|
|
6427
5172
|
issues.push({
|
|
6428
5173
|
code: "pages.nodes.required",
|
|
6429
5174
|
message: "At least one section is required.",
|
|
@@ -6431,7 +5176,7 @@ var validatePageDocument = (document2) => {
|
|
|
6431
5176
|
severity: "error"
|
|
6432
5177
|
});
|
|
6433
5178
|
}
|
|
6434
|
-
|
|
5179
|
+
document.nodes.forEach((node, index) => {
|
|
6435
5180
|
if (node.type === "hero" && typeof node.data.headline !== "string") {
|
|
6436
5181
|
issues.push({
|
|
6437
5182
|
code: "pages.hero.headline",
|