@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
@@ -1096,6 +1096,158 @@ function WelcomeHeader({
1096
1096
 
1097
1097
  // src/admin/components/studio/AdminStudioDashboard.tsx
1098
1098
  import { SetStepNav } from "@payloadcms/ui";
1099
+
1100
+ // src/shared/studioSections.ts
1101
+ var studioRoles = /* @__PURE__ */ new Set(["admin", "editor", "client"]);
1102
+ var isRecord = (value) => Boolean(value) && typeof value === "object" && !Array.isArray(value);
1103
+ var isAbsoluteExternalURL = (value) => /^[a-zA-Z][a-zA-Z\d+\-.]*:/.test(value) || value.startsWith("//");
1104
+ var normalizePathLikeValue = (value) => {
1105
+ const trimmed = value.trim();
1106
+ if (!trimmed) {
1107
+ return "";
1108
+ }
1109
+ if (isAbsoluteExternalURL(trimmed)) {
1110
+ return trimmed;
1111
+ }
1112
+ const withLeadingSlash = trimmed.startsWith("/") ? trimmed : `/${trimmed}`;
1113
+ const normalized = withLeadingSlash.replace(/\/+$/, "");
1114
+ return normalized || "/";
1115
+ };
1116
+ var normalizeStringArray = (value) => {
1117
+ if (!Array.isArray(value)) {
1118
+ return [];
1119
+ }
1120
+ return value.filter((entry) => typeof entry === "string").map((entry) => normalizePathLikeValue(entry)).filter((entry) => entry.length > 0);
1121
+ };
1122
+ var normalizeRoles = (value) => {
1123
+ if (!Array.isArray(value)) {
1124
+ return void 0;
1125
+ }
1126
+ const roles = value.filter((entry) => typeof entry === "string" && studioRoles.has(entry));
1127
+ return roles.length > 0 ? roles : void 0;
1128
+ };
1129
+ var normalizeCard = (value) => {
1130
+ if (!isRecord(value) || typeof value.title !== "string") {
1131
+ return void 0;
1132
+ }
1133
+ const title = value.title.trim();
1134
+ if (!title) {
1135
+ return void 0;
1136
+ }
1137
+ return {
1138
+ title,
1139
+ ...typeof value.description === "string" && value.description.trim().length > 0 ? { description: value.description.trim() } : {}
1140
+ };
1141
+ };
1142
+ var resolveStudioSections = (value) => {
1143
+ if (!Array.isArray(value)) {
1144
+ return [];
1145
+ }
1146
+ const sections = [];
1147
+ const seen = /* @__PURE__ */ new Set();
1148
+ for (const entry of value) {
1149
+ if (!isRecord(entry) || typeof entry.id !== "string" || typeof entry.label !== "string") {
1150
+ continue;
1151
+ }
1152
+ const id = entry.id.trim();
1153
+ const label = entry.label.trim();
1154
+ if (!id || !label || seen.has(id)) {
1155
+ continue;
1156
+ }
1157
+ 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) : "";
1158
+ if (!href) {
1159
+ continue;
1160
+ }
1161
+ const matchPrefixes = Array.from(/* @__PURE__ */ new Set([href, ...normalizeStringArray(entry.matchPrefixes)]));
1162
+ sections.push({
1163
+ id,
1164
+ label,
1165
+ href,
1166
+ matchPrefixes,
1167
+ ...normalizeRoles(entry.roles) ? { roles: normalizeRoles(entry.roles) } : {},
1168
+ ...normalizeCard(entry.card) ? { card: normalizeCard(entry.card) } : {}
1169
+ });
1170
+ seen.add(id);
1171
+ }
1172
+ return sections;
1173
+ };
1174
+
1175
+ // src/admin/components/studio/adminPathUtils.ts
1176
+ import { useEffect as useEffect6, useState as useState5 } from "react";
1177
+ var DEFAULT_ADMIN_BASE_PATH = "/admin";
1178
+ var normalizePath = (value) => {
1179
+ if (!value || value === "/") return "/";
1180
+ const withLeadingSlash = value.startsWith("/") ? value : `/${value}`;
1181
+ const trimmed = withLeadingSlash.replace(/\/+$/, "");
1182
+ return trimmed.length > 0 ? trimmed : "/";
1183
+ };
1184
+ var normalizeAdminBasePath = (value) => {
1185
+ const normalized = normalizePath(value);
1186
+ return normalized === "/" ? DEFAULT_ADMIN_BASE_PATH : normalized;
1187
+ };
1188
+ var detectAdminBasePath = (pathname, fallback = DEFAULT_ADMIN_BASE_PATH) => {
1189
+ const normalizedPathname = normalizePath(pathname);
1190
+ const normalizedFallback = normalizeAdminBasePath(fallback);
1191
+ const markers = [
1192
+ "/studio-contact-form",
1193
+ "/studio-globals",
1194
+ "/collections/",
1195
+ "/globals/",
1196
+ "/pages/",
1197
+ "/tools",
1198
+ "/media",
1199
+ "/logout",
1200
+ "/login"
1201
+ ];
1202
+ for (const marker of markers) {
1203
+ const index = normalizedPathname.indexOf(marker);
1204
+ if (index > 0) {
1205
+ return normalizeAdminBasePath(normalizedPathname.slice(0, index));
1206
+ }
1207
+ }
1208
+ if (normalizedPathname === normalizedFallback || normalizedPathname.startsWith(`${normalizedFallback}/`)) {
1209
+ return normalizedFallback;
1210
+ }
1211
+ const segments = normalizedPathname.split("/").filter(Boolean);
1212
+ if (segments.length > 0) {
1213
+ return normalizeAdminBasePath(`/${segments[0]}`);
1214
+ }
1215
+ return normalizedFallback;
1216
+ };
1217
+ var isAbsoluteExternalURL2 = (value) => /^[a-zA-Z][a-zA-Z\d+\-.]*:/.test(value) || value.startsWith("//");
1218
+ var resolveAdminPath = (adminBasePath, targetPath) => {
1219
+ if (!targetPath) return adminBasePath;
1220
+ if (isAbsoluteExternalURL2(targetPath)) return targetPath;
1221
+ const normalizedBasePath = normalizeAdminBasePath(adminBasePath);
1222
+ const normalizedTargetPath = normalizePath(targetPath);
1223
+ if (normalizedTargetPath === "/admin") {
1224
+ return normalizedBasePath;
1225
+ }
1226
+ if (normalizedTargetPath.startsWith("/admin/")) {
1227
+ return `${normalizedBasePath}${normalizedTargetPath.slice("/admin".length)}`;
1228
+ }
1229
+ if (normalizedTargetPath === normalizedBasePath || normalizedTargetPath.startsWith(`${normalizedBasePath}/`)) {
1230
+ return normalizedTargetPath;
1231
+ }
1232
+ if (normalizedTargetPath === "/") {
1233
+ return normalizedBasePath;
1234
+ }
1235
+ return `${normalizedBasePath}${normalizedTargetPath}`;
1236
+ };
1237
+ var useAdminBasePath = (fallback = DEFAULT_ADMIN_BASE_PATH) => {
1238
+ const [adminBasePath, setAdminBasePath] = useState5(normalizeAdminBasePath(fallback));
1239
+ useEffect6(() => {
1240
+ const update = () => {
1241
+ setAdminBasePath(detectAdminBasePath(window.location.pathname, fallback));
1242
+ };
1243
+ update();
1244
+ window.addEventListener("popstate", update);
1245
+ return () => window.removeEventListener("popstate", update);
1246
+ }, [fallback]);
1247
+ return adminBasePath;
1248
+ };
1249
+
1250
+ // src/admin/components/studio/AdminStudioDashboard.tsx
1099
1251
  import { jsx as jsx10, jsxs as jsxs9 } from "react/jsx-runtime";
1100
1252
  var cardStyle = {
1101
1253
  background: "var(--theme-elevation-0)",
@@ -1116,12 +1268,45 @@ var getPropString = (props, key, fallback) => {
1116
1268
  }
1117
1269
  return fallback;
1118
1270
  };
1271
+ var getPropBoolean = (props, key, fallback) => {
1272
+ if (!props || typeof props !== "object") return fallback;
1273
+ const direct = props[key];
1274
+ if (typeof direct === "boolean") return direct;
1275
+ const clientProps = props.clientProps;
1276
+ if (clientProps && typeof clientProps === "object") {
1277
+ const nested = clientProps[key];
1278
+ if (typeof nested === "boolean") return nested;
1279
+ }
1280
+ return fallback;
1281
+ };
1282
+ var getPropSections = (props, key) => {
1283
+ if (!props || typeof props !== "object") return [];
1284
+ const direct = resolveStudioSections(props[key]);
1285
+ if (direct.length > 0) return direct;
1286
+ const clientProps = props.clientProps;
1287
+ if (clientProps && typeof clientProps === "object") {
1288
+ return resolveStudioSections(clientProps[key]);
1289
+ }
1290
+ return [];
1291
+ };
1119
1292
  function AdminStudioDashboard(props) {
1293
+ const formsEnabled = getPropBoolean(props, "formsEnabled", false);
1120
1294
  const pagesCollectionSlug = getPropString(props, "pagesCollectionSlug", "pages");
1121
1295
  const mediaCollectionSlug = getPropString(props, "mediaCollectionSlug", "media");
1122
- const globalsBasePath = getPropString(props, "globalsBasePath", "/admin/globals");
1296
+ const globalsBasePath = getPropString(props, "globalsBasePath", "/studio-globals");
1297
+ const sections = getPropSections(props, "sections");
1298
+ const adminBasePath = useAdminBasePath();
1299
+ const resolvedGlobalsBasePath = resolveAdminPath(adminBasePath, globalsBasePath);
1300
+ const formsPath = resolveAdminPath(adminBasePath, "/studio-forms");
1301
+ const pagesPath = resolveAdminPath(adminBasePath, `/collections/${pagesCollectionSlug}`);
1302
+ const mediaPath = resolveAdminPath(adminBasePath, `/collections/${mediaCollectionSlug}`);
1303
+ const extensionCards = sections.filter((section) => section.card).map((section) => ({
1304
+ href: resolveAdminPath(adminBasePath, section.href),
1305
+ title: section.card?.title || section.label,
1306
+ description: section.card?.description || ""
1307
+ }));
1123
1308
  return /* @__PURE__ */ jsxs9("div", { style: { padding: "1.2rem 1.2rem 2.5rem" }, children: [
1124
- /* @__PURE__ */ jsx10(SetStepNav, { nav: [{ label: "Dashboard", url: "/admin" }] }),
1309
+ /* @__PURE__ */ jsx10(SetStepNav, { nav: [{ label: "Dashboard", url: adminBasePath }] }),
1125
1310
  /* @__PURE__ */ jsx10("h1", { style: { fontSize: "1.6rem", margin: 0 }, children: "Studio" }),
1126
1311
  /* @__PURE__ */ jsx10("p", { style: { color: "var(--theme-elevation-600)", marginTop: "0.35rem" }, children: "Pick what you want to edit." }),
1127
1312
  /* @__PURE__ */ jsxs9(
@@ -1134,18 +1319,26 @@ function AdminStudioDashboard(props) {
1134
1319
  marginTop: "1.1rem"
1135
1320
  },
1136
1321
  children: [
1137
- /* @__PURE__ */ jsxs9("a", { href: `/admin/collections/${pagesCollectionSlug}`, style: cardStyle, children: [
1322
+ /* @__PURE__ */ jsxs9("a", { href: pagesPath, style: cardStyle, children: [
1138
1323
  /* @__PURE__ */ jsx10("div", { style: { fontWeight: 900 }, children: "Pages" }),
1139
1324
  /* @__PURE__ */ jsx10("div", { style: { color: "var(--theme-elevation-600)", marginTop: "0.25rem" }, children: "Edit your site pages with the custom editor." })
1140
1325
  ] }),
1141
- /* @__PURE__ */ jsxs9("a", { href: globalsBasePath, style: cardStyle, children: [
1326
+ formsEnabled ? /* @__PURE__ */ jsxs9("a", { href: formsPath, style: cardStyle, children: [
1327
+ /* @__PURE__ */ jsx10("div", { style: { fontWeight: 900 }, children: "Forms" }),
1328
+ /* @__PURE__ */ jsx10("div", { style: { color: "var(--theme-elevation-600)", marginTop: "0.25rem" }, children: "Review forms, submissions, and uploaded files." })
1329
+ ] }) : null,
1330
+ /* @__PURE__ */ jsxs9("a", { href: resolvedGlobalsBasePath, style: cardStyle, children: [
1142
1331
  /* @__PURE__ */ jsx10("div", { style: { fontWeight: 900 }, children: "Globals" }),
1143
1332
  /* @__PURE__ */ jsx10("div", { style: { color: "var(--theme-elevation-600)", marginTop: "0.25rem" }, children: "Site settings, header, footer." })
1144
1333
  ] }),
1145
- /* @__PURE__ */ jsxs9("a", { href: `/admin/collections/${mediaCollectionSlug}`, style: cardStyle, children: [
1334
+ /* @__PURE__ */ jsxs9("a", { href: mediaPath, style: cardStyle, children: [
1146
1335
  /* @__PURE__ */ jsx10("div", { style: { fontWeight: 900 }, children: "Media" }),
1147
1336
  /* @__PURE__ */ jsx10("div", { style: { color: "var(--theme-elevation-600)", marginTop: "0.25rem" }, children: "Upload and manage images and files." })
1148
- ] })
1337
+ ] }),
1338
+ extensionCards.map((card) => /* @__PURE__ */ jsxs9("a", { href: card.href, style: cardStyle, children: [
1339
+ /* @__PURE__ */ jsx10("div", { style: { fontWeight: 900 }, children: card.title }),
1340
+ /* @__PURE__ */ jsx10("div", { style: { color: "var(--theme-elevation-600)", marginTop: "0.25rem" }, children: card.description })
1341
+ ] }, card.href))
1149
1342
  ]
1150
1343
  }
1151
1344
  )
@@ -1153,14 +1346,9 @@ function AdminStudioDashboard(props) {
1153
1346
  }
1154
1347
 
1155
1348
  // src/admin/components/studio/AdminStudioNav.tsx
1156
- import { useEffect as useEffect6, useMemo, useState as useState5 } from "react";
1349
+ import { useEffect as useEffect7, useMemo, useState as useState6 } from "react";
1157
1350
  import { Logout, useAuth } from "@payloadcms/ui";
1158
1351
  import { Fragment as Fragment2, jsx as jsx11, jsxs as jsxs10 } from "react/jsx-runtime";
1159
- var isAdmin = (user) => {
1160
- if (!user || typeof user !== "object") return false;
1161
- const role = user.role;
1162
- return typeof role === "string" && role === "admin";
1163
- };
1164
1352
  var getPropString2 = (props, key, fallback) => {
1165
1353
  if (!props || typeof props !== "object") return fallback;
1166
1354
  const direct = props[key];
@@ -1172,7 +1360,7 @@ var getPropString2 = (props, key, fallback) => {
1172
1360
  }
1173
1361
  return fallback;
1174
1362
  };
1175
- var getPropBoolean = (props, key, fallback) => {
1363
+ var getPropBoolean2 = (props, key, fallback) => {
1176
1364
  if (!props || typeof props !== "object") return fallback;
1177
1365
  const direct = props[key];
1178
1366
  if (typeof direct === "boolean") return direct;
@@ -1183,47 +1371,131 @@ var getPropBoolean = (props, key, fallback) => {
1183
1371
  }
1184
1372
  return fallback;
1185
1373
  };
1374
+ var getPropStringArray = (props, key, fallback) => {
1375
+ if (!props || typeof props !== "object") return fallback;
1376
+ const read = (candidate) => Array.isArray(candidate) ? candidate.filter((value) => typeof value === "string" && value.length > 0) : null;
1377
+ const direct = read(props[key]);
1378
+ if (direct) return direct;
1379
+ const clientProps = props.clientProps;
1380
+ if (clientProps && typeof clientProps === "object") {
1381
+ const nested = read(clientProps[key]);
1382
+ if (nested) return nested;
1383
+ }
1384
+ return fallback;
1385
+ };
1386
+ var getPropSections2 = (props, key) => {
1387
+ if (!props || typeof props !== "object") return [];
1388
+ const direct = resolveStudioSections(props[key]);
1389
+ if (direct.length > 0) return direct;
1390
+ const clientProps = props.clientProps;
1391
+ if (clientProps && typeof clientProps === "object") {
1392
+ return resolveStudioSections(clientProps[key]);
1393
+ }
1394
+ return [];
1395
+ };
1396
+ var roleCanAccessSection = (role, section) => {
1397
+ if (!section.roles || section.roles.length === 0) {
1398
+ return true;
1399
+ }
1400
+ if (!role) {
1401
+ return false;
1402
+ }
1403
+ return section.roles.includes(role);
1404
+ };
1405
+ var readUserRole = (user) => {
1406
+ if (!user || typeof user !== "object") {
1407
+ return void 0;
1408
+ }
1409
+ const role = user.role;
1410
+ return typeof role === "string" ? role : void 0;
1411
+ };
1186
1412
  function AdminStudioNav(props) {
1187
1413
  const { user } = useAuth();
1188
1414
  const brandName = getPropString2(props, "brandName", "Orion Studio");
1189
1415
  const logoUrl = getPropString2(props, "logoUrl", "");
1416
+ const formsEnabled = getPropBoolean2(props, "formsEnabled", false);
1417
+ const formsCollectionSlug = getPropString2(props, "formsCollectionSlug", "forms");
1190
1418
  const pagesCollectionSlug = getPropString2(props, "pagesCollectionSlug", "pages");
1191
1419
  const mediaCollectionSlug = getPropString2(props, "mediaCollectionSlug", "media");
1192
- const globalsBasePath = getPropString2(props, "globalsBasePath", "/admin/globals");
1193
- const compact = getPropBoolean(props, "compact", false);
1420
+ const globalsBasePath = getPropString2(props, "globalsBasePath", "/studio-globals");
1421
+ const globalsExtraMatchPrefixes = getPropStringArray(props, "globalsExtraMatchPrefixes", []);
1422
+ const sections = getPropSections2(props, "sections");
1423
+ const compact = getPropBoolean2(props, "compact", false);
1424
+ const adminBasePath = useAdminBasePath();
1194
1425
  const branding = useSiteBranding(brandName, logoUrl || void 0);
1195
1426
  const resolvedName = branding.siteName || brandName;
1196
- const [pathname, setPathname] = useState5("");
1197
- useEffect6(() => {
1427
+ const [pathname, setPathname] = useState6("");
1428
+ useEffect7(() => {
1198
1429
  const update = () => setPathname(window.location.pathname);
1199
1430
  update();
1200
1431
  window.addEventListener("popstate", update);
1201
1432
  return () => window.removeEventListener("popstate", update);
1202
1433
  }, []);
1203
- const pagesPath = `/admin/collections/${pagesCollectionSlug}`;
1204
- const mediaPath = `/admin/collections/${mediaCollectionSlug}`;
1434
+ const pagesPath = resolveAdminPath(adminBasePath, `/collections/${pagesCollectionSlug}`);
1435
+ const formsPath = resolveAdminPath(adminBasePath, "/studio-forms");
1436
+ const mediaPath = resolveAdminPath(adminBasePath, `/collections/${mediaCollectionSlug}`);
1437
+ const usersPath = resolveAdminPath(adminBasePath, "/collections/users");
1438
+ const resolvedGlobalsBasePath = resolveAdminPath(adminBasePath, globalsBasePath);
1439
+ const resolvedGlobalsExtraMatchPrefixes = globalsExtraMatchPrefixes.map(
1440
+ (prefix) => resolveAdminPath(adminBasePath, prefix)
1441
+ );
1442
+ const dashboardPath = adminBasePath;
1443
+ const userRole = readUserRole(user);
1205
1444
  const links = useMemo(
1206
- () => [
1207
- { href: "/admin", label: "Dashboard", matchPrefixes: ["/admin"] },
1208
- {
1209
- href: pagesPath,
1210
- label: "Pages",
1211
- matchPrefixes: [pagesPath]
1212
- },
1213
- { href: globalsBasePath, label: "Globals", matchPrefixes: [globalsBasePath, "/admin/globals"] },
1214
- {
1215
- href: mediaPath,
1216
- label: "Media",
1217
- matchPrefixes: [mediaPath]
1218
- },
1219
- {
1220
- href: "/admin/collections/users",
1221
- label: "Admin Tools",
1222
- matchPrefixes: ["/admin/collections/users"],
1223
- adminOnly: true
1224
- }
1225
- ],
1226
- [globalsBasePath, mediaPath, pagesPath]
1445
+ () => {
1446
+ const defaultSections = [
1447
+ { id: "dashboard", href: dashboardPath, label: "Dashboard", matchPrefixes: [dashboardPath] },
1448
+ { id: "pages", href: pagesPath, label: "Pages", matchPrefixes: [pagesPath] },
1449
+ ...formsEnabled ? [
1450
+ {
1451
+ id: "forms",
1452
+ href: formsPath,
1453
+ label: "Forms",
1454
+ matchPrefixes: [
1455
+ formsPath,
1456
+ resolveAdminPath(adminBasePath, `/collections/${formsCollectionSlug}`)
1457
+ ]
1458
+ }
1459
+ ] : [],
1460
+ {
1461
+ id: "globals",
1462
+ href: resolvedGlobalsBasePath,
1463
+ label: "Globals",
1464
+ matchPrefixes: [
1465
+ resolvedGlobalsBasePath,
1466
+ resolveAdminPath(adminBasePath, "/globals"),
1467
+ ...resolvedGlobalsExtraMatchPrefixes
1468
+ ]
1469
+ },
1470
+ { id: "media", href: mediaPath, label: "Media", matchPrefixes: [mediaPath] },
1471
+ {
1472
+ id: "admin-tools",
1473
+ href: usersPath,
1474
+ label: "Admin Tools",
1475
+ matchPrefixes: [usersPath],
1476
+ roles: ["admin"]
1477
+ }
1478
+ ];
1479
+ const extensionSections = sections.map((section) => ({
1480
+ ...section,
1481
+ href: resolveAdminPath(adminBasePath, section.href),
1482
+ matchPrefixes: section.matchPrefixes.map((prefix) => resolveAdminPath(adminBasePath, prefix))
1483
+ }));
1484
+ return [...defaultSections, ...extensionSections];
1485
+ },
1486
+ [
1487
+ adminBasePath,
1488
+ dashboardPath,
1489
+ formsCollectionSlug,
1490
+ formsEnabled,
1491
+ formsPath,
1492
+ mediaPath,
1493
+ pagesPath,
1494
+ resolvedGlobalsBasePath,
1495
+ resolvedGlobalsExtraMatchPrefixes,
1496
+ sections,
1497
+ usersPath
1498
+ ]
1227
1499
  );
1228
1500
  const linkStyle = (active) => ({
1229
1501
  alignItems: "center",
@@ -1280,8 +1552,8 @@ function AdminStudioNav(props) {
1280
1552
  ),
1281
1553
  !compact ? /* @__PURE__ */ jsx11("div", { style: { color: "var(--theme-elevation-600)", fontSize: "0.85rem" }, children: "Studio" }) : null
1282
1554
  ] }),
1283
- /* @__PURE__ */ jsx11("nav", { style: { display: "grid", gap: "0.25rem" }, children: links.filter((link) => !link.adminOnly || isAdmin(user)).map((link) => {
1284
- const active = link.href === "/admin" ? pathname === "/admin" : link.matchPrefixes.some((prefix) => pathname.startsWith(prefix));
1555
+ /* @__PURE__ */ jsx11("nav", { style: { display: "grid", gap: "0.25rem" }, children: links.filter((link) => roleCanAccessSection(userRole, link)).map((link) => {
1556
+ const active = link.href === dashboardPath ? pathname === dashboardPath : link.matchPrefixes.some((prefix) => pathname.startsWith(prefix));
1285
1557
  return /* @__PURE__ */ jsx11("a", { href: link.href, style: linkStyle(active), title: link.label, children: compact ? link.label.slice(0, 1) : link.label }, link.href);
1286
1558
  }) }),
1287
1559
  /* @__PURE__ */ jsx11("div", { style: { flex: 1 } }),
@@ -1308,10 +1580,10 @@ function AdminStudioNav(props) {
1308
1580
  }
1309
1581
 
1310
1582
  // src/admin/components/studio/AdminStudioPagesListView.tsx
1311
- import { useEffect as useEffect7, useMemo as useMemo2, useState as useState6 } from "react";
1583
+ import { useEffect as useEffect8, useMemo as useMemo2, useState as useState7 } from "react";
1312
1584
  import { SetStepNav as SetStepNav2, useAuth as useAuth2 } from "@payloadcms/ui";
1313
1585
  import { Fragment as Fragment3, jsx as jsx12, jsxs as jsxs11 } from "react/jsx-runtime";
1314
- var isAdmin2 = (user) => {
1586
+ var isAdmin = (user) => {
1315
1587
  if (!user || typeof user !== "object") return false;
1316
1588
  const role = user.role;
1317
1589
  return typeof role === "string" && role === "admin";
@@ -1330,9 +1602,12 @@ var getPropString3 = (props, key, fallback) => {
1330
1602
  function AdminStudioPagesListView(props) {
1331
1603
  const { user } = useAuth2();
1332
1604
  const pagesCollectionSlug = getPropString3(props, "pagesCollectionSlug", "pages");
1333
- const [loading, setLoading] = useState6(true);
1334
- const [error, setError] = useState6(null);
1335
- const [docs, setDocs] = useState6([]);
1605
+ const adminBasePath = useAdminBasePath();
1606
+ const pagesPath = resolveAdminPath(adminBasePath, "/pages");
1607
+ const rawPagesCollectionPath = resolveAdminPath(adminBasePath, `/collections/${pagesCollectionSlug}`);
1608
+ const [loading, setLoading] = useState7(true);
1609
+ const [error, setError] = useState7(null);
1610
+ const [docs, setDocs] = useState7([]);
1336
1611
  const apiURL = useMemo2(() => {
1337
1612
  const params = new URLSearchParams({
1338
1613
  depth: "0",
@@ -1342,7 +1617,7 @@ function AdminStudioPagesListView(props) {
1342
1617
  });
1343
1618
  return `/api/${pagesCollectionSlug}?${params.toString()}`;
1344
1619
  }, [pagesCollectionSlug]);
1345
- useEffect7(() => {
1620
+ useEffect8(() => {
1346
1621
  let cancelled = false;
1347
1622
  const run = async () => {
1348
1623
  setLoading(true);
@@ -1368,16 +1643,16 @@ function AdminStudioPagesListView(props) {
1368
1643
  };
1369
1644
  }, [apiURL]);
1370
1645
  return /* @__PURE__ */ jsxs11(Fragment3, { children: [
1371
- /* @__PURE__ */ jsx12(SetStepNav2, { nav: [{ label: "Pages", url: "/admin/pages" }] }),
1646
+ /* @__PURE__ */ jsx12(SetStepNav2, { nav: [{ label: "Pages", url: pagesPath }] }),
1372
1647
  /* @__PURE__ */ jsxs11("div", { style: { alignItems: "flex-end", display: "flex", gap: "0.75rem" }, children: [
1373
1648
  /* @__PURE__ */ jsxs11("div", { style: { flex: 1 }, children: [
1374
1649
  /* @__PURE__ */ jsx12("h1", { style: { margin: 0 }, children: "Pages" }),
1375
1650
  /* @__PURE__ */ jsx12("p", { style: { color: "var(--theme-elevation-600)", marginTop: "0.35rem" }, children: "Open a page to edit it in the custom editor." })
1376
1651
  ] }),
1377
- isAdmin2(user) ? /* @__PURE__ */ jsx12(
1652
+ isAdmin(user) ? /* @__PURE__ */ jsx12(
1378
1653
  "a",
1379
1654
  {
1380
- href: `/admin/collections/${pagesCollectionSlug}/create`,
1655
+ href: `${rawPagesCollectionPath}/create`,
1381
1656
  style: {
1382
1657
  background: "var(--theme-elevation-900)",
1383
1658
  borderRadius: 12,
@@ -1414,7 +1689,7 @@ function AdminStudioPagesListView(props) {
1414
1689
  return /* @__PURE__ */ jsxs11(
1415
1690
  "a",
1416
1691
  {
1417
- href: `/admin/pages/${id}`,
1692
+ href: resolveAdminPath(adminBasePath, `/pages/${id}`),
1418
1693
  style: {
1419
1694
  background: "var(--theme-elevation-0)",
1420
1695
  border: "1px solid var(--theme-elevation-150)",
@@ -1481,10 +1756,10 @@ function AdminStudioPagesListView(props) {
1481
1756
  }
1482
1757
 
1483
1758
  // src/admin/components/studio/AdminStudioPageEditView.tsx
1484
- import { useEffect as useEffect8, useMemo as useMemo3, useRef as useRef3, useState as useState7 } from "react";
1759
+ import { useEffect as useEffect9, useMemo as useMemo3, useRef as useRef3, useState as useState8 } from "react";
1485
1760
  import { SetStepNav as SetStepNav3, toast, useAuth as useAuth3 } from "@payloadcms/ui";
1486
1761
  import { Fragment as Fragment4, jsx as jsx13, jsxs as jsxs12 } from "react/jsx-runtime";
1487
- var isAdmin3 = (user) => {
1762
+ var isAdmin2 = (user) => {
1488
1763
  if (!user || typeof user !== "object") return false;
1489
1764
  const role = user.role;
1490
1765
  return typeof role === "string" && role === "admin";
@@ -1514,18 +1789,27 @@ var getParam = (params, key) => {
1514
1789
  return null;
1515
1790
  };
1516
1791
  var getPageIDFromPathname = (pathname) => {
1517
- const match = pathname.match(/\/admin\/pages\/([^/]+)(?:\/|$)/);
1518
- return match?.[1] ? decodeURIComponent(match[1]) : null;
1792
+ const marker = "/pages/";
1793
+ const markerIndex = pathname.indexOf(marker);
1794
+ if (markerIndex < 0) return null;
1795
+ const pagePart = pathname.slice(markerIndex + marker.length).split("/")[0];
1796
+ return pagePart ? decodeURIComponent(pagePart) : null;
1519
1797
  };
1520
1798
  function AdminStudioPageEditView(props) {
1521
1799
  const { user } = useAuth3();
1800
+ const adminBasePath = useAdminBasePath();
1522
1801
  const iframeRef = useRef3(null);
1523
- const [saving, setSaving] = useState7(null);
1802
+ const [saving, setSaving] = useState8(null);
1803
+ const [dirty, setDirty] = useState8(false);
1804
+ const [hasUnpublishedChanges, setHasUnpublishedChanges] = useState8(false);
1805
+ const [canUndo, setCanUndo] = useState8(false);
1806
+ const [canRedo, setCanRedo] = useState8(false);
1524
1807
  const builderBasePath = getPropString4(props, "builderBasePath", "/builder");
1808
+ const pagesPath = resolveAdminPath(adminBasePath, "/pages");
1525
1809
  const pageIDFromParams = useMemo3(() => getParam(props.params, "id"), [props.params]);
1526
- const [pageID, setPageID] = useState7(pageIDFromParams);
1527
- const [didResolvePathFallback, setDidResolvePathFallback] = useState7(false);
1528
- useEffect8(() => {
1810
+ const [pageID, setPageID] = useState8(pageIDFromParams);
1811
+ const [didResolvePathFallback, setDidResolvePathFallback] = useState8(false);
1812
+ useEffect9(() => {
1529
1813
  if (pageIDFromParams) {
1530
1814
  setPageID(pageIDFromParams);
1531
1815
  setDidResolvePathFallback(true);
@@ -1536,7 +1820,45 @@ function AdminStudioPageEditView(props) {
1536
1820
  }
1537
1821
  setDidResolvePathFallback(true);
1538
1822
  }, [pageIDFromParams]);
1539
- const canPublish = isAdmin3(user) || isEditor(user);
1823
+ const canPublish = isAdmin2(user) || isEditor(user);
1824
+ const refreshUnpublishedState = async (id) => {
1825
+ try {
1826
+ const response = await fetch(
1827
+ `/api/pages/versions?depth=0&limit=25&sort=-updatedAt&where[parent][equals]=${encodeURIComponent(id)}`,
1828
+ {
1829
+ credentials: "include"
1830
+ }
1831
+ );
1832
+ if (!response.ok) {
1833
+ return;
1834
+ }
1835
+ const payload = await response.json();
1836
+ const docs = Array.isArray(payload.docs) ? payload.docs : [];
1837
+ let latestDraft = 0;
1838
+ let latestPublished = 0;
1839
+ docs.forEach((doc) => {
1840
+ const status = doc.version?._status;
1841
+ const millis = typeof doc.updatedAt === "string" ? Date.parse(doc.updatedAt) : Number.NaN;
1842
+ if (!Number.isFinite(millis)) {
1843
+ return;
1844
+ }
1845
+ if (status === "draft") {
1846
+ latestDraft = Math.max(latestDraft, millis);
1847
+ }
1848
+ if (status === "published") {
1849
+ latestPublished = Math.max(latestPublished, millis);
1850
+ }
1851
+ });
1852
+ setHasUnpublishedChanges(latestDraft > 0 && latestDraft >= latestPublished);
1853
+ } catch {
1854
+ }
1855
+ };
1856
+ useEffect9(() => {
1857
+ if (!pageID) {
1858
+ return;
1859
+ }
1860
+ void refreshUnpublishedState(pageID);
1861
+ }, [pageID]);
1540
1862
  const requestSave = (status) => {
1541
1863
  const iframe = iframeRef.current;
1542
1864
  if (!iframe?.contentWindow) {
@@ -1546,17 +1868,43 @@ function AdminStudioPageEditView(props) {
1546
1868
  setSaving(status);
1547
1869
  iframe.contentWindow.postMessage({ source: "payload-visual-builder-parent", type: "save", status }, "*");
1548
1870
  };
1549
- useEffect8(() => {
1871
+ const requestHistoryAction = (type) => {
1872
+ const iframe = iframeRef.current;
1873
+ if (!iframe?.contentWindow) {
1874
+ toast.error("Editor is not ready yet. Please try again.");
1875
+ return;
1876
+ }
1877
+ iframe.contentWindow.postMessage({ source: "payload-visual-builder-parent", type }, "*");
1878
+ };
1879
+ useEffect9(() => {
1550
1880
  const onMessage = (event) => {
1551
1881
  const data = event.data;
1552
- if (!data || data.source !== "payload-visual-builder-child" || data.type !== "save-result") {
1882
+ if (!data || data.source !== "payload-visual-builder-child" || typeof data.type !== "string") {
1553
1883
  return;
1554
1884
  }
1555
- setSaving(null);
1556
- if (data.ok) {
1557
- toast.success(typeof data.message === "string" ? data.message : "Saved.");
1558
- } else {
1559
- toast.error(typeof data.message === "string" ? data.message : "Save failed.");
1885
+ if (data.type === "dirty-state") {
1886
+ setDirty(Boolean(data.dirty));
1887
+ return;
1888
+ }
1889
+ if (data.type === "history-state") {
1890
+ setCanUndo(Boolean(data.canUndo));
1891
+ setCanRedo(Boolean(data.canRedo));
1892
+ return;
1893
+ }
1894
+ if (data.type === "save-result") {
1895
+ setSaving(null);
1896
+ if (data.ok) {
1897
+ if (data.status === "draft") {
1898
+ setHasUnpublishedChanges(true);
1899
+ } else if (data.status === "published") {
1900
+ setHasUnpublishedChanges(false);
1901
+ } else if (pageID) {
1902
+ void refreshUnpublishedState(pageID);
1903
+ }
1904
+ toast.success(typeof data.message === "string" ? data.message : "Saved.");
1905
+ } else {
1906
+ toast.error(typeof data.message === "string" ? data.message : "Save failed.");
1907
+ }
1560
1908
  }
1561
1909
  };
1562
1910
  window.addEventListener("message", onMessage);
@@ -1568,8 +1916,8 @@ function AdminStudioPageEditView(props) {
1568
1916
  SetStepNav3,
1569
1917
  {
1570
1918
  nav: [
1571
- { label: "Pages", url: "/admin/pages" },
1572
- { label: "Page Editor", url: "/admin/pages" }
1919
+ { label: "Pages", url: pagesPath },
1920
+ { label: "Page Editor", url: pagesPath }
1573
1921
  ]
1574
1922
  }
1575
1923
  ),
@@ -1583,8 +1931,8 @@ function AdminStudioPageEditView(props) {
1583
1931
  SetStepNav3,
1584
1932
  {
1585
1933
  nav: [
1586
- { label: "Pages", url: "/admin/pages" },
1587
- { label: "Page Editor", url: "/admin/pages" }
1934
+ { label: "Pages", url: pagesPath },
1935
+ { label: "Page Editor", url: pagesPath }
1588
1936
  ]
1589
1937
  }
1590
1938
  ),
@@ -1597,8 +1945,8 @@ function AdminStudioPageEditView(props) {
1597
1945
  SetStepNav3,
1598
1946
  {
1599
1947
  nav: [
1600
- { label: "Pages", url: "/admin/pages" },
1601
- { label: `Page ${pageID}`, url: `/admin/pages/${pageID}` }
1948
+ { label: "Pages", url: pagesPath },
1949
+ { label: `Page ${pageID}`, url: resolveAdminPath(adminBasePath, `/pages/${pageID}`) }
1602
1950
  ]
1603
1951
  }
1604
1952
  ),
@@ -1638,6 +1986,56 @@ function AdminStudioPageEditView(props) {
1638
1986
  )
1639
1987
  ] }),
1640
1988
  /* @__PURE__ */ jsxs12("div", { style: { alignItems: "center", display: "flex", gap: "0.5rem" }, children: [
1989
+ /* @__PURE__ */ jsx13("div", { style: { color: dirty ? "var(--theme-elevation-900)" : "var(--theme-elevation-600)", fontSize: "0.85rem", fontWeight: 700 }, children: dirty ? "Unsaved changes" : "All changes saved" }),
1990
+ /* @__PURE__ */ jsx13(
1991
+ "div",
1992
+ {
1993
+ style: {
1994
+ background: hasUnpublishedChanges ? "#fff3cd" : "var(--theme-success-50)",
1995
+ border: `1px solid ${hasUnpublishedChanges ? "#f0c36d" : "var(--theme-success-300)"}`,
1996
+ borderRadius: 999,
1997
+ color: hasUnpublishedChanges ? "#6a4a00" : "var(--theme-success-700)",
1998
+ fontSize: "0.75rem",
1999
+ fontWeight: 800,
2000
+ padding: "0.2rem 0.55rem",
2001
+ whiteSpace: "nowrap"
2002
+ },
2003
+ title: hasUnpublishedChanges ? "There are saved draft changes not yet published." : "The live page matches the latest published content.",
2004
+ children: hasUnpublishedChanges ? "Unpublished draft changes" : "Live is up to date"
2005
+ }
2006
+ ),
2007
+ /* @__PURE__ */ jsx13(
2008
+ "button",
2009
+ {
2010
+ disabled: !canUndo,
2011
+ onClick: () => requestHistoryAction("undo"),
2012
+ style: {
2013
+ border: "1px solid var(--theme-elevation-300)",
2014
+ borderRadius: 12,
2015
+ cursor: canUndo ? "pointer" : "not-allowed",
2016
+ fontWeight: 800,
2017
+ padding: "0.5rem 0.65rem"
2018
+ },
2019
+ type: "button",
2020
+ children: "Undo"
2021
+ }
2022
+ ),
2023
+ /* @__PURE__ */ jsx13(
2024
+ "button",
2025
+ {
2026
+ disabled: !canRedo,
2027
+ onClick: () => requestHistoryAction("redo"),
2028
+ style: {
2029
+ border: "1px solid var(--theme-elevation-300)",
2030
+ borderRadius: 12,
2031
+ cursor: canRedo ? "pointer" : "not-allowed",
2032
+ fontWeight: 800,
2033
+ padding: "0.5rem 0.65rem"
2034
+ },
2035
+ type: "button",
2036
+ children: "Redo"
2037
+ }
2038
+ ),
1641
2039
  /* @__PURE__ */ jsx13(
1642
2040
  "button",
1643
2041
  {
@@ -1660,7 +2058,7 @@ function AdminStudioPageEditView(props) {
1660
2058
  disabled: !canPublish || saving !== null,
1661
2059
  onClick: () => requestSave("published"),
1662
2060
  style: {
1663
- background: canPublish ? "var(--theme-elevation-900)" : "var(--theme-elevation-300)",
2061
+ background: canPublish ? "var(--theme-success-700)" : "var(--theme-elevation-300)",
1664
2062
  border: "none",
1665
2063
  borderRadius: 12,
1666
2064
  color: canPublish ? "var(--theme-elevation-0)" : "var(--theme-elevation-700)",
@@ -1683,7 +2081,13 @@ function AdminStudioPageEditView(props) {
1683
2081
  ref: iframeRef,
1684
2082
  src: `${builderBasePath.replace(/\/$/, "")}/${pageID}`,
1685
2083
  style: { border: "none", height: "100%", width: "100%" },
1686
- title: "Page Builder"
2084
+ title: "Page Builder",
2085
+ onLoad: () => {
2086
+ const iframe = iframeRef.current;
2087
+ if (!iframe?.contentWindow) return;
2088
+ iframe.contentWindow.postMessage({ source: "payload-visual-builder-parent", type: "dirty-check-request" }, "*");
2089
+ iframe.contentWindow.postMessage({ source: "payload-visual-builder-parent", type: "history-check-request" }, "*");
2090
+ }
1687
2091
  }
1688
2092
  )
1689
2093
  ] })
@@ -1716,42 +2120,48 @@ var getPropString5 = (props, key, fallback) => {
1716
2120
  return fallback;
1717
2121
  };
1718
2122
  function AdminStudioGlobalsView(props) {
1719
- const globalsBasePath = getPropString5(props, "globalsBasePath", "/admin/studio-globals");
2123
+ const globalsBasePath = getPropString5(props, "globalsBasePath", "/studio-globals");
2124
+ const adminBasePath = useAdminBasePath();
2125
+ const resolvedGlobalsBasePath = resolveAdminPath(adminBasePath, globalsBasePath);
1720
2126
  const globals = getPropGlobals(props) || [
1721
2127
  { slug: "site-settings", label: "Website Settings" },
1722
2128
  { slug: "header", label: "Header & Navigation" },
1723
- { slug: "footer", label: "Footer" }
2129
+ { slug: "footer", label: "Footer" },
2130
+ { slug: "contact-form", label: "Contact Form", href: "/studio-contact-form" }
1724
2131
  ];
1725
2132
  return /* @__PURE__ */ jsxs13(Fragment5, { children: [
1726
- /* @__PURE__ */ jsx14(SetStepNav4, { nav: [{ label: "Globals", url: globalsBasePath }] }),
2133
+ /* @__PURE__ */ jsx14(SetStepNav4, { nav: [{ label: "Globals", url: resolvedGlobalsBasePath }] }),
1727
2134
  /* @__PURE__ */ jsx14("h1", { style: { margin: 0 }, children: "Globals" }),
1728
2135
  /* @__PURE__ */ jsx14("p", { style: { color: "var(--theme-elevation-600)", marginTop: "0.35rem" }, children: "Site-wide settings." }),
1729
- /* @__PURE__ */ jsx14("div", { style: { display: "grid", gap: "0.6rem", marginTop: "1rem" }, children: globals.map((global) => /* @__PURE__ */ jsxs13(
1730
- "a",
1731
- {
1732
- href: `/admin/globals/${global.slug}`,
1733
- style: {
1734
- background: "var(--theme-elevation-0)",
1735
- border: "1px solid var(--theme-elevation-150)",
1736
- borderRadius: 16,
1737
- color: "inherit",
1738
- padding: "0.85rem 1rem",
1739
- textDecoration: "none"
2136
+ /* @__PURE__ */ jsx14("div", { style: { display: "grid", gap: "0.6rem", marginTop: "1rem" }, children: globals.map((global) => {
2137
+ const href = resolveAdminPath(
2138
+ adminBasePath,
2139
+ typeof global.href === "string" ? global.href : `/globals/${global.slug}`
2140
+ );
2141
+ return /* @__PURE__ */ jsxs13(
2142
+ "a",
2143
+ {
2144
+ href,
2145
+ style: {
2146
+ background: "var(--theme-elevation-0)",
2147
+ border: "1px solid var(--theme-elevation-150)",
2148
+ borderRadius: 16,
2149
+ color: "inherit",
2150
+ padding: "0.85rem 1rem",
2151
+ textDecoration: "none"
2152
+ },
2153
+ children: [
2154
+ /* @__PURE__ */ jsx14("div", { style: { fontWeight: 900 }, children: global.label }),
2155
+ /* @__PURE__ */ jsx14("div", { style: { color: "var(--theme-elevation-600)", fontSize: "0.9rem" }, children: typeof global.description === "string" && global.description.length > 0 ? global.description : href })
2156
+ ]
1740
2157
  },
1741
- children: [
1742
- /* @__PURE__ */ jsx14("div", { style: { fontWeight: 900 }, children: global.label }),
1743
- /* @__PURE__ */ jsxs13("div", { style: { color: "var(--theme-elevation-600)", fontSize: "0.9rem" }, children: [
1744
- "/admin/globals/",
1745
- global.slug
1746
- ] })
1747
- ]
1748
- },
1749
- global.slug
1750
- )) }),
2158
+ global.slug
2159
+ );
2160
+ }) }),
1751
2161
  /* @__PURE__ */ jsx14("div", { style: { marginTop: "1rem" }, children: /* @__PURE__ */ jsx14(
1752
2162
  "a",
1753
2163
  {
1754
- href: globalsBasePath,
2164
+ href: resolvedGlobalsBasePath,
1755
2165
  style: { color: "var(--theme-elevation-700)", fontSize: "0.85rem", textDecoration: "none" },
1756
2166
  children: "Reload Globals view"
1757
2167
  }
@@ -1759,9 +2169,24 @@ function AdminStudioGlobalsView(props) {
1759
2169
  ] });
1760
2170
  }
1761
2171
 
1762
- // src/admin/components/studio/AdminStudioMediaView.tsx
2172
+ // src/admin/components/studio/AdminStudioContactFormView.tsx
2173
+ import { useEffect as useEffect10, useMemo as useMemo4, useState as useState9 } from "react";
1763
2174
  import { SetStepNav as SetStepNav5 } from "@payloadcms/ui";
1764
- import { Fragment as Fragment6, jsx as jsx15, jsxs as jsxs14 } from "react/jsx-runtime";
2175
+ import { jsx as jsx15, jsxs as jsxs14 } from "react/jsx-runtime";
2176
+ var defaultDoc = {
2177
+ disabledMessage: "This form is temporarily unavailable. Please call us for immediate service.",
2178
+ enabled: true,
2179
+ errorMessage: "Submission failed. Please call us at (512) 555-0149.",
2180
+ notificationEmail: "",
2181
+ serviceOptions: [
2182
+ { label: "Tree Trimming" },
2183
+ { label: "Tree Removal" },
2184
+ { label: "Stump Grinding" },
2185
+ { label: "Storm Cleanup" }
2186
+ ],
2187
+ submitButtonLabel: "Send Request",
2188
+ successMessage: "Thanks, your request has been received. We will follow up shortly."
2189
+ };
1765
2190
  var getPropString6 = (props, key, fallback) => {
1766
2191
  if (!props || typeof props !== "object") return fallback;
1767
2192
  const direct = props[key];
@@ -1773,110 +2198,1169 @@ var getPropString6 = (props, key, fallback) => {
1773
2198
  }
1774
2199
  return fallback;
1775
2200
  };
1776
- function AdminStudioMediaView(props) {
1777
- const mediaCollectionSlug = getPropString6(props, "mediaCollectionSlug", "media");
1778
- return /* @__PURE__ */ jsxs14(Fragment6, { children: [
1779
- /* @__PURE__ */ jsx15(SetStepNav5, { nav: [{ label: "Media", url: "/admin/media" }] }),
1780
- /* @__PURE__ */ jsx15("h1", { style: { margin: 0 }, children: "Media" }),
1781
- /* @__PURE__ */ jsx15("p", { style: { color: "var(--theme-elevation-600)", marginTop: "0.35rem" }, children: "Media management is currently using Payload's library." }),
1782
- /* @__PURE__ */ jsx15("div", { style: { display: "grid", gap: "0.6rem", marginTop: "1rem" }, children: /* @__PURE__ */ jsxs14(
1783
- "a",
1784
- {
1785
- href: `/admin/collections/${mediaCollectionSlug}`,
1786
- style: {
1787
- background: "var(--theme-elevation-0)",
1788
- border: "1px solid var(--theme-elevation-150)",
1789
- borderRadius: 16,
1790
- color: "inherit",
1791
- padding: "0.85rem 1rem",
1792
- textDecoration: "none"
1793
- },
1794
- children: [
1795
- /* @__PURE__ */ jsx15("div", { style: { fontWeight: 900 }, children: "Open Media Library" }),
1796
- /* @__PURE__ */ jsxs14("div", { style: { color: "var(--theme-elevation-600)", fontSize: "0.9rem" }, children: [
1797
- "/admin/collections/",
1798
- mediaCollectionSlug
1799
- ] })
1800
- ]
1801
- }
1802
- ) })
1803
- ] });
1804
- }
1805
-
1806
- // src/admin/components/studio/AdminStudioToolsView.tsx
1807
- import { SetStepNav as SetStepNav6, useAuth as useAuth4 } from "@payloadcms/ui";
1808
- import { Fragment as Fragment7, jsx as jsx16, jsxs as jsxs15 } from "react/jsx-runtime";
1809
- var isAdmin4 = (user) => {
1810
- if (!user || typeof user !== "object") return false;
1811
- const role = user.role;
1812
- return typeof role === "string" && role === "admin";
2201
+ var normalizeOption = (value) => {
2202
+ if (!value || typeof value !== "object" || Array.isArray(value)) return null;
2203
+ const label = value.label;
2204
+ if (typeof label !== "string") return null;
2205
+ const trimmed = label.trim();
2206
+ if (!trimmed) return null;
2207
+ return { label: trimmed };
1813
2208
  };
1814
- var getPropString7 = (props, key, fallback) => {
1815
- if (!props || typeof props !== "object") return fallback;
1816
- const direct = props[key];
1817
- if (typeof direct === "string" && direct.length > 0) return direct;
1818
- const clientProps = props.clientProps;
1819
- if (clientProps && typeof clientProps === "object") {
1820
- const nested = clientProps[key];
1821
- if (typeof nested === "string" && nested.length > 0) return nested;
2209
+ var normalizeDoc = (value) => {
2210
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
2211
+ return defaultDoc;
1822
2212
  }
1823
- return fallback;
2213
+ const record = value;
2214
+ const options = Array.isArray(record.serviceOptions) ? record.serviceOptions.map(normalizeOption).filter((option) => option !== null) : defaultDoc.serviceOptions;
2215
+ return {
2216
+ disabledMessage: typeof record.disabledMessage === "string" && record.disabledMessage.length > 0 ? record.disabledMessage : defaultDoc.disabledMessage,
2217
+ enabled: record.enabled !== false,
2218
+ errorMessage: typeof record.errorMessage === "string" && record.errorMessage.length > 0 ? record.errorMessage : defaultDoc.errorMessage,
2219
+ notificationEmail: typeof record.notificationEmail === "string" ? record.notificationEmail : defaultDoc.notificationEmail,
2220
+ serviceOptions: options.length > 0 ? options : defaultDoc.serviceOptions,
2221
+ submitButtonLabel: typeof record.submitButtonLabel === "string" && record.submitButtonLabel.length > 0 ? record.submitButtonLabel : defaultDoc.submitButtonLabel,
2222
+ successMessage: typeof record.successMessage === "string" && record.successMessage.length > 0 ? record.successMessage : defaultDoc.successMessage
2223
+ };
1824
2224
  };
1825
- function AdminStudioToolsView(props) {
1826
- const { user } = useAuth4();
1827
- if (!isAdmin4(user)) {
1828
- return /* @__PURE__ */ jsxs15(Fragment7, { children: [
1829
- /* @__PURE__ */ jsx16(SetStepNav6, { nav: [{ label: "Admin Tools", url: "/admin/tools" }] }),
1830
- /* @__PURE__ */ jsx16("h1", { style: { margin: 0 }, children: "Admin Tools" }),
1831
- /* @__PURE__ */ jsx16("p", { style: { color: "var(--theme-elevation-600)" }, children: "You do not have access to this page." })
1832
- ] });
1833
- }
1834
- const pagesCollectionSlug = getPropString7(props, "pagesCollectionSlug", "pages");
1835
- const mediaCollectionSlug = getPropString7(props, "mediaCollectionSlug", "media");
1836
- const links = [
1837
- { href: `/admin/collections/${pagesCollectionSlug}`, label: "Raw Pages Collection" },
1838
- { href: `/admin/collections/${mediaCollectionSlug}`, label: "Raw Media Collection" },
1839
- { href: "/admin/globals/site-settings", label: "Raw Site Settings Global" },
1840
- { href: "/admin/globals/header", label: "Raw Header Global" },
1841
- { href: "/admin/globals/footer", label: "Raw Footer Global" },
1842
- { href: "/admin/collections/users", label: "Users / Roles" }
1843
- ];
1844
- return /* @__PURE__ */ jsxs15(Fragment7, { children: [
1845
- /* @__PURE__ */ jsx16(SetStepNav6, { nav: [{ label: "Admin Tools", url: "/admin/tools" }] }),
1846
- /* @__PURE__ */ jsx16("h1", { style: { margin: 0 }, children: "Admin Tools" }),
1847
- /* @__PURE__ */ jsx16("p", { style: { color: "var(--theme-elevation-600)", marginTop: "0.35rem" }, children: "Hidden fallback links for administrators." }),
1848
- /* @__PURE__ */ jsx16("div", { style: { display: "grid", gap: "0.6rem", marginTop: "1rem" }, children: links.map((link) => /* @__PURE__ */ jsxs15(
1849
- "a",
1850
- {
1851
- href: link.href,
1852
- style: {
1853
- background: "var(--theme-elevation-0)",
1854
- border: "1px solid var(--theme-elevation-150)",
1855
- borderRadius: 16,
1856
- color: "inherit",
1857
- padding: "0.85rem 1rem",
1858
- textDecoration: "none"
1859
- },
1860
- children: [
1861
- /* @__PURE__ */ jsx16("div", { style: { fontWeight: 900 }, children: link.label }),
1862
- /* @__PURE__ */ jsx16("div", { style: { color: "var(--theme-elevation-600)", fontSize: "0.9rem" }, children: link.href })
1863
- ]
1864
- },
1865
- link.href
1866
- )) })
1867
- ] });
2225
+ var inputStyle = {
2226
+ background: "var(--theme-elevation-0)",
2227
+ border: "1px solid var(--theme-elevation-200)",
2228
+ borderRadius: 10,
2229
+ color: "inherit",
2230
+ fontSize: "0.95rem",
2231
+ minHeight: 42,
2232
+ padding: "0.55rem 0.65rem",
2233
+ width: "100%"
2234
+ };
2235
+ var fieldLabelStyle = {
2236
+ color: "var(--theme-elevation-800)",
2237
+ display: "grid",
2238
+ fontSize: "0.88rem",
2239
+ fontWeight: 700,
2240
+ gap: "0.35rem"
2241
+ };
2242
+ var buttonStyle = {
2243
+ background: "var(--theme-success-700)",
2244
+ border: "1px solid var(--theme-success-700)",
2245
+ borderRadius: 10,
2246
+ color: "#fff",
2247
+ cursor: "pointer",
2248
+ fontSize: "0.9rem",
2249
+ fontWeight: 800,
2250
+ minHeight: 40,
2251
+ padding: "0 0.9rem"
2252
+ };
2253
+ var ghostButtonStyle = {
2254
+ ...buttonStyle,
2255
+ background: "transparent",
2256
+ color: "var(--theme-elevation-900)"
2257
+ };
2258
+ function AdminStudioContactFormView(props) {
2259
+ const globalSlug = getPropString6(props, "globalSlug", "contact-form");
2260
+ const globalsBasePath = getPropString6(props, "globalsBasePath", "/studio-globals");
2261
+ const adminBasePath = useAdminBasePath();
2262
+ const resolvedGlobalsBasePath = resolveAdminPath(adminBasePath, globalsBasePath);
2263
+ const rawGlobalPath = resolveAdminPath(adminBasePath, `/globals/${globalSlug}`);
2264
+ const [doc, setDoc] = useState9(defaultDoc);
2265
+ const [error, setError] = useState9(null);
2266
+ const [isLoading, setIsLoading] = useState9(true);
2267
+ const [isSaving, setIsSaving] = useState9(false);
2268
+ const [savedMessage, setSavedMessage] = useState9(null);
2269
+ useEffect10(() => {
2270
+ let mounted = true;
2271
+ const load = async () => {
2272
+ setIsLoading(true);
2273
+ setError(null);
2274
+ setSavedMessage(null);
2275
+ try {
2276
+ const response = await fetch(`/api/globals/${globalSlug}?depth=0&draft=true`, {
2277
+ credentials: "same-origin"
2278
+ });
2279
+ if (!response.ok) {
2280
+ throw new Error(`Failed to load global (${response.status}).`);
2281
+ }
2282
+ const json = await response.json();
2283
+ if (!mounted) return;
2284
+ setDoc(normalizeDoc(json));
2285
+ } catch (loadError) {
2286
+ if (!mounted) return;
2287
+ setError(loadError instanceof Error ? loadError.message : "Failed to load contact form settings.");
2288
+ } finally {
2289
+ if (mounted) {
2290
+ setIsLoading(false);
2291
+ }
2292
+ }
2293
+ };
2294
+ void load();
2295
+ return () => {
2296
+ mounted = false;
2297
+ };
2298
+ }, [globalSlug]);
2299
+ const payload = useMemo4(
2300
+ () => ({
2301
+ disabledMessage: doc.disabledMessage,
2302
+ enabled: doc.enabled,
2303
+ errorMessage: doc.errorMessage,
2304
+ notificationEmail: doc.notificationEmail.trim(),
2305
+ serviceOptions: doc.serviceOptions.map((option) => ({ label: option.label.trim() })).filter((option) => option.label.length > 0),
2306
+ submitButtonLabel: doc.submitButtonLabel,
2307
+ successMessage: doc.successMessage
2308
+ }),
2309
+ [doc]
2310
+ );
2311
+ const save = async () => {
2312
+ setIsSaving(true);
2313
+ setError(null);
2314
+ setSavedMessage(null);
2315
+ try {
2316
+ const response = await fetch(`/api/globals/${globalSlug}`, {
2317
+ body: JSON.stringify(payload),
2318
+ credentials: "same-origin",
2319
+ headers: {
2320
+ "Content-Type": "application/json"
2321
+ },
2322
+ method: "PATCH"
2323
+ });
2324
+ if (!response.ok) {
2325
+ throw new Error(`Failed to save settings (${response.status}).`);
2326
+ }
2327
+ const json = await response.json();
2328
+ setDoc(normalizeDoc(json));
2329
+ setSavedMessage("Saved.");
2330
+ } catch (saveError) {
2331
+ setError(saveError instanceof Error ? saveError.message : "Failed to save contact form settings.");
2332
+ } finally {
2333
+ setIsSaving(false);
2334
+ }
2335
+ };
2336
+ return /* @__PURE__ */ jsxs14("div", { style: { paddingBottom: "2rem" }, children: [
2337
+ /* @__PURE__ */ jsx15(
2338
+ SetStepNav5,
2339
+ {
2340
+ nav: [
2341
+ { label: "Globals", url: resolvedGlobalsBasePath },
2342
+ { label: "Contact Form" }
2343
+ ]
2344
+ }
2345
+ ),
2346
+ /* @__PURE__ */ jsx15("h1", { style: { margin: 0 }, children: "Contact Form" }),
2347
+ /* @__PURE__ */ jsx15("p", { style: { color: "var(--theme-elevation-600)", marginTop: "0.35rem" }, children: "Edit form behavior and submission messaging without leaving Studio." }),
2348
+ isLoading ? /* @__PURE__ */ jsx15("p", { style: { color: "var(--theme-elevation-600)" }, children: "Loading form settings\u2026" }) : null,
2349
+ error ? /* @__PURE__ */ jsx15("p", { style: { color: "var(--theme-error-600)" }, children: error }) : null,
2350
+ savedMessage ? /* @__PURE__ */ jsx15("p", { style: { color: "var(--theme-success-700)" }, children: savedMessage }) : null,
2351
+ !isLoading ? /* @__PURE__ */ jsxs14("div", { style: { display: "grid", gap: "1rem", marginTop: "1rem", maxWidth: 900 }, children: [
2352
+ /* @__PURE__ */ jsxs14("label", { style: { ...fieldLabelStyle, alignItems: "center", display: "flex", gap: "0.6rem" }, children: [
2353
+ /* @__PURE__ */ jsx15(
2354
+ "input",
2355
+ {
2356
+ checked: doc.enabled,
2357
+ onChange: (event) => setDoc((prev) => ({ ...prev, enabled: event.target.checked })),
2358
+ type: "checkbox"
2359
+ }
2360
+ ),
2361
+ "Form enabled"
2362
+ ] }),
2363
+ /* @__PURE__ */ jsxs14("label", { style: fieldLabelStyle, children: [
2364
+ "Notification Email",
2365
+ /* @__PURE__ */ jsx15(
2366
+ "input",
2367
+ {
2368
+ onChange: (event) => setDoc((prev) => ({ ...prev, notificationEmail: event.target.value })),
2369
+ style: inputStyle,
2370
+ type: "email",
2371
+ value: doc.notificationEmail
2372
+ }
2373
+ )
2374
+ ] }),
2375
+ /* @__PURE__ */ jsxs14("label", { style: fieldLabelStyle, children: [
2376
+ "Submit Button Label",
2377
+ /* @__PURE__ */ jsx15(
2378
+ "input",
2379
+ {
2380
+ onChange: (event) => setDoc((prev) => ({ ...prev, submitButtonLabel: event.target.value })),
2381
+ style: inputStyle,
2382
+ type: "text",
2383
+ value: doc.submitButtonLabel
2384
+ }
2385
+ )
2386
+ ] }),
2387
+ /* @__PURE__ */ jsxs14("label", { style: fieldLabelStyle, children: [
2388
+ "Success Message",
2389
+ /* @__PURE__ */ jsx15(
2390
+ "input",
2391
+ {
2392
+ onChange: (event) => setDoc((prev) => ({ ...prev, successMessage: event.target.value })),
2393
+ style: inputStyle,
2394
+ type: "text",
2395
+ value: doc.successMessage
2396
+ }
2397
+ )
2398
+ ] }),
2399
+ /* @__PURE__ */ jsxs14("label", { style: fieldLabelStyle, children: [
2400
+ "Error Message",
2401
+ /* @__PURE__ */ jsx15(
2402
+ "input",
2403
+ {
2404
+ onChange: (event) => setDoc((prev) => ({ ...prev, errorMessage: event.target.value })),
2405
+ style: inputStyle,
2406
+ type: "text",
2407
+ value: doc.errorMessage
2408
+ }
2409
+ )
2410
+ ] }),
2411
+ /* @__PURE__ */ jsxs14("label", { style: fieldLabelStyle, children: [
2412
+ "Disabled Message",
2413
+ /* @__PURE__ */ jsx15(
2414
+ "input",
2415
+ {
2416
+ onChange: (event) => setDoc((prev) => ({ ...prev, disabledMessage: event.target.value })),
2417
+ style: inputStyle,
2418
+ type: "text",
2419
+ value: doc.disabledMessage
2420
+ }
2421
+ )
2422
+ ] }),
2423
+ /* @__PURE__ */ jsxs14(
2424
+ "div",
2425
+ {
2426
+ style: {
2427
+ background: "var(--theme-elevation-0)",
2428
+ border: "1px solid var(--theme-elevation-200)",
2429
+ borderRadius: 14,
2430
+ padding: "0.85rem"
2431
+ },
2432
+ children: [
2433
+ /* @__PURE__ */ jsx15("div", { style: { fontWeight: 900, marginBottom: "0.65rem" }, children: "Service Options" }),
2434
+ /* @__PURE__ */ jsx15("div", { style: { display: "grid", gap: "0.55rem" }, children: doc.serviceOptions.map((option, index) => /* @__PURE__ */ jsxs14("div", { style: { display: "flex", gap: "0.5rem" }, children: [
2435
+ /* @__PURE__ */ jsx15(
2436
+ "input",
2437
+ {
2438
+ onChange: (event) => setDoc((prev) => ({
2439
+ ...prev,
2440
+ serviceOptions: prev.serviceOptions.map(
2441
+ (row, rowIndex) => rowIndex === index ? { label: event.target.value } : row
2442
+ )
2443
+ })),
2444
+ style: inputStyle,
2445
+ type: "text",
2446
+ value: option.label
2447
+ }
2448
+ ),
2449
+ /* @__PURE__ */ jsx15(
2450
+ "button",
2451
+ {
2452
+ onClick: () => setDoc((prev) => ({
2453
+ ...prev,
2454
+ serviceOptions: prev.serviceOptions.length > 1 ? prev.serviceOptions.filter((_, rowIndex) => rowIndex !== index) : prev.serviceOptions
2455
+ })),
2456
+ style: ghostButtonStyle,
2457
+ type: "button",
2458
+ children: "Remove"
2459
+ }
2460
+ )
2461
+ ] }, `${index}-${option.label}`)) }),
2462
+ /* @__PURE__ */ jsx15(
2463
+ "button",
2464
+ {
2465
+ onClick: () => setDoc((prev) => ({
2466
+ ...prev,
2467
+ serviceOptions: [...prev.serviceOptions, { label: "" }]
2468
+ })),
2469
+ style: { ...ghostButtonStyle, marginTop: "0.7rem" },
2470
+ type: "button",
2471
+ children: "Add Service"
2472
+ }
2473
+ )
2474
+ ]
2475
+ }
2476
+ ),
2477
+ /* @__PURE__ */ jsxs14("div", { style: { display: "flex", gap: "0.6rem" }, children: [
2478
+ /* @__PURE__ */ jsx15("button", { disabled: isSaving, onClick: () => void save(), style: buttonStyle, type: "button", children: isSaving ? "Saving\u2026" : "Save Form Settings" }),
2479
+ /* @__PURE__ */ jsx15(
2480
+ "a",
2481
+ {
2482
+ href: rawGlobalPath,
2483
+ style: {
2484
+ ...ghostButtonStyle,
2485
+ alignItems: "center",
2486
+ display: "inline-flex",
2487
+ justifyContent: "center",
2488
+ textDecoration: "none"
2489
+ },
2490
+ children: "Open Raw Global"
2491
+ }
2492
+ )
2493
+ ] })
2494
+ ] }) : null
2495
+ ] });
2496
+ }
2497
+
2498
+ // src/admin/components/studio/AdminStudioMediaView.tsx
2499
+ import { SetStepNav as SetStepNav6 } from "@payloadcms/ui";
2500
+ import { Fragment as Fragment6, jsx as jsx16, jsxs as jsxs15 } from "react/jsx-runtime";
2501
+ var getPropString7 = (props, key, fallback) => {
2502
+ if (!props || typeof props !== "object") return fallback;
2503
+ const direct = props[key];
2504
+ if (typeof direct === "string" && direct.length > 0) return direct;
2505
+ const clientProps = props.clientProps;
2506
+ if (clientProps && typeof clientProps === "object") {
2507
+ const nested = clientProps[key];
2508
+ if (typeof nested === "string" && nested.length > 0) return nested;
2509
+ }
2510
+ return fallback;
2511
+ };
2512
+ function AdminStudioMediaView(props) {
2513
+ const mediaCollectionSlug = getPropString7(props, "mediaCollectionSlug", "media");
2514
+ const adminBasePath = useAdminBasePath();
2515
+ const mediaPath = resolveAdminPath(adminBasePath, `/collections/${mediaCollectionSlug}`);
2516
+ const mediaViewPath = resolveAdminPath(adminBasePath, "/media");
2517
+ return /* @__PURE__ */ jsxs15(Fragment6, { children: [
2518
+ /* @__PURE__ */ jsx16(SetStepNav6, { nav: [{ label: "Media", url: mediaViewPath }] }),
2519
+ /* @__PURE__ */ jsx16("h1", { style: { margin: 0 }, children: "Media" }),
2520
+ /* @__PURE__ */ jsx16("p", { style: { color: "var(--theme-elevation-600)", marginTop: "0.35rem" }, children: "Media management is currently using Payload's library." }),
2521
+ /* @__PURE__ */ jsx16("div", { style: { display: "grid", gap: "0.6rem", marginTop: "1rem" }, children: /* @__PURE__ */ jsxs15(
2522
+ "a",
2523
+ {
2524
+ href: mediaPath,
2525
+ style: {
2526
+ background: "var(--theme-elevation-0)",
2527
+ border: "1px solid var(--theme-elevation-150)",
2528
+ borderRadius: 16,
2529
+ color: "inherit",
2530
+ padding: "0.85rem 1rem",
2531
+ textDecoration: "none"
2532
+ },
2533
+ children: [
2534
+ /* @__PURE__ */ jsx16("div", { style: { fontWeight: 900 }, children: "Open Media Library" }),
2535
+ /* @__PURE__ */ jsx16("div", { style: { color: "var(--theme-elevation-600)", fontSize: "0.9rem" }, children: mediaPath })
2536
+ ]
2537
+ }
2538
+ ) })
2539
+ ] });
2540
+ }
2541
+
2542
+ // src/admin/components/studio/AdminStudioFormsView.tsx
2543
+ import { useEffect as useEffect11, useMemo as useMemo5, useState as useState10 } from "react";
2544
+ import { SetStepNav as SetStepNav7, useAuth as useAuth4 } from "@payloadcms/ui";
2545
+ import { Fragment as Fragment7, jsx as jsx17, jsxs as jsxs16 } from "react/jsx-runtime";
2546
+ var isAdmin3 = (user) => {
2547
+ if (!user || typeof user !== "object") return false;
2548
+ const role = user.role;
2549
+ return typeof role === "string" && role === "admin";
2550
+ };
2551
+ var isEditor2 = (user) => {
2552
+ if (!user || typeof user !== "object") return false;
2553
+ const role = user.role;
2554
+ return typeof role === "string" && role === "editor";
2555
+ };
2556
+ var canReviewForms = (user) => isAdmin3(user) || isEditor2(user);
2557
+ var getPropString8 = (props, key, fallback) => {
2558
+ if (!props || typeof props !== "object") return fallback;
2559
+ const direct = props[key];
2560
+ if (typeof direct === "string" && direct.length > 0) return direct;
2561
+ const clientProps = props.clientProps;
2562
+ if (clientProps && typeof clientProps === "object") {
2563
+ const nested = clientProps[key];
2564
+ if (typeof nested === "string" && nested.length > 0) return nested;
2565
+ }
2566
+ return fallback;
2567
+ };
2568
+ var formatDate = (value) => {
2569
+ if (typeof value !== "string" || value.length === 0) {
2570
+ return "Unknown date";
2571
+ }
2572
+ const parsed = new Date(value);
2573
+ if (Number.isNaN(parsed.getTime())) {
2574
+ return value;
2575
+ }
2576
+ return parsed.toLocaleString();
2577
+ };
2578
+ var formatFileSize = (value) => {
2579
+ if (typeof value !== "number" || !Number.isFinite(value) || value <= 0) {
2580
+ return null;
2581
+ }
2582
+ if (value < 1024) return `${value} B`;
2583
+ if (value < 1024 * 1024) return `${(value / 1024).toFixed(1)} KB`;
2584
+ return `${(value / (1024 * 1024)).toFixed(1)} MB`;
2585
+ };
2586
+ var getFieldEntries = (value) => {
2587
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
2588
+ return [];
2589
+ }
2590
+ return Object.entries(value);
2591
+ };
2592
+ var getString = (value) => typeof value === "string" && value.trim().length > 0 ? value.trim() : null;
2593
+ var getSubmissionIdentity = (value) => {
2594
+ const entries = getFieldEntries(value);
2595
+ const byKey = Object.fromEntries(entries);
2596
+ const firstName = getString(byKey.firstName) || getString(byKey.first_name);
2597
+ const lastName = getString(byKey.lastName) || getString(byKey.last_name);
2598
+ const email = getString(byKey.email) || getString(byKey.contactEmail) || getString(byKey.contact_email);
2599
+ const fullName = getString(byKey.name) || [firstName, lastName].filter(Boolean).join(" ").trim() || void 0;
2600
+ return {
2601
+ ...email ? { email } : {},
2602
+ ...fullName ? { name: fullName } : {}
2603
+ };
2604
+ };
2605
+ var renderValue = (value) => {
2606
+ if (value === null || value === void 0 || value === "") {
2607
+ return /* @__PURE__ */ jsx17("span", { style: { color: "var(--theme-elevation-500)" }, children: "\u2014" });
2608
+ }
2609
+ if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
2610
+ return String(value);
2611
+ }
2612
+ if (Array.isArray(value)) {
2613
+ if (value.length === 0) {
2614
+ return /* @__PURE__ */ jsx17("span", { style: { color: "var(--theme-elevation-500)" }, children: "\u2014" });
2615
+ }
2616
+ const primitiveValues = value.every(
2617
+ (entry) => typeof entry === "string" || typeof entry === "number" || typeof entry === "boolean" || entry === null
2618
+ );
2619
+ if (primitiveValues) {
2620
+ return value.map((entry) => String(entry)).join(", ");
2621
+ }
2622
+ return /* @__PURE__ */ jsx17(
2623
+ "pre",
2624
+ {
2625
+ style: {
2626
+ margin: 0,
2627
+ overflowX: "auto",
2628
+ whiteSpace: "pre-wrap",
2629
+ wordBreak: "break-word"
2630
+ },
2631
+ children: JSON.stringify(value, null, 2)
2632
+ }
2633
+ );
2634
+ }
2635
+ if (typeof value === "object") {
2636
+ return /* @__PURE__ */ jsx17(
2637
+ "pre",
2638
+ {
2639
+ style: {
2640
+ margin: 0,
2641
+ overflowX: "auto",
2642
+ whiteSpace: "pre-wrap",
2643
+ wordBreak: "break-word"
2644
+ },
2645
+ children: JSON.stringify(value, null, 2)
2646
+ }
2647
+ );
2648
+ }
2649
+ return String(value);
2650
+ };
2651
+ var getFormID = (value) => {
2652
+ if (typeof value === "string" || typeof value === "number") {
2653
+ return String(value);
2654
+ }
2655
+ if (value && typeof value === "object") {
2656
+ const id = value.id;
2657
+ if (typeof id === "string" || typeof id === "number") {
2658
+ return String(id);
2659
+ }
2660
+ }
2661
+ return null;
2662
+ };
2663
+ var getUploads = (value) => {
2664
+ if (!Array.isArray(value)) {
2665
+ return [];
2666
+ }
2667
+ return value.map((entry) => {
2668
+ if (typeof entry === "string" || typeof entry === "number") {
2669
+ return { id: entry };
2670
+ }
2671
+ if (entry && typeof entry === "object") {
2672
+ return entry;
2673
+ }
2674
+ return null;
2675
+ }).filter((entry) => Boolean(entry));
2676
+ };
2677
+ var panelStyle = {
2678
+ background: "var(--theme-elevation-0)",
2679
+ border: "1px solid var(--theme-elevation-150)",
2680
+ borderRadius: 18
2681
+ };
2682
+ function AdminStudioFormsView(props) {
2683
+ const { user } = useAuth4();
2684
+ const formsCollectionSlug = getPropString8(props, "formsCollectionSlug", "forms");
2685
+ const formSubmissionsCollectionSlug = getPropString8(
2686
+ props,
2687
+ "formSubmissionsCollectionSlug",
2688
+ "form-submissions"
2689
+ );
2690
+ const formUploadsCollectionSlug = getPropString8(props, "formUploadsCollectionSlug", "form-uploads");
2691
+ const adminBasePath = useAdminBasePath();
2692
+ const formsViewPath = resolveAdminPath(adminBasePath, "/studio-forms");
2693
+ const rawFormsPath = resolveAdminPath(adminBasePath, `/collections/${formsCollectionSlug}`);
2694
+ const rawSubmissionsPath = resolveAdminPath(
2695
+ adminBasePath,
2696
+ `/collections/${formSubmissionsCollectionSlug}`
2697
+ );
2698
+ const rawUploadsPath = resolveAdminPath(adminBasePath, `/collections/${formUploadsCollectionSlug}`);
2699
+ const [selectedFormID, setSelectedFormID] = useState10("");
2700
+ const [forms, setForms] = useState10([]);
2701
+ const [submissions, setSubmissions] = useState10([]);
2702
+ const [formsLoading, setFormsLoading] = useState10(true);
2703
+ const [submissionsLoading, setSubmissionsLoading] = useState10(false);
2704
+ const [formsError, setFormsError] = useState10(null);
2705
+ const [submissionsError, setSubmissionsError] = useState10(null);
2706
+ const selectedForm = useMemo5(
2707
+ () => forms.find((form) => {
2708
+ const id = typeof form.id === "string" || typeof form.id === "number" ? String(form.id) : "";
2709
+ return selectedFormID.length > 0 && id === selectedFormID;
2710
+ }) || null,
2711
+ [forms, selectedFormID]
2712
+ );
2713
+ useEffect11(() => {
2714
+ if (typeof window === "undefined") {
2715
+ return;
2716
+ }
2717
+ const params = new URLSearchParams(window.location.search);
2718
+ const formID = params.get("form");
2719
+ if (formID) {
2720
+ setSelectedFormID(formID);
2721
+ }
2722
+ }, []);
2723
+ useEffect11(() => {
2724
+ if (!canReviewForms(user)) {
2725
+ return;
2726
+ }
2727
+ let cancelled = false;
2728
+ const run = async () => {
2729
+ setFormsLoading(true);
2730
+ setFormsError(null);
2731
+ try {
2732
+ const params = new URLSearchParams({
2733
+ depth: "0",
2734
+ limit: "100",
2735
+ sort: "title"
2736
+ });
2737
+ const response = await fetch(`/api/${formsCollectionSlug}?${params.toString()}`, {
2738
+ credentials: "include"
2739
+ });
2740
+ if (!response.ok) {
2741
+ const body = await response.text();
2742
+ throw new Error(body || "Failed to fetch forms");
2743
+ }
2744
+ const next = await response.json();
2745
+ const docs = Array.isArray(next.docs) ? next.docs : [];
2746
+ if (cancelled) return;
2747
+ setForms(docs);
2748
+ setSelectedFormID((current) => {
2749
+ if (docs.length === 0) {
2750
+ return "";
2751
+ }
2752
+ const knownSelected = docs.some((doc) => {
2753
+ const id = typeof doc.id === "string" || typeof doc.id === "number" ? String(doc.id) : "";
2754
+ return id === current;
2755
+ });
2756
+ if (knownSelected) {
2757
+ return current;
2758
+ }
2759
+ const firstID = docs[0]?.id;
2760
+ return typeof firstID === "string" || typeof firstID === "number" ? String(firstID) : "";
2761
+ });
2762
+ } catch (error) {
2763
+ if (!cancelled) {
2764
+ setFormsError(error instanceof Error ? error.message : "Failed to fetch forms");
2765
+ }
2766
+ } finally {
2767
+ if (!cancelled) {
2768
+ setFormsLoading(false);
2769
+ }
2770
+ }
2771
+ };
2772
+ void run();
2773
+ return () => {
2774
+ cancelled = true;
2775
+ };
2776
+ }, [formsCollectionSlug, user]);
2777
+ useEffect11(() => {
2778
+ if (!selectedFormID || !canReviewForms(user)) {
2779
+ setSubmissions([]);
2780
+ return;
2781
+ }
2782
+ let cancelled = false;
2783
+ const run = async () => {
2784
+ setSubmissionsLoading(true);
2785
+ setSubmissionsError(null);
2786
+ try {
2787
+ const params = new URLSearchParams({
2788
+ depth: "1",
2789
+ limit: "100",
2790
+ sort: "-submittedAt"
2791
+ });
2792
+ params.set("where[form][equals]", selectedFormID);
2793
+ const response = await fetch(`/api/${formSubmissionsCollectionSlug}?${params.toString()}`, {
2794
+ credentials: "include"
2795
+ });
2796
+ if (!response.ok) {
2797
+ const body = await response.text();
2798
+ throw new Error(body || "Failed to fetch submissions");
2799
+ }
2800
+ const next = await response.json();
2801
+ if (!cancelled) {
2802
+ setSubmissions(Array.isArray(next.docs) ? next.docs : []);
2803
+ }
2804
+ } catch (error) {
2805
+ if (!cancelled) {
2806
+ setSubmissionsError(
2807
+ error instanceof Error ? error.message : "Failed to fetch form submissions"
2808
+ );
2809
+ }
2810
+ } finally {
2811
+ if (!cancelled) {
2812
+ setSubmissionsLoading(false);
2813
+ }
2814
+ }
2815
+ };
2816
+ void run();
2817
+ return () => {
2818
+ cancelled = true;
2819
+ };
2820
+ }, [formSubmissionsCollectionSlug, selectedFormID, user]);
2821
+ useEffect11(() => {
2822
+ if (typeof window === "undefined" || !selectedFormID) {
2823
+ return;
2824
+ }
2825
+ const url = new URL(window.location.href);
2826
+ url.searchParams.set("form", selectedFormID);
2827
+ window.history.replaceState({}, "", url.toString());
2828
+ }, [selectedFormID]);
2829
+ if (!canReviewForms(user)) {
2830
+ return /* @__PURE__ */ jsxs16(Fragment7, { children: [
2831
+ /* @__PURE__ */ jsx17(SetStepNav7, { nav: [{ label: "Forms", url: formsViewPath }] }),
2832
+ /* @__PURE__ */ jsx17("h1", { style: { margin: 0 }, children: "Forms" }),
2833
+ /* @__PURE__ */ jsx17("p", { style: { color: "var(--theme-elevation-600)", marginTop: "0.35rem" }, children: "You do not have access to this page." })
2834
+ ] });
2835
+ }
2836
+ const selectedTitle = selectedForm && typeof selectedForm.title === "string" && selectedForm.title || "Forms";
2837
+ const selectedSlug = selectedForm && typeof selectedForm.slug === "string" && selectedForm.slug || null;
2838
+ const selectedStepCount = Array.isArray(selectedForm?.steps) ? selectedForm.steps.length : 0;
2839
+ const selectedFieldCount = Array.isArray(selectedForm?.steps) ? selectedForm.steps.reduce((count, step) => {
2840
+ if (!step || typeof step !== "object") return count;
2841
+ const fields = step.fields;
2842
+ return count + (Array.isArray(fields) ? fields.length : 0);
2843
+ }, 0) : 0;
2844
+ return /* @__PURE__ */ jsxs16(Fragment7, { children: [
2845
+ /* @__PURE__ */ jsx17(SetStepNav7, { nav: [{ label: "Forms", url: formsViewPath }] }),
2846
+ /* @__PURE__ */ jsxs16("div", { style: { alignItems: "flex-end", display: "flex", flexWrap: "wrap", gap: "0.75rem" }, children: [
2847
+ /* @__PURE__ */ jsxs16("div", { style: { flex: 1, minWidth: 240 }, children: [
2848
+ /* @__PURE__ */ jsx17("h1", { style: { margin: 0 }, children: "Forms" }),
2849
+ /* @__PURE__ */ jsx17("p", { style: { color: "var(--theme-elevation-600)", marginTop: "0.35rem" }, children: "Review your forms, responses, and any uploaded files in one place." })
2850
+ ] }),
2851
+ /* @__PURE__ */ jsxs16("div", { style: { display: "flex", flexWrap: "wrap", gap: "0.5rem" }, children: [
2852
+ /* @__PURE__ */ jsx17(
2853
+ "a",
2854
+ {
2855
+ href: rawFormsPath,
2856
+ style: {
2857
+ background: "var(--theme-elevation-900)",
2858
+ borderRadius: 12,
2859
+ color: "var(--theme-elevation-0)",
2860
+ fontWeight: 800,
2861
+ padding: "0.55rem 0.85rem",
2862
+ textDecoration: "none"
2863
+ },
2864
+ children: "Open Forms Collection"
2865
+ }
2866
+ ),
2867
+ /* @__PURE__ */ jsx17(
2868
+ "a",
2869
+ {
2870
+ href: rawSubmissionsPath,
2871
+ style: {
2872
+ border: "1px solid var(--theme-elevation-200)",
2873
+ borderRadius: 12,
2874
+ color: "inherit",
2875
+ fontWeight: 800,
2876
+ padding: "0.55rem 0.85rem",
2877
+ textDecoration: "none"
2878
+ },
2879
+ children: "Open Submissions"
2880
+ }
2881
+ ),
2882
+ /* @__PURE__ */ jsx17(
2883
+ "a",
2884
+ {
2885
+ href: rawUploadsPath,
2886
+ style: {
2887
+ border: "1px solid var(--theme-elevation-200)",
2888
+ borderRadius: 12,
2889
+ color: "inherit",
2890
+ fontWeight: 800,
2891
+ padding: "0.55rem 0.85rem",
2892
+ textDecoration: "none"
2893
+ },
2894
+ children: "Open Uploads"
2895
+ }
2896
+ )
2897
+ ] })
2898
+ ] }),
2899
+ /* @__PURE__ */ jsxs16(
2900
+ "div",
2901
+ {
2902
+ style: {
2903
+ display: "grid",
2904
+ gap: "1rem",
2905
+ gridTemplateColumns: "minmax(260px, 320px) minmax(0, 1fr)",
2906
+ marginTop: "1rem"
2907
+ },
2908
+ children: [
2909
+ /* @__PURE__ */ jsxs16("section", { style: { ...panelStyle, padding: "1rem" }, children: [
2910
+ /* @__PURE__ */ jsx17("div", { style: { fontSize: "0.82rem", fontWeight: 900, letterSpacing: "0.08em", textTransform: "uppercase" }, children: "Site forms" }),
2911
+ formsLoading ? /* @__PURE__ */ jsx17("div", { style: { color: "var(--theme-elevation-600)", marginTop: "0.85rem" }, children: "Loading forms\u2026" }) : null,
2912
+ formsError ? /* @__PURE__ */ jsx17("div", { style: { color: "crimson", marginTop: "0.85rem" }, children: formsError }) : null,
2913
+ !formsLoading && !formsError && forms.length === 0 ? /* @__PURE__ */ jsx17(
2914
+ "div",
2915
+ {
2916
+ style: {
2917
+ border: "1px dashed var(--theme-elevation-300)",
2918
+ borderRadius: 16,
2919
+ color: "var(--theme-elevation-700)",
2920
+ marginTop: "0.85rem",
2921
+ padding: "0.9rem"
2922
+ },
2923
+ children: "No forms found."
2924
+ }
2925
+ ) : null,
2926
+ /* @__PURE__ */ jsx17("div", { style: { display: "grid", gap: "0.55rem", marginTop: "0.85rem" }, children: forms.map((form) => {
2927
+ const id = typeof form.id === "string" || typeof form.id === "number" ? String(form.id) : "";
2928
+ if (!id) return null;
2929
+ const title = typeof form.title === "string" ? form.title : "Untitled Form";
2930
+ const slug = typeof form.slug === "string" ? form.slug : "";
2931
+ const isSelected = id === selectedFormID;
2932
+ return /* @__PURE__ */ jsxs16(
2933
+ "button",
2934
+ {
2935
+ onClick: () => setSelectedFormID(id),
2936
+ style: {
2937
+ background: isSelected ? "var(--theme-elevation-50)" : "var(--theme-elevation-0)",
2938
+ border: `1px solid ${isSelected ? "var(--theme-elevation-300)" : "var(--theme-elevation-150)"}`,
2939
+ borderRadius: 16,
2940
+ cursor: "pointer",
2941
+ padding: "0.85rem",
2942
+ textAlign: "left"
2943
+ },
2944
+ type: "button",
2945
+ children: [
2946
+ /* @__PURE__ */ jsx17("div", { style: { fontWeight: 900 }, children: title }),
2947
+ slug ? /* @__PURE__ */ jsx17(
2948
+ "div",
2949
+ {
2950
+ style: {
2951
+ color: "var(--theme-elevation-600)",
2952
+ fontSize: "0.9rem",
2953
+ marginTop: "0.2rem"
2954
+ },
2955
+ children: slug
2956
+ }
2957
+ ) : null
2958
+ ]
2959
+ },
2960
+ id
2961
+ );
2962
+ }) })
2963
+ ] }),
2964
+ /* @__PURE__ */ jsxs16("section", { style: { display: "grid", gap: "1rem" }, children: [
2965
+ /* @__PURE__ */ jsxs16("div", { style: { ...panelStyle, padding: "1rem" }, children: [
2966
+ /* @__PURE__ */ jsxs16(
2967
+ "div",
2968
+ {
2969
+ style: {
2970
+ alignItems: "flex-start",
2971
+ display: "flex",
2972
+ flexWrap: "wrap",
2973
+ gap: "0.9rem",
2974
+ justifyContent: "space-between"
2975
+ },
2976
+ children: [
2977
+ /* @__PURE__ */ jsxs16("div", { children: [
2978
+ /* @__PURE__ */ jsx17(
2979
+ "div",
2980
+ {
2981
+ style: {
2982
+ color: "var(--theme-elevation-600)",
2983
+ fontSize: "0.82rem",
2984
+ fontWeight: 900,
2985
+ letterSpacing: "0.08em",
2986
+ textTransform: "uppercase"
2987
+ },
2988
+ children: "Selected form"
2989
+ }
2990
+ ),
2991
+ /* @__PURE__ */ jsx17("h2", { style: { margin: "0.2rem 0 0", fontSize: "1.45rem" }, children: selectedTitle }),
2992
+ selectedSlug ? /* @__PURE__ */ jsx17("div", { style: { color: "var(--theme-elevation-600)", marginTop: "0.2rem" }, children: selectedSlug }) : null
2993
+ ] }),
2994
+ selectedFormID ? /* @__PURE__ */ jsx17(
2995
+ "a",
2996
+ {
2997
+ href: `${rawFormsPath}/${selectedFormID}`,
2998
+ style: {
2999
+ border: "1px solid var(--theme-elevation-200)",
3000
+ borderRadius: 12,
3001
+ color: "inherit",
3002
+ fontWeight: 800,
3003
+ padding: "0.55rem 0.85rem",
3004
+ textDecoration: "none"
3005
+ },
3006
+ children: "Edit Form"
3007
+ }
3008
+ ) : null
3009
+ ]
3010
+ }
3011
+ ),
3012
+ selectedForm ? /* @__PURE__ */ jsxs16(
3013
+ "div",
3014
+ {
3015
+ style: {
3016
+ display: "grid",
3017
+ gap: "0.75rem",
3018
+ gridTemplateColumns: "repeat(auto-fit, minmax(180px, 1fr))",
3019
+ marginTop: "1rem"
3020
+ },
3021
+ children: [
3022
+ /* @__PURE__ */ jsxs16("div", { style: { ...panelStyle, padding: "0.8rem 0.9rem" }, children: [
3023
+ /* @__PURE__ */ jsx17("div", { style: { color: "var(--theme-elevation-600)", fontSize: "0.82rem" }, children: "Steps" }),
3024
+ /* @__PURE__ */ jsx17("div", { style: { fontSize: "1.35rem", fontWeight: 900, marginTop: "0.2rem" }, children: selectedStepCount })
3025
+ ] }),
3026
+ /* @__PURE__ */ jsxs16("div", { style: { ...panelStyle, padding: "0.8rem 0.9rem" }, children: [
3027
+ /* @__PURE__ */ jsx17("div", { style: { color: "var(--theme-elevation-600)", fontSize: "0.82rem" }, children: "Fields" }),
3028
+ /* @__PURE__ */ jsx17("div", { style: { fontSize: "1.35rem", fontWeight: 900, marginTop: "0.2rem" }, children: selectedFieldCount })
3029
+ ] }),
3030
+ /* @__PURE__ */ jsxs16("div", { style: { ...panelStyle, padding: "0.8rem 0.9rem" }, children: [
3031
+ /* @__PURE__ */ jsx17("div", { style: { color: "var(--theme-elevation-600)", fontSize: "0.82rem" }, children: "Submit label" }),
3032
+ /* @__PURE__ */ jsx17("div", { style: { fontSize: "1rem", fontWeight: 900, marginTop: "0.2rem" }, children: typeof selectedForm.submitLabel === "string" && selectedForm.submitLabel.length > 0 ? selectedForm.submitLabel : "Submit" })
3033
+ ] }),
3034
+ /* @__PURE__ */ jsxs16("div", { style: { ...panelStyle, padding: "0.8rem 0.9rem" }, children: [
3035
+ /* @__PURE__ */ jsx17("div", { style: { color: "var(--theme-elevation-600)", fontSize: "0.82rem" }, children: "Updated" }),
3036
+ /* @__PURE__ */ jsx17("div", { style: { fontSize: "1rem", fontWeight: 900, marginTop: "0.2rem" }, children: formatDate(selectedForm.updatedAt) })
3037
+ ] })
3038
+ ]
3039
+ }
3040
+ ) : /* @__PURE__ */ jsx17("div", { style: { color: "var(--theme-elevation-600)", marginTop: "1rem" }, children: "Pick a form to review its responses." })
3041
+ ] }),
3042
+ /* @__PURE__ */ jsxs16("div", { style: { ...panelStyle, padding: "1rem" }, children: [
3043
+ /* @__PURE__ */ jsxs16(
3044
+ "div",
3045
+ {
3046
+ style: {
3047
+ alignItems: "center",
3048
+ display: "flex",
3049
+ flexWrap: "wrap",
3050
+ gap: "0.75rem",
3051
+ justifyContent: "space-between"
3052
+ },
3053
+ children: [
3054
+ /* @__PURE__ */ jsxs16("div", { children: [
3055
+ /* @__PURE__ */ jsx17("h2", { style: { fontSize: "1.2rem", margin: 0 }, children: "Responses" }),
3056
+ /* @__PURE__ */ jsx17("p", { style: { color: "var(--theme-elevation-600)", margin: "0.25rem 0 0" }, children: "Latest submissions and any files they uploaded." })
3057
+ ] }),
3058
+ selectedFormID ? /* @__PURE__ */ jsx17(
3059
+ "a",
3060
+ {
3061
+ href: rawSubmissionsPath,
3062
+ style: {
3063
+ border: "1px solid var(--theme-elevation-200)",
3064
+ borderRadius: 12,
3065
+ color: "inherit",
3066
+ fontWeight: 800,
3067
+ padding: "0.55rem 0.85rem",
3068
+ textDecoration: "none"
3069
+ },
3070
+ children: "Raw Submissions"
3071
+ }
3072
+ ) : null
3073
+ ]
3074
+ }
3075
+ ),
3076
+ submissionsLoading ? /* @__PURE__ */ jsx17("div", { style: { color: "var(--theme-elevation-600)", marginTop: "1rem" }, children: "Loading responses\u2026" }) : null,
3077
+ submissionsError ? /* @__PURE__ */ jsx17("div", { style: { color: "crimson", marginTop: "1rem" }, children: submissionsError }) : null,
3078
+ !submissionsLoading && !submissionsError && selectedFormID && submissions.length === 0 ? /* @__PURE__ */ jsx17(
3079
+ "div",
3080
+ {
3081
+ style: {
3082
+ border: "1px dashed var(--theme-elevation-300)",
3083
+ borderRadius: 16,
3084
+ color: "var(--theme-elevation-700)",
3085
+ marginTop: "1rem",
3086
+ padding: "1rem"
3087
+ },
3088
+ children: "No responses yet for this form."
3089
+ }
3090
+ ) : null,
3091
+ /* @__PURE__ */ jsx17("div", { style: { display: "grid", gap: "0.9rem", marginTop: "1rem" }, children: submissions.map((submission) => {
3092
+ const id = typeof submission.id === "string" || typeof submission.id === "number" ? String(submission.id) : "";
3093
+ if (!id) return null;
3094
+ const submissionData = submission.data;
3095
+ const identity = getSubmissionIdentity(submissionData);
3096
+ const uploads = getUploads(submission.files);
3097
+ const formSlug = getString(submission.formSlug);
3098
+ const submissionFormID = getFormID(submission.form);
3099
+ return /* @__PURE__ */ jsxs16("article", { style: { ...panelStyle, padding: "1rem" }, children: [
3100
+ /* @__PURE__ */ jsxs16(
3101
+ "div",
3102
+ {
3103
+ style: {
3104
+ alignItems: "flex-start",
3105
+ display: "flex",
3106
+ flexWrap: "wrap",
3107
+ gap: "0.75rem",
3108
+ justifyContent: "space-between"
3109
+ },
3110
+ children: [
3111
+ /* @__PURE__ */ jsxs16("div", { children: [
3112
+ /* @__PURE__ */ jsx17("div", { style: { fontWeight: 900 }, children: identity.name || identity.email || "Submission" }),
3113
+ /* @__PURE__ */ jsxs16("div", { style: { color: "var(--theme-elevation-600)", marginTop: "0.2rem" }, children: [
3114
+ formatDate(submission.submittedAt),
3115
+ formSlug ? ` \xB7 ${formSlug}` : ""
3116
+ ] })
3117
+ ] }),
3118
+ /* @__PURE__ */ jsxs16("div", { style: { display: "flex", flexWrap: "wrap", gap: "0.5rem" }, children: [
3119
+ submissionFormID ? /* @__PURE__ */ jsx17(
3120
+ "a",
3121
+ {
3122
+ href: `${rawFormsPath}/${submissionFormID}`,
3123
+ style: {
3124
+ border: "1px solid var(--theme-elevation-200)",
3125
+ borderRadius: 999,
3126
+ color: "inherit",
3127
+ fontSize: "0.88rem",
3128
+ fontWeight: 800,
3129
+ padding: "0.3rem 0.65rem",
3130
+ textDecoration: "none"
3131
+ },
3132
+ children: "Form"
3133
+ }
3134
+ ) : null,
3135
+ /* @__PURE__ */ jsx17(
3136
+ "a",
3137
+ {
3138
+ href: `${rawSubmissionsPath}/${id}`,
3139
+ style: {
3140
+ border: "1px solid var(--theme-elevation-200)",
3141
+ borderRadius: 999,
3142
+ color: "inherit",
3143
+ fontSize: "0.88rem",
3144
+ fontWeight: 800,
3145
+ padding: "0.3rem 0.65rem",
3146
+ textDecoration: "none"
3147
+ },
3148
+ children: "Submission"
3149
+ }
3150
+ )
3151
+ ] })
3152
+ ]
3153
+ }
3154
+ ),
3155
+ identity.name || identity.email ? /* @__PURE__ */ jsxs16(
3156
+ "div",
3157
+ {
3158
+ style: {
3159
+ display: "grid",
3160
+ gap: "0.65rem",
3161
+ gridTemplateColumns: "repeat(auto-fit, minmax(180px, 1fr))",
3162
+ marginTop: "0.9rem"
3163
+ },
3164
+ children: [
3165
+ identity.name ? /* @__PURE__ */ jsxs16("div", { style: { ...panelStyle, padding: "0.75rem 0.85rem" }, children: [
3166
+ /* @__PURE__ */ jsx17("div", { style: { color: "var(--theme-elevation-600)", fontSize: "0.82rem" }, children: "Name" }),
3167
+ /* @__PURE__ */ jsx17("div", { style: { fontWeight: 900, marginTop: "0.2rem" }, children: identity.name })
3168
+ ] }) : null,
3169
+ identity.email ? /* @__PURE__ */ jsxs16("div", { style: { ...panelStyle, padding: "0.75rem 0.85rem" }, children: [
3170
+ /* @__PURE__ */ jsx17("div", { style: { color: "var(--theme-elevation-600)", fontSize: "0.82rem" }, children: "Email" }),
3171
+ /* @__PURE__ */ jsx17("div", { style: { fontWeight: 900, marginTop: "0.2rem" }, children: identity.email })
3172
+ ] }) : null
3173
+ ]
3174
+ }
3175
+ ) : null,
3176
+ /* @__PURE__ */ jsxs16("div", { style: { marginTop: "1rem" }, children: [
3177
+ /* @__PURE__ */ jsx17(
3178
+ "div",
3179
+ {
3180
+ style: {
3181
+ color: "var(--theme-elevation-600)",
3182
+ fontSize: "0.82rem",
3183
+ fontWeight: 900,
3184
+ letterSpacing: "0.08em",
3185
+ marginBottom: "0.5rem",
3186
+ textTransform: "uppercase"
3187
+ },
3188
+ children: "Response data"
3189
+ }
3190
+ ),
3191
+ /* @__PURE__ */ jsx17("div", { style: { display: "grid", gap: "0.55rem" }, children: getFieldEntries(submissionData).map(([key, value]) => /* @__PURE__ */ jsxs16(
3192
+ "div",
3193
+ {
3194
+ style: {
3195
+ ...panelStyle,
3196
+ display: "grid",
3197
+ gap: "0.45rem",
3198
+ gridTemplateColumns: "minmax(160px, 220px) minmax(0, 1fr)",
3199
+ padding: "0.8rem 0.9rem"
3200
+ },
3201
+ children: [
3202
+ /* @__PURE__ */ jsx17(
3203
+ "div",
3204
+ {
3205
+ style: {
3206
+ color: "var(--theme-elevation-700)",
3207
+ fontSize: "0.92rem",
3208
+ fontWeight: 900,
3209
+ overflowWrap: "anywhere"
3210
+ },
3211
+ children: key
3212
+ }
3213
+ ),
3214
+ /* @__PURE__ */ jsx17("div", { style: { overflowWrap: "anywhere" }, children: renderValue(value) })
3215
+ ]
3216
+ },
3217
+ key
3218
+ )) })
3219
+ ] }),
3220
+ /* @__PURE__ */ jsxs16("div", { style: { marginTop: "1rem" }, children: [
3221
+ /* @__PURE__ */ jsx17(
3222
+ "div",
3223
+ {
3224
+ style: {
3225
+ color: "var(--theme-elevation-600)",
3226
+ fontSize: "0.82rem",
3227
+ fontWeight: 900,
3228
+ letterSpacing: "0.08em",
3229
+ marginBottom: "0.5rem",
3230
+ textTransform: "uppercase"
3231
+ },
3232
+ children: "Uploads"
3233
+ }
3234
+ ),
3235
+ uploads.length === 0 ? /* @__PURE__ */ jsx17("div", { style: { color: "var(--theme-elevation-600)" }, children: "No files attached." }) : /* @__PURE__ */ jsx17("div", { style: { display: "grid", gap: "0.55rem" }, children: uploads.map((upload, index) => {
3236
+ const uploadID = typeof upload.id === "string" || typeof upload.id === "number" ? String(upload.id) : "";
3237
+ if (!uploadID) return null;
3238
+ const label = typeof upload.filename === "string" && upload.filename || `Upload ${index + 1}`;
3239
+ const meta = [
3240
+ typeof upload.mimeType === "string" ? upload.mimeType : null,
3241
+ formatFileSize(upload.filesize)
3242
+ ].filter(Boolean);
3243
+ return /* @__PURE__ */ jsxs16(
3244
+ "a",
3245
+ {
3246
+ href: `${rawUploadsPath}/${uploadID}`,
3247
+ style: {
3248
+ ...panelStyle,
3249
+ color: "inherit",
3250
+ display: "flex",
3251
+ gap: "0.75rem",
3252
+ justifyContent: "space-between",
3253
+ padding: "0.8rem 0.9rem",
3254
+ textDecoration: "none"
3255
+ },
3256
+ children: [
3257
+ /* @__PURE__ */ jsxs16("div", { children: [
3258
+ /* @__PURE__ */ jsx17("div", { style: { fontWeight: 900 }, children: label }),
3259
+ meta.length > 0 ? /* @__PURE__ */ jsx17(
3260
+ "div",
3261
+ {
3262
+ style: {
3263
+ color: "var(--theme-elevation-600)",
3264
+ fontSize: "0.9rem",
3265
+ marginTop: "0.2rem"
3266
+ },
3267
+ children: meta.join(" \xB7 ")
3268
+ }
3269
+ ) : null
3270
+ ] }),
3271
+ /* @__PURE__ */ jsx17("div", { style: { color: "var(--theme-elevation-600)", fontWeight: 800 }, children: "Open" })
3272
+ ]
3273
+ },
3274
+ uploadID
3275
+ );
3276
+ }) })
3277
+ ] })
3278
+ ] }, id);
3279
+ }) })
3280
+ ] })
3281
+ ] })
3282
+ ]
3283
+ }
3284
+ )
3285
+ ] });
3286
+ }
3287
+
3288
+ // src/admin/components/studio/AdminStudioToolsView.tsx
3289
+ import { SetStepNav as SetStepNav8, useAuth as useAuth5 } from "@payloadcms/ui";
3290
+ import { Fragment as Fragment8, jsx as jsx18, jsxs as jsxs17 } from "react/jsx-runtime";
3291
+ var isAdmin4 = (user) => {
3292
+ if (!user || typeof user !== "object") return false;
3293
+ const role = user.role;
3294
+ return typeof role === "string" && role === "admin";
3295
+ };
3296
+ var getPropString9 = (props, key, fallback) => {
3297
+ if (!props || typeof props !== "object") return fallback;
3298
+ const direct = props[key];
3299
+ if (typeof direct === "string" && direct.length > 0) return direct;
3300
+ const clientProps = props.clientProps;
3301
+ if (clientProps && typeof clientProps === "object") {
3302
+ const nested = clientProps[key];
3303
+ if (typeof nested === "string" && nested.length > 0) return nested;
3304
+ }
3305
+ return fallback;
3306
+ };
3307
+ function AdminStudioToolsView(props) {
3308
+ const { user } = useAuth5();
3309
+ const adminBasePath = useAdminBasePath();
3310
+ const toolsPath = resolveAdminPath(adminBasePath, "/tools");
3311
+ if (!isAdmin4(user)) {
3312
+ return /* @__PURE__ */ jsxs17(Fragment8, { children: [
3313
+ /* @__PURE__ */ jsx18(SetStepNav8, { nav: [{ label: "Admin Tools", url: toolsPath }] }),
3314
+ /* @__PURE__ */ jsx18("h1", { style: { margin: 0 }, children: "Admin Tools" }),
3315
+ /* @__PURE__ */ jsx18("p", { style: { color: "var(--theme-elevation-600)" }, children: "You do not have access to this page." })
3316
+ ] });
3317
+ }
3318
+ const pagesCollectionSlug = getPropString9(props, "pagesCollectionSlug", "pages");
3319
+ const mediaCollectionSlug = getPropString9(props, "mediaCollectionSlug", "media");
3320
+ const links = [
3321
+ { href: resolveAdminPath(adminBasePath, `/collections/${pagesCollectionSlug}`), label: "Raw Pages Collection" },
3322
+ { href: resolveAdminPath(adminBasePath, `/collections/${mediaCollectionSlug}`), label: "Raw Media Collection" },
3323
+ { href: resolveAdminPath(adminBasePath, "/globals/site-settings"), label: "Raw Site Settings Global" },
3324
+ { href: resolveAdminPath(adminBasePath, "/globals/header"), label: "Raw Header Global" },
3325
+ { href: resolveAdminPath(adminBasePath, "/globals/footer"), label: "Raw Footer Global" },
3326
+ { href: resolveAdminPath(adminBasePath, "/collections/users"), label: "Users / Roles" }
3327
+ ];
3328
+ return /* @__PURE__ */ jsxs17(Fragment8, { children: [
3329
+ /* @__PURE__ */ jsx18(SetStepNav8, { nav: [{ label: "Admin Tools", url: toolsPath }] }),
3330
+ /* @__PURE__ */ jsx18("h1", { style: { margin: 0 }, children: "Admin Tools" }),
3331
+ /* @__PURE__ */ jsx18("p", { style: { color: "var(--theme-elevation-600)", marginTop: "0.35rem" }, children: "Hidden fallback links for administrators." }),
3332
+ /* @__PURE__ */ jsx18("div", { style: { display: "grid", gap: "0.6rem", marginTop: "1rem" }, children: links.map((link) => /* @__PURE__ */ jsxs17(
3333
+ "a",
3334
+ {
3335
+ href: link.href,
3336
+ style: {
3337
+ background: "var(--theme-elevation-0)",
3338
+ border: "1px solid var(--theme-elevation-150)",
3339
+ borderRadius: 16,
3340
+ color: "inherit",
3341
+ padding: "0.85rem 1rem",
3342
+ textDecoration: "none"
3343
+ },
3344
+ children: [
3345
+ /* @__PURE__ */ jsx18("div", { style: { fontWeight: 900 }, children: link.label }),
3346
+ /* @__PURE__ */ jsx18("div", { style: { color: "var(--theme-elevation-600)", fontSize: "0.9rem" }, children: link.href })
3347
+ ]
3348
+ },
3349
+ link.href
3350
+ )) })
3351
+ ] });
1868
3352
  }
1869
3353
 
1870
3354
  // src/admin/components/studio/OpenInStudioMenuItem.tsx
1871
3355
  import { useDocumentInfo } from "@payloadcms/ui";
1872
- import { jsx as jsx17 } from "react/jsx-runtime";
3356
+ import { jsx as jsx19 } from "react/jsx-runtime";
1873
3357
  function OpenInStudioMenuItem({ pagesPathBase = "/studio/pages" }) {
1874
3358
  const documentInfo = useDocumentInfo();
1875
3359
  const id = documentInfo?.id;
1876
3360
  if (!id) {
1877
3361
  return null;
1878
3362
  }
1879
- return /* @__PURE__ */ jsx17(
3363
+ return /* @__PURE__ */ jsx19(
1880
3364
  "a",
1881
3365
  {
1882
3366
  href: `${pagesPathBase}/${id}`,
@@ -1895,19 +3379,19 @@ function OpenInStudioMenuItem({ pagesPathBase = "/studio/pages" }) {
1895
3379
  }
1896
3380
 
1897
3381
  // src/admin/components/studio/PageEditRedirectToStudio.tsx
1898
- import { useEffect as useEffect9 } from "react";
3382
+ import { useEffect as useEffect12 } from "react";
1899
3383
  import { useDocumentInfo as useDocumentInfo2 } from "@payloadcms/ui";
1900
- import { jsx as jsx18, jsxs as jsxs16 } from "react/jsx-runtime";
3384
+ import { jsx as jsx20, jsxs as jsxs18 } from "react/jsx-runtime";
1901
3385
  function PageEditRedirectToStudio({ pagesPathBase = "/studio/pages" }) {
1902
3386
  const documentInfo = useDocumentInfo2();
1903
3387
  const id = documentInfo?.id;
1904
- useEffect9(() => {
3388
+ useEffect12(() => {
1905
3389
  if (!id) {
1906
3390
  return;
1907
3391
  }
1908
3392
  window.location.replace(`${pagesPathBase}/${id}`);
1909
3393
  }, [id, pagesPathBase]);
1910
- return /* @__PURE__ */ jsxs16(
3394
+ return /* @__PURE__ */ jsxs18(
1911
3395
  "div",
1912
3396
  {
1913
3397
  style: {
@@ -1919,56 +3403,113 @@ function PageEditRedirectToStudio({ pagesPathBase = "/studio/pages" }) {
1919
3403
  minHeight: "50vh"
1920
3404
  },
1921
3405
  children: [
1922
- /* @__PURE__ */ jsx18("h2", { style: { margin: 0 }, children: "Opening Editor..." }),
1923
- /* @__PURE__ */ jsx18("p", { style: { color: "var(--theme-elevation-600)", margin: 0 }, children: "Redirecting to the custom page editor." }),
1924
- id ? /* @__PURE__ */ jsx18("a", { href: `${pagesPathBase}/${id}`, children: "Continue to Editor" }) : /* @__PURE__ */ jsx18("a", { href: pagesPathBase, children: "Open Pages" })
3406
+ /* @__PURE__ */ jsx20("h2", { style: { margin: 0 }, children: "Opening Editor..." }),
3407
+ /* @__PURE__ */ jsx20("p", { style: { color: "var(--theme-elevation-600)", margin: 0 }, children: "Redirecting to the custom page editor." }),
3408
+ id ? /* @__PURE__ */ jsx20("a", { href: `${pagesPathBase}/${id}`, children: "Continue to Editor" }) : /* @__PURE__ */ jsx20("a", { href: pagesPathBase, children: "Open Pages" })
1925
3409
  ]
1926
3410
  }
1927
3411
  );
1928
3412
  }
1929
3413
 
1930
3414
  // src/admin/components/studio/StudioBackBreadcrumb.tsx
1931
- import { SetStepNav as SetStepNav7 } from "@payloadcms/ui";
1932
- import { usePathname } from "next/navigation";
1933
- import { jsx as jsx19 } from "react/jsx-runtime";
3415
+ import { useEffect as useEffect13, useState as useState11 } from "react";
3416
+ import { SetStepNav as SetStepNav9 } from "@payloadcms/ui";
3417
+ import { jsx as jsx21 } from "react/jsx-runtime";
1934
3418
  var toTitle = (slug) => slug.split("-").filter(Boolean).map((part) => part.charAt(0).toUpperCase() + part.slice(1)).join(" ");
1935
- var buildNav = (pathname) => {
3419
+ var buildNav = (pathname, adminBasePath) => {
1936
3420
  if (pathname.includes("/globals/")) {
1937
3421
  const slug = pathname.split("/globals/")[1]?.split("/")[0] || "";
1938
3422
  const currentLabel = slug === "site-settings" ? "Website Settings" : toTitle(slug) || "Global";
1939
3423
  return [
1940
- { label: "Globals", url: "/admin/studio-globals" },
3424
+ { label: "Globals", url: resolveAdminPath(adminBasePath, "/studio-globals") },
1941
3425
  { label: currentLabel }
1942
3426
  ];
1943
3427
  }
1944
- if (pathname.includes("/collections/pages") || pathname.startsWith("/admin/pages/")) {
3428
+ if (pathname.includes("/studio-contact-form")) {
1945
3429
  return [
1946
- { label: "Pages", url: "/admin/collections/pages" },
3430
+ { label: "Globals", url: resolveAdminPath(adminBasePath, "/studio-globals") },
3431
+ { label: "Contact Form" }
3432
+ ];
3433
+ }
3434
+ if (pathname.includes("/collections/pages") || pathname.includes("/pages/")) {
3435
+ return [
3436
+ { label: "Pages", url: resolveAdminPath(adminBasePath, "/collections/pages") },
1947
3437
  { label: "Page" }
1948
3438
  ];
1949
3439
  }
1950
3440
  if (pathname.includes("/collections/media")) {
1951
3441
  return [
1952
- { label: "Media", url: "/admin/collections/media" },
3442
+ { label: "Media", url: resolveAdminPath(adminBasePath, "/collections/media") },
1953
3443
  { label: "Media Item" }
1954
3444
  ];
1955
3445
  }
1956
- if (pathname.startsWith("/admin/tools") || pathname.includes("/collections/users")) {
3446
+ if (pathname.includes("/tools") || pathname.includes("/collections/users")) {
1957
3447
  return [
1958
- { label: "Admin Tools", url: "/admin/collections/users" },
3448
+ { label: "Admin Tools", url: resolveAdminPath(adminBasePath, "/collections/users") },
1959
3449
  { label: "Tool" }
1960
3450
  ];
1961
3451
  }
1962
3452
  return null;
1963
3453
  };
1964
3454
  function StudioBackBreadcrumb() {
1965
- const pathname = usePathname();
1966
- const nav = buildNav(pathname);
3455
+ const adminBasePath = useAdminBasePath();
3456
+ const [pathname, setPathname] = useState11("");
3457
+ useEffect13(() => {
3458
+ const update = () => setPathname(window.location.pathname);
3459
+ update();
3460
+ window.addEventListener("popstate", update);
3461
+ return () => window.removeEventListener("popstate", update);
3462
+ }, []);
3463
+ const nav = buildNav(pathname, adminBasePath);
1967
3464
  if (!nav) return null;
1968
- return /* @__PURE__ */ jsx19(SetStepNav7, { nav });
3465
+ return /* @__PURE__ */ jsx21(SetStepNav9, { nav });
3466
+ }
3467
+
3468
+ // src/admin/components/studio/StudioContactFormRedirect.tsx
3469
+ import { useEffect as useEffect14 } from "react";
3470
+ import { jsx as jsx22, jsxs as jsxs19 } from "react/jsx-runtime";
3471
+ var getPropString10 = (props, key, fallback) => {
3472
+ if (!props || typeof props !== "object") return fallback;
3473
+ const direct = props[key];
3474
+ if (typeof direct === "string" && direct.length > 0) return direct;
3475
+ const clientProps = props.clientProps;
3476
+ if (clientProps && typeof clientProps === "object") {
3477
+ const nested = clientProps[key];
3478
+ if (typeof nested === "string" && nested.length > 0) return nested;
3479
+ }
3480
+ return fallback;
3481
+ };
3482
+ function StudioContactFormRedirect(props) {
3483
+ const adminBasePath = useAdminBasePath();
3484
+ const studioContactFormPath = getPropString10(props, "studioContactFormPath", "/studio-contact-form");
3485
+ const targetPath = resolveAdminPath(adminBasePath, studioContactFormPath);
3486
+ useEffect14(() => {
3487
+ if (window.location.pathname === targetPath) return;
3488
+ window.location.replace(targetPath);
3489
+ }, [targetPath]);
3490
+ return /* @__PURE__ */ jsxs19(
3491
+ "div",
3492
+ {
3493
+ style: {
3494
+ alignItems: "center",
3495
+ color: "var(--theme-elevation-800)",
3496
+ display: "flex",
3497
+ flexDirection: "column",
3498
+ gap: "0.75rem",
3499
+ justifyContent: "center",
3500
+ minHeight: "40vh"
3501
+ },
3502
+ children: [
3503
+ /* @__PURE__ */ jsx22("h2", { style: { margin: 0 }, children: "Opening Contact Form Editor..." }),
3504
+ /* @__PURE__ */ jsx22("a", { href: targetPath, children: "Continue" })
3505
+ ]
3506
+ }
3507
+ );
1969
3508
  }
1970
3509
  export {
3510
+ AdminStudioContactFormView,
1971
3511
  AdminStudioDashboard,
3512
+ AdminStudioFormsView,
1972
3513
  AdminStudioGlobalsView,
1973
3514
  AdminStudioMediaView,
1974
3515
  AdminStudioNav,
@@ -1987,6 +3528,7 @@ export {
1987
3528
  SectionTabs,
1988
3529
  StatusBadge,
1989
3530
  StudioBackBreadcrumb,
3531
+ StudioContactFormRedirect,
1990
3532
  ThemeProvider,
1991
3533
  ThemeSwitcher,
1992
3534
  WelcomeHeader,