@orion-studios/payload-studio 0.5.0-beta.23 → 0.5.0-beta.25

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.
@@ -1,3 +1,3 @@
1
- export { A as AdminBreadcrumbItem, a as AdminBreadcrumbs, b as AdminNavItem, c as AdminPage, d as AdminRole, n as navItemIsActive, r as roleCanAccessNav } from '../index-BallJs-K.mjs';
1
+ export { A as AdminBreadcrumbItem, a as AdminBreadcrumbs, b as AdminNavItem, c as AdminNavLinkItem, d as AdminPage, e as AdminPageLinkOption, f as AdminPageRecord, g as AdminRole, h as buildAdminPageLinkOptions, j as getAdminNavRows, n as navItemIsActive, p as parseAdminHeaderNavFromForm, r as roleCanAccessNav } from '../index-Ge9Rh94G.mjs';
2
2
  import 'react/jsx-runtime';
3
3
  import 'react';
@@ -1,3 +1,3 @@
1
- export { A as AdminBreadcrumbItem, a as AdminBreadcrumbs, b as AdminNavItem, c as AdminPage, d as AdminRole, n as navItemIsActive, r as roleCanAccessNav } from '../index-BallJs-K.js';
1
+ export { A as AdminBreadcrumbItem, a as AdminBreadcrumbs, b as AdminNavItem, c as AdminNavLinkItem, d as AdminPage, e as AdminPageLinkOption, f as AdminPageRecord, g as AdminRole, h as buildAdminPageLinkOptions, j as getAdminNavRows, n as navItemIsActive, p as parseAdminHeaderNavFromForm, r as roleCanAccessNav } from '../index-Ge9Rh94G.js';
2
2
  import 'react/jsx-runtime';
3
3
  import 'react';
@@ -22,7 +22,10 @@ var admin_app_exports = {};
22
22
  __export(admin_app_exports, {
23
23
  AdminBreadcrumbs: () => AdminBreadcrumbs,
24
24
  AdminPage: () => AdminPage,
25
+ buildAdminPageLinkOptions: () => buildAdminPageLinkOptions,
26
+ getAdminNavRows: () => getAdminNavRows,
25
27
  navItemIsActive: () => navItemIsActive,
28
+ parseAdminHeaderNavFromForm: () => parseAdminHeaderNavFromForm,
26
29
  roleCanAccessNav: () => roleCanAccessNav
27
30
  });
28
31
  module.exports = __toCommonJS(admin_app_exports);
@@ -57,6 +60,115 @@ function AdminPage({ title, description, breadcrumbs, actions, children }) {
57
60
  ] });
58
61
  }
59
62
 
63
+ // src/admin-app/navigationLinks.ts
64
+ var fallbackHomeOption = {
65
+ href: "/",
66
+ label: "Home",
67
+ title: "Home"
68
+ };
69
+ var buildAdminPageLinkOptions = (pages) => {
70
+ const options = pages.map((page) => {
71
+ const href = typeof page.path === "string" ? page.path.trim() : "";
72
+ const title = typeof page.title === "string" && page.title.trim().length > 0 ? page.title.trim() : "Untitled Page";
73
+ if (!href) {
74
+ return null;
75
+ }
76
+ const depth = href === "/" ? 0 : href.split("/").filter(Boolean).length;
77
+ const indentLevel = Math.max(depth - 1, 0);
78
+ const indent = indentLevel > 0 ? `${"\u21B3 ".repeat(indentLevel)}` : "";
79
+ return {
80
+ href,
81
+ label: `${indent}${title}`,
82
+ title
83
+ };
84
+ }).filter((option) => option !== null).sort((a, b) => {
85
+ if (a.href === "/" && b.href !== "/") return -1;
86
+ if (b.href === "/" && a.href !== "/") return 1;
87
+ return a.href.localeCompare(b.href);
88
+ });
89
+ if (options.length === 0) {
90
+ return [fallbackHomeOption];
91
+ }
92
+ return options;
93
+ };
94
+ var getAdminNavRows = (navItems, pageOptions, minRows = 6, maxRows = 20) => {
95
+ const preferredRows = Math.max(navItems.length + 2, Math.min(8, pageOptions.length));
96
+ return Math.min(Math.max(minRows, preferredRows), maxRows);
97
+ };
98
+ var normalizeParsedNavRows = (rows, pageOptions) => {
99
+ const allowedLinks = new Map(pageOptions.map((option) => [option.href, option.title]));
100
+ const deduped = [];
101
+ const seen = /* @__PURE__ */ new Set();
102
+ for (const row of rows) {
103
+ const href = typeof row.href === "string" ? row.href.trim() : "";
104
+ const defaultLabel = allowedLinks.get(href);
105
+ const explicitLabel = typeof row.label === "string" ? row.label.trim() : "";
106
+ const parentHref = typeof row.parentHref === "string" ? row.parentHref.trim() : "";
107
+ if (!href || !defaultLabel || seen.has(href)) {
108
+ continue;
109
+ }
110
+ seen.add(href);
111
+ deduped.push({
112
+ href,
113
+ label: explicitLabel.length > 0 ? explicitLabel : defaultLabel,
114
+ ...parentHref.length > 0 ? { parentHref } : {}
115
+ });
116
+ }
117
+ const hrefs = new Set(deduped.map((item) => item.href));
118
+ const parentByHref = new Map(deduped.map((item) => [item.href, item.parentHref || ""]));
119
+ const createsCycle = (href, parentHref) => {
120
+ const visited = /* @__PURE__ */ new Set([href]);
121
+ let current = parentHref;
122
+ while (current) {
123
+ if (visited.has(current)) {
124
+ return true;
125
+ }
126
+ visited.add(current);
127
+ current = parentByHref.get(current) || "";
128
+ }
129
+ return false;
130
+ };
131
+ return deduped.map((item) => {
132
+ const parentHref = item.parentHref;
133
+ if (!parentHref || parentHref === item.href || !hrefs.has(parentHref) || createsCycle(item.href, parentHref)) {
134
+ return {
135
+ href: item.href,
136
+ label: item.label
137
+ };
138
+ }
139
+ return item;
140
+ });
141
+ };
142
+ var parseAdminHeaderNavFromForm = (formData, pageOptions, maxRows = 24) => {
143
+ const serialized = String(formData.get("navItemsState") || "").trim();
144
+ if (serialized.length > 0) {
145
+ try {
146
+ const parsed = JSON.parse(serialized);
147
+ if (Array.isArray(parsed)) {
148
+ return normalizeParsedNavRows(parsed.slice(0, maxRows), pageOptions);
149
+ }
150
+ } catch {
151
+ }
152
+ }
153
+ const rawCount = Number(String(formData.get("navCount") || "0"));
154
+ const navCount = Number.isFinite(rawCount) ? Math.max(0, Math.min(rawCount, maxRows)) : 0;
155
+ const navRows = [];
156
+ for (let index = 0; index < navCount; index += 1) {
157
+ const href = String(formData.get(`navPage_${index}`) || "").trim();
158
+ const label = String(formData.get(`navLabel_${index}`) || "").trim();
159
+ const parentHref = String(formData.get(`navParentHref_${index}`) || "").trim();
160
+ navRows.push({
161
+ href,
162
+ label,
163
+ parentHref
164
+ });
165
+ }
166
+ if (navRows.length > 0) {
167
+ return normalizeParsedNavRows(navRows, pageOptions);
168
+ }
169
+ return [];
170
+ };
171
+
60
172
  // src/admin-app/routeRegistry.ts
61
173
  var roleCanAccessNav = (role, item) => {
62
174
  if (!item.roles || item.roles.length === 0) {
@@ -77,6 +189,9 @@ var navItemIsActive = (pathname, item) => {
77
189
  0 && (module.exports = {
78
190
  AdminBreadcrumbs,
79
191
  AdminPage,
192
+ buildAdminPageLinkOptions,
193
+ getAdminNavRows,
80
194
  navItemIsActive,
195
+ parseAdminHeaderNavFromForm,
81
196
  roleCanAccessNav
82
197
  });
@@ -1,13 +1,19 @@
1
1
  import {
2
2
  AdminBreadcrumbs,
3
3
  AdminPage,
4
+ buildAdminPageLinkOptions,
5
+ getAdminNavRows,
4
6
  navItemIsActive,
7
+ parseAdminHeaderNavFromForm,
5
8
  roleCanAccessNav
6
- } from "../chunk-AAOHJDNS.mjs";
9
+ } from "../chunk-3CO6ZBR2.mjs";
7
10
  import "../chunk-6BWS3CLP.mjs";
8
11
  export {
9
12
  AdminBreadcrumbs,
10
13
  AdminPage,
14
+ buildAdminPageLinkOptions,
15
+ getAdminNavRows,
11
16
  navItemIsActive,
17
+ parseAdminHeaderNavFromForm,
12
18
  roleCanAccessNav
13
19
  };
@@ -0,0 +1,182 @@
1
+ import {
2
+ __export
3
+ } from "./chunk-6BWS3CLP.mjs";
4
+
5
+ // src/admin-app/index.ts
6
+ var admin_app_exports = {};
7
+ __export(admin_app_exports, {
8
+ AdminBreadcrumbs: () => AdminBreadcrumbs,
9
+ AdminPage: () => AdminPage,
10
+ buildAdminPageLinkOptions: () => buildAdminPageLinkOptions,
11
+ getAdminNavRows: () => getAdminNavRows,
12
+ navItemIsActive: () => navItemIsActive,
13
+ parseAdminHeaderNavFromForm: () => parseAdminHeaderNavFromForm,
14
+ roleCanAccessNav: () => roleCanAccessNav
15
+ });
16
+
17
+ // src/admin-app/components/AdminBreadcrumbs.tsx
18
+ import { jsx, jsxs } from "react/jsx-runtime";
19
+ function AdminBreadcrumbs({ items }) {
20
+ return /* @__PURE__ */ jsx("nav", { "aria-label": "Breadcrumb", className: "orion-admin-breadcrumbs", children: items.map((item, index) => {
21
+ const isLast = index === items.length - 1;
22
+ return /* @__PURE__ */ jsxs("span", { children: [
23
+ item.href && !isLast ? /* @__PURE__ */ jsx("a", { href: item.href, children: item.label }) : /* @__PURE__ */ jsx("span", { children: item.label }),
24
+ !isLast ? /* @__PURE__ */ jsx("span", { className: "orion-admin-breadcrumb-sep", children: "/" }) : null
25
+ ] }, `${item.label}-${index}`);
26
+ }) });
27
+ }
28
+
29
+ // src/admin-app/components/AdminPage.tsx
30
+ import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
31
+ function AdminPage({ title, description, breadcrumbs, actions, children }) {
32
+ return /* @__PURE__ */ jsxs2("div", { className: "orion-admin-page", children: [
33
+ /* @__PURE__ */ jsxs2("div", { className: "orion-admin-page-header", children: [
34
+ /* @__PURE__ */ jsx2(AdminBreadcrumbs, { items: breadcrumbs }),
35
+ /* @__PURE__ */ jsxs2("div", { className: "orion-admin-page-title-row", children: [
36
+ /* @__PURE__ */ jsxs2("div", { children: [
37
+ /* @__PURE__ */ jsx2("h1", { children: title }),
38
+ description ? /* @__PURE__ */ jsx2("p", { children: description }) : null
39
+ ] }),
40
+ actions ? /* @__PURE__ */ jsx2("div", { className: "orion-admin-page-actions", children: actions }) : null
41
+ ] })
42
+ ] }),
43
+ /* @__PURE__ */ jsx2("div", { className: "orion-admin-page-content", children })
44
+ ] });
45
+ }
46
+
47
+ // src/admin-app/navigationLinks.ts
48
+ var fallbackHomeOption = {
49
+ href: "/",
50
+ label: "Home",
51
+ title: "Home"
52
+ };
53
+ var buildAdminPageLinkOptions = (pages) => {
54
+ const options = pages.map((page) => {
55
+ const href = typeof page.path === "string" ? page.path.trim() : "";
56
+ const title = typeof page.title === "string" && page.title.trim().length > 0 ? page.title.trim() : "Untitled Page";
57
+ if (!href) {
58
+ return null;
59
+ }
60
+ const depth = href === "/" ? 0 : href.split("/").filter(Boolean).length;
61
+ const indentLevel = Math.max(depth - 1, 0);
62
+ const indent = indentLevel > 0 ? `${"\u21B3 ".repeat(indentLevel)}` : "";
63
+ return {
64
+ href,
65
+ label: `${indent}${title}`,
66
+ title
67
+ };
68
+ }).filter((option) => option !== null).sort((a, b) => {
69
+ if (a.href === "/" && b.href !== "/") return -1;
70
+ if (b.href === "/" && a.href !== "/") return 1;
71
+ return a.href.localeCompare(b.href);
72
+ });
73
+ if (options.length === 0) {
74
+ return [fallbackHomeOption];
75
+ }
76
+ return options;
77
+ };
78
+ var getAdminNavRows = (navItems, pageOptions, minRows = 6, maxRows = 20) => {
79
+ const preferredRows = Math.max(navItems.length + 2, Math.min(8, pageOptions.length));
80
+ return Math.min(Math.max(minRows, preferredRows), maxRows);
81
+ };
82
+ var normalizeParsedNavRows = (rows, pageOptions) => {
83
+ const allowedLinks = new Map(pageOptions.map((option) => [option.href, option.title]));
84
+ const deduped = [];
85
+ const seen = /* @__PURE__ */ new Set();
86
+ for (const row of rows) {
87
+ const href = typeof row.href === "string" ? row.href.trim() : "";
88
+ const defaultLabel = allowedLinks.get(href);
89
+ const explicitLabel = typeof row.label === "string" ? row.label.trim() : "";
90
+ const parentHref = typeof row.parentHref === "string" ? row.parentHref.trim() : "";
91
+ if (!href || !defaultLabel || seen.has(href)) {
92
+ continue;
93
+ }
94
+ seen.add(href);
95
+ deduped.push({
96
+ href,
97
+ label: explicitLabel.length > 0 ? explicitLabel : defaultLabel,
98
+ ...parentHref.length > 0 ? { parentHref } : {}
99
+ });
100
+ }
101
+ const hrefs = new Set(deduped.map((item) => item.href));
102
+ const parentByHref = new Map(deduped.map((item) => [item.href, item.parentHref || ""]));
103
+ const createsCycle = (href, parentHref) => {
104
+ const visited = /* @__PURE__ */ new Set([href]);
105
+ let current = parentHref;
106
+ while (current) {
107
+ if (visited.has(current)) {
108
+ return true;
109
+ }
110
+ visited.add(current);
111
+ current = parentByHref.get(current) || "";
112
+ }
113
+ return false;
114
+ };
115
+ return deduped.map((item) => {
116
+ const parentHref = item.parentHref;
117
+ if (!parentHref || parentHref === item.href || !hrefs.has(parentHref) || createsCycle(item.href, parentHref)) {
118
+ return {
119
+ href: item.href,
120
+ label: item.label
121
+ };
122
+ }
123
+ return item;
124
+ });
125
+ };
126
+ var parseAdminHeaderNavFromForm = (formData, pageOptions, maxRows = 24) => {
127
+ const serialized = String(formData.get("navItemsState") || "").trim();
128
+ if (serialized.length > 0) {
129
+ try {
130
+ const parsed = JSON.parse(serialized);
131
+ if (Array.isArray(parsed)) {
132
+ return normalizeParsedNavRows(parsed.slice(0, maxRows), pageOptions);
133
+ }
134
+ } catch {
135
+ }
136
+ }
137
+ const rawCount = Number(String(formData.get("navCount") || "0"));
138
+ const navCount = Number.isFinite(rawCount) ? Math.max(0, Math.min(rawCount, maxRows)) : 0;
139
+ const navRows = [];
140
+ for (let index = 0; index < navCount; index += 1) {
141
+ const href = String(formData.get(`navPage_${index}`) || "").trim();
142
+ const label = String(formData.get(`navLabel_${index}`) || "").trim();
143
+ const parentHref = String(formData.get(`navParentHref_${index}`) || "").trim();
144
+ navRows.push({
145
+ href,
146
+ label,
147
+ parentHref
148
+ });
149
+ }
150
+ if (navRows.length > 0) {
151
+ return normalizeParsedNavRows(navRows, pageOptions);
152
+ }
153
+ return [];
154
+ };
155
+
156
+ // src/admin-app/routeRegistry.ts
157
+ var roleCanAccessNav = (role, item) => {
158
+ if (!item.roles || item.roles.length === 0) {
159
+ return true;
160
+ }
161
+ if (!role) {
162
+ return false;
163
+ }
164
+ return item.roles.includes(role);
165
+ };
166
+ var navItemIsActive = (pathname, item) => {
167
+ if (item.href === "/admin") {
168
+ return pathname === "/admin";
169
+ }
170
+ return item.matchPrefixes.some((prefix) => pathname.startsWith(prefix));
171
+ };
172
+
173
+ export {
174
+ AdminBreadcrumbs,
175
+ AdminPage,
176
+ buildAdminPageLinkOptions,
177
+ getAdminNavRows,
178
+ parseAdminHeaderNavFromForm,
179
+ roleCanAccessNav,
180
+ navItemIsActive,
181
+ admin_app_exports
182
+ };
@@ -29,6 +29,7 @@ type SiteNavItem = {
29
29
  id?: string;
30
30
  label: string;
31
31
  href: string;
32
+ parentHref?: string;
32
33
  };
33
34
  type SiteSettingsData = {
34
35
  siteName?: string;
@@ -29,6 +29,7 @@ type SiteNavItem = {
29
29
  id?: string;
30
30
  label: string;
31
31
  href: string;
32
+ parentHref?: string;
32
33
  };
33
34
  type SiteSettingsData = {
34
35
  siteName?: string;
@@ -0,0 +1,67 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+ import { ReactNode } from 'react';
3
+
4
+ type AdminRole = 'admin' | 'editor' | 'client';
5
+ type AdminNavItem = {
6
+ href: string;
7
+ label: string;
8
+ matchPrefixes: string[];
9
+ roles?: AdminRole[];
10
+ };
11
+ type AdminBreadcrumbItem = {
12
+ label: string;
13
+ href?: string;
14
+ };
15
+ declare const roleCanAccessNav: (role: string | undefined, item: AdminNavItem) => boolean;
16
+ declare const navItemIsActive: (pathname: string, item: AdminNavItem) => boolean;
17
+
18
+ type AdminBreadcrumbsProps = {
19
+ items: AdminBreadcrumbItem[];
20
+ };
21
+ declare function AdminBreadcrumbs({ items }: AdminBreadcrumbsProps): react_jsx_runtime.JSX.Element;
22
+
23
+ type AdminPageProps = {
24
+ title: string;
25
+ description?: string;
26
+ breadcrumbs: AdminBreadcrumbItem[];
27
+ actions?: ReactNode;
28
+ children: ReactNode;
29
+ };
30
+ declare function AdminPage({ title, description, breadcrumbs, actions, children }: AdminPageProps): react_jsx_runtime.JSX.Element;
31
+
32
+ type AdminNavLinkItem = {
33
+ href: string;
34
+ label: string;
35
+ parentHref?: string;
36
+ };
37
+ type AdminPageRecord = {
38
+ path?: string;
39
+ title?: string;
40
+ };
41
+ type AdminPageLinkOption = {
42
+ href: string;
43
+ label: string;
44
+ title: string;
45
+ };
46
+ declare const buildAdminPageLinkOptions: (pages: AdminPageRecord[]) => AdminPageLinkOption[];
47
+ declare const getAdminNavRows: (navItems: AdminNavLinkItem[], pageOptions: AdminPageLinkOption[], minRows?: number, maxRows?: number) => number;
48
+ declare const parseAdminHeaderNavFromForm: (formData: FormData, pageOptions: AdminPageLinkOption[], maxRows?: number) => AdminNavLinkItem[];
49
+
50
+ type index_AdminBreadcrumbItem = AdminBreadcrumbItem;
51
+ declare const index_AdminBreadcrumbs: typeof AdminBreadcrumbs;
52
+ type index_AdminNavItem = AdminNavItem;
53
+ type index_AdminNavLinkItem = AdminNavLinkItem;
54
+ declare const index_AdminPage: typeof AdminPage;
55
+ type index_AdminPageLinkOption = AdminPageLinkOption;
56
+ type index_AdminPageRecord = AdminPageRecord;
57
+ type index_AdminRole = AdminRole;
58
+ declare const index_buildAdminPageLinkOptions: typeof buildAdminPageLinkOptions;
59
+ declare const index_getAdminNavRows: typeof getAdminNavRows;
60
+ declare const index_navItemIsActive: typeof navItemIsActive;
61
+ declare const index_parseAdminHeaderNavFromForm: typeof parseAdminHeaderNavFromForm;
62
+ declare const index_roleCanAccessNav: typeof roleCanAccessNav;
63
+ declare namespace index {
64
+ export { type index_AdminBreadcrumbItem as AdminBreadcrumbItem, index_AdminBreadcrumbs as AdminBreadcrumbs, type index_AdminNavItem as AdminNavItem, type index_AdminNavLinkItem as AdminNavLinkItem, index_AdminPage as AdminPage, type index_AdminPageLinkOption as AdminPageLinkOption, type index_AdminPageRecord as AdminPageRecord, type index_AdminRole as AdminRole, index_buildAdminPageLinkOptions as buildAdminPageLinkOptions, index_getAdminNavRows as getAdminNavRows, index_navItemIsActive as navItemIsActive, index_parseAdminHeaderNavFromForm as parseAdminHeaderNavFromForm, index_roleCanAccessNav as roleCanAccessNav };
65
+ }
66
+
67
+ export { type AdminBreadcrumbItem as A, AdminBreadcrumbs as a, type AdminNavItem as b, type AdminNavLinkItem as c, AdminPage as d, type AdminPageLinkOption as e, type AdminPageRecord as f, type AdminRole as g, buildAdminPageLinkOptions as h, index as i, getAdminNavRows as j, navItemIsActive as n, parseAdminHeaderNavFromForm as p, roleCanAccessNav as r };
@@ -0,0 +1,67 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+ import { ReactNode } from 'react';
3
+
4
+ type AdminRole = 'admin' | 'editor' | 'client';
5
+ type AdminNavItem = {
6
+ href: string;
7
+ label: string;
8
+ matchPrefixes: string[];
9
+ roles?: AdminRole[];
10
+ };
11
+ type AdminBreadcrumbItem = {
12
+ label: string;
13
+ href?: string;
14
+ };
15
+ declare const roleCanAccessNav: (role: string | undefined, item: AdminNavItem) => boolean;
16
+ declare const navItemIsActive: (pathname: string, item: AdminNavItem) => boolean;
17
+
18
+ type AdminBreadcrumbsProps = {
19
+ items: AdminBreadcrumbItem[];
20
+ };
21
+ declare function AdminBreadcrumbs({ items }: AdminBreadcrumbsProps): react_jsx_runtime.JSX.Element;
22
+
23
+ type AdminPageProps = {
24
+ title: string;
25
+ description?: string;
26
+ breadcrumbs: AdminBreadcrumbItem[];
27
+ actions?: ReactNode;
28
+ children: ReactNode;
29
+ };
30
+ declare function AdminPage({ title, description, breadcrumbs, actions, children }: AdminPageProps): react_jsx_runtime.JSX.Element;
31
+
32
+ type AdminNavLinkItem = {
33
+ href: string;
34
+ label: string;
35
+ parentHref?: string;
36
+ };
37
+ type AdminPageRecord = {
38
+ path?: string;
39
+ title?: string;
40
+ };
41
+ type AdminPageLinkOption = {
42
+ href: string;
43
+ label: string;
44
+ title: string;
45
+ };
46
+ declare const buildAdminPageLinkOptions: (pages: AdminPageRecord[]) => AdminPageLinkOption[];
47
+ declare const getAdminNavRows: (navItems: AdminNavLinkItem[], pageOptions: AdminPageLinkOption[], minRows?: number, maxRows?: number) => number;
48
+ declare const parseAdminHeaderNavFromForm: (formData: FormData, pageOptions: AdminPageLinkOption[], maxRows?: number) => AdminNavLinkItem[];
49
+
50
+ type index_AdminBreadcrumbItem = AdminBreadcrumbItem;
51
+ declare const index_AdminBreadcrumbs: typeof AdminBreadcrumbs;
52
+ type index_AdminNavItem = AdminNavItem;
53
+ type index_AdminNavLinkItem = AdminNavLinkItem;
54
+ declare const index_AdminPage: typeof AdminPage;
55
+ type index_AdminPageLinkOption = AdminPageLinkOption;
56
+ type index_AdminPageRecord = AdminPageRecord;
57
+ type index_AdminRole = AdminRole;
58
+ declare const index_buildAdminPageLinkOptions: typeof buildAdminPageLinkOptions;
59
+ declare const index_getAdminNavRows: typeof getAdminNavRows;
60
+ declare const index_navItemIsActive: typeof navItemIsActive;
61
+ declare const index_parseAdminHeaderNavFromForm: typeof parseAdminHeaderNavFromForm;
62
+ declare const index_roleCanAccessNav: typeof roleCanAccessNav;
63
+ declare namespace index {
64
+ export { type index_AdminBreadcrumbItem as AdminBreadcrumbItem, index_AdminBreadcrumbs as AdminBreadcrumbs, type index_AdminNavItem as AdminNavItem, type index_AdminNavLinkItem as AdminNavLinkItem, index_AdminPage as AdminPage, type index_AdminPageLinkOption as AdminPageLinkOption, type index_AdminPageRecord as AdminPageRecord, type index_AdminRole as AdminRole, index_buildAdminPageLinkOptions as buildAdminPageLinkOptions, index_getAdminNavRows as getAdminNavRows, index_navItemIsActive as navItemIsActive, index_parseAdminHeaderNavFromForm as parseAdminHeaderNavFromForm, index_roleCanAccessNav as roleCanAccessNav };
65
+ }
66
+
67
+ export { type AdminBreadcrumbItem as A, AdminBreadcrumbs as a, type AdminNavItem as b, type AdminNavLinkItem as c, AdminPage as d, type AdminPageLinkOption as e, type AdminPageRecord as f, type AdminRole as g, buildAdminPageLinkOptions as h, index as i, getAdminNavRows as j, navItemIsActive as n, parseAdminHeaderNavFromForm as p, roleCanAccessNav as r };
package/dist/index.d.mts CHANGED
@@ -1,7 +1,7 @@
1
1
  export { i as admin } from './index-DJFhANvJ.mjs';
2
- export { i as adminApp } from './index-BallJs-K.mjs';
2
+ export { i as adminApp } from './index-Ge9Rh94G.mjs';
3
3
  export { i as blocks } from './index-CluwY0ZQ.mjs';
4
- export { i as nextjs } from './index-DbH0Ljwp.mjs';
4
+ export { i as nextjs } from './index-CpG3UHcS.mjs';
5
5
  export { i as studio } from './index-CmR6NInu.mjs';
6
6
  export { i as studioPages } from './index-B9N5MyjF.mjs';
7
7
  import 'payload';
package/dist/index.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  export { i as admin } from './index-DJFhANvJ.js';
2
- export { i as adminApp } from './index-BallJs-K.js';
2
+ export { i as adminApp } from './index-Ge9Rh94G.js';
3
3
  export { i as blocks } from './index-CluwY0ZQ.js';
4
- export { i as nextjs } from './index-DbH0Ljwp.js';
4
+ export { i as nextjs } from './index-CpG3UHcS.js';
5
5
  export { i as studio } from './index-CmR6NInu.js';
6
6
  export { i as studioPages } from './index-g8tBHLKD.js';
7
7
  import 'payload';
package/dist/index.js CHANGED
@@ -311,7 +311,10 @@ var admin_app_exports = {};
311
311
  __export(admin_app_exports, {
312
312
  AdminBreadcrumbs: () => AdminBreadcrumbs,
313
313
  AdminPage: () => AdminPage,
314
+ buildAdminPageLinkOptions: () => buildAdminPageLinkOptions,
315
+ getAdminNavRows: () => getAdminNavRows,
314
316
  navItemIsActive: () => navItemIsActive,
317
+ parseAdminHeaderNavFromForm: () => parseAdminHeaderNavFromForm,
315
318
  roleCanAccessNav: () => roleCanAccessNav
316
319
  });
317
320
 
@@ -345,6 +348,115 @@ function AdminPage({ title, description, breadcrumbs, actions, children }) {
345
348
  ] });
346
349
  }
347
350
 
351
+ // src/admin-app/navigationLinks.ts
352
+ var fallbackHomeOption = {
353
+ href: "/",
354
+ label: "Home",
355
+ title: "Home"
356
+ };
357
+ var buildAdminPageLinkOptions = (pages) => {
358
+ const options = pages.map((page) => {
359
+ const href = typeof page.path === "string" ? page.path.trim() : "";
360
+ const title = typeof page.title === "string" && page.title.trim().length > 0 ? page.title.trim() : "Untitled Page";
361
+ if (!href) {
362
+ return null;
363
+ }
364
+ const depth = href === "/" ? 0 : href.split("/").filter(Boolean).length;
365
+ const indentLevel = Math.max(depth - 1, 0);
366
+ const indent = indentLevel > 0 ? `${"\u21B3 ".repeat(indentLevel)}` : "";
367
+ return {
368
+ href,
369
+ label: `${indent}${title}`,
370
+ title
371
+ };
372
+ }).filter((option) => option !== null).sort((a, b) => {
373
+ if (a.href === "/" && b.href !== "/") return -1;
374
+ if (b.href === "/" && a.href !== "/") return 1;
375
+ return a.href.localeCompare(b.href);
376
+ });
377
+ if (options.length === 0) {
378
+ return [fallbackHomeOption];
379
+ }
380
+ return options;
381
+ };
382
+ var getAdminNavRows = (navItems, pageOptions, minRows = 6, maxRows = 20) => {
383
+ const preferredRows = Math.max(navItems.length + 2, Math.min(8, pageOptions.length));
384
+ return Math.min(Math.max(minRows, preferredRows), maxRows);
385
+ };
386
+ var normalizeParsedNavRows = (rows, pageOptions) => {
387
+ const allowedLinks = new Map(pageOptions.map((option) => [option.href, option.title]));
388
+ const deduped = [];
389
+ const seen = /* @__PURE__ */ new Set();
390
+ for (const row of rows) {
391
+ const href = typeof row.href === "string" ? row.href.trim() : "";
392
+ const defaultLabel = allowedLinks.get(href);
393
+ const explicitLabel = typeof row.label === "string" ? row.label.trim() : "";
394
+ const parentHref = typeof row.parentHref === "string" ? row.parentHref.trim() : "";
395
+ if (!href || !defaultLabel || seen.has(href)) {
396
+ continue;
397
+ }
398
+ seen.add(href);
399
+ deduped.push({
400
+ href,
401
+ label: explicitLabel.length > 0 ? explicitLabel : defaultLabel,
402
+ ...parentHref.length > 0 ? { parentHref } : {}
403
+ });
404
+ }
405
+ const hrefs = new Set(deduped.map((item) => item.href));
406
+ const parentByHref = new Map(deduped.map((item) => [item.href, item.parentHref || ""]));
407
+ const createsCycle = (href, parentHref) => {
408
+ const visited = /* @__PURE__ */ new Set([href]);
409
+ let current = parentHref;
410
+ while (current) {
411
+ if (visited.has(current)) {
412
+ return true;
413
+ }
414
+ visited.add(current);
415
+ current = parentByHref.get(current) || "";
416
+ }
417
+ return false;
418
+ };
419
+ return deduped.map((item) => {
420
+ const parentHref = item.parentHref;
421
+ if (!parentHref || parentHref === item.href || !hrefs.has(parentHref) || createsCycle(item.href, parentHref)) {
422
+ return {
423
+ href: item.href,
424
+ label: item.label
425
+ };
426
+ }
427
+ return item;
428
+ });
429
+ };
430
+ var parseAdminHeaderNavFromForm = (formData, pageOptions, maxRows = 24) => {
431
+ const serialized = String(formData.get("navItemsState") || "").trim();
432
+ if (serialized.length > 0) {
433
+ try {
434
+ const parsed = JSON.parse(serialized);
435
+ if (Array.isArray(parsed)) {
436
+ return normalizeParsedNavRows(parsed.slice(0, maxRows), pageOptions);
437
+ }
438
+ } catch {
439
+ }
440
+ }
441
+ const rawCount = Number(String(formData.get("navCount") || "0"));
442
+ const navCount = Number.isFinite(rawCount) ? Math.max(0, Math.min(rawCount, maxRows)) : 0;
443
+ const navRows = [];
444
+ for (let index = 0; index < navCount; index += 1) {
445
+ const href = String(formData.get(`navPage_${index}`) || "").trim();
446
+ const label = String(formData.get(`navLabel_${index}`) || "").trim();
447
+ const parentHref = String(formData.get(`navParentHref_${index}`) || "").trim();
448
+ navRows.push({
449
+ href,
450
+ label,
451
+ parentHref
452
+ });
453
+ }
454
+ if (navRows.length > 0) {
455
+ return normalizeParsedNavRows(navRows, pageOptions);
456
+ }
457
+ return [];
458
+ };
459
+
348
460
  // src/admin-app/routeRegistry.ts
349
461
  var roleCanAccessNav = (role, item) => {
350
462
  if (!item.roles || item.roles.length === 0) {
package/dist/index.mjs CHANGED
@@ -4,19 +4,19 @@ import {
4
4
  import {
5
5
  nextjs_exports
6
6
  } from "./chunk-GPQPDEB5.mjs";
7
- import {
8
- blocks_exports
9
- } from "./chunk-H7DSTEVT.mjs";
10
7
  import {
11
8
  studio_exports
12
9
  } from "./chunk-N67KVM2S.mjs";
10
+ import {
11
+ admin_app_exports
12
+ } from "./chunk-3CO6ZBR2.mjs";
13
+ import {
14
+ blocks_exports
15
+ } from "./chunk-H7DSTEVT.mjs";
13
16
  import {
14
17
  studio_pages_exports
15
18
  } from "./chunk-QW24Y4UH.mjs";
16
19
  import "./chunk-SIL2J5MF.mjs";
17
- import {
18
- admin_app_exports
19
- } from "./chunk-AAOHJDNS.mjs";
20
20
  import "./chunk-6BWS3CLP.mjs";
21
21
  export {
22
22
  admin_exports as admin,
@@ -1,2 +1,2 @@
1
- export { F as FooterData, H as HeaderData, S as SiteNavItem, a as SiteSettingsData, W as WEBSITE_CONTENT_TAG, c as createPageQueries, b as createPayloadClient, d as createSiteQueries, r as resolveMedia } from '../index-DbH0Ljwp.mjs';
1
+ export { F as FooterData, H as HeaderData, S as SiteNavItem, a as SiteSettingsData, W as WEBSITE_CONTENT_TAG, c as createPageQueries, b as createPayloadClient, d as createSiteQueries, r as resolveMedia } from '../index-CpG3UHcS.mjs';
2
2
  import 'payload';
@@ -1,2 +1,2 @@
1
- export { F as FooterData, H as HeaderData, S as SiteNavItem, a as SiteSettingsData, W as WEBSITE_CONTENT_TAG, c as createPageQueries, b as createPayloadClient, d as createSiteQueries, r as resolveMedia } from '../index-DbH0Ljwp.js';
1
+ export { F as FooterData, H as HeaderData, S as SiteNavItem, a as SiteSettingsData, W as WEBSITE_CONTENT_TAG, c as createPageQueries, b as createPayloadClient, d as createSiteQueries, r as resolveMedia } from '../index-CpG3UHcS.js';
2
2
  import 'payload';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@orion-studios/payload-studio",
3
- "version": "0.5.0-beta.23",
3
+ "version": "0.5.0-beta.25",
4
4
  "description": "Unified Payload CMS toolkit for Orion Studios",
5
5
  "types": "./dist/index.d.ts",
6
6
  "exports": {
@@ -1,67 +0,0 @@
1
- import {
2
- __export
3
- } from "./chunk-6BWS3CLP.mjs";
4
-
5
- // src/admin-app/index.ts
6
- var admin_app_exports = {};
7
- __export(admin_app_exports, {
8
- AdminBreadcrumbs: () => AdminBreadcrumbs,
9
- AdminPage: () => AdminPage,
10
- navItemIsActive: () => navItemIsActive,
11
- roleCanAccessNav: () => roleCanAccessNav
12
- });
13
-
14
- // src/admin-app/components/AdminBreadcrumbs.tsx
15
- import { jsx, jsxs } from "react/jsx-runtime";
16
- function AdminBreadcrumbs({ items }) {
17
- return /* @__PURE__ */ jsx("nav", { "aria-label": "Breadcrumb", className: "orion-admin-breadcrumbs", children: items.map((item, index) => {
18
- const isLast = index === items.length - 1;
19
- return /* @__PURE__ */ jsxs("span", { children: [
20
- item.href && !isLast ? /* @__PURE__ */ jsx("a", { href: item.href, children: item.label }) : /* @__PURE__ */ jsx("span", { children: item.label }),
21
- !isLast ? /* @__PURE__ */ jsx("span", { className: "orion-admin-breadcrumb-sep", children: "/" }) : null
22
- ] }, `${item.label}-${index}`);
23
- }) });
24
- }
25
-
26
- // src/admin-app/components/AdminPage.tsx
27
- import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
28
- function AdminPage({ title, description, breadcrumbs, actions, children }) {
29
- return /* @__PURE__ */ jsxs2("div", { className: "orion-admin-page", children: [
30
- /* @__PURE__ */ jsxs2("div", { className: "orion-admin-page-header", children: [
31
- /* @__PURE__ */ jsx2(AdminBreadcrumbs, { items: breadcrumbs }),
32
- /* @__PURE__ */ jsxs2("div", { className: "orion-admin-page-title-row", children: [
33
- /* @__PURE__ */ jsxs2("div", { children: [
34
- /* @__PURE__ */ jsx2("h1", { children: title }),
35
- description ? /* @__PURE__ */ jsx2("p", { children: description }) : null
36
- ] }),
37
- actions ? /* @__PURE__ */ jsx2("div", { className: "orion-admin-page-actions", children: actions }) : null
38
- ] })
39
- ] }),
40
- /* @__PURE__ */ jsx2("div", { className: "orion-admin-page-content", children })
41
- ] });
42
- }
43
-
44
- // src/admin-app/routeRegistry.ts
45
- var roleCanAccessNav = (role, item) => {
46
- if (!item.roles || item.roles.length === 0) {
47
- return true;
48
- }
49
- if (!role) {
50
- return false;
51
- }
52
- return item.roles.includes(role);
53
- };
54
- var navItemIsActive = (pathname, item) => {
55
- if (item.href === "/admin") {
56
- return pathname === "/admin";
57
- }
58
- return item.matchPrefixes.some((prefix) => pathname.startsWith(prefix));
59
- };
60
-
61
- export {
62
- AdminBreadcrumbs,
63
- AdminPage,
64
- roleCanAccessNav,
65
- navItemIsActive,
66
- admin_app_exports
67
- };
@@ -1,43 +0,0 @@
1
- import * as react_jsx_runtime from 'react/jsx-runtime';
2
- import { ReactNode } from 'react';
3
-
4
- type AdminRole = 'admin' | 'editor' | 'client';
5
- type AdminNavItem = {
6
- href: string;
7
- label: string;
8
- matchPrefixes: string[];
9
- roles?: AdminRole[];
10
- };
11
- type AdminBreadcrumbItem = {
12
- label: string;
13
- href?: string;
14
- };
15
- declare const roleCanAccessNav: (role: string | undefined, item: AdminNavItem) => boolean;
16
- declare const navItemIsActive: (pathname: string, item: AdminNavItem) => boolean;
17
-
18
- type AdminBreadcrumbsProps = {
19
- items: AdminBreadcrumbItem[];
20
- };
21
- declare function AdminBreadcrumbs({ items }: AdminBreadcrumbsProps): react_jsx_runtime.JSX.Element;
22
-
23
- type AdminPageProps = {
24
- title: string;
25
- description?: string;
26
- breadcrumbs: AdminBreadcrumbItem[];
27
- actions?: ReactNode;
28
- children: ReactNode;
29
- };
30
- declare function AdminPage({ title, description, breadcrumbs, actions, children }: AdminPageProps): react_jsx_runtime.JSX.Element;
31
-
32
- type index_AdminBreadcrumbItem = AdminBreadcrumbItem;
33
- declare const index_AdminBreadcrumbs: typeof AdminBreadcrumbs;
34
- type index_AdminNavItem = AdminNavItem;
35
- declare const index_AdminPage: typeof AdminPage;
36
- type index_AdminRole = AdminRole;
37
- declare const index_navItemIsActive: typeof navItemIsActive;
38
- declare const index_roleCanAccessNav: typeof roleCanAccessNav;
39
- declare namespace index {
40
- export { type index_AdminBreadcrumbItem as AdminBreadcrumbItem, index_AdminBreadcrumbs as AdminBreadcrumbs, type index_AdminNavItem as AdminNavItem, index_AdminPage as AdminPage, type index_AdminRole as AdminRole, index_navItemIsActive as navItemIsActive, index_roleCanAccessNav as roleCanAccessNav };
41
- }
42
-
43
- export { type AdminBreadcrumbItem as A, AdminBreadcrumbs as a, type AdminNavItem as b, AdminPage as c, type AdminRole as d, index as i, navItemIsActive as n, roleCanAccessNav as r };
@@ -1,43 +0,0 @@
1
- import * as react_jsx_runtime from 'react/jsx-runtime';
2
- import { ReactNode } from 'react';
3
-
4
- type AdminRole = 'admin' | 'editor' | 'client';
5
- type AdminNavItem = {
6
- href: string;
7
- label: string;
8
- matchPrefixes: string[];
9
- roles?: AdminRole[];
10
- };
11
- type AdminBreadcrumbItem = {
12
- label: string;
13
- href?: string;
14
- };
15
- declare const roleCanAccessNav: (role: string | undefined, item: AdminNavItem) => boolean;
16
- declare const navItemIsActive: (pathname: string, item: AdminNavItem) => boolean;
17
-
18
- type AdminBreadcrumbsProps = {
19
- items: AdminBreadcrumbItem[];
20
- };
21
- declare function AdminBreadcrumbs({ items }: AdminBreadcrumbsProps): react_jsx_runtime.JSX.Element;
22
-
23
- type AdminPageProps = {
24
- title: string;
25
- description?: string;
26
- breadcrumbs: AdminBreadcrumbItem[];
27
- actions?: ReactNode;
28
- children: ReactNode;
29
- };
30
- declare function AdminPage({ title, description, breadcrumbs, actions, children }: AdminPageProps): react_jsx_runtime.JSX.Element;
31
-
32
- type index_AdminBreadcrumbItem = AdminBreadcrumbItem;
33
- declare const index_AdminBreadcrumbs: typeof AdminBreadcrumbs;
34
- type index_AdminNavItem = AdminNavItem;
35
- declare const index_AdminPage: typeof AdminPage;
36
- type index_AdminRole = AdminRole;
37
- declare const index_navItemIsActive: typeof navItemIsActive;
38
- declare const index_roleCanAccessNav: typeof roleCanAccessNav;
39
- declare namespace index {
40
- export { type index_AdminBreadcrumbItem as AdminBreadcrumbItem, index_AdminBreadcrumbs as AdminBreadcrumbs, type index_AdminNavItem as AdminNavItem, index_AdminPage as AdminPage, type index_AdminRole as AdminRole, index_navItemIsActive as navItemIsActive, index_roleCanAccessNav as roleCanAccessNav };
41
- }
42
-
43
- export { type AdminBreadcrumbItem as A, AdminBreadcrumbs as a, type AdminNavItem as b, AdminPage as c, type AdminRole as d, index as i, navItemIsActive as n, roleCanAccessNav as r };