@orion-studios/payload-studio 0.5.0-beta.11 → 0.5.0-beta.111

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (77) hide show
  1. package/README.md +54 -0
  2. package/dist/admin/client.d.mts +3 -0
  3. package/dist/admin/client.d.ts +3 -0
  4. package/dist/admin/client.js +1745 -200
  5. package/dist/admin/client.mjs +1756 -214
  6. package/dist/admin/index.d.mts +2 -1
  7. package/dist/admin/index.d.ts +2 -1
  8. package/dist/admin/index.js +424 -11
  9. package/dist/admin/index.mjs +19 -1
  10. package/dist/admin-app/client.d.mts +7 -0
  11. package/dist/admin-app/client.d.ts +7 -0
  12. package/dist/admin-app/client.js +1270 -3
  13. package/dist/admin-app/client.mjs +1172 -2
  14. package/dist/admin-app/index.d.mts +1 -1
  15. package/dist/admin-app/index.d.ts +1 -1
  16. package/dist/admin-app/index.js +167 -0
  17. package/dist/admin-app/index.mjs +13 -1
  18. package/dist/admin-app/styles.css +247 -0
  19. package/dist/admin.css +8 -0
  20. package/dist/blocks/index.js +1011 -191
  21. package/dist/blocks/index.mjs +2 -2
  22. package/dist/chunk-ADIIWIYL.mjs +322 -0
  23. package/dist/{chunk-ZLLNO5FM.mjs → chunk-BET2YLAS.mjs} +104 -15
  24. package/dist/chunk-DAIZDGHL.mjs +614 -0
  25. package/dist/chunk-GKMBYYXF.mjs +776 -0
  26. package/dist/chunk-JQAHXYAM.mjs +1829 -0
  27. package/dist/chunk-OQSEJXC4.mjs +166 -0
  28. package/dist/chunk-PF3EBZXF.mjs +326 -0
  29. package/dist/chunk-ROTPP5CU.mjs +99 -0
  30. package/dist/chunk-XVH5SCBD.mjs +234 -0
  31. package/dist/chunk-ZTXJG4K5.mjs +85 -0
  32. package/dist/index-7lxTrxSG.d.mts +128 -0
  33. package/dist/index-7lxTrxSG.d.ts +128 -0
  34. package/dist/index-B7QvY3yF.d.mts +245 -0
  35. package/dist/index-BK03FiEM.d.ts +245 -0
  36. package/dist/{index-CmR6NInu.d.ts → index-BzKOThsI.d.mts} +30 -3
  37. package/dist/{index-CmR6NInu.d.mts → index-BzKOThsI.d.ts} +30 -3
  38. package/dist/{index-DbH0Ljwp.d.mts → index-D8BNfUJb.d.mts} +17 -2
  39. package/dist/{index-DbH0Ljwp.d.ts → index-DD_E2UfJ.d.ts} +17 -2
  40. package/dist/index-DUi_XND6.d.ts +193 -0
  41. package/dist/index-gLl_358v.d.mts +193 -0
  42. package/dist/index.d.mts +6 -5
  43. package/dist/index.d.ts +6 -5
  44. package/dist/index.js +2876 -460
  45. package/dist/index.mjs +12 -10
  46. package/dist/nextjs/index.d.mts +2 -1
  47. package/dist/nextjs/index.d.ts +2 -1
  48. package/dist/nextjs/index.js +497 -16
  49. package/dist/nextjs/index.mjs +8 -3
  50. package/dist/socialMedia-C05Iy-SV.d.mts +21 -0
  51. package/dist/socialMedia-C05Iy-SV.d.ts +21 -0
  52. package/dist/studio/index.d.mts +2 -1
  53. package/dist/studio/index.d.ts +2 -1
  54. package/dist/studio/index.js +171 -5
  55. package/dist/studio/index.mjs +7 -3
  56. package/dist/studio-pages/builder.css +517 -32
  57. package/dist/studio-pages/client.d.mts +75 -1
  58. package/dist/studio-pages/client.d.ts +75 -1
  59. package/dist/studio-pages/client.js +5662 -2759
  60. package/dist/studio-pages/client.mjs +5578 -2767
  61. package/dist/studio-pages/index.d.mts +4 -2
  62. package/dist/studio-pages/index.d.ts +4 -2
  63. package/dist/studio-pages/index.js +859 -71
  64. package/dist/studio-pages/index.mjs +10 -4
  65. package/package.json +35 -13
  66. package/dist/chunk-AAOHJDNS.mjs +0 -67
  67. package/dist/chunk-ETRRXURT.mjs +0 -141
  68. package/dist/chunk-J7W5EE3B.mjs +0 -278
  69. package/dist/chunk-N67KVM2S.mjs +0 -156
  70. package/dist/chunk-NESLJZFE.mjs +0 -303
  71. package/dist/chunk-U5BSPWAD.mjs +0 -1034
  72. package/dist/index-B9N5MyjF.d.mts +0 -39
  73. package/dist/index-BallJs-K.d.mts +0 -43
  74. package/dist/index-BallJs-K.d.ts +0 -43
  75. package/dist/index-DJFhANvJ.d.mts +0 -128
  76. package/dist/index-DJFhANvJ.d.ts +0 -128
  77. package/dist/index-g8tBHLKD.d.ts +0 -39
@@ -1156,7 +1156,9 @@ var init_OrionBlocksFieldImpl = __esm({
1156
1156
  // src/admin/client.ts
1157
1157
  var client_exports = {};
1158
1158
  __export(client_exports, {
1159
+ AdminStudioContactFormView: () => AdminStudioContactFormView,
1159
1160
  AdminStudioDashboard: () => AdminStudioDashboard,
1161
+ AdminStudioFormsView: () => AdminStudioFormsView,
1160
1162
  AdminStudioGlobalsView: () => AdminStudioGlobalsView,
1161
1163
  AdminStudioMediaView: () => AdminStudioMediaView,
1162
1164
  AdminStudioNav: () => AdminStudioNav,
@@ -1175,6 +1177,7 @@ __export(client_exports, {
1175
1177
  SectionTabs: () => SectionTabs,
1176
1178
  StatusBadge: () => StatusBadge,
1177
1179
  StudioBackBreadcrumb: () => StudioBackBreadcrumb,
1180
+ StudioContactFormRedirect: () => StudioContactFormRedirect,
1178
1181
  ThemeProvider: () => ThemeProvider,
1179
1182
  ThemeSwitcher: () => ThemeSwitcher,
1180
1183
  WelcomeHeader: () => WelcomeHeader,
@@ -2277,6 +2280,158 @@ function WelcomeHeader({
2277
2280
 
2278
2281
  // src/admin/components/studio/AdminStudioDashboard.tsx
2279
2282
  var import_ui3 = require("@payloadcms/ui");
2283
+
2284
+ // src/shared/studioSections.ts
2285
+ var studioRoles = /* @__PURE__ */ new Set(["admin", "editor", "client"]);
2286
+ var isRecord = (value) => Boolean(value) && typeof value === "object" && !Array.isArray(value);
2287
+ var isAbsoluteExternalURL = (value) => /^[a-zA-Z][a-zA-Z\d+\-.]*:/.test(value) || value.startsWith("//");
2288
+ var normalizePathLikeValue = (value) => {
2289
+ const trimmed = value.trim();
2290
+ if (!trimmed) {
2291
+ return "";
2292
+ }
2293
+ if (isAbsoluteExternalURL(trimmed)) {
2294
+ return trimmed;
2295
+ }
2296
+ const withLeadingSlash = trimmed.startsWith("/") ? trimmed : `/${trimmed}`;
2297
+ const normalized = withLeadingSlash.replace(/\/+$/, "");
2298
+ return normalized || "/";
2299
+ };
2300
+ var normalizeStringArray = (value) => {
2301
+ if (!Array.isArray(value)) {
2302
+ return [];
2303
+ }
2304
+ return value.filter((entry) => typeof entry === "string").map((entry) => normalizePathLikeValue(entry)).filter((entry) => entry.length > 0);
2305
+ };
2306
+ var normalizeRoles = (value) => {
2307
+ if (!Array.isArray(value)) {
2308
+ return void 0;
2309
+ }
2310
+ const roles = value.filter((entry) => typeof entry === "string" && studioRoles.has(entry));
2311
+ return roles.length > 0 ? roles : void 0;
2312
+ };
2313
+ var normalizeCard = (value) => {
2314
+ if (!isRecord(value) || typeof value.title !== "string") {
2315
+ return void 0;
2316
+ }
2317
+ const title = value.title.trim();
2318
+ if (!title) {
2319
+ return void 0;
2320
+ }
2321
+ return {
2322
+ title,
2323
+ ...typeof value.description === "string" && value.description.trim().length > 0 ? { description: value.description.trim() } : {}
2324
+ };
2325
+ };
2326
+ var resolveStudioSections = (value) => {
2327
+ if (!Array.isArray(value)) {
2328
+ return [];
2329
+ }
2330
+ const sections = [];
2331
+ const seen = /* @__PURE__ */ new Set();
2332
+ for (const entry of value) {
2333
+ if (!isRecord(entry) || typeof entry.id !== "string" || typeof entry.label !== "string") {
2334
+ continue;
2335
+ }
2336
+ const id = entry.id.trim();
2337
+ const label = entry.label.trim();
2338
+ if (!id || !label || seen.has(id)) {
2339
+ continue;
2340
+ }
2341
+ 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) : "";
2342
+ if (!href) {
2343
+ continue;
2344
+ }
2345
+ const matchPrefixes = Array.from(/* @__PURE__ */ new Set([href, ...normalizeStringArray(entry.matchPrefixes)]));
2346
+ sections.push({
2347
+ id,
2348
+ label,
2349
+ href,
2350
+ matchPrefixes,
2351
+ ...normalizeRoles(entry.roles) ? { roles: normalizeRoles(entry.roles) } : {},
2352
+ ...normalizeCard(entry.card) ? { card: normalizeCard(entry.card) } : {}
2353
+ });
2354
+ seen.add(id);
2355
+ }
2356
+ return sections;
2357
+ };
2358
+
2359
+ // src/admin/components/studio/adminPathUtils.ts
2360
+ var import_react11 = require("react");
2361
+ var DEFAULT_ADMIN_BASE_PATH = "/admin";
2362
+ var normalizePath = (value) => {
2363
+ if (!value || value === "/") return "/";
2364
+ const withLeadingSlash = value.startsWith("/") ? value : `/${value}`;
2365
+ const trimmed = withLeadingSlash.replace(/\/+$/, "");
2366
+ return trimmed.length > 0 ? trimmed : "/";
2367
+ };
2368
+ var normalizeAdminBasePath = (value) => {
2369
+ const normalized = normalizePath(value);
2370
+ return normalized === "/" ? DEFAULT_ADMIN_BASE_PATH : normalized;
2371
+ };
2372
+ var detectAdminBasePath = (pathname, fallback = DEFAULT_ADMIN_BASE_PATH) => {
2373
+ const normalizedPathname = normalizePath(pathname);
2374
+ const normalizedFallback = normalizeAdminBasePath(fallback);
2375
+ const markers = [
2376
+ "/studio-contact-form",
2377
+ "/studio-globals",
2378
+ "/collections/",
2379
+ "/globals/",
2380
+ "/pages/",
2381
+ "/tools",
2382
+ "/media",
2383
+ "/logout",
2384
+ "/login"
2385
+ ];
2386
+ for (const marker of markers) {
2387
+ const index = normalizedPathname.indexOf(marker);
2388
+ if (index > 0) {
2389
+ return normalizeAdminBasePath(normalizedPathname.slice(0, index));
2390
+ }
2391
+ }
2392
+ if (normalizedPathname === normalizedFallback || normalizedPathname.startsWith(`${normalizedFallback}/`)) {
2393
+ return normalizedFallback;
2394
+ }
2395
+ const segments = normalizedPathname.split("/").filter(Boolean);
2396
+ if (segments.length > 0) {
2397
+ return normalizeAdminBasePath(`/${segments[0]}`);
2398
+ }
2399
+ return normalizedFallback;
2400
+ };
2401
+ var isAbsoluteExternalURL2 = (value) => /^[a-zA-Z][a-zA-Z\d+\-.]*:/.test(value) || value.startsWith("//");
2402
+ var resolveAdminPath = (adminBasePath, targetPath) => {
2403
+ if (!targetPath) return adminBasePath;
2404
+ if (isAbsoluteExternalURL2(targetPath)) return targetPath;
2405
+ const normalizedBasePath = normalizeAdminBasePath(adminBasePath);
2406
+ const normalizedTargetPath = normalizePath(targetPath);
2407
+ if (normalizedTargetPath === "/admin") {
2408
+ return normalizedBasePath;
2409
+ }
2410
+ if (normalizedTargetPath.startsWith("/admin/")) {
2411
+ return `${normalizedBasePath}${normalizedTargetPath.slice("/admin".length)}`;
2412
+ }
2413
+ if (normalizedTargetPath === normalizedBasePath || normalizedTargetPath.startsWith(`${normalizedBasePath}/`)) {
2414
+ return normalizedTargetPath;
2415
+ }
2416
+ if (normalizedTargetPath === "/") {
2417
+ return normalizedBasePath;
2418
+ }
2419
+ return `${normalizedBasePath}${normalizedTargetPath}`;
2420
+ };
2421
+ var useAdminBasePath = (fallback = DEFAULT_ADMIN_BASE_PATH) => {
2422
+ const [adminBasePath, setAdminBasePath] = (0, import_react11.useState)(normalizeAdminBasePath(fallback));
2423
+ (0, import_react11.useEffect)(() => {
2424
+ const update = () => {
2425
+ setAdminBasePath(detectAdminBasePath(window.location.pathname, fallback));
2426
+ };
2427
+ update();
2428
+ window.addEventListener("popstate", update);
2429
+ return () => window.removeEventListener("popstate", update);
2430
+ }, [fallback]);
2431
+ return adminBasePath;
2432
+ };
2433
+
2434
+ // src/admin/components/studio/AdminStudioDashboard.tsx
2280
2435
  var import_jsx_runtime14 = require("react/jsx-runtime");
2281
2436
  var cardStyle = {
2282
2437
  background: "var(--theme-elevation-0)",
@@ -2297,12 +2452,45 @@ var getPropString = (props, key, fallback) => {
2297
2452
  }
2298
2453
  return fallback;
2299
2454
  };
2455
+ var getPropBoolean = (props, key, fallback) => {
2456
+ if (!props || typeof props !== "object") return fallback;
2457
+ const direct = props[key];
2458
+ if (typeof direct === "boolean") return direct;
2459
+ const clientProps = props.clientProps;
2460
+ if (clientProps && typeof clientProps === "object") {
2461
+ const nested = clientProps[key];
2462
+ if (typeof nested === "boolean") return nested;
2463
+ }
2464
+ return fallback;
2465
+ };
2466
+ var getPropSections = (props, key) => {
2467
+ if (!props || typeof props !== "object") return [];
2468
+ const direct = resolveStudioSections(props[key]);
2469
+ if (direct.length > 0) return direct;
2470
+ const clientProps = props.clientProps;
2471
+ if (clientProps && typeof clientProps === "object") {
2472
+ return resolveStudioSections(clientProps[key]);
2473
+ }
2474
+ return [];
2475
+ };
2300
2476
  function AdminStudioDashboard(props) {
2477
+ const formsEnabled = getPropBoolean(props, "formsEnabled", false);
2301
2478
  const pagesCollectionSlug = getPropString(props, "pagesCollectionSlug", "pages");
2302
2479
  const mediaCollectionSlug = getPropString(props, "mediaCollectionSlug", "media");
2303
- const globalsBasePath = getPropString(props, "globalsBasePath", "/admin/globals");
2480
+ const globalsBasePath = getPropString(props, "globalsBasePath", "/studio-globals");
2481
+ const sections = getPropSections(props, "sections");
2482
+ const adminBasePath = useAdminBasePath();
2483
+ const resolvedGlobalsBasePath = resolveAdminPath(adminBasePath, globalsBasePath);
2484
+ const formsPath = resolveAdminPath(adminBasePath, "/studio-forms");
2485
+ const pagesPath = resolveAdminPath(adminBasePath, `/collections/${pagesCollectionSlug}`);
2486
+ const mediaPath = resolveAdminPath(adminBasePath, `/collections/${mediaCollectionSlug}`);
2487
+ const extensionCards = sections.filter((section) => section.card).map((section) => ({
2488
+ href: resolveAdminPath(adminBasePath, section.href),
2489
+ title: section.card?.title || section.label,
2490
+ description: section.card?.description || ""
2491
+ }));
2304
2492
  return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { style: { padding: "1.2rem 1.2rem 2.5rem" }, children: [
2305
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_ui3.SetStepNav, { nav: [{ label: "Dashboard", url: "/admin" }] }),
2493
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_ui3.SetStepNav, { nav: [{ label: "Dashboard", url: adminBasePath }] }),
2306
2494
  /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("h1", { style: { fontSize: "1.6rem", margin: 0 }, children: "Studio" }),
2307
2495
  /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("p", { style: { color: "var(--theme-elevation-600)", marginTop: "0.35rem" }, children: "Pick what you want to edit." }),
2308
2496
  /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(
@@ -2315,18 +2503,26 @@ function AdminStudioDashboard(props) {
2315
2503
  marginTop: "1.1rem"
2316
2504
  },
2317
2505
  children: [
2318
- /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("a", { href: `/admin/collections/${pagesCollectionSlug}`, style: cardStyle, children: [
2506
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("a", { href: pagesPath, style: cardStyle, children: [
2319
2507
  /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { style: { fontWeight: 900 }, children: "Pages" }),
2320
2508
  /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { style: { color: "var(--theme-elevation-600)", marginTop: "0.25rem" }, children: "Edit your site pages with the custom editor." })
2321
2509
  ] }),
2322
- /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("a", { href: globalsBasePath, style: cardStyle, children: [
2510
+ formsEnabled ? /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("a", { href: formsPath, style: cardStyle, children: [
2511
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { style: { fontWeight: 900 }, children: "Forms" }),
2512
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { style: { color: "var(--theme-elevation-600)", marginTop: "0.25rem" }, children: "Review forms, submissions, and uploaded files." })
2513
+ ] }) : null,
2514
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("a", { href: resolvedGlobalsBasePath, style: cardStyle, children: [
2323
2515
  /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { style: { fontWeight: 900 }, children: "Globals" }),
2324
2516
  /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { style: { color: "var(--theme-elevation-600)", marginTop: "0.25rem" }, children: "Site settings, header, footer." })
2325
2517
  ] }),
2326
- /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("a", { href: `/admin/collections/${mediaCollectionSlug}`, style: cardStyle, children: [
2518
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("a", { href: mediaPath, style: cardStyle, children: [
2327
2519
  /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { style: { fontWeight: 900 }, children: "Media" }),
2328
2520
  /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { style: { color: "var(--theme-elevation-600)", marginTop: "0.25rem" }, children: "Upload and manage images and files." })
2329
- ] })
2521
+ ] }),
2522
+ extensionCards.map((card) => /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("a", { href: card.href, style: cardStyle, children: [
2523
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { style: { fontWeight: 900 }, children: card.title }),
2524
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { style: { color: "var(--theme-elevation-600)", marginTop: "0.25rem" }, children: card.description })
2525
+ ] }, card.href))
2330
2526
  ]
2331
2527
  }
2332
2528
  )
@@ -2334,14 +2530,9 @@ function AdminStudioDashboard(props) {
2334
2530
  }
2335
2531
 
2336
2532
  // src/admin/components/studio/AdminStudioNav.tsx
2337
- var import_react11 = require("react");
2533
+ var import_react12 = require("react");
2338
2534
  var import_ui4 = require("@payloadcms/ui");
2339
2535
  var import_jsx_runtime15 = require("react/jsx-runtime");
2340
- var isAdmin = (user) => {
2341
- if (!user || typeof user !== "object") return false;
2342
- const role = user.role;
2343
- return typeof role === "string" && role === "admin";
2344
- };
2345
2536
  var getPropString2 = (props, key, fallback) => {
2346
2537
  if (!props || typeof props !== "object") return fallback;
2347
2538
  const direct = props[key];
@@ -2353,7 +2544,7 @@ var getPropString2 = (props, key, fallback) => {
2353
2544
  }
2354
2545
  return fallback;
2355
2546
  };
2356
- var getPropBoolean = (props, key, fallback) => {
2547
+ var getPropBoolean2 = (props, key, fallback) => {
2357
2548
  if (!props || typeof props !== "object") return fallback;
2358
2549
  const direct = props[key];
2359
2550
  if (typeof direct === "boolean") return direct;
@@ -2364,47 +2555,131 @@ var getPropBoolean = (props, key, fallback) => {
2364
2555
  }
2365
2556
  return fallback;
2366
2557
  };
2558
+ var getPropStringArray = (props, key, fallback) => {
2559
+ if (!props || typeof props !== "object") return fallback;
2560
+ const read = (candidate) => Array.isArray(candidate) ? candidate.filter((value) => typeof value === "string" && value.length > 0) : null;
2561
+ const direct = read(props[key]);
2562
+ if (direct) return direct;
2563
+ const clientProps = props.clientProps;
2564
+ if (clientProps && typeof clientProps === "object") {
2565
+ const nested = read(clientProps[key]);
2566
+ if (nested) return nested;
2567
+ }
2568
+ return fallback;
2569
+ };
2570
+ var getPropSections2 = (props, key) => {
2571
+ if (!props || typeof props !== "object") return [];
2572
+ const direct = resolveStudioSections(props[key]);
2573
+ if (direct.length > 0) return direct;
2574
+ const clientProps = props.clientProps;
2575
+ if (clientProps && typeof clientProps === "object") {
2576
+ return resolveStudioSections(clientProps[key]);
2577
+ }
2578
+ return [];
2579
+ };
2580
+ var roleCanAccessSection = (role, section) => {
2581
+ if (!section.roles || section.roles.length === 0) {
2582
+ return true;
2583
+ }
2584
+ if (!role) {
2585
+ return false;
2586
+ }
2587
+ return section.roles.includes(role);
2588
+ };
2589
+ var readUserRole = (user) => {
2590
+ if (!user || typeof user !== "object") {
2591
+ return void 0;
2592
+ }
2593
+ const role = user.role;
2594
+ return typeof role === "string" ? role : void 0;
2595
+ };
2367
2596
  function AdminStudioNav(props) {
2368
2597
  const { user } = (0, import_ui4.useAuth)();
2369
2598
  const brandName = getPropString2(props, "brandName", "Orion Studio");
2370
2599
  const logoUrl = getPropString2(props, "logoUrl", "");
2600
+ const formsEnabled = getPropBoolean2(props, "formsEnabled", false);
2601
+ const formsCollectionSlug = getPropString2(props, "formsCollectionSlug", "forms");
2371
2602
  const pagesCollectionSlug = getPropString2(props, "pagesCollectionSlug", "pages");
2372
2603
  const mediaCollectionSlug = getPropString2(props, "mediaCollectionSlug", "media");
2373
- const globalsBasePath = getPropString2(props, "globalsBasePath", "/admin/globals");
2374
- const compact = getPropBoolean(props, "compact", false);
2604
+ const globalsBasePath = getPropString2(props, "globalsBasePath", "/studio-globals");
2605
+ const globalsExtraMatchPrefixes = getPropStringArray(props, "globalsExtraMatchPrefixes", []);
2606
+ const sections = getPropSections2(props, "sections");
2607
+ const compact = getPropBoolean2(props, "compact", false);
2608
+ const adminBasePath = useAdminBasePath();
2375
2609
  const branding = useSiteBranding(brandName, logoUrl || void 0);
2376
2610
  const resolvedName = branding.siteName || brandName;
2377
- const [pathname, setPathname] = (0, import_react11.useState)("");
2378
- (0, import_react11.useEffect)(() => {
2611
+ const [pathname, setPathname] = (0, import_react12.useState)("");
2612
+ (0, import_react12.useEffect)(() => {
2379
2613
  const update = () => setPathname(window.location.pathname);
2380
2614
  update();
2381
2615
  window.addEventListener("popstate", update);
2382
2616
  return () => window.removeEventListener("popstate", update);
2383
2617
  }, []);
2384
- const pagesPath = `/admin/collections/${pagesCollectionSlug}`;
2385
- const mediaPath = `/admin/collections/${mediaCollectionSlug}`;
2386
- const links = (0, import_react11.useMemo)(
2387
- () => [
2388
- { href: "/admin", label: "Dashboard", matchPrefixes: ["/admin"] },
2389
- {
2390
- href: pagesPath,
2391
- label: "Pages",
2392
- matchPrefixes: [pagesPath]
2393
- },
2394
- { href: globalsBasePath, label: "Globals", matchPrefixes: [globalsBasePath, "/admin/globals"] },
2395
- {
2396
- href: mediaPath,
2397
- label: "Media",
2398
- matchPrefixes: [mediaPath]
2399
- },
2400
- {
2401
- href: "/admin/collections/users",
2402
- label: "Admin Tools",
2403
- matchPrefixes: ["/admin/collections/users"],
2404
- adminOnly: true
2405
- }
2406
- ],
2407
- [globalsBasePath, mediaPath, pagesPath]
2618
+ const pagesPath = resolveAdminPath(adminBasePath, `/collections/${pagesCollectionSlug}`);
2619
+ const formsPath = resolveAdminPath(adminBasePath, "/studio-forms");
2620
+ const mediaPath = resolveAdminPath(adminBasePath, `/collections/${mediaCollectionSlug}`);
2621
+ const usersPath = resolveAdminPath(adminBasePath, "/collections/users");
2622
+ const resolvedGlobalsBasePath = resolveAdminPath(adminBasePath, globalsBasePath);
2623
+ const resolvedGlobalsExtraMatchPrefixes = globalsExtraMatchPrefixes.map(
2624
+ (prefix) => resolveAdminPath(adminBasePath, prefix)
2625
+ );
2626
+ const dashboardPath = adminBasePath;
2627
+ const userRole = readUserRole(user);
2628
+ const links = (0, import_react12.useMemo)(
2629
+ () => {
2630
+ const defaultSections = [
2631
+ { id: "dashboard", href: dashboardPath, label: "Dashboard", matchPrefixes: [dashboardPath] },
2632
+ { id: "pages", href: pagesPath, label: "Pages", matchPrefixes: [pagesPath] },
2633
+ ...formsEnabled ? [
2634
+ {
2635
+ id: "forms",
2636
+ href: formsPath,
2637
+ label: "Forms",
2638
+ matchPrefixes: [
2639
+ formsPath,
2640
+ resolveAdminPath(adminBasePath, `/collections/${formsCollectionSlug}`)
2641
+ ]
2642
+ }
2643
+ ] : [],
2644
+ {
2645
+ id: "globals",
2646
+ href: resolvedGlobalsBasePath,
2647
+ label: "Globals",
2648
+ matchPrefixes: [
2649
+ resolvedGlobalsBasePath,
2650
+ resolveAdminPath(adminBasePath, "/globals"),
2651
+ ...resolvedGlobalsExtraMatchPrefixes
2652
+ ]
2653
+ },
2654
+ { id: "media", href: mediaPath, label: "Media", matchPrefixes: [mediaPath] },
2655
+ {
2656
+ id: "admin-tools",
2657
+ href: usersPath,
2658
+ label: "Admin Tools",
2659
+ matchPrefixes: [usersPath],
2660
+ roles: ["admin"]
2661
+ }
2662
+ ];
2663
+ const extensionSections = sections.map((section) => ({
2664
+ ...section,
2665
+ href: resolveAdminPath(adminBasePath, section.href),
2666
+ matchPrefixes: section.matchPrefixes.map((prefix) => resolveAdminPath(adminBasePath, prefix))
2667
+ }));
2668
+ return [...defaultSections, ...extensionSections];
2669
+ },
2670
+ [
2671
+ adminBasePath,
2672
+ dashboardPath,
2673
+ formsCollectionSlug,
2674
+ formsEnabled,
2675
+ formsPath,
2676
+ mediaPath,
2677
+ pagesPath,
2678
+ resolvedGlobalsBasePath,
2679
+ resolvedGlobalsExtraMatchPrefixes,
2680
+ sections,
2681
+ usersPath
2682
+ ]
2408
2683
  );
2409
2684
  const linkStyle = (active) => ({
2410
2685
  alignItems: "center",
@@ -2461,8 +2736,8 @@ function AdminStudioNav(props) {
2461
2736
  ),
2462
2737
  !compact ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { style: { color: "var(--theme-elevation-600)", fontSize: "0.85rem" }, children: "Studio" }) : null
2463
2738
  ] }),
2464
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("nav", { style: { display: "grid", gap: "0.25rem" }, children: links.filter((link) => !link.adminOnly || isAdmin(user)).map((link) => {
2465
- const active = link.href === "/admin" ? pathname === "/admin" : link.matchPrefixes.some((prefix) => pathname.startsWith(prefix));
2739
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("nav", { style: { display: "grid", gap: "0.25rem" }, children: links.filter((link) => roleCanAccessSection(userRole, link)).map((link) => {
2740
+ const active = link.href === dashboardPath ? pathname === dashboardPath : link.matchPrefixes.some((prefix) => pathname.startsWith(prefix));
2466
2741
  return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("a", { href: link.href, style: linkStyle(active), title: link.label, children: compact ? link.label.slice(0, 1) : link.label }, link.href);
2467
2742
  }) }),
2468
2743
  /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { style: { flex: 1 } }),
@@ -2489,10 +2764,10 @@ function AdminStudioNav(props) {
2489
2764
  }
2490
2765
 
2491
2766
  // src/admin/components/studio/AdminStudioPagesListView.tsx
2492
- var import_react12 = require("react");
2767
+ var import_react13 = require("react");
2493
2768
  var import_ui5 = require("@payloadcms/ui");
2494
2769
  var import_jsx_runtime16 = require("react/jsx-runtime");
2495
- var isAdmin2 = (user) => {
2770
+ var isAdmin = (user) => {
2496
2771
  if (!user || typeof user !== "object") return false;
2497
2772
  const role = user.role;
2498
2773
  return typeof role === "string" && role === "admin";
@@ -2511,10 +2786,13 @@ var getPropString3 = (props, key, fallback) => {
2511
2786
  function AdminStudioPagesListView(props) {
2512
2787
  const { user } = (0, import_ui5.useAuth)();
2513
2788
  const pagesCollectionSlug = getPropString3(props, "pagesCollectionSlug", "pages");
2514
- const [loading, setLoading] = (0, import_react12.useState)(true);
2515
- const [error, setError] = (0, import_react12.useState)(null);
2516
- const [docs, setDocs] = (0, import_react12.useState)([]);
2517
- const apiURL = (0, import_react12.useMemo)(() => {
2789
+ const adminBasePath = useAdminBasePath();
2790
+ const pagesPath = resolveAdminPath(adminBasePath, "/pages");
2791
+ const rawPagesCollectionPath = resolveAdminPath(adminBasePath, `/collections/${pagesCollectionSlug}`);
2792
+ const [loading, setLoading] = (0, import_react13.useState)(true);
2793
+ const [error, setError] = (0, import_react13.useState)(null);
2794
+ const [docs, setDocs] = (0, import_react13.useState)([]);
2795
+ const apiURL = (0, import_react13.useMemo)(() => {
2518
2796
  const params = new URLSearchParams({
2519
2797
  depth: "0",
2520
2798
  limit: "100",
@@ -2523,7 +2801,7 @@ function AdminStudioPagesListView(props) {
2523
2801
  });
2524
2802
  return `/api/${pagesCollectionSlug}?${params.toString()}`;
2525
2803
  }, [pagesCollectionSlug]);
2526
- (0, import_react12.useEffect)(() => {
2804
+ (0, import_react13.useEffect)(() => {
2527
2805
  let cancelled = false;
2528
2806
  const run = async () => {
2529
2807
  setLoading(true);
@@ -2549,16 +2827,16 @@ function AdminStudioPagesListView(props) {
2549
2827
  };
2550
2828
  }, [apiURL]);
2551
2829
  return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(import_jsx_runtime16.Fragment, { children: [
2552
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_ui5.SetStepNav, { nav: [{ label: "Pages", url: "/admin/pages" }] }),
2830
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_ui5.SetStepNav, { nav: [{ label: "Pages", url: pagesPath }] }),
2553
2831
  /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { style: { alignItems: "flex-end", display: "flex", gap: "0.75rem" }, children: [
2554
2832
  /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { style: { flex: 1 }, children: [
2555
2833
  /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("h1", { style: { margin: 0 }, children: "Pages" }),
2556
2834
  /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("p", { style: { color: "var(--theme-elevation-600)", marginTop: "0.35rem" }, children: "Open a page to edit it in the custom editor." })
2557
2835
  ] }),
2558
- isAdmin2(user) ? /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
2836
+ isAdmin(user) ? /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
2559
2837
  "a",
2560
2838
  {
2561
- href: `/admin/collections/${pagesCollectionSlug}/create`,
2839
+ href: `${rawPagesCollectionPath}/create`,
2562
2840
  style: {
2563
2841
  background: "var(--theme-elevation-900)",
2564
2842
  borderRadius: 12,
@@ -2595,7 +2873,7 @@ function AdminStudioPagesListView(props) {
2595
2873
  return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(
2596
2874
  "a",
2597
2875
  {
2598
- href: `/admin/pages/${id}`,
2876
+ href: resolveAdminPath(adminBasePath, `/pages/${id}`),
2599
2877
  style: {
2600
2878
  background: "var(--theme-elevation-0)",
2601
2879
  border: "1px solid var(--theme-elevation-150)",
@@ -2662,10 +2940,10 @@ function AdminStudioPagesListView(props) {
2662
2940
  }
2663
2941
 
2664
2942
  // src/admin/components/studio/AdminStudioPageEditView.tsx
2665
- var import_react13 = require("react");
2943
+ var import_react14 = require("react");
2666
2944
  var import_ui6 = require("@payloadcms/ui");
2667
2945
  var import_jsx_runtime17 = require("react/jsx-runtime");
2668
- var isAdmin3 = (user) => {
2946
+ var isAdmin2 = (user) => {
2669
2947
  if (!user || typeof user !== "object") return false;
2670
2948
  const role = user.role;
2671
2949
  return typeof role === "string" && role === "admin";
@@ -2695,18 +2973,27 @@ var getParam = (params, key) => {
2695
2973
  return null;
2696
2974
  };
2697
2975
  var getPageIDFromPathname = (pathname) => {
2698
- const match = pathname.match(/\/admin\/pages\/([^/]+)(?:\/|$)/);
2699
- return match?.[1] ? decodeURIComponent(match[1]) : null;
2976
+ const marker = "/pages/";
2977
+ const markerIndex = pathname.indexOf(marker);
2978
+ if (markerIndex < 0) return null;
2979
+ const pagePart = pathname.slice(markerIndex + marker.length).split("/")[0];
2980
+ return pagePart ? decodeURIComponent(pagePart) : null;
2700
2981
  };
2701
2982
  function AdminStudioPageEditView(props) {
2702
2983
  const { user } = (0, import_ui6.useAuth)();
2703
- const iframeRef = (0, import_react13.useRef)(null);
2704
- const [saving, setSaving] = (0, import_react13.useState)(null);
2984
+ const adminBasePath = useAdminBasePath();
2985
+ const iframeRef = (0, import_react14.useRef)(null);
2986
+ const [saving, setSaving] = (0, import_react14.useState)(null);
2987
+ const [dirty, setDirty] = (0, import_react14.useState)(false);
2988
+ const [hasUnpublishedChanges, setHasUnpublishedChanges] = (0, import_react14.useState)(false);
2989
+ const [canUndo, setCanUndo] = (0, import_react14.useState)(false);
2990
+ const [canRedo, setCanRedo] = (0, import_react14.useState)(false);
2705
2991
  const builderBasePath = getPropString4(props, "builderBasePath", "/builder");
2706
- const pageIDFromParams = (0, import_react13.useMemo)(() => getParam(props.params, "id"), [props.params]);
2707
- const [pageID, setPageID] = (0, import_react13.useState)(pageIDFromParams);
2708
- const [didResolvePathFallback, setDidResolvePathFallback] = (0, import_react13.useState)(false);
2709
- (0, import_react13.useEffect)(() => {
2992
+ const pagesPath = resolveAdminPath(adminBasePath, "/pages");
2993
+ const pageIDFromParams = (0, import_react14.useMemo)(() => getParam(props.params, "id"), [props.params]);
2994
+ const [pageID, setPageID] = (0, import_react14.useState)(pageIDFromParams);
2995
+ const [didResolvePathFallback, setDidResolvePathFallback] = (0, import_react14.useState)(false);
2996
+ (0, import_react14.useEffect)(() => {
2710
2997
  if (pageIDFromParams) {
2711
2998
  setPageID(pageIDFromParams);
2712
2999
  setDidResolvePathFallback(true);
@@ -2717,7 +3004,45 @@ function AdminStudioPageEditView(props) {
2717
3004
  }
2718
3005
  setDidResolvePathFallback(true);
2719
3006
  }, [pageIDFromParams]);
2720
- const canPublish = isAdmin3(user) || isEditor(user);
3007
+ const canPublish = isAdmin2(user) || isEditor(user);
3008
+ const refreshUnpublishedState = async (id) => {
3009
+ try {
3010
+ const response = await fetch(
3011
+ `/api/pages/versions?depth=0&limit=25&sort=-updatedAt&where[parent][equals]=${encodeURIComponent(id)}`,
3012
+ {
3013
+ credentials: "include"
3014
+ }
3015
+ );
3016
+ if (!response.ok) {
3017
+ return;
3018
+ }
3019
+ const payload = await response.json();
3020
+ const docs = Array.isArray(payload.docs) ? payload.docs : [];
3021
+ let latestDraft = 0;
3022
+ let latestPublished = 0;
3023
+ docs.forEach((doc) => {
3024
+ const status = doc.version?._status;
3025
+ const millis = typeof doc.updatedAt === "string" ? Date.parse(doc.updatedAt) : Number.NaN;
3026
+ if (!Number.isFinite(millis)) {
3027
+ return;
3028
+ }
3029
+ if (status === "draft") {
3030
+ latestDraft = Math.max(latestDraft, millis);
3031
+ }
3032
+ if (status === "published") {
3033
+ latestPublished = Math.max(latestPublished, millis);
3034
+ }
3035
+ });
3036
+ setHasUnpublishedChanges(latestDraft > 0 && latestDraft >= latestPublished);
3037
+ } catch {
3038
+ }
3039
+ };
3040
+ (0, import_react14.useEffect)(() => {
3041
+ if (!pageID) {
3042
+ return;
3043
+ }
3044
+ void refreshUnpublishedState(pageID);
3045
+ }, [pageID]);
2721
3046
  const requestSave = (status) => {
2722
3047
  const iframe = iframeRef.current;
2723
3048
  if (!iframe?.contentWindow) {
@@ -2727,17 +3052,43 @@ function AdminStudioPageEditView(props) {
2727
3052
  setSaving(status);
2728
3053
  iframe.contentWindow.postMessage({ source: "payload-visual-builder-parent", type: "save", status }, "*");
2729
3054
  };
2730
- (0, import_react13.useEffect)(() => {
3055
+ const requestHistoryAction = (type) => {
3056
+ const iframe = iframeRef.current;
3057
+ if (!iframe?.contentWindow) {
3058
+ import_ui6.toast.error("Editor is not ready yet. Please try again.");
3059
+ return;
3060
+ }
3061
+ iframe.contentWindow.postMessage({ source: "payload-visual-builder-parent", type }, "*");
3062
+ };
3063
+ (0, import_react14.useEffect)(() => {
2731
3064
  const onMessage = (event) => {
2732
3065
  const data = event.data;
2733
- if (!data || data.source !== "payload-visual-builder-child" || data.type !== "save-result") {
3066
+ if (!data || data.source !== "payload-visual-builder-child" || typeof data.type !== "string") {
2734
3067
  return;
2735
3068
  }
2736
- setSaving(null);
2737
- if (data.ok) {
2738
- import_ui6.toast.success(typeof data.message === "string" ? data.message : "Saved.");
2739
- } else {
2740
- import_ui6.toast.error(typeof data.message === "string" ? data.message : "Save failed.");
3069
+ if (data.type === "dirty-state") {
3070
+ setDirty(Boolean(data.dirty));
3071
+ return;
3072
+ }
3073
+ if (data.type === "history-state") {
3074
+ setCanUndo(Boolean(data.canUndo));
3075
+ setCanRedo(Boolean(data.canRedo));
3076
+ return;
3077
+ }
3078
+ if (data.type === "save-result") {
3079
+ setSaving(null);
3080
+ if (data.ok) {
3081
+ if (data.status === "draft") {
3082
+ setHasUnpublishedChanges(true);
3083
+ } else if (data.status === "published") {
3084
+ setHasUnpublishedChanges(false);
3085
+ } else if (pageID) {
3086
+ void refreshUnpublishedState(pageID);
3087
+ }
3088
+ import_ui6.toast.success(typeof data.message === "string" ? data.message : "Saved.");
3089
+ } else {
3090
+ import_ui6.toast.error(typeof data.message === "string" ? data.message : "Save failed.");
3091
+ }
2741
3092
  }
2742
3093
  };
2743
3094
  window.addEventListener("message", onMessage);
@@ -2749,8 +3100,8 @@ function AdminStudioPageEditView(props) {
2749
3100
  import_ui6.SetStepNav,
2750
3101
  {
2751
3102
  nav: [
2752
- { label: "Pages", url: "/admin/pages" },
2753
- { label: "Page Editor", url: "/admin/pages" }
3103
+ { label: "Pages", url: pagesPath },
3104
+ { label: "Page Editor", url: pagesPath }
2754
3105
  ]
2755
3106
  }
2756
3107
  ),
@@ -2764,8 +3115,8 @@ function AdminStudioPageEditView(props) {
2764
3115
  import_ui6.SetStepNav,
2765
3116
  {
2766
3117
  nav: [
2767
- { label: "Pages", url: "/admin/pages" },
2768
- { label: "Page Editor", url: "/admin/pages" }
3118
+ { label: "Pages", url: pagesPath },
3119
+ { label: "Page Editor", url: pagesPath }
2769
3120
  ]
2770
3121
  }
2771
3122
  ),
@@ -2778,8 +3129,8 @@ function AdminStudioPageEditView(props) {
2778
3129
  import_ui6.SetStepNav,
2779
3130
  {
2780
3131
  nav: [
2781
- { label: "Pages", url: "/admin/pages" },
2782
- { label: `Page ${pageID}`, url: `/admin/pages/${pageID}` }
3132
+ { label: "Pages", url: pagesPath },
3133
+ { label: `Page ${pageID}`, url: resolveAdminPath(adminBasePath, `/pages/${pageID}`) }
2783
3134
  ]
2784
3135
  }
2785
3136
  ),
@@ -2819,6 +3170,56 @@ function AdminStudioPageEditView(props) {
2819
3170
  )
2820
3171
  ] }),
2821
3172
  /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { style: { alignItems: "center", display: "flex", gap: "0.5rem" }, children: [
3173
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { style: { color: dirty ? "var(--theme-elevation-900)" : "var(--theme-elevation-600)", fontSize: "0.85rem", fontWeight: 700 }, children: dirty ? "Unsaved changes" : "All changes saved" }),
3174
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
3175
+ "div",
3176
+ {
3177
+ style: {
3178
+ background: hasUnpublishedChanges ? "#fff3cd" : "var(--theme-success-50)",
3179
+ border: `1px solid ${hasUnpublishedChanges ? "#f0c36d" : "var(--theme-success-300)"}`,
3180
+ borderRadius: 999,
3181
+ color: hasUnpublishedChanges ? "#6a4a00" : "var(--theme-success-700)",
3182
+ fontSize: "0.75rem",
3183
+ fontWeight: 800,
3184
+ padding: "0.2rem 0.55rem",
3185
+ whiteSpace: "nowrap"
3186
+ },
3187
+ title: hasUnpublishedChanges ? "There are saved draft changes not yet published." : "The live page matches the latest published content.",
3188
+ children: hasUnpublishedChanges ? "Unpublished draft changes" : "Live is up to date"
3189
+ }
3190
+ ),
3191
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
3192
+ "button",
3193
+ {
3194
+ disabled: !canUndo,
3195
+ onClick: () => requestHistoryAction("undo"),
3196
+ style: {
3197
+ border: "1px solid var(--theme-elevation-300)",
3198
+ borderRadius: 12,
3199
+ cursor: canUndo ? "pointer" : "not-allowed",
3200
+ fontWeight: 800,
3201
+ padding: "0.5rem 0.65rem"
3202
+ },
3203
+ type: "button",
3204
+ children: "Undo"
3205
+ }
3206
+ ),
3207
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
3208
+ "button",
3209
+ {
3210
+ disabled: !canRedo,
3211
+ onClick: () => requestHistoryAction("redo"),
3212
+ style: {
3213
+ border: "1px solid var(--theme-elevation-300)",
3214
+ borderRadius: 12,
3215
+ cursor: canRedo ? "pointer" : "not-allowed",
3216
+ fontWeight: 800,
3217
+ padding: "0.5rem 0.65rem"
3218
+ },
3219
+ type: "button",
3220
+ children: "Redo"
3221
+ }
3222
+ ),
2822
3223
  /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
2823
3224
  "button",
2824
3225
  {
@@ -2841,7 +3242,7 @@ function AdminStudioPageEditView(props) {
2841
3242
  disabled: !canPublish || saving !== null,
2842
3243
  onClick: () => requestSave("published"),
2843
3244
  style: {
2844
- background: canPublish ? "var(--theme-elevation-900)" : "var(--theme-elevation-300)",
3245
+ background: canPublish ? "var(--theme-success-700)" : "var(--theme-elevation-300)",
2845
3246
  border: "none",
2846
3247
  borderRadius: 12,
2847
3248
  color: canPublish ? "var(--theme-elevation-0)" : "var(--theme-elevation-700)",
@@ -2864,7 +3265,13 @@ function AdminStudioPageEditView(props) {
2864
3265
  ref: iframeRef,
2865
3266
  src: `${builderBasePath.replace(/\/$/, "")}/${pageID}`,
2866
3267
  style: { border: "none", height: "100%", width: "100%" },
2867
- title: "Page Builder"
3268
+ title: "Page Builder",
3269
+ onLoad: () => {
3270
+ const iframe = iframeRef.current;
3271
+ if (!iframe?.contentWindow) return;
3272
+ iframe.contentWindow.postMessage({ source: "payload-visual-builder-parent", type: "dirty-check-request" }, "*");
3273
+ iframe.contentWindow.postMessage({ source: "payload-visual-builder-parent", type: "history-check-request" }, "*");
3274
+ }
2868
3275
  }
2869
3276
  )
2870
3277
  ] })
@@ -2897,42 +3304,48 @@ var getPropString5 = (props, key, fallback) => {
2897
3304
  return fallback;
2898
3305
  };
2899
3306
  function AdminStudioGlobalsView(props) {
2900
- const globalsBasePath = getPropString5(props, "globalsBasePath", "/admin/studio-globals");
3307
+ const globalsBasePath = getPropString5(props, "globalsBasePath", "/studio-globals");
3308
+ const adminBasePath = useAdminBasePath();
3309
+ const resolvedGlobalsBasePath = resolveAdminPath(adminBasePath, globalsBasePath);
2901
3310
  const globals = getPropGlobals(props) || [
2902
3311
  { slug: "site-settings", label: "Website Settings" },
2903
3312
  { slug: "header", label: "Header & Navigation" },
2904
- { slug: "footer", label: "Footer" }
3313
+ { slug: "footer", label: "Footer" },
3314
+ { slug: "contact-form", label: "Contact Form", href: "/studio-contact-form" }
2905
3315
  ];
2906
3316
  return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(import_jsx_runtime18.Fragment, { children: [
2907
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_ui7.SetStepNav, { nav: [{ label: "Globals", url: globalsBasePath }] }),
3317
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_ui7.SetStepNav, { nav: [{ label: "Globals", url: resolvedGlobalsBasePath }] }),
2908
3318
  /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("h1", { style: { margin: 0 }, children: "Globals" }),
2909
3319
  /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("p", { style: { color: "var(--theme-elevation-600)", marginTop: "0.35rem" }, children: "Site-wide settings." }),
2910
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { style: { display: "grid", gap: "0.6rem", marginTop: "1rem" }, children: globals.map((global) => /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(
2911
- "a",
2912
- {
2913
- href: `/admin/globals/${global.slug}`,
2914
- style: {
2915
- background: "var(--theme-elevation-0)",
2916
- border: "1px solid var(--theme-elevation-150)",
2917
- borderRadius: 16,
2918
- color: "inherit",
2919
- padding: "0.85rem 1rem",
2920
- textDecoration: "none"
3320
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { style: { display: "grid", gap: "0.6rem", marginTop: "1rem" }, children: globals.map((global) => {
3321
+ const href = resolveAdminPath(
3322
+ adminBasePath,
3323
+ typeof global.href === "string" ? global.href : `/globals/${global.slug}`
3324
+ );
3325
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(
3326
+ "a",
3327
+ {
3328
+ href,
3329
+ style: {
3330
+ background: "var(--theme-elevation-0)",
3331
+ border: "1px solid var(--theme-elevation-150)",
3332
+ borderRadius: 16,
3333
+ color: "inherit",
3334
+ padding: "0.85rem 1rem",
3335
+ textDecoration: "none"
3336
+ },
3337
+ children: [
3338
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { style: { fontWeight: 900 }, children: global.label }),
3339
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { style: { color: "var(--theme-elevation-600)", fontSize: "0.9rem" }, children: typeof global.description === "string" && global.description.length > 0 ? global.description : href })
3340
+ ]
2921
3341
  },
2922
- children: [
2923
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { style: { fontWeight: 900 }, children: global.label }),
2924
- /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { style: { color: "var(--theme-elevation-600)", fontSize: "0.9rem" }, children: [
2925
- "/admin/globals/",
2926
- global.slug
2927
- ] })
2928
- ]
2929
- },
2930
- global.slug
2931
- )) }),
3342
+ global.slug
3343
+ );
3344
+ }) }),
2932
3345
  /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { style: { marginTop: "1rem" }, children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
2933
3346
  "a",
2934
3347
  {
2935
- href: globalsBasePath,
3348
+ href: resolvedGlobalsBasePath,
2936
3349
  style: { color: "var(--theme-elevation-700)", fontSize: "0.85rem", textDecoration: "none" },
2937
3350
  children: "Reload Globals view"
2938
3351
  }
@@ -2940,9 +3353,24 @@ function AdminStudioGlobalsView(props) {
2940
3353
  ] });
2941
3354
  }
2942
3355
 
2943
- // src/admin/components/studio/AdminStudioMediaView.tsx
3356
+ // src/admin/components/studio/AdminStudioContactFormView.tsx
3357
+ var import_react15 = require("react");
2944
3358
  var import_ui8 = require("@payloadcms/ui");
2945
3359
  var import_jsx_runtime19 = require("react/jsx-runtime");
3360
+ var defaultDoc = {
3361
+ disabledMessage: "This form is temporarily unavailable. Please call us for immediate service.",
3362
+ enabled: true,
3363
+ errorMessage: "Submission failed. Please call us at (512) 555-0149.",
3364
+ notificationEmail: "",
3365
+ serviceOptions: [
3366
+ { label: "Tree Trimming" },
3367
+ { label: "Tree Removal" },
3368
+ { label: "Stump Grinding" },
3369
+ { label: "Storm Cleanup" }
3370
+ ],
3371
+ submitButtonLabel: "Send Request",
3372
+ successMessage: "Thanks, your request has been received. We will follow up shortly."
3373
+ };
2946
3374
  var getPropString6 = (props, key, fallback) => {
2947
3375
  if (!props || typeof props !== "object") return fallback;
2948
3376
  const direct = props[key];
@@ -2954,79 +3382,1138 @@ var getPropString6 = (props, key, fallback) => {
2954
3382
  }
2955
3383
  return fallback;
2956
3384
  };
2957
- function AdminStudioMediaView(props) {
2958
- const mediaCollectionSlug = getPropString6(props, "mediaCollectionSlug", "media");
2959
- return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(import_jsx_runtime19.Fragment, { children: [
2960
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_ui8.SetStepNav, { nav: [{ label: "Media", url: "/admin/media" }] }),
2961
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("h1", { style: { margin: 0 }, children: "Media" }),
2962
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("p", { style: { color: "var(--theme-elevation-600)", marginTop: "0.35rem" }, children: "Media management is currently using Payload's library." }),
2963
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { style: { display: "grid", gap: "0.6rem", marginTop: "1rem" }, children: /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(
2964
- "a",
2965
- {
2966
- href: `/admin/collections/${mediaCollectionSlug}`,
2967
- style: {
2968
- background: "var(--theme-elevation-0)",
2969
- border: "1px solid var(--theme-elevation-150)",
2970
- borderRadius: 16,
2971
- color: "inherit",
2972
- padding: "0.85rem 1rem",
2973
- textDecoration: "none"
2974
- },
2975
- children: [
2976
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { style: { fontWeight: 900 }, children: "Open Media Library" }),
2977
- /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { style: { color: "var(--theme-elevation-600)", fontSize: "0.9rem" }, children: [
2978
- "/admin/collections/",
2979
- mediaCollectionSlug
2980
- ] })
2981
- ]
2982
- }
2983
- ) })
2984
- ] });
2985
- }
2986
-
2987
- // src/admin/components/studio/AdminStudioToolsView.tsx
2988
- var import_ui9 = require("@payloadcms/ui");
2989
- var import_jsx_runtime20 = require("react/jsx-runtime");
2990
- var isAdmin4 = (user) => {
2991
- if (!user || typeof user !== "object") return false;
2992
- const role = user.role;
2993
- return typeof role === "string" && role === "admin";
3385
+ var normalizeOption = (value) => {
3386
+ if (!value || typeof value !== "object" || Array.isArray(value)) return null;
3387
+ const label = value.label;
3388
+ if (typeof label !== "string") return null;
3389
+ const trimmed = label.trim();
3390
+ if (!trimmed) return null;
3391
+ return { label: trimmed };
2994
3392
  };
2995
- var getPropString7 = (props, key, fallback) => {
2996
- if (!props || typeof props !== "object") return fallback;
2997
- const direct = props[key];
2998
- if (typeof direct === "string" && direct.length > 0) return direct;
2999
- const clientProps = props.clientProps;
3000
- if (clientProps && typeof clientProps === "object") {
3001
- const nested = clientProps[key];
3002
- if (typeof nested === "string" && nested.length > 0) return nested;
3393
+ var normalizeDoc = (value) => {
3394
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
3395
+ return defaultDoc;
3003
3396
  }
3004
- return fallback;
3397
+ const record = value;
3398
+ const options = Array.isArray(record.serviceOptions) ? record.serviceOptions.map(normalizeOption).filter((option) => option !== null) : defaultDoc.serviceOptions;
3399
+ return {
3400
+ disabledMessage: typeof record.disabledMessage === "string" && record.disabledMessage.length > 0 ? record.disabledMessage : defaultDoc.disabledMessage,
3401
+ enabled: record.enabled !== false,
3402
+ errorMessage: typeof record.errorMessage === "string" && record.errorMessage.length > 0 ? record.errorMessage : defaultDoc.errorMessage,
3403
+ notificationEmail: typeof record.notificationEmail === "string" ? record.notificationEmail : defaultDoc.notificationEmail,
3404
+ serviceOptions: options.length > 0 ? options : defaultDoc.serviceOptions,
3405
+ submitButtonLabel: typeof record.submitButtonLabel === "string" && record.submitButtonLabel.length > 0 ? record.submitButtonLabel : defaultDoc.submitButtonLabel,
3406
+ successMessage: typeof record.successMessage === "string" && record.successMessage.length > 0 ? record.successMessage : defaultDoc.successMessage
3407
+ };
3005
3408
  };
3006
- function AdminStudioToolsView(props) {
3007
- const { user } = (0, import_ui9.useAuth)();
3008
- if (!isAdmin4(user)) {
3009
- return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(import_jsx_runtime20.Fragment, { children: [
3010
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_ui9.SetStepNav, { nav: [{ label: "Admin Tools", url: "/admin/tools" }] }),
3011
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("h1", { style: { margin: 0 }, children: "Admin Tools" }),
3012
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("p", { style: { color: "var(--theme-elevation-600)" }, children: "You do not have access to this page." })
3013
- ] });
3409
+ var inputStyle = {
3410
+ background: "var(--theme-elevation-0)",
3411
+ border: "1px solid var(--theme-elevation-200)",
3412
+ borderRadius: 10,
3413
+ color: "inherit",
3414
+ fontSize: "0.95rem",
3415
+ minHeight: 42,
3416
+ padding: "0.55rem 0.65rem",
3417
+ width: "100%"
3418
+ };
3419
+ var fieldLabelStyle = {
3420
+ color: "var(--theme-elevation-800)",
3421
+ display: "grid",
3422
+ fontSize: "0.88rem",
3423
+ fontWeight: 700,
3424
+ gap: "0.35rem"
3425
+ };
3426
+ var buttonStyle = {
3427
+ background: "var(--theme-success-700)",
3428
+ border: "1px solid var(--theme-success-700)",
3429
+ borderRadius: 10,
3430
+ color: "#fff",
3431
+ cursor: "pointer",
3432
+ fontSize: "0.9rem",
3433
+ fontWeight: 800,
3434
+ minHeight: 40,
3435
+ padding: "0 0.9rem"
3436
+ };
3437
+ var ghostButtonStyle = {
3438
+ ...buttonStyle,
3439
+ background: "transparent",
3440
+ color: "var(--theme-elevation-900)"
3441
+ };
3442
+ function AdminStudioContactFormView(props) {
3443
+ const globalSlug = getPropString6(props, "globalSlug", "contact-form");
3444
+ const globalsBasePath = getPropString6(props, "globalsBasePath", "/studio-globals");
3445
+ const adminBasePath = useAdminBasePath();
3446
+ const resolvedGlobalsBasePath = resolveAdminPath(adminBasePath, globalsBasePath);
3447
+ const rawGlobalPath = resolveAdminPath(adminBasePath, `/globals/${globalSlug}`);
3448
+ const [doc, setDoc] = (0, import_react15.useState)(defaultDoc);
3449
+ const [error, setError] = (0, import_react15.useState)(null);
3450
+ const [isLoading, setIsLoading] = (0, import_react15.useState)(true);
3451
+ const [isSaving, setIsSaving] = (0, import_react15.useState)(false);
3452
+ const [savedMessage, setSavedMessage] = (0, import_react15.useState)(null);
3453
+ (0, import_react15.useEffect)(() => {
3454
+ let mounted = true;
3455
+ const load = async () => {
3456
+ setIsLoading(true);
3457
+ setError(null);
3458
+ setSavedMessage(null);
3459
+ try {
3460
+ const response = await fetch(`/api/globals/${globalSlug}?depth=0&draft=true`, {
3461
+ credentials: "same-origin"
3462
+ });
3463
+ if (!response.ok) {
3464
+ throw new Error(`Failed to load global (${response.status}).`);
3465
+ }
3466
+ const json = await response.json();
3467
+ if (!mounted) return;
3468
+ setDoc(normalizeDoc(json));
3469
+ } catch (loadError) {
3470
+ if (!mounted) return;
3471
+ setError(loadError instanceof Error ? loadError.message : "Failed to load contact form settings.");
3472
+ } finally {
3473
+ if (mounted) {
3474
+ setIsLoading(false);
3475
+ }
3476
+ }
3477
+ };
3478
+ void load();
3479
+ return () => {
3480
+ mounted = false;
3481
+ };
3482
+ }, [globalSlug]);
3483
+ const payload = (0, import_react15.useMemo)(
3484
+ () => ({
3485
+ disabledMessage: doc.disabledMessage,
3486
+ enabled: doc.enabled,
3487
+ errorMessage: doc.errorMessage,
3488
+ notificationEmail: doc.notificationEmail.trim(),
3489
+ serviceOptions: doc.serviceOptions.map((option) => ({ label: option.label.trim() })).filter((option) => option.label.length > 0),
3490
+ submitButtonLabel: doc.submitButtonLabel,
3491
+ successMessage: doc.successMessage
3492
+ }),
3493
+ [doc]
3494
+ );
3495
+ const save = async () => {
3496
+ setIsSaving(true);
3497
+ setError(null);
3498
+ setSavedMessage(null);
3499
+ try {
3500
+ const response = await fetch(`/api/globals/${globalSlug}`, {
3501
+ body: JSON.stringify(payload),
3502
+ credentials: "same-origin",
3503
+ headers: {
3504
+ "Content-Type": "application/json"
3505
+ },
3506
+ method: "PATCH"
3507
+ });
3508
+ if (!response.ok) {
3509
+ throw new Error(`Failed to save settings (${response.status}).`);
3510
+ }
3511
+ const json = await response.json();
3512
+ setDoc(normalizeDoc(json));
3513
+ setSavedMessage("Saved.");
3514
+ } catch (saveError) {
3515
+ setError(saveError instanceof Error ? saveError.message : "Failed to save contact form settings.");
3516
+ } finally {
3517
+ setIsSaving(false);
3518
+ }
3519
+ };
3520
+ return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { style: { paddingBottom: "2rem" }, children: [
3521
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
3522
+ import_ui8.SetStepNav,
3523
+ {
3524
+ nav: [
3525
+ { label: "Globals", url: resolvedGlobalsBasePath },
3526
+ { label: "Contact Form" }
3527
+ ]
3528
+ }
3529
+ ),
3530
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("h1", { style: { margin: 0 }, children: "Contact Form" }),
3531
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("p", { style: { color: "var(--theme-elevation-600)", marginTop: "0.35rem" }, children: "Edit form behavior and submission messaging without leaving Studio." }),
3532
+ isLoading ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("p", { style: { color: "var(--theme-elevation-600)" }, children: "Loading form settings\u2026" }) : null,
3533
+ error ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("p", { style: { color: "var(--theme-error-600)" }, children: error }) : null,
3534
+ savedMessage ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("p", { style: { color: "var(--theme-success-700)" }, children: savedMessage }) : null,
3535
+ !isLoading ? /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { style: { display: "grid", gap: "1rem", marginTop: "1rem", maxWidth: 900 }, children: [
3536
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("label", { style: { ...fieldLabelStyle, alignItems: "center", display: "flex", gap: "0.6rem" }, children: [
3537
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
3538
+ "input",
3539
+ {
3540
+ checked: doc.enabled,
3541
+ onChange: (event) => setDoc((prev) => ({ ...prev, enabled: event.target.checked })),
3542
+ type: "checkbox"
3543
+ }
3544
+ ),
3545
+ "Form enabled"
3546
+ ] }),
3547
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("label", { style: fieldLabelStyle, children: [
3548
+ "Notification Email",
3549
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
3550
+ "input",
3551
+ {
3552
+ onChange: (event) => setDoc((prev) => ({ ...prev, notificationEmail: event.target.value })),
3553
+ style: inputStyle,
3554
+ type: "email",
3555
+ value: doc.notificationEmail
3556
+ }
3557
+ )
3558
+ ] }),
3559
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("label", { style: fieldLabelStyle, children: [
3560
+ "Submit Button Label",
3561
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
3562
+ "input",
3563
+ {
3564
+ onChange: (event) => setDoc((prev) => ({ ...prev, submitButtonLabel: event.target.value })),
3565
+ style: inputStyle,
3566
+ type: "text",
3567
+ value: doc.submitButtonLabel
3568
+ }
3569
+ )
3570
+ ] }),
3571
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("label", { style: fieldLabelStyle, children: [
3572
+ "Success Message",
3573
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
3574
+ "input",
3575
+ {
3576
+ onChange: (event) => setDoc((prev) => ({ ...prev, successMessage: event.target.value })),
3577
+ style: inputStyle,
3578
+ type: "text",
3579
+ value: doc.successMessage
3580
+ }
3581
+ )
3582
+ ] }),
3583
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("label", { style: fieldLabelStyle, children: [
3584
+ "Error Message",
3585
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
3586
+ "input",
3587
+ {
3588
+ onChange: (event) => setDoc((prev) => ({ ...prev, errorMessage: event.target.value })),
3589
+ style: inputStyle,
3590
+ type: "text",
3591
+ value: doc.errorMessage
3592
+ }
3593
+ )
3594
+ ] }),
3595
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("label", { style: fieldLabelStyle, children: [
3596
+ "Disabled Message",
3597
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
3598
+ "input",
3599
+ {
3600
+ onChange: (event) => setDoc((prev) => ({ ...prev, disabledMessage: event.target.value })),
3601
+ style: inputStyle,
3602
+ type: "text",
3603
+ value: doc.disabledMessage
3604
+ }
3605
+ )
3606
+ ] }),
3607
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(
3608
+ "div",
3609
+ {
3610
+ style: {
3611
+ background: "var(--theme-elevation-0)",
3612
+ border: "1px solid var(--theme-elevation-200)",
3613
+ borderRadius: 14,
3614
+ padding: "0.85rem"
3615
+ },
3616
+ children: [
3617
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { style: { fontWeight: 900, marginBottom: "0.65rem" }, children: "Service Options" }),
3618
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { style: { display: "grid", gap: "0.55rem" }, children: doc.serviceOptions.map((option, index) => /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { style: { display: "flex", gap: "0.5rem" }, children: [
3619
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
3620
+ "input",
3621
+ {
3622
+ onChange: (event) => setDoc((prev) => ({
3623
+ ...prev,
3624
+ serviceOptions: prev.serviceOptions.map(
3625
+ (row, rowIndex) => rowIndex === index ? { label: event.target.value } : row
3626
+ )
3627
+ })),
3628
+ style: inputStyle,
3629
+ type: "text",
3630
+ value: option.label
3631
+ }
3632
+ ),
3633
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
3634
+ "button",
3635
+ {
3636
+ onClick: () => setDoc((prev) => ({
3637
+ ...prev,
3638
+ serviceOptions: prev.serviceOptions.length > 1 ? prev.serviceOptions.filter((_, rowIndex) => rowIndex !== index) : prev.serviceOptions
3639
+ })),
3640
+ style: ghostButtonStyle,
3641
+ type: "button",
3642
+ children: "Remove"
3643
+ }
3644
+ )
3645
+ ] }, `${index}-${option.label}`)) }),
3646
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
3647
+ "button",
3648
+ {
3649
+ onClick: () => setDoc((prev) => ({
3650
+ ...prev,
3651
+ serviceOptions: [...prev.serviceOptions, { label: "" }]
3652
+ })),
3653
+ style: { ...ghostButtonStyle, marginTop: "0.7rem" },
3654
+ type: "button",
3655
+ children: "Add Service"
3656
+ }
3657
+ )
3658
+ ]
3659
+ }
3660
+ ),
3661
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { style: { display: "flex", gap: "0.6rem" }, children: [
3662
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("button", { disabled: isSaving, onClick: () => void save(), style: buttonStyle, type: "button", children: isSaving ? "Saving\u2026" : "Save Form Settings" }),
3663
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
3664
+ "a",
3665
+ {
3666
+ href: rawGlobalPath,
3667
+ style: {
3668
+ ...ghostButtonStyle,
3669
+ alignItems: "center",
3670
+ display: "inline-flex",
3671
+ justifyContent: "center",
3672
+ textDecoration: "none"
3673
+ },
3674
+ children: "Open Raw Global"
3675
+ }
3676
+ )
3677
+ ] })
3678
+ ] }) : null
3679
+ ] });
3680
+ }
3681
+
3682
+ // src/admin/components/studio/AdminStudioMediaView.tsx
3683
+ var import_ui9 = require("@payloadcms/ui");
3684
+ var import_jsx_runtime20 = require("react/jsx-runtime");
3685
+ var getPropString7 = (props, key, fallback) => {
3686
+ if (!props || typeof props !== "object") return fallback;
3687
+ const direct = props[key];
3688
+ if (typeof direct === "string" && direct.length > 0) return direct;
3689
+ const clientProps = props.clientProps;
3690
+ if (clientProps && typeof clientProps === "object") {
3691
+ const nested = clientProps[key];
3692
+ if (typeof nested === "string" && nested.length > 0) return nested;
3014
3693
  }
3015
- const pagesCollectionSlug = getPropString7(props, "pagesCollectionSlug", "pages");
3694
+ return fallback;
3695
+ };
3696
+ function AdminStudioMediaView(props) {
3016
3697
  const mediaCollectionSlug = getPropString7(props, "mediaCollectionSlug", "media");
3698
+ const adminBasePath = useAdminBasePath();
3699
+ const mediaPath = resolveAdminPath(adminBasePath, `/collections/${mediaCollectionSlug}`);
3700
+ const mediaViewPath = resolveAdminPath(adminBasePath, "/media");
3701
+ return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(import_jsx_runtime20.Fragment, { children: [
3702
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_ui9.SetStepNav, { nav: [{ label: "Media", url: mediaViewPath }] }),
3703
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("h1", { style: { margin: 0 }, children: "Media" }),
3704
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("p", { style: { color: "var(--theme-elevation-600)", marginTop: "0.35rem" }, children: "Media management is currently using Payload's library." }),
3705
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { style: { display: "grid", gap: "0.6rem", marginTop: "1rem" }, children: /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(
3706
+ "a",
3707
+ {
3708
+ href: mediaPath,
3709
+ style: {
3710
+ background: "var(--theme-elevation-0)",
3711
+ border: "1px solid var(--theme-elevation-150)",
3712
+ borderRadius: 16,
3713
+ color: "inherit",
3714
+ padding: "0.85rem 1rem",
3715
+ textDecoration: "none"
3716
+ },
3717
+ children: [
3718
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { style: { fontWeight: 900 }, children: "Open Media Library" }),
3719
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { style: { color: "var(--theme-elevation-600)", fontSize: "0.9rem" }, children: mediaPath })
3720
+ ]
3721
+ }
3722
+ ) })
3723
+ ] });
3724
+ }
3725
+
3726
+ // src/admin/components/studio/AdminStudioFormsView.tsx
3727
+ var import_react16 = require("react");
3728
+ var import_ui10 = require("@payloadcms/ui");
3729
+ var import_jsx_runtime21 = require("react/jsx-runtime");
3730
+ var isAdmin3 = (user) => {
3731
+ if (!user || typeof user !== "object") return false;
3732
+ const role = user.role;
3733
+ return typeof role === "string" && role === "admin";
3734
+ };
3735
+ var isEditor2 = (user) => {
3736
+ if (!user || typeof user !== "object") return false;
3737
+ const role = user.role;
3738
+ return typeof role === "string" && role === "editor";
3739
+ };
3740
+ var canReviewForms = (user) => isAdmin3(user) || isEditor2(user);
3741
+ var getPropString8 = (props, key, fallback) => {
3742
+ if (!props || typeof props !== "object") return fallback;
3743
+ const direct = props[key];
3744
+ if (typeof direct === "string" && direct.length > 0) return direct;
3745
+ const clientProps = props.clientProps;
3746
+ if (clientProps && typeof clientProps === "object") {
3747
+ const nested = clientProps[key];
3748
+ if (typeof nested === "string" && nested.length > 0) return nested;
3749
+ }
3750
+ return fallback;
3751
+ };
3752
+ var formatDate = (value) => {
3753
+ if (typeof value !== "string" || value.length === 0) {
3754
+ return "Unknown date";
3755
+ }
3756
+ const parsed = new Date(value);
3757
+ if (Number.isNaN(parsed.getTime())) {
3758
+ return value;
3759
+ }
3760
+ return parsed.toLocaleString();
3761
+ };
3762
+ var formatFileSize = (value) => {
3763
+ if (typeof value !== "number" || !Number.isFinite(value) || value <= 0) {
3764
+ return null;
3765
+ }
3766
+ if (value < 1024) return `${value} B`;
3767
+ if (value < 1024 * 1024) return `${(value / 1024).toFixed(1)} KB`;
3768
+ return `${(value / (1024 * 1024)).toFixed(1)} MB`;
3769
+ };
3770
+ var getFieldEntries = (value) => {
3771
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
3772
+ return [];
3773
+ }
3774
+ return Object.entries(value);
3775
+ };
3776
+ var getString = (value) => typeof value === "string" && value.trim().length > 0 ? value.trim() : null;
3777
+ var getSubmissionIdentity = (value) => {
3778
+ const entries = getFieldEntries(value);
3779
+ const byKey = Object.fromEntries(entries);
3780
+ const firstName = getString(byKey.firstName) || getString(byKey.first_name);
3781
+ const lastName = getString(byKey.lastName) || getString(byKey.last_name);
3782
+ const email = getString(byKey.email) || getString(byKey.contactEmail) || getString(byKey.contact_email);
3783
+ const fullName = getString(byKey.name) || [firstName, lastName].filter(Boolean).join(" ").trim() || void 0;
3784
+ return {
3785
+ ...email ? { email } : {},
3786
+ ...fullName ? { name: fullName } : {}
3787
+ };
3788
+ };
3789
+ var renderValue = (value) => {
3790
+ if (value === null || value === void 0 || value === "") {
3791
+ return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { style: { color: "var(--theme-elevation-500)" }, children: "\u2014" });
3792
+ }
3793
+ if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
3794
+ return String(value);
3795
+ }
3796
+ if (Array.isArray(value)) {
3797
+ if (value.length === 0) {
3798
+ return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { style: { color: "var(--theme-elevation-500)" }, children: "\u2014" });
3799
+ }
3800
+ const primitiveValues = value.every(
3801
+ (entry) => typeof entry === "string" || typeof entry === "number" || typeof entry === "boolean" || entry === null
3802
+ );
3803
+ if (primitiveValues) {
3804
+ return value.map((entry) => String(entry)).join(", ");
3805
+ }
3806
+ return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
3807
+ "pre",
3808
+ {
3809
+ style: {
3810
+ margin: 0,
3811
+ overflowX: "auto",
3812
+ whiteSpace: "pre-wrap",
3813
+ wordBreak: "break-word"
3814
+ },
3815
+ children: JSON.stringify(value, null, 2)
3816
+ }
3817
+ );
3818
+ }
3819
+ if (typeof value === "object") {
3820
+ return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
3821
+ "pre",
3822
+ {
3823
+ style: {
3824
+ margin: 0,
3825
+ overflowX: "auto",
3826
+ whiteSpace: "pre-wrap",
3827
+ wordBreak: "break-word"
3828
+ },
3829
+ children: JSON.stringify(value, null, 2)
3830
+ }
3831
+ );
3832
+ }
3833
+ return String(value);
3834
+ };
3835
+ var getFormID = (value) => {
3836
+ if (typeof value === "string" || typeof value === "number") {
3837
+ return String(value);
3838
+ }
3839
+ if (value && typeof value === "object") {
3840
+ const id = value.id;
3841
+ if (typeof id === "string" || typeof id === "number") {
3842
+ return String(id);
3843
+ }
3844
+ }
3845
+ return null;
3846
+ };
3847
+ var getUploads = (value) => {
3848
+ if (!Array.isArray(value)) {
3849
+ return [];
3850
+ }
3851
+ return value.map((entry) => {
3852
+ if (typeof entry === "string" || typeof entry === "number") {
3853
+ return { id: entry };
3854
+ }
3855
+ if (entry && typeof entry === "object") {
3856
+ return entry;
3857
+ }
3858
+ return null;
3859
+ }).filter((entry) => Boolean(entry));
3860
+ };
3861
+ var panelStyle = {
3862
+ background: "var(--theme-elevation-0)",
3863
+ border: "1px solid var(--theme-elevation-150)",
3864
+ borderRadius: 18
3865
+ };
3866
+ function AdminStudioFormsView(props) {
3867
+ const { user } = (0, import_ui10.useAuth)();
3868
+ const formsCollectionSlug = getPropString8(props, "formsCollectionSlug", "forms");
3869
+ const formSubmissionsCollectionSlug = getPropString8(
3870
+ props,
3871
+ "formSubmissionsCollectionSlug",
3872
+ "form-submissions"
3873
+ );
3874
+ const formUploadsCollectionSlug = getPropString8(props, "formUploadsCollectionSlug", "form-uploads");
3875
+ const adminBasePath = useAdminBasePath();
3876
+ const formsViewPath = resolveAdminPath(adminBasePath, "/studio-forms");
3877
+ const rawFormsPath = resolveAdminPath(adminBasePath, `/collections/${formsCollectionSlug}`);
3878
+ const rawSubmissionsPath = resolveAdminPath(
3879
+ adminBasePath,
3880
+ `/collections/${formSubmissionsCollectionSlug}`
3881
+ );
3882
+ const rawUploadsPath = resolveAdminPath(adminBasePath, `/collections/${formUploadsCollectionSlug}`);
3883
+ const [selectedFormID, setSelectedFormID] = (0, import_react16.useState)("");
3884
+ const [forms, setForms] = (0, import_react16.useState)([]);
3885
+ const [submissions, setSubmissions] = (0, import_react16.useState)([]);
3886
+ const [formsLoading, setFormsLoading] = (0, import_react16.useState)(true);
3887
+ const [submissionsLoading, setSubmissionsLoading] = (0, import_react16.useState)(false);
3888
+ const [formsError, setFormsError] = (0, import_react16.useState)(null);
3889
+ const [submissionsError, setSubmissionsError] = (0, import_react16.useState)(null);
3890
+ const selectedForm = (0, import_react16.useMemo)(
3891
+ () => forms.find((form) => {
3892
+ const id = typeof form.id === "string" || typeof form.id === "number" ? String(form.id) : "";
3893
+ return selectedFormID.length > 0 && id === selectedFormID;
3894
+ }) || null,
3895
+ [forms, selectedFormID]
3896
+ );
3897
+ (0, import_react16.useEffect)(() => {
3898
+ if (typeof window === "undefined") {
3899
+ return;
3900
+ }
3901
+ const params = new URLSearchParams(window.location.search);
3902
+ const formID = params.get("form");
3903
+ if (formID) {
3904
+ setSelectedFormID(formID);
3905
+ }
3906
+ }, []);
3907
+ (0, import_react16.useEffect)(() => {
3908
+ if (!canReviewForms(user)) {
3909
+ return;
3910
+ }
3911
+ let cancelled = false;
3912
+ const run = async () => {
3913
+ setFormsLoading(true);
3914
+ setFormsError(null);
3915
+ try {
3916
+ const params = new URLSearchParams({
3917
+ depth: "0",
3918
+ limit: "100",
3919
+ sort: "title"
3920
+ });
3921
+ const response = await fetch(`/api/${formsCollectionSlug}?${params.toString()}`, {
3922
+ credentials: "include"
3923
+ });
3924
+ if (!response.ok) {
3925
+ const body = await response.text();
3926
+ throw new Error(body || "Failed to fetch forms");
3927
+ }
3928
+ const next = await response.json();
3929
+ const docs = Array.isArray(next.docs) ? next.docs : [];
3930
+ if (cancelled) return;
3931
+ setForms(docs);
3932
+ setSelectedFormID((current) => {
3933
+ if (docs.length === 0) {
3934
+ return "";
3935
+ }
3936
+ const knownSelected = docs.some((doc) => {
3937
+ const id = typeof doc.id === "string" || typeof doc.id === "number" ? String(doc.id) : "";
3938
+ return id === current;
3939
+ });
3940
+ if (knownSelected) {
3941
+ return current;
3942
+ }
3943
+ const firstID = docs[0]?.id;
3944
+ return typeof firstID === "string" || typeof firstID === "number" ? String(firstID) : "";
3945
+ });
3946
+ } catch (error) {
3947
+ if (!cancelled) {
3948
+ setFormsError(error instanceof Error ? error.message : "Failed to fetch forms");
3949
+ }
3950
+ } finally {
3951
+ if (!cancelled) {
3952
+ setFormsLoading(false);
3953
+ }
3954
+ }
3955
+ };
3956
+ void run();
3957
+ return () => {
3958
+ cancelled = true;
3959
+ };
3960
+ }, [formsCollectionSlug, user]);
3961
+ (0, import_react16.useEffect)(() => {
3962
+ if (!selectedFormID || !canReviewForms(user)) {
3963
+ setSubmissions([]);
3964
+ return;
3965
+ }
3966
+ let cancelled = false;
3967
+ const run = async () => {
3968
+ setSubmissionsLoading(true);
3969
+ setSubmissionsError(null);
3970
+ try {
3971
+ const params = new URLSearchParams({
3972
+ depth: "1",
3973
+ limit: "100",
3974
+ sort: "-submittedAt"
3975
+ });
3976
+ params.set("where[form][equals]", selectedFormID);
3977
+ const response = await fetch(`/api/${formSubmissionsCollectionSlug}?${params.toString()}`, {
3978
+ credentials: "include"
3979
+ });
3980
+ if (!response.ok) {
3981
+ const body = await response.text();
3982
+ throw new Error(body || "Failed to fetch submissions");
3983
+ }
3984
+ const next = await response.json();
3985
+ if (!cancelled) {
3986
+ setSubmissions(Array.isArray(next.docs) ? next.docs : []);
3987
+ }
3988
+ } catch (error) {
3989
+ if (!cancelled) {
3990
+ setSubmissionsError(
3991
+ error instanceof Error ? error.message : "Failed to fetch form submissions"
3992
+ );
3993
+ }
3994
+ } finally {
3995
+ if (!cancelled) {
3996
+ setSubmissionsLoading(false);
3997
+ }
3998
+ }
3999
+ };
4000
+ void run();
4001
+ return () => {
4002
+ cancelled = true;
4003
+ };
4004
+ }, [formSubmissionsCollectionSlug, selectedFormID, user]);
4005
+ (0, import_react16.useEffect)(() => {
4006
+ if (typeof window === "undefined" || !selectedFormID) {
4007
+ return;
4008
+ }
4009
+ const url = new URL(window.location.href);
4010
+ url.searchParams.set("form", selectedFormID);
4011
+ window.history.replaceState({}, "", url.toString());
4012
+ }, [selectedFormID]);
4013
+ if (!canReviewForms(user)) {
4014
+ return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(import_jsx_runtime21.Fragment, { children: [
4015
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_ui10.SetStepNav, { nav: [{ label: "Forms", url: formsViewPath }] }),
4016
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("h1", { style: { margin: 0 }, children: "Forms" }),
4017
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("p", { style: { color: "var(--theme-elevation-600)", marginTop: "0.35rem" }, children: "You do not have access to this page." })
4018
+ ] });
4019
+ }
4020
+ const selectedTitle = selectedForm && typeof selectedForm.title === "string" && selectedForm.title || "Forms";
4021
+ const selectedSlug = selectedForm && typeof selectedForm.slug === "string" && selectedForm.slug || null;
4022
+ const selectedStepCount = Array.isArray(selectedForm?.steps) ? selectedForm.steps.length : 0;
4023
+ const selectedFieldCount = Array.isArray(selectedForm?.steps) ? selectedForm.steps.reduce((count, step) => {
4024
+ if (!step || typeof step !== "object") return count;
4025
+ const fields = step.fields;
4026
+ return count + (Array.isArray(fields) ? fields.length : 0);
4027
+ }, 0) : 0;
4028
+ return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(import_jsx_runtime21.Fragment, { children: [
4029
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_ui10.SetStepNav, { nav: [{ label: "Forms", url: formsViewPath }] }),
4030
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { style: { alignItems: "flex-end", display: "flex", flexWrap: "wrap", gap: "0.75rem" }, children: [
4031
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { style: { flex: 1, minWidth: 240 }, children: [
4032
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("h1", { style: { margin: 0 }, children: "Forms" }),
4033
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("p", { style: { color: "var(--theme-elevation-600)", marginTop: "0.35rem" }, children: "Review your forms, responses, and any uploaded files in one place." })
4034
+ ] }),
4035
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { style: { display: "flex", flexWrap: "wrap", gap: "0.5rem" }, children: [
4036
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
4037
+ "a",
4038
+ {
4039
+ href: rawFormsPath,
4040
+ style: {
4041
+ background: "var(--theme-elevation-900)",
4042
+ borderRadius: 12,
4043
+ color: "var(--theme-elevation-0)",
4044
+ fontWeight: 800,
4045
+ padding: "0.55rem 0.85rem",
4046
+ textDecoration: "none"
4047
+ },
4048
+ children: "Open Forms Collection"
4049
+ }
4050
+ ),
4051
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
4052
+ "a",
4053
+ {
4054
+ href: rawSubmissionsPath,
4055
+ style: {
4056
+ border: "1px solid var(--theme-elevation-200)",
4057
+ borderRadius: 12,
4058
+ color: "inherit",
4059
+ fontWeight: 800,
4060
+ padding: "0.55rem 0.85rem",
4061
+ textDecoration: "none"
4062
+ },
4063
+ children: "Open Submissions"
4064
+ }
4065
+ ),
4066
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
4067
+ "a",
4068
+ {
4069
+ href: rawUploadsPath,
4070
+ style: {
4071
+ border: "1px solid var(--theme-elevation-200)",
4072
+ borderRadius: 12,
4073
+ color: "inherit",
4074
+ fontWeight: 800,
4075
+ padding: "0.55rem 0.85rem",
4076
+ textDecoration: "none"
4077
+ },
4078
+ children: "Open Uploads"
4079
+ }
4080
+ )
4081
+ ] })
4082
+ ] }),
4083
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(
4084
+ "div",
4085
+ {
4086
+ style: {
4087
+ display: "grid",
4088
+ gap: "1rem",
4089
+ gridTemplateColumns: "minmax(260px, 320px) minmax(0, 1fr)",
4090
+ marginTop: "1rem"
4091
+ },
4092
+ children: [
4093
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("section", { style: { ...panelStyle, padding: "1rem" }, children: [
4094
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { style: { fontSize: "0.82rem", fontWeight: 900, letterSpacing: "0.08em", textTransform: "uppercase" }, children: "Site forms" }),
4095
+ formsLoading ? /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { style: { color: "var(--theme-elevation-600)", marginTop: "0.85rem" }, children: "Loading forms\u2026" }) : null,
4096
+ formsError ? /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { style: { color: "crimson", marginTop: "0.85rem" }, children: formsError }) : null,
4097
+ !formsLoading && !formsError && forms.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
4098
+ "div",
4099
+ {
4100
+ style: {
4101
+ border: "1px dashed var(--theme-elevation-300)",
4102
+ borderRadius: 16,
4103
+ color: "var(--theme-elevation-700)",
4104
+ marginTop: "0.85rem",
4105
+ padding: "0.9rem"
4106
+ },
4107
+ children: "No forms found."
4108
+ }
4109
+ ) : null,
4110
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { style: { display: "grid", gap: "0.55rem", marginTop: "0.85rem" }, children: forms.map((form) => {
4111
+ const id = typeof form.id === "string" || typeof form.id === "number" ? String(form.id) : "";
4112
+ if (!id) return null;
4113
+ const title = typeof form.title === "string" ? form.title : "Untitled Form";
4114
+ const slug = typeof form.slug === "string" ? form.slug : "";
4115
+ const isSelected = id === selectedFormID;
4116
+ return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(
4117
+ "button",
4118
+ {
4119
+ onClick: () => setSelectedFormID(id),
4120
+ style: {
4121
+ background: isSelected ? "var(--theme-elevation-50)" : "var(--theme-elevation-0)",
4122
+ border: `1px solid ${isSelected ? "var(--theme-elevation-300)" : "var(--theme-elevation-150)"}`,
4123
+ borderRadius: 16,
4124
+ cursor: "pointer",
4125
+ padding: "0.85rem",
4126
+ textAlign: "left"
4127
+ },
4128
+ type: "button",
4129
+ children: [
4130
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { style: { fontWeight: 900 }, children: title }),
4131
+ slug ? /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
4132
+ "div",
4133
+ {
4134
+ style: {
4135
+ color: "var(--theme-elevation-600)",
4136
+ fontSize: "0.9rem",
4137
+ marginTop: "0.2rem"
4138
+ },
4139
+ children: slug
4140
+ }
4141
+ ) : null
4142
+ ]
4143
+ },
4144
+ id
4145
+ );
4146
+ }) })
4147
+ ] }),
4148
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("section", { style: { display: "grid", gap: "1rem" }, children: [
4149
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { style: { ...panelStyle, padding: "1rem" }, children: [
4150
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(
4151
+ "div",
4152
+ {
4153
+ style: {
4154
+ alignItems: "flex-start",
4155
+ display: "flex",
4156
+ flexWrap: "wrap",
4157
+ gap: "0.9rem",
4158
+ justifyContent: "space-between"
4159
+ },
4160
+ children: [
4161
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { children: [
4162
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
4163
+ "div",
4164
+ {
4165
+ style: {
4166
+ color: "var(--theme-elevation-600)",
4167
+ fontSize: "0.82rem",
4168
+ fontWeight: 900,
4169
+ letterSpacing: "0.08em",
4170
+ textTransform: "uppercase"
4171
+ },
4172
+ children: "Selected form"
4173
+ }
4174
+ ),
4175
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("h2", { style: { margin: "0.2rem 0 0", fontSize: "1.45rem" }, children: selectedTitle }),
4176
+ selectedSlug ? /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { style: { color: "var(--theme-elevation-600)", marginTop: "0.2rem" }, children: selectedSlug }) : null
4177
+ ] }),
4178
+ selectedFormID ? /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
4179
+ "a",
4180
+ {
4181
+ href: `${rawFormsPath}/${selectedFormID}`,
4182
+ style: {
4183
+ border: "1px solid var(--theme-elevation-200)",
4184
+ borderRadius: 12,
4185
+ color: "inherit",
4186
+ fontWeight: 800,
4187
+ padding: "0.55rem 0.85rem",
4188
+ textDecoration: "none"
4189
+ },
4190
+ children: "Edit Form"
4191
+ }
4192
+ ) : null
4193
+ ]
4194
+ }
4195
+ ),
4196
+ selectedForm ? /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(
4197
+ "div",
4198
+ {
4199
+ style: {
4200
+ display: "grid",
4201
+ gap: "0.75rem",
4202
+ gridTemplateColumns: "repeat(auto-fit, minmax(180px, 1fr))",
4203
+ marginTop: "1rem"
4204
+ },
4205
+ children: [
4206
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { style: { ...panelStyle, padding: "0.8rem 0.9rem" }, children: [
4207
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { style: { color: "var(--theme-elevation-600)", fontSize: "0.82rem" }, children: "Steps" }),
4208
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { style: { fontSize: "1.35rem", fontWeight: 900, marginTop: "0.2rem" }, children: selectedStepCount })
4209
+ ] }),
4210
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { style: { ...panelStyle, padding: "0.8rem 0.9rem" }, children: [
4211
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { style: { color: "var(--theme-elevation-600)", fontSize: "0.82rem" }, children: "Fields" }),
4212
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { style: { fontSize: "1.35rem", fontWeight: 900, marginTop: "0.2rem" }, children: selectedFieldCount })
4213
+ ] }),
4214
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { style: { ...panelStyle, padding: "0.8rem 0.9rem" }, children: [
4215
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { style: { color: "var(--theme-elevation-600)", fontSize: "0.82rem" }, children: "Submit label" }),
4216
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { style: { fontSize: "1rem", fontWeight: 900, marginTop: "0.2rem" }, children: typeof selectedForm.submitLabel === "string" && selectedForm.submitLabel.length > 0 ? selectedForm.submitLabel : "Submit" })
4217
+ ] }),
4218
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { style: { ...panelStyle, padding: "0.8rem 0.9rem" }, children: [
4219
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { style: { color: "var(--theme-elevation-600)", fontSize: "0.82rem" }, children: "Updated" }),
4220
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { style: { fontSize: "1rem", fontWeight: 900, marginTop: "0.2rem" }, children: formatDate(selectedForm.updatedAt) })
4221
+ ] })
4222
+ ]
4223
+ }
4224
+ ) : /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { style: { color: "var(--theme-elevation-600)", marginTop: "1rem" }, children: "Pick a form to review its responses." })
4225
+ ] }),
4226
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { style: { ...panelStyle, padding: "1rem" }, children: [
4227
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(
4228
+ "div",
4229
+ {
4230
+ style: {
4231
+ alignItems: "center",
4232
+ display: "flex",
4233
+ flexWrap: "wrap",
4234
+ gap: "0.75rem",
4235
+ justifyContent: "space-between"
4236
+ },
4237
+ children: [
4238
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { children: [
4239
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("h2", { style: { fontSize: "1.2rem", margin: 0 }, children: "Responses" }),
4240
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("p", { style: { color: "var(--theme-elevation-600)", margin: "0.25rem 0 0" }, children: "Latest submissions and any files they uploaded." })
4241
+ ] }),
4242
+ selectedFormID ? /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
4243
+ "a",
4244
+ {
4245
+ href: rawSubmissionsPath,
4246
+ style: {
4247
+ border: "1px solid var(--theme-elevation-200)",
4248
+ borderRadius: 12,
4249
+ color: "inherit",
4250
+ fontWeight: 800,
4251
+ padding: "0.55rem 0.85rem",
4252
+ textDecoration: "none"
4253
+ },
4254
+ children: "Raw Submissions"
4255
+ }
4256
+ ) : null
4257
+ ]
4258
+ }
4259
+ ),
4260
+ submissionsLoading ? /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { style: { color: "var(--theme-elevation-600)", marginTop: "1rem" }, children: "Loading responses\u2026" }) : null,
4261
+ submissionsError ? /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { style: { color: "crimson", marginTop: "1rem" }, children: submissionsError }) : null,
4262
+ !submissionsLoading && !submissionsError && selectedFormID && submissions.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
4263
+ "div",
4264
+ {
4265
+ style: {
4266
+ border: "1px dashed var(--theme-elevation-300)",
4267
+ borderRadius: 16,
4268
+ color: "var(--theme-elevation-700)",
4269
+ marginTop: "1rem",
4270
+ padding: "1rem"
4271
+ },
4272
+ children: "No responses yet for this form."
4273
+ }
4274
+ ) : null,
4275
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { style: { display: "grid", gap: "0.9rem", marginTop: "1rem" }, children: submissions.map((submission) => {
4276
+ const id = typeof submission.id === "string" || typeof submission.id === "number" ? String(submission.id) : "";
4277
+ if (!id) return null;
4278
+ const submissionData = submission.data;
4279
+ const identity = getSubmissionIdentity(submissionData);
4280
+ const uploads = getUploads(submission.files);
4281
+ const formSlug = getString(submission.formSlug);
4282
+ const submissionFormID = getFormID(submission.form);
4283
+ return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("article", { style: { ...panelStyle, padding: "1rem" }, children: [
4284
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(
4285
+ "div",
4286
+ {
4287
+ style: {
4288
+ alignItems: "flex-start",
4289
+ display: "flex",
4290
+ flexWrap: "wrap",
4291
+ gap: "0.75rem",
4292
+ justifyContent: "space-between"
4293
+ },
4294
+ children: [
4295
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { children: [
4296
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { style: { fontWeight: 900 }, children: identity.name || identity.email || "Submission" }),
4297
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { style: { color: "var(--theme-elevation-600)", marginTop: "0.2rem" }, children: [
4298
+ formatDate(submission.submittedAt),
4299
+ formSlug ? ` \xB7 ${formSlug}` : ""
4300
+ ] })
4301
+ ] }),
4302
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { style: { display: "flex", flexWrap: "wrap", gap: "0.5rem" }, children: [
4303
+ submissionFormID ? /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
4304
+ "a",
4305
+ {
4306
+ href: `${rawFormsPath}/${submissionFormID}`,
4307
+ style: {
4308
+ border: "1px solid var(--theme-elevation-200)",
4309
+ borderRadius: 999,
4310
+ color: "inherit",
4311
+ fontSize: "0.88rem",
4312
+ fontWeight: 800,
4313
+ padding: "0.3rem 0.65rem",
4314
+ textDecoration: "none"
4315
+ },
4316
+ children: "Form"
4317
+ }
4318
+ ) : null,
4319
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
4320
+ "a",
4321
+ {
4322
+ href: `${rawSubmissionsPath}/${id}`,
4323
+ style: {
4324
+ border: "1px solid var(--theme-elevation-200)",
4325
+ borderRadius: 999,
4326
+ color: "inherit",
4327
+ fontSize: "0.88rem",
4328
+ fontWeight: 800,
4329
+ padding: "0.3rem 0.65rem",
4330
+ textDecoration: "none"
4331
+ },
4332
+ children: "Submission"
4333
+ }
4334
+ )
4335
+ ] })
4336
+ ]
4337
+ }
4338
+ ),
4339
+ identity.name || identity.email ? /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(
4340
+ "div",
4341
+ {
4342
+ style: {
4343
+ display: "grid",
4344
+ gap: "0.65rem",
4345
+ gridTemplateColumns: "repeat(auto-fit, minmax(180px, 1fr))",
4346
+ marginTop: "0.9rem"
4347
+ },
4348
+ children: [
4349
+ identity.name ? /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { style: { ...panelStyle, padding: "0.75rem 0.85rem" }, children: [
4350
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { style: { color: "var(--theme-elevation-600)", fontSize: "0.82rem" }, children: "Name" }),
4351
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { style: { fontWeight: 900, marginTop: "0.2rem" }, children: identity.name })
4352
+ ] }) : null,
4353
+ identity.email ? /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { style: { ...panelStyle, padding: "0.75rem 0.85rem" }, children: [
4354
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { style: { color: "var(--theme-elevation-600)", fontSize: "0.82rem" }, children: "Email" }),
4355
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { style: { fontWeight: 900, marginTop: "0.2rem" }, children: identity.email })
4356
+ ] }) : null
4357
+ ]
4358
+ }
4359
+ ) : null,
4360
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { style: { marginTop: "1rem" }, children: [
4361
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
4362
+ "div",
4363
+ {
4364
+ style: {
4365
+ color: "var(--theme-elevation-600)",
4366
+ fontSize: "0.82rem",
4367
+ fontWeight: 900,
4368
+ letterSpacing: "0.08em",
4369
+ marginBottom: "0.5rem",
4370
+ textTransform: "uppercase"
4371
+ },
4372
+ children: "Response data"
4373
+ }
4374
+ ),
4375
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { style: { display: "grid", gap: "0.55rem" }, children: getFieldEntries(submissionData).map(([key, value]) => /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(
4376
+ "div",
4377
+ {
4378
+ style: {
4379
+ ...panelStyle,
4380
+ display: "grid",
4381
+ gap: "0.45rem",
4382
+ gridTemplateColumns: "minmax(160px, 220px) minmax(0, 1fr)",
4383
+ padding: "0.8rem 0.9rem"
4384
+ },
4385
+ children: [
4386
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
4387
+ "div",
4388
+ {
4389
+ style: {
4390
+ color: "var(--theme-elevation-700)",
4391
+ fontSize: "0.92rem",
4392
+ fontWeight: 900,
4393
+ overflowWrap: "anywhere"
4394
+ },
4395
+ children: key
4396
+ }
4397
+ ),
4398
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { style: { overflowWrap: "anywhere" }, children: renderValue(value) })
4399
+ ]
4400
+ },
4401
+ key
4402
+ )) })
4403
+ ] }),
4404
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { style: { marginTop: "1rem" }, children: [
4405
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
4406
+ "div",
4407
+ {
4408
+ style: {
4409
+ color: "var(--theme-elevation-600)",
4410
+ fontSize: "0.82rem",
4411
+ fontWeight: 900,
4412
+ letterSpacing: "0.08em",
4413
+ marginBottom: "0.5rem",
4414
+ textTransform: "uppercase"
4415
+ },
4416
+ children: "Uploads"
4417
+ }
4418
+ ),
4419
+ uploads.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { style: { color: "var(--theme-elevation-600)" }, children: "No files attached." }) : /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { style: { display: "grid", gap: "0.55rem" }, children: uploads.map((upload, index) => {
4420
+ const uploadID = typeof upload.id === "string" || typeof upload.id === "number" ? String(upload.id) : "";
4421
+ if (!uploadID) return null;
4422
+ const label = typeof upload.filename === "string" && upload.filename || `Upload ${index + 1}`;
4423
+ const meta = [
4424
+ typeof upload.mimeType === "string" ? upload.mimeType : null,
4425
+ formatFileSize(upload.filesize)
4426
+ ].filter(Boolean);
4427
+ return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(
4428
+ "a",
4429
+ {
4430
+ href: `${rawUploadsPath}/${uploadID}`,
4431
+ style: {
4432
+ ...panelStyle,
4433
+ color: "inherit",
4434
+ display: "flex",
4435
+ gap: "0.75rem",
4436
+ justifyContent: "space-between",
4437
+ padding: "0.8rem 0.9rem",
4438
+ textDecoration: "none"
4439
+ },
4440
+ children: [
4441
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { children: [
4442
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { style: { fontWeight: 900 }, children: label }),
4443
+ meta.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
4444
+ "div",
4445
+ {
4446
+ style: {
4447
+ color: "var(--theme-elevation-600)",
4448
+ fontSize: "0.9rem",
4449
+ marginTop: "0.2rem"
4450
+ },
4451
+ children: meta.join(" \xB7 ")
4452
+ }
4453
+ ) : null
4454
+ ] }),
4455
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { style: { color: "var(--theme-elevation-600)", fontWeight: 800 }, children: "Open" })
4456
+ ]
4457
+ },
4458
+ uploadID
4459
+ );
4460
+ }) })
4461
+ ] })
4462
+ ] }, id);
4463
+ }) })
4464
+ ] })
4465
+ ] })
4466
+ ]
4467
+ }
4468
+ )
4469
+ ] });
4470
+ }
4471
+
4472
+ // src/admin/components/studio/AdminStudioToolsView.tsx
4473
+ var import_ui11 = require("@payloadcms/ui");
4474
+ var import_jsx_runtime22 = require("react/jsx-runtime");
4475
+ var isAdmin4 = (user) => {
4476
+ if (!user || typeof user !== "object") return false;
4477
+ const role = user.role;
4478
+ return typeof role === "string" && role === "admin";
4479
+ };
4480
+ var getPropString9 = (props, key, fallback) => {
4481
+ if (!props || typeof props !== "object") return fallback;
4482
+ const direct = props[key];
4483
+ if (typeof direct === "string" && direct.length > 0) return direct;
4484
+ const clientProps = props.clientProps;
4485
+ if (clientProps && typeof clientProps === "object") {
4486
+ const nested = clientProps[key];
4487
+ if (typeof nested === "string" && nested.length > 0) return nested;
4488
+ }
4489
+ return fallback;
4490
+ };
4491
+ function AdminStudioToolsView(props) {
4492
+ const { user } = (0, import_ui11.useAuth)();
4493
+ const adminBasePath = useAdminBasePath();
4494
+ const toolsPath = resolveAdminPath(adminBasePath, "/tools");
4495
+ if (!isAdmin4(user)) {
4496
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(import_jsx_runtime22.Fragment, { children: [
4497
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_ui11.SetStepNav, { nav: [{ label: "Admin Tools", url: toolsPath }] }),
4498
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("h1", { style: { margin: 0 }, children: "Admin Tools" }),
4499
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("p", { style: { color: "var(--theme-elevation-600)" }, children: "You do not have access to this page." })
4500
+ ] });
4501
+ }
4502
+ const pagesCollectionSlug = getPropString9(props, "pagesCollectionSlug", "pages");
4503
+ const mediaCollectionSlug = getPropString9(props, "mediaCollectionSlug", "media");
3017
4504
  const links = [
3018
- { href: `/admin/collections/${pagesCollectionSlug}`, label: "Raw Pages Collection" },
3019
- { href: `/admin/collections/${mediaCollectionSlug}`, label: "Raw Media Collection" },
3020
- { href: "/admin/globals/site-settings", label: "Raw Site Settings Global" },
3021
- { href: "/admin/globals/header", label: "Raw Header Global" },
3022
- { href: "/admin/globals/footer", label: "Raw Footer Global" },
3023
- { href: "/admin/collections/users", label: "Users / Roles" }
4505
+ { href: resolveAdminPath(adminBasePath, `/collections/${pagesCollectionSlug}`), label: "Raw Pages Collection" },
4506
+ { href: resolveAdminPath(adminBasePath, `/collections/${mediaCollectionSlug}`), label: "Raw Media Collection" },
4507
+ { href: resolveAdminPath(adminBasePath, "/globals/site-settings"), label: "Raw Site Settings Global" },
4508
+ { href: resolveAdminPath(adminBasePath, "/globals/header"), label: "Raw Header Global" },
4509
+ { href: resolveAdminPath(adminBasePath, "/globals/footer"), label: "Raw Footer Global" },
4510
+ { href: resolveAdminPath(adminBasePath, "/collections/users"), label: "Users / Roles" }
3024
4511
  ];
3025
- return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(import_jsx_runtime20.Fragment, { children: [
3026
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_ui9.SetStepNav, { nav: [{ label: "Admin Tools", url: "/admin/tools" }] }),
3027
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("h1", { style: { margin: 0 }, children: "Admin Tools" }),
3028
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("p", { style: { color: "var(--theme-elevation-600)", marginTop: "0.35rem" }, children: "Hidden fallback links for administrators." }),
3029
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { style: { display: "grid", gap: "0.6rem", marginTop: "1rem" }, children: links.map((link) => /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(
4512
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(import_jsx_runtime22.Fragment, { children: [
4513
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_ui11.SetStepNav, { nav: [{ label: "Admin Tools", url: toolsPath }] }),
4514
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("h1", { style: { margin: 0 }, children: "Admin Tools" }),
4515
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("p", { style: { color: "var(--theme-elevation-600)", marginTop: "0.35rem" }, children: "Hidden fallback links for administrators." }),
4516
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { style: { display: "grid", gap: "0.6rem", marginTop: "1rem" }, children: links.map((link) => /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(
3030
4517
  "a",
3031
4518
  {
3032
4519
  href: link.href,
@@ -3039,8 +4526,8 @@ function AdminStudioToolsView(props) {
3039
4526
  textDecoration: "none"
3040
4527
  },
3041
4528
  children: [
3042
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { style: { fontWeight: 900 }, children: link.label }),
3043
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { style: { color: "var(--theme-elevation-600)", fontSize: "0.9rem" }, children: link.href })
4529
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { style: { fontWeight: 900 }, children: link.label }),
4530
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { style: { color: "var(--theme-elevation-600)", fontSize: "0.9rem" }, children: link.href })
3044
4531
  ]
3045
4532
  },
3046
4533
  link.href
@@ -3049,15 +4536,15 @@ function AdminStudioToolsView(props) {
3049
4536
  }
3050
4537
 
3051
4538
  // src/admin/components/studio/OpenInStudioMenuItem.tsx
3052
- var import_ui10 = require("@payloadcms/ui");
3053
- var import_jsx_runtime21 = require("react/jsx-runtime");
4539
+ var import_ui12 = require("@payloadcms/ui");
4540
+ var import_jsx_runtime23 = require("react/jsx-runtime");
3054
4541
  function OpenInStudioMenuItem({ pagesPathBase = "/studio/pages" }) {
3055
- const documentInfo = (0, import_ui10.useDocumentInfo)();
4542
+ const documentInfo = (0, import_ui12.useDocumentInfo)();
3056
4543
  const id = documentInfo?.id;
3057
4544
  if (!id) {
3058
4545
  return null;
3059
4546
  }
3060
- return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
4547
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
3061
4548
  "a",
3062
4549
  {
3063
4550
  href: `${pagesPathBase}/${id}`,
@@ -3076,19 +4563,19 @@ function OpenInStudioMenuItem({ pagesPathBase = "/studio/pages" }) {
3076
4563
  }
3077
4564
 
3078
4565
  // src/admin/components/studio/PageEditRedirectToStudio.tsx
3079
- var import_react14 = require("react");
3080
- var import_ui11 = require("@payloadcms/ui");
3081
- var import_jsx_runtime22 = require("react/jsx-runtime");
4566
+ var import_react17 = require("react");
4567
+ var import_ui13 = require("@payloadcms/ui");
4568
+ var import_jsx_runtime24 = require("react/jsx-runtime");
3082
4569
  function PageEditRedirectToStudio({ pagesPathBase = "/studio/pages" }) {
3083
- const documentInfo = (0, import_ui11.useDocumentInfo)();
4570
+ const documentInfo = (0, import_ui13.useDocumentInfo)();
3084
4571
  const id = documentInfo?.id;
3085
- (0, import_react14.useEffect)(() => {
4572
+ (0, import_react17.useEffect)(() => {
3086
4573
  if (!id) {
3087
4574
  return;
3088
4575
  }
3089
4576
  window.location.replace(`${pagesPathBase}/${id}`);
3090
4577
  }, [id, pagesPathBase]);
3091
- return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(
4578
+ return /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(
3092
4579
  "div",
3093
4580
  {
3094
4581
  style: {
@@ -3100,57 +4587,114 @@ function PageEditRedirectToStudio({ pagesPathBase = "/studio/pages" }) {
3100
4587
  minHeight: "50vh"
3101
4588
  },
3102
4589
  children: [
3103
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("h2", { style: { margin: 0 }, children: "Opening Editor..." }),
3104
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("p", { style: { color: "var(--theme-elevation-600)", margin: 0 }, children: "Redirecting to the custom page editor." }),
3105
- id ? /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("a", { href: `${pagesPathBase}/${id}`, children: "Continue to Editor" }) : /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("a", { href: pagesPathBase, children: "Open Pages" })
4590
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("h2", { style: { margin: 0 }, children: "Opening Editor..." }),
4591
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("p", { style: { color: "var(--theme-elevation-600)", margin: 0 }, children: "Redirecting to the custom page editor." }),
4592
+ id ? /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("a", { href: `${pagesPathBase}/${id}`, children: "Continue to Editor" }) : /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("a", { href: pagesPathBase, children: "Open Pages" })
3106
4593
  ]
3107
4594
  }
3108
4595
  );
3109
4596
  }
3110
4597
 
3111
4598
  // src/admin/components/studio/StudioBackBreadcrumb.tsx
3112
- var import_ui12 = require("@payloadcms/ui");
3113
- var import_navigation = require("next/navigation");
3114
- var import_jsx_runtime23 = require("react/jsx-runtime");
4599
+ var import_react18 = require("react");
4600
+ var import_ui14 = require("@payloadcms/ui");
4601
+ var import_jsx_runtime25 = require("react/jsx-runtime");
3115
4602
  var toTitle = (slug) => slug.split("-").filter(Boolean).map((part) => part.charAt(0).toUpperCase() + part.slice(1)).join(" ");
3116
- var buildNav = (pathname) => {
4603
+ var buildNav = (pathname, adminBasePath) => {
3117
4604
  if (pathname.includes("/globals/")) {
3118
4605
  const slug = pathname.split("/globals/")[1]?.split("/")[0] || "";
3119
4606
  const currentLabel = slug === "site-settings" ? "Website Settings" : toTitle(slug) || "Global";
3120
4607
  return [
3121
- { label: "Globals", url: "/admin/studio-globals" },
4608
+ { label: "Globals", url: resolveAdminPath(adminBasePath, "/studio-globals") },
3122
4609
  { label: currentLabel }
3123
4610
  ];
3124
4611
  }
3125
- if (pathname.includes("/collections/pages") || pathname.startsWith("/admin/pages/")) {
4612
+ if (pathname.includes("/studio-contact-form")) {
3126
4613
  return [
3127
- { label: "Pages", url: "/admin/collections/pages" },
4614
+ { label: "Globals", url: resolveAdminPath(adminBasePath, "/studio-globals") },
4615
+ { label: "Contact Form" }
4616
+ ];
4617
+ }
4618
+ if (pathname.includes("/collections/pages") || pathname.includes("/pages/")) {
4619
+ return [
4620
+ { label: "Pages", url: resolveAdminPath(adminBasePath, "/collections/pages") },
3128
4621
  { label: "Page" }
3129
4622
  ];
3130
4623
  }
3131
4624
  if (pathname.includes("/collections/media")) {
3132
4625
  return [
3133
- { label: "Media", url: "/admin/collections/media" },
4626
+ { label: "Media", url: resolveAdminPath(adminBasePath, "/collections/media") },
3134
4627
  { label: "Media Item" }
3135
4628
  ];
3136
4629
  }
3137
- if (pathname.startsWith("/admin/tools") || pathname.includes("/collections/users")) {
4630
+ if (pathname.includes("/tools") || pathname.includes("/collections/users")) {
3138
4631
  return [
3139
- { label: "Admin Tools", url: "/admin/collections/users" },
4632
+ { label: "Admin Tools", url: resolveAdminPath(adminBasePath, "/collections/users") },
3140
4633
  { label: "Tool" }
3141
4634
  ];
3142
4635
  }
3143
4636
  return null;
3144
4637
  };
3145
4638
  function StudioBackBreadcrumb() {
3146
- const pathname = (0, import_navigation.usePathname)();
3147
- const nav = buildNav(pathname);
4639
+ const adminBasePath = useAdminBasePath();
4640
+ const [pathname, setPathname] = (0, import_react18.useState)("");
4641
+ (0, import_react18.useEffect)(() => {
4642
+ const update = () => setPathname(window.location.pathname);
4643
+ update();
4644
+ window.addEventListener("popstate", update);
4645
+ return () => window.removeEventListener("popstate", update);
4646
+ }, []);
4647
+ const nav = buildNav(pathname, adminBasePath);
3148
4648
  if (!nav) return null;
3149
- return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_ui12.SetStepNav, { nav });
4649
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_ui14.SetStepNav, { nav });
4650
+ }
4651
+
4652
+ // src/admin/components/studio/StudioContactFormRedirect.tsx
4653
+ var import_react19 = require("react");
4654
+ var import_jsx_runtime26 = require("react/jsx-runtime");
4655
+ var getPropString10 = (props, key, fallback) => {
4656
+ if (!props || typeof props !== "object") return fallback;
4657
+ const direct = props[key];
4658
+ if (typeof direct === "string" && direct.length > 0) return direct;
4659
+ const clientProps = props.clientProps;
4660
+ if (clientProps && typeof clientProps === "object") {
4661
+ const nested = clientProps[key];
4662
+ if (typeof nested === "string" && nested.length > 0) return nested;
4663
+ }
4664
+ return fallback;
4665
+ };
4666
+ function StudioContactFormRedirect(props) {
4667
+ const adminBasePath = useAdminBasePath();
4668
+ const studioContactFormPath = getPropString10(props, "studioContactFormPath", "/studio-contact-form");
4669
+ const targetPath = resolveAdminPath(adminBasePath, studioContactFormPath);
4670
+ (0, import_react19.useEffect)(() => {
4671
+ if (window.location.pathname === targetPath) return;
4672
+ window.location.replace(targetPath);
4673
+ }, [targetPath]);
4674
+ return /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(
4675
+ "div",
4676
+ {
4677
+ style: {
4678
+ alignItems: "center",
4679
+ color: "var(--theme-elevation-800)",
4680
+ display: "flex",
4681
+ flexDirection: "column",
4682
+ gap: "0.75rem",
4683
+ justifyContent: "center",
4684
+ minHeight: "40vh"
4685
+ },
4686
+ children: [
4687
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("h2", { style: { margin: 0 }, children: "Opening Contact Form Editor..." }),
4688
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("a", { href: targetPath, children: "Continue" })
4689
+ ]
4690
+ }
4691
+ );
3150
4692
  }
3151
4693
  // Annotate the CommonJS export names for ESM import in node:
3152
4694
  0 && (module.exports = {
4695
+ AdminStudioContactFormView,
3153
4696
  AdminStudioDashboard,
4697
+ AdminStudioFormsView,
3154
4698
  AdminStudioGlobalsView,
3155
4699
  AdminStudioMediaView,
3156
4700
  AdminStudioNav,
@@ -3169,6 +4713,7 @@ function StudioBackBreadcrumb() {
3169
4713
  SectionTabs,
3170
4714
  StatusBadge,
3171
4715
  StudioBackBreadcrumb,
4716
+ StudioContactFormRedirect,
3172
4717
  ThemeProvider,
3173
4718
  ThemeSwitcher,
3174
4719
  WelcomeHeader,