@orion-studios/payload-studio 0.5.0-beta.98 → 0.6.0-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +58 -68
- package/dist/admin/client.d.mts +5 -0
- package/dist/admin/client.d.ts +5 -0
- package/dist/admin/client.js +4491 -736
- package/dist/admin/client.mjs +3367 -752
- package/dist/admin/index.d.mts +2 -1
- package/dist/admin/index.d.ts +2 -1
- package/dist/admin/index.js +498 -53
- package/dist/admin/index.mjs +2 -1
- package/dist/admin-app/client.d.mts +1 -0
- package/dist/admin-app/client.d.ts +1 -0
- package/dist/admin-app/client.js +285 -109
- package/dist/admin-app/client.mjs +59 -871
- package/dist/admin-app/index.d.mts +2 -1
- package/dist/admin-app/index.d.ts +2 -1
- package/dist/admin-app/index.mjs +5 -3
- package/dist/admin-app/styles.css +1708 -56
- package/dist/admin.css +158 -35
- package/dist/blocks/index.js +415 -200
- package/dist/blocks/index.mjs +2 -2
- package/dist/{chunk-XK3K5GRP.mjs → chunk-JQAHXYAM.mjs} +271 -67
- package/dist/chunk-KPIX7OSV.mjs +1051 -0
- package/dist/chunk-OQSEJXC4.mjs +166 -0
- package/dist/{chunk-XHWQJUX5.mjs → chunk-OTHERBGX.mjs} +3 -3
- package/dist/chunk-PF3EBZXF.mjs +326 -0
- package/dist/chunk-Q2HGC67S.mjs +904 -0
- package/dist/{chunk-XVH5SCBD.mjs → chunk-RKTIFEUY.mjs} +4 -19
- package/dist/chunk-W2UOCJDX.mjs +32 -0
- package/dist/{chunk-C4J35SPJ.mjs → chunk-XKUTZ7IU.mjs} +257 -452
- package/dist/{index-ZbOx4OCF.d.ts → index-52HdVLQq.d.ts} +12 -22
- package/dist/index-BMitiKK8.d.ts +435 -0
- package/dist/index-Crx_MtPw.d.ts +223 -0
- package/dist/index-Cv-6qnrw.d.mts +223 -0
- package/dist/{index-ZbOx4OCF.d.mts → index-DEQC3Dwj.d.mts} +12 -22
- package/dist/{index-BIwu3qIH.d.mts → index-DWmudwDm.d.mts} +2 -1
- package/dist/{index-BIwu3qIH.d.ts → index-DWmudwDm.d.ts} +2 -1
- package/dist/index-D_b24Gef.d.mts +435 -0
- package/dist/index.d.mts +5 -4
- package/dist/index.d.ts +5 -4
- package/dist/index.js +1968 -1198
- package/dist/index.mjs +10 -8
- package/dist/nextjs/index.js +5 -684
- package/dist/nextjs/index.mjs +2 -3
- package/dist/sitePreviewTypes-BkHCWxNW.d.mts +58 -0
- package/dist/sitePreviewTypes-BkHCWxNW.d.ts +58 -0
- package/dist/studio/index.d.mts +1 -1
- package/dist/studio/index.d.ts +1 -1
- package/dist/studio-pages/builder.css +125 -83
- package/dist/studio-pages/client.d.mts +58 -1
- package/dist/studio-pages/client.d.ts +58 -1
- package/dist/studio-pages/client.js +450 -241
- package/dist/studio-pages/client.mjs +455 -247
- package/dist/studio-pages/index.d.mts +3 -2
- package/dist/studio-pages/index.d.ts +3 -2
- package/dist/studio-pages/index.js +418 -183
- package/dist/studio-pages/index.mjs +15 -6
- package/package.json +19 -5
- package/dist/chunk-2FO2ROW4.mjs +0 -468
- package/dist/chunk-SIL2J5MF.mjs +0 -155
- package/dist/index-BFXZue5i.d.ts +0 -178
- package/dist/index-CoYRBbf6.d.mts +0 -178
- package/dist/index-R7hA134j.d.mts +0 -140
- package/dist/index-vjrjy0P4.d.ts +0 -140
|
@@ -1,833 +1,19 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
return true;
|
|
14
|
-
}
|
|
15
|
-
if (!role) {
|
|
16
|
-
return false;
|
|
17
|
-
}
|
|
18
|
-
return item.roles.includes(role);
|
|
19
|
-
};
|
|
20
|
-
var navItemIsActive = (pathname, item) => {
|
|
21
|
-
if (item.href === "/admin") {
|
|
22
|
-
return pathname === "/admin";
|
|
23
|
-
}
|
|
24
|
-
return item.matchPrefixes.some((prefix) => pathname.startsWith(prefix));
|
|
25
|
-
};
|
|
26
|
-
|
|
27
|
-
// src/admin-app/components/AdminShellClient.tsx
|
|
28
|
-
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
29
|
-
var iconSize = 20;
|
|
30
|
-
var iconStyle = { display: "block", flexShrink: 0 };
|
|
31
|
-
function NavIcon({ name }) {
|
|
32
|
-
const props = { width: iconSize, height: iconSize, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2, strokeLinecap: "round", strokeLinejoin: "round", style: iconStyle };
|
|
33
|
-
switch (name) {
|
|
34
|
-
case "dashboard":
|
|
35
|
-
return /* @__PURE__ */ jsxs("svg", { ...props, children: [
|
|
36
|
-
/* @__PURE__ */ jsx("rect", { x: "3", y: "3", width: "7", height: "9", rx: "1" }),
|
|
37
|
-
/* @__PURE__ */ jsx("rect", { x: "14", y: "3", width: "7", height: "5", rx: "1" }),
|
|
38
|
-
/* @__PURE__ */ jsx("rect", { x: "14", y: "12", width: "7", height: "9", rx: "1" }),
|
|
39
|
-
/* @__PURE__ */ jsx("rect", { x: "3", y: "16", width: "7", height: "5", rx: "1" })
|
|
40
|
-
] });
|
|
41
|
-
case "pages":
|
|
42
|
-
return /* @__PURE__ */ jsxs("svg", { ...props, children: [
|
|
43
|
-
/* @__PURE__ */ jsx("path", { d: "M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8Z" }),
|
|
44
|
-
/* @__PURE__ */ jsx("polyline", { points: "14 2 14 8 20 8" }),
|
|
45
|
-
/* @__PURE__ */ jsx("line", { x1: "8", y1: "13", x2: "16", y2: "13" }),
|
|
46
|
-
/* @__PURE__ */ jsx("line", { x1: "8", y1: "17", x2: "12", y2: "17" })
|
|
47
|
-
] });
|
|
48
|
-
case "globals":
|
|
49
|
-
return /* @__PURE__ */ jsxs("svg", { ...props, children: [
|
|
50
|
-
/* @__PURE__ */ jsx("circle", { cx: "12", cy: "12", r: "3" }),
|
|
51
|
-
/* @__PURE__ */ jsx("path", { d: "M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1-2.83 2.83l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-4 0v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83-2.83l.06-.06A1.65 1.65 0 0 0 4.68 15a1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1 0-4h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 2.83-2.83l.06.06A1.65 1.65 0 0 0 9 4.68a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 4 0v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 2.83l-.06.06A1.65 1.65 0 0 0 19.4 9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 0 4h-.09a1.65 1.65 0 0 0-1.51 1Z" })
|
|
52
|
-
] });
|
|
53
|
-
case "media":
|
|
54
|
-
return /* @__PURE__ */ jsxs("svg", { ...props, children: [
|
|
55
|
-
/* @__PURE__ */ jsx("rect", { x: "3", y: "3", width: "18", height: "18", rx: "2", ry: "2" }),
|
|
56
|
-
/* @__PURE__ */ jsx("circle", { cx: "8.5", cy: "8.5", r: "1.5" }),
|
|
57
|
-
/* @__PURE__ */ jsx("polyline", { points: "21 15 16 10 5 21" })
|
|
58
|
-
] });
|
|
59
|
-
case "tools":
|
|
60
|
-
return /* @__PURE__ */ jsx("svg", { ...props, children: /* @__PURE__ */ jsx("path", { d: "M14.7 6.3a1 1 0 0 0 0 1.4l1.6 1.6a1 1 0 0 0 1.4 0l3.77-3.77a6 6 0 0 1-7.94 7.94l-6.91 6.91a2.12 2.12 0 0 1-3-3l6.91-6.91a6 6 0 0 1 7.94-7.94l-3.76 3.76Z" }) });
|
|
61
|
-
case "account":
|
|
62
|
-
return /* @__PURE__ */ jsxs("svg", { ...props, children: [
|
|
63
|
-
/* @__PURE__ */ jsx("path", { d: "M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2" }),
|
|
64
|
-
/* @__PURE__ */ jsx("circle", { cx: "12", cy: "7", r: "4" })
|
|
65
|
-
] });
|
|
66
|
-
default:
|
|
67
|
-
return null;
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
function AdminShellClient({
|
|
71
|
-
children,
|
|
72
|
-
brandName,
|
|
73
|
-
logoUrl,
|
|
74
|
-
userEmail,
|
|
75
|
-
userRole,
|
|
76
|
-
pathname,
|
|
77
|
-
navItems,
|
|
78
|
-
onLogout,
|
|
79
|
-
storageKey = "orion-admin-shell-collapsed"
|
|
80
|
-
}) {
|
|
81
|
-
const [collapsed, setCollapsed] = useState(false);
|
|
82
|
-
const [loggingOut, setLoggingOut] = useState(false);
|
|
83
|
-
useEffect(() => {
|
|
84
|
-
try {
|
|
85
|
-
const stored = window.localStorage.getItem(storageKey);
|
|
86
|
-
if (stored === "1") {
|
|
87
|
-
setCollapsed(true);
|
|
88
|
-
}
|
|
89
|
-
} catch {
|
|
90
|
-
}
|
|
91
|
-
}, [storageKey]);
|
|
92
|
-
const toggleSidebar = () => {
|
|
93
|
-
setCollapsed((current) => {
|
|
94
|
-
const next = !current;
|
|
95
|
-
try {
|
|
96
|
-
window.localStorage.setItem(storageKey, next ? "1" : "0");
|
|
97
|
-
} catch {
|
|
98
|
-
}
|
|
99
|
-
return next;
|
|
100
|
-
});
|
|
101
|
-
};
|
|
102
|
-
const handleLogout = async () => {
|
|
103
|
-
setLoggingOut(true);
|
|
104
|
-
try {
|
|
105
|
-
await onLogout();
|
|
106
|
-
} finally {
|
|
107
|
-
setLoggingOut(false);
|
|
108
|
-
}
|
|
109
|
-
};
|
|
110
|
-
return /* @__PURE__ */ jsxs("div", { className: `orion-admin-shell ${collapsed ? "is-collapsed" : ""}`, children: [
|
|
111
|
-
/* @__PURE__ */ jsxs("aside", { className: "orion-admin-sidebar", children: [
|
|
112
|
-
/* @__PURE__ */ jsx(
|
|
113
|
-
"button",
|
|
114
|
-
{
|
|
115
|
-
"aria-label": collapsed ? "Expand sidebar" : "Collapse sidebar",
|
|
116
|
-
className: "orion-admin-sidebar-toggle",
|
|
117
|
-
onClick: toggleSidebar,
|
|
118
|
-
type: "button",
|
|
119
|
-
children: collapsed ? ">" : "<"
|
|
120
|
-
}
|
|
121
|
-
),
|
|
122
|
-
/* @__PURE__ */ jsxs("div", { className: "orion-admin-brand-wrap", children: [
|
|
123
|
-
logoUrl ? /* @__PURE__ */ jsx("div", { className: "orion-admin-brand-logo", children: /* @__PURE__ */ jsx("img", { alt: `${brandName} logo`, src: logoUrl }) }) : null,
|
|
124
|
-
/* @__PURE__ */ jsxs("div", { className: "orion-admin-brand-text", children: [
|
|
125
|
-
/* @__PURE__ */ jsx("div", { className: "orion-admin-brand-name", title: brandName, children: collapsed ? brandName.slice(0, 1).toUpperCase() : brandName }),
|
|
126
|
-
!collapsed ? /* @__PURE__ */ jsx("div", { className: "orion-admin-brand-subtitle", children: "Studio" }) : null
|
|
127
|
-
] })
|
|
128
|
-
] }),
|
|
129
|
-
/* @__PURE__ */ jsx("nav", { className: "orion-admin-nav", children: navItems.filter((item) => roleCanAccessNav(userRole, item)).map((item) => {
|
|
130
|
-
const active = navItemIsActive(pathname, item);
|
|
131
|
-
return /* @__PURE__ */ jsx(
|
|
132
|
-
"a",
|
|
133
|
-
{
|
|
134
|
-
className: `orion-admin-nav-link ${active ? "is-active" : ""}`,
|
|
135
|
-
href: item.href,
|
|
136
|
-
title: item.label,
|
|
137
|
-
children: item.icon ? collapsed ? /* @__PURE__ */ jsx(NavIcon, { name: item.icon }) : /* @__PURE__ */ jsxs("span", { style: { alignItems: "center", display: "flex", gap: "0.6rem" }, children: [
|
|
138
|
-
/* @__PURE__ */ jsx(NavIcon, { name: item.icon }),
|
|
139
|
-
item.label
|
|
140
|
-
] }) : collapsed ? item.label.slice(0, 1) : item.label
|
|
141
|
-
},
|
|
142
|
-
item.href
|
|
143
|
-
);
|
|
144
|
-
}) }),
|
|
145
|
-
/* @__PURE__ */ jsxs("div", { className: "orion-admin-sidebar-footer", children: [
|
|
146
|
-
!collapsed ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
147
|
-
/* @__PURE__ */ jsx("div", { className: "orion-admin-user-label", children: "Signed in as" }),
|
|
148
|
-
/* @__PURE__ */ jsx("div", { className: "orion-admin-user-email", children: userEmail })
|
|
149
|
-
] }) : null,
|
|
150
|
-
/* @__PURE__ */ jsx("button", { className: "orion-admin-logout", disabled: loggingOut, onClick: handleLogout, type: "button", children: loggingOut ? "..." : "Log out" })
|
|
151
|
-
] })
|
|
152
|
-
] }),
|
|
153
|
-
/* @__PURE__ */ jsx("main", { className: "orion-admin-main", children })
|
|
154
|
-
] });
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
// src/admin-app/components/HeaderNavItemsEditor.tsx
|
|
158
|
-
import { useEffect as useEffect2, useMemo, useState as useState2 } from "react";
|
|
159
|
-
|
|
160
|
-
// src/admin-app/navigationLinks.ts
|
|
161
|
-
var normalizeAdminNavInputs = (rows, pageOptions) => {
|
|
162
|
-
const allowedLinks = new Map(pageOptions.map((option) => [option.href, option.title]));
|
|
163
|
-
const deduped = [];
|
|
164
|
-
const seen = /* @__PURE__ */ new Set();
|
|
165
|
-
for (const row of rows) {
|
|
166
|
-
const href = typeof row.href === "string" ? row.href.trim() : "";
|
|
167
|
-
const defaultLabel = allowedLinks.get(href);
|
|
168
|
-
const explicitLabel = typeof row.label === "string" ? row.label.trim() : "";
|
|
169
|
-
const parentHref = typeof row.parentHref === "string" ? row.parentHref.trim() : "";
|
|
170
|
-
if (!href || !defaultLabel || seen.has(href)) {
|
|
171
|
-
continue;
|
|
172
|
-
}
|
|
173
|
-
seen.add(href);
|
|
174
|
-
deduped.push({
|
|
175
|
-
href,
|
|
176
|
-
label: explicitLabel.length > 0 ? explicitLabel : defaultLabel,
|
|
177
|
-
...parentHref.length > 0 ? { parentHref } : {}
|
|
178
|
-
});
|
|
179
|
-
}
|
|
180
|
-
const hrefs = new Set(deduped.map((item) => item.href));
|
|
181
|
-
const parentByHref = new Map(deduped.map((item) => [item.href, item.parentHref || ""]));
|
|
182
|
-
const createsCycle = (href, parentHref) => {
|
|
183
|
-
const visited = /* @__PURE__ */ new Set([href]);
|
|
184
|
-
let current = parentHref;
|
|
185
|
-
while (current) {
|
|
186
|
-
if (visited.has(current)) {
|
|
187
|
-
return true;
|
|
188
|
-
}
|
|
189
|
-
visited.add(current);
|
|
190
|
-
current = parentByHref.get(current) || "";
|
|
191
|
-
}
|
|
192
|
-
return false;
|
|
193
|
-
};
|
|
194
|
-
return deduped.map((item) => {
|
|
195
|
-
const parentHref = item.parentHref;
|
|
196
|
-
if (!parentHref || parentHref === item.href || !hrefs.has(parentHref) || createsCycle(item.href, parentHref)) {
|
|
197
|
-
return {
|
|
198
|
-
href: item.href,
|
|
199
|
-
label: item.label
|
|
200
|
-
};
|
|
201
|
-
}
|
|
202
|
-
return item;
|
|
203
|
-
});
|
|
204
|
-
};
|
|
205
|
-
|
|
206
|
-
// src/admin-app/components/HeaderNavItemsEditor.tsx
|
|
207
|
-
import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
208
|
-
var toRow = (item, index) => ({
|
|
209
|
-
id: `row-${index}-${item.href || "empty"}`,
|
|
210
|
-
href: item.href || "",
|
|
211
|
-
label: item.label || "",
|
|
212
|
-
parentHref: item.parentHref || ""
|
|
213
|
-
});
|
|
214
|
-
var moveRow = (rows, fromIndex, toIndex) => {
|
|
215
|
-
if (fromIndex === toIndex || fromIndex < 0 || toIndex < 0 || fromIndex >= rows.length || toIndex >= rows.length) {
|
|
216
|
-
return rows;
|
|
217
|
-
}
|
|
218
|
-
const next = [...rows];
|
|
219
|
-
const [moved] = next.splice(fromIndex, 1);
|
|
220
|
-
if (!moved) {
|
|
221
|
-
return rows;
|
|
222
|
-
}
|
|
223
|
-
next.splice(toIndex, 0, moved);
|
|
224
|
-
return next;
|
|
225
|
-
};
|
|
226
|
-
function HeaderNavItemsEditor({ initialItems, pageOptions, onItemsChange }) {
|
|
227
|
-
const [rows, setRows] = useState2(() => initialItems.map(toRow));
|
|
228
|
-
const [nextRowID, setNextRowID] = useState2(initialItems.length);
|
|
229
|
-
const [draggingRowID, setDraggingRowID] = useState2(null);
|
|
230
|
-
const [dragOverRowID, setDragOverRowID] = useState2(null);
|
|
231
|
-
const pageOptionByHref = useMemo(() => new Map(pageOptions.map((option) => [option.href, option])), [pageOptions]);
|
|
232
|
-
const serializedState = useMemo(
|
|
233
|
-
() => JSON.stringify(
|
|
234
|
-
rows.map((row) => ({
|
|
235
|
-
href: row.href.trim(),
|
|
236
|
-
label: row.label.trim(),
|
|
237
|
-
parentHref: row.parentHref.trim() || void 0
|
|
238
|
-
}))
|
|
239
|
-
),
|
|
240
|
-
[rows]
|
|
241
|
-
);
|
|
242
|
-
const normalizedItems = useMemo(() => {
|
|
243
|
-
const inputs = rows.map((row) => ({
|
|
244
|
-
href: row.href,
|
|
245
|
-
label: row.label,
|
|
246
|
-
parentHref: row.parentHref
|
|
247
|
-
}));
|
|
248
|
-
return normalizeAdminNavInputs(inputs, pageOptions);
|
|
249
|
-
}, [rows, pageOptions]);
|
|
250
|
-
useEffect2(() => {
|
|
251
|
-
onItemsChange?.(normalizedItems);
|
|
252
|
-
}, [normalizedItems, onItemsChange]);
|
|
253
|
-
const setRowValue = (rowID, changes) => {
|
|
254
|
-
setRows(
|
|
255
|
-
(currentRows) => currentRows.map((row) => {
|
|
256
|
-
if (row.id !== rowID) {
|
|
257
|
-
return row;
|
|
258
|
-
}
|
|
259
|
-
const nextRow = { ...row, ...changes };
|
|
260
|
-
if (nextRow.parentHref === nextRow.href) {
|
|
261
|
-
nextRow.parentHref = "";
|
|
262
|
-
}
|
|
263
|
-
return nextRow;
|
|
264
|
-
})
|
|
265
|
-
);
|
|
266
|
-
};
|
|
267
|
-
const removeRow = (rowID) => {
|
|
268
|
-
setRows((currentRows) => {
|
|
269
|
-
const removedRow = currentRows.find((candidate) => candidate.id === rowID);
|
|
270
|
-
const removedHref = removedRow?.href || "";
|
|
271
|
-
return currentRows.filter((row) => row.id !== rowID).map((row) => removedHref && row.parentHref === removedHref ? { ...row, parentHref: "" } : row);
|
|
272
|
-
});
|
|
273
|
-
};
|
|
274
|
-
const addRow = () => {
|
|
275
|
-
setRows((currentRows) => [
|
|
276
|
-
...currentRows,
|
|
277
|
-
{
|
|
278
|
-
id: `row-new-${nextRowID}`,
|
|
279
|
-
href: "",
|
|
280
|
-
label: "",
|
|
281
|
-
parentHref: ""
|
|
282
|
-
}
|
|
283
|
-
]);
|
|
284
|
-
setNextRowID((current) => current + 1);
|
|
285
|
-
};
|
|
286
|
-
return /* @__PURE__ */ jsxs2("div", { className: "orion-admin-nav-editor", children: [
|
|
287
|
-
/* @__PURE__ */ jsx2("input", { name: "navItemsState", readOnly: true, type: "hidden", value: serializedState }),
|
|
288
|
-
/* @__PURE__ */ jsxs2("div", { className: "orion-admin-nav-editor-head", children: [
|
|
289
|
-
/* @__PURE__ */ jsx2("div", { className: "orion-admin-nav-editor-title", children: "Navigation Items" }),
|
|
290
|
-
/* @__PURE__ */ jsx2("button", { className: "orion-admin-nav-editor-add", onClick: addRow, type: "button", children: "Add Item" })
|
|
291
|
-
] }),
|
|
292
|
-
/* @__PURE__ */ jsx2("div", { className: "orion-admin-nav-editor-help", children: "Add only links you want in the menu. Drag rows to reorder. Set a parent to create dropdown items." }),
|
|
293
|
-
rows.length === 0 ? /* @__PURE__ */ jsx2("div", { className: "orion-admin-nav-editor-empty", children: 'No navigation items yet. Click "Add Item" to start.' }) : null,
|
|
294
|
-
/* @__PURE__ */ jsx2("div", { className: "orion-admin-nav-editor-list", children: rows.map((row, rowIndex) => {
|
|
295
|
-
const parentCandidates = rows.filter((candidate) => candidate.id !== row.id && candidate.href.trim().length > 0).map((candidate) => {
|
|
296
|
-
const resolved = pageOptionByHref.get(candidate.href);
|
|
297
|
-
return {
|
|
298
|
-
href: candidate.href,
|
|
299
|
-
label: candidate.label.trim() || resolved?.title || candidate.href
|
|
300
|
-
};
|
|
301
|
-
});
|
|
302
|
-
const selectedPage = pageOptionByHref.get(row.href);
|
|
303
|
-
const labelPlaceholder = selectedPage?.title || "Navigation Label";
|
|
304
|
-
return /* @__PURE__ */ jsxs2(
|
|
305
|
-
"div",
|
|
306
|
-
{
|
|
307
|
-
className: `orion-admin-nav-editor-row${draggingRowID === row.id ? " is-dragging" : ""}${dragOverRowID === row.id && draggingRowID !== row.id ? " is-drop-target" : ""}`,
|
|
308
|
-
draggable: true,
|
|
309
|
-
onDragEnd: () => {
|
|
310
|
-
setDraggingRowID(null);
|
|
311
|
-
setDragOverRowID(null);
|
|
312
|
-
},
|
|
313
|
-
onDragEnter: () => {
|
|
314
|
-
if (draggingRowID && draggingRowID !== row.id) {
|
|
315
|
-
setDragOverRowID(row.id);
|
|
316
|
-
}
|
|
317
|
-
},
|
|
318
|
-
onDragLeave: () => {
|
|
319
|
-
if (dragOverRowID === row.id) {
|
|
320
|
-
setDragOverRowID(null);
|
|
321
|
-
}
|
|
322
|
-
},
|
|
323
|
-
onDragOver: (event) => {
|
|
324
|
-
event.preventDefault();
|
|
325
|
-
if (draggingRowID && draggingRowID !== row.id && dragOverRowID !== row.id) {
|
|
326
|
-
setDragOverRowID(row.id);
|
|
327
|
-
}
|
|
328
|
-
},
|
|
329
|
-
onDragStart: (event) => {
|
|
330
|
-
setDraggingRowID(row.id);
|
|
331
|
-
event.dataTransfer.effectAllowed = "move";
|
|
332
|
-
},
|
|
333
|
-
onDrop: (event) => {
|
|
334
|
-
event.preventDefault();
|
|
335
|
-
if (!draggingRowID || draggingRowID === row.id) {
|
|
336
|
-
return;
|
|
337
|
-
}
|
|
338
|
-
setRows((currentRows) => {
|
|
339
|
-
const fromIndex = currentRows.findIndex((entry) => entry.id === draggingRowID);
|
|
340
|
-
const toIndex = currentRows.findIndex((entry) => entry.id === row.id);
|
|
341
|
-
return moveRow(currentRows, fromIndex, toIndex);
|
|
342
|
-
});
|
|
343
|
-
setDraggingRowID(null);
|
|
344
|
-
setDragOverRowID(null);
|
|
345
|
-
},
|
|
346
|
-
children: [
|
|
347
|
-
/* @__PURE__ */ jsxs2("div", { className: "orion-admin-nav-editor-row-head", children: [
|
|
348
|
-
/* @__PURE__ */ jsx2("span", { className: "orion-admin-nav-editor-drag", children: "Drag" }),
|
|
349
|
-
/* @__PURE__ */ jsxs2("span", { className: "orion-admin-nav-editor-row-index", children: [
|
|
350
|
-
"#",
|
|
351
|
-
rowIndex + 1
|
|
352
|
-
] }),
|
|
353
|
-
/* @__PURE__ */ jsx2("button", { className: "orion-admin-nav-editor-remove", onClick: () => removeRow(row.id), type: "button", children: "Remove" })
|
|
354
|
-
] }),
|
|
355
|
-
/* @__PURE__ */ jsxs2("div", { className: "orion-admin-nav-editor-row-grid", children: [
|
|
356
|
-
/* @__PURE__ */ jsxs2("label", { children: [
|
|
357
|
-
"Label",
|
|
358
|
-
/* @__PURE__ */ jsx2(
|
|
359
|
-
"input",
|
|
360
|
-
{
|
|
361
|
-
name: `navLabel_${rowIndex}`,
|
|
362
|
-
onChange: (event) => setRowValue(row.id, { label: event.target.value }),
|
|
363
|
-
placeholder: labelPlaceholder,
|
|
364
|
-
type: "text",
|
|
365
|
-
value: row.label
|
|
366
|
-
}
|
|
367
|
-
)
|
|
368
|
-
] }),
|
|
369
|
-
/* @__PURE__ */ jsxs2("label", { children: [
|
|
370
|
-
"Page",
|
|
371
|
-
/* @__PURE__ */ jsxs2(
|
|
372
|
-
"select",
|
|
373
|
-
{
|
|
374
|
-
name: `navPage_${rowIndex}`,
|
|
375
|
-
onChange: (event) => {
|
|
376
|
-
const nextHref = event.target.value;
|
|
377
|
-
const nextParent = row.parentHref && row.parentHref === nextHref ? "" : row.parentHref;
|
|
378
|
-
setRowValue(row.id, { href: nextHref, parentHref: nextParent });
|
|
379
|
-
},
|
|
380
|
-
value: row.href,
|
|
381
|
-
children: [
|
|
382
|
-
/* @__PURE__ */ jsx2("option", { value: "", children: "Select page..." }),
|
|
383
|
-
pageOptions.map((pageOption) => /* @__PURE__ */ jsx2("option", { value: pageOption.href, children: pageOption.label }, `${pageOption.href}-${pageOption.title}`))
|
|
384
|
-
]
|
|
385
|
-
}
|
|
386
|
-
)
|
|
387
|
-
] }),
|
|
388
|
-
/* @__PURE__ */ jsxs2("label", { children: [
|
|
389
|
-
"Parent (dropdown under)",
|
|
390
|
-
/* @__PURE__ */ jsxs2(
|
|
391
|
-
"select",
|
|
392
|
-
{
|
|
393
|
-
name: `navParentHref_${rowIndex}`,
|
|
394
|
-
onChange: (event) => setRowValue(row.id, { parentHref: event.target.value }),
|
|
395
|
-
value: row.parentHref,
|
|
396
|
-
children: [
|
|
397
|
-
/* @__PURE__ */ jsx2("option", { value: "", children: "Top-level item" }),
|
|
398
|
-
parentCandidates.map((candidate) => /* @__PURE__ */ jsx2("option", { value: candidate.href, children: candidate.label }, `${row.id}-parent-${candidate.href}`))
|
|
399
|
-
]
|
|
400
|
-
}
|
|
401
|
-
)
|
|
402
|
-
] })
|
|
403
|
-
] })
|
|
404
|
-
]
|
|
405
|
-
},
|
|
406
|
-
row.id
|
|
407
|
-
);
|
|
408
|
-
}) })
|
|
409
|
-
] });
|
|
410
|
-
}
|
|
411
|
-
|
|
412
|
-
// src/admin-app/components/HeaderNavEditorWithPreview.tsx
|
|
413
|
-
import { useMemo as useMemo2, useState as useState3 } from "react";
|
|
414
|
-
|
|
415
|
-
// src/admin-app/nestedNavigation.ts
|
|
416
|
-
var normalizeNestedNavItems = (items) => {
|
|
417
|
-
const deduped = [];
|
|
418
|
-
const seen = /* @__PURE__ */ new Set();
|
|
419
|
-
for (const item of items) {
|
|
420
|
-
const href = typeof item.href === "string" ? item.href.trim() : "";
|
|
421
|
-
const label = typeof item.label === "string" ? item.label.trim() : "";
|
|
422
|
-
const parentHref = typeof item.parentHref === "string" ? item.parentHref.trim() : "";
|
|
423
|
-
if (!href || !label || seen.has(href)) {
|
|
424
|
-
continue;
|
|
425
|
-
}
|
|
426
|
-
seen.add(href);
|
|
427
|
-
deduped.push({
|
|
428
|
-
href,
|
|
429
|
-
label,
|
|
430
|
-
...parentHref ? { parentHref } : {}
|
|
431
|
-
});
|
|
432
|
-
}
|
|
433
|
-
const hrefs = new Set(deduped.map((item) => item.href));
|
|
434
|
-
return deduped.map((item) => ({
|
|
435
|
-
href: item.href,
|
|
436
|
-
label: item.label,
|
|
437
|
-
...item.parentHref && item.parentHref !== item.href && hrefs.has(item.parentHref) ? { parentHref: item.parentHref } : {}
|
|
438
|
-
}));
|
|
439
|
-
};
|
|
440
|
-
var buildNestedNavTree = (items) => {
|
|
441
|
-
const childrenByParent = /* @__PURE__ */ new Map();
|
|
442
|
-
const topLevel = [];
|
|
443
|
-
for (const item of items) {
|
|
444
|
-
if (!item.parentHref) {
|
|
445
|
-
topLevel.push(item);
|
|
446
|
-
continue;
|
|
447
|
-
}
|
|
448
|
-
const children = childrenByParent.get(item.parentHref) || [];
|
|
449
|
-
children.push(item);
|
|
450
|
-
childrenByParent.set(item.parentHref, children);
|
|
451
|
-
}
|
|
452
|
-
if (topLevel.length === 0 && items.length > 0) {
|
|
453
|
-
return {
|
|
454
|
-
topLevel: items.map((item) => ({ href: item.href, label: item.label })),
|
|
455
|
-
childrenByParent: /* @__PURE__ */ new Map()
|
|
456
|
-
};
|
|
457
|
-
}
|
|
458
|
-
return { childrenByParent, topLevel };
|
|
459
|
-
};
|
|
460
|
-
|
|
461
|
-
// src/admin-app/components/HeaderNavEditorWithPreview.tsx
|
|
462
|
-
import { Fragment as Fragment2, jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
463
|
-
var fallbackNav = [{ href: "/", label: "Home" }];
|
|
464
|
-
function HeaderNavEditorWithPreview({
|
|
465
|
-
brandName,
|
|
466
|
-
initialItems,
|
|
467
|
-
logoUrl,
|
|
468
|
-
pageOptions,
|
|
469
|
-
tagline = ""
|
|
470
|
-
}) {
|
|
471
|
-
const [liveItems, setLiveItems] = useState3(initialItems);
|
|
472
|
-
const previewItems = useMemo2(() => {
|
|
473
|
-
const normalized = normalizeNestedNavItems(liveItems);
|
|
474
|
-
const tree = buildNestedNavTree(normalized);
|
|
475
|
-
return tree.topLevel.length > 0 ? tree : buildNestedNavTree(fallbackNav);
|
|
476
|
-
}, [liveItems]);
|
|
477
|
-
return /* @__PURE__ */ jsxs3(Fragment2, { children: [
|
|
478
|
-
/* @__PURE__ */ jsx3(HeaderNavItemsEditor, { initialItems, onItemsChange: setLiveItems, pageOptions }),
|
|
479
|
-
/* @__PURE__ */ jsx3("div", { style: { color: "#5d6664", fontSize: "0.88rem", fontWeight: 700 }, children: "Header Preview" }),
|
|
480
|
-
/* @__PURE__ */ jsx3(
|
|
481
|
-
"div",
|
|
482
|
-
{
|
|
483
|
-
style: {
|
|
484
|
-
border: "1px solid #dce2e0",
|
|
485
|
-
borderRadius: 14,
|
|
486
|
-
overflow: "hidden"
|
|
487
|
-
},
|
|
488
|
-
children: /* @__PURE__ */ jsx3("header", { className: "site-header", style: { position: "relative", top: "auto" }, children: /* @__PURE__ */ jsxs3("div", { className: "container container-content header-wrap", children: [
|
|
489
|
-
/* @__PURE__ */ jsxs3("a", { className: "brand", href: "#", children: [
|
|
490
|
-
logoUrl ? /* @__PURE__ */ jsx3("img", { alt: `${brandName} logo`, src: logoUrl }) : null,
|
|
491
|
-
/* @__PURE__ */ jsxs3("div", { children: [
|
|
492
|
-
/* @__PURE__ */ jsx3("div", { className: "brand-title", children: brandName }),
|
|
493
|
-
tagline ? /* @__PURE__ */ jsx3("div", { className: "brand-subtitle", children: tagline }) : null
|
|
494
|
-
] })
|
|
495
|
-
] }),
|
|
496
|
-
/* @__PURE__ */ jsx3("nav", { className: "site-nav open", children: previewItems.topLevel.map((item, index) => {
|
|
497
|
-
const children = previewItems.childrenByParent.get(item.href) || [];
|
|
498
|
-
return /* @__PURE__ */ jsxs3(
|
|
499
|
-
"div",
|
|
500
|
-
{
|
|
501
|
-
className: children.length > 0 ? "site-nav-item has-children" : "site-nav-item",
|
|
502
|
-
children: [
|
|
503
|
-
/* @__PURE__ */ jsx3("a", { className: index === 0 ? "active" : "", href: item.href, children: item.label }),
|
|
504
|
-
children.length > 0 ? /* @__PURE__ */ jsx3("div", { className: "site-subnav", children: children.map((child) => /* @__PURE__ */ jsx3("a", { href: child.href, children: child.label }, `${item.href}-${child.href}`)) }) : null
|
|
505
|
-
]
|
|
506
|
-
},
|
|
507
|
-
`${item.href}-${index}`
|
|
508
|
-
);
|
|
509
|
-
}) })
|
|
510
|
-
] }) })
|
|
511
|
-
}
|
|
512
|
-
)
|
|
513
|
-
] });
|
|
514
|
-
}
|
|
515
|
-
|
|
516
|
-
// src/admin-app/components/MediaDetailPanel.tsx
|
|
517
|
-
import { useState as useState4 } from "react";
|
|
518
|
-
import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
519
|
-
function formatFileSize(bytes) {
|
|
520
|
-
if (bytes < 1024) return `${bytes} B`;
|
|
521
|
-
if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
|
|
522
|
-
return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
|
|
523
|
-
}
|
|
524
|
-
function MediaDetailPanel({
|
|
525
|
-
id,
|
|
526
|
-
filename,
|
|
527
|
-
alt,
|
|
528
|
-
url,
|
|
529
|
-
filesize,
|
|
530
|
-
width,
|
|
531
|
-
height,
|
|
532
|
-
mimeType,
|
|
533
|
-
createdAt,
|
|
534
|
-
updateAction,
|
|
535
|
-
deleteAction
|
|
536
|
-
}) {
|
|
537
|
-
const [copied, setCopied] = useState4(false);
|
|
538
|
-
const [confirmDelete, setConfirmDelete] = useState4(false);
|
|
539
|
-
const copyUrl = async () => {
|
|
540
|
-
if (!url) return;
|
|
541
|
-
try {
|
|
542
|
-
await navigator.clipboard.writeText(url);
|
|
543
|
-
setCopied(true);
|
|
544
|
-
setTimeout(() => setCopied(false), 2e3);
|
|
545
|
-
} catch {
|
|
546
|
-
const input = document.createElement("input");
|
|
547
|
-
input.value = url;
|
|
548
|
-
document.body.appendChild(input);
|
|
549
|
-
input.select();
|
|
550
|
-
document.execCommand("copy");
|
|
551
|
-
document.body.removeChild(input);
|
|
552
|
-
setCopied(true);
|
|
553
|
-
setTimeout(() => setCopied(false), 2e3);
|
|
554
|
-
}
|
|
555
|
-
};
|
|
556
|
-
const metaRows = [];
|
|
557
|
-
if (filename) metaRows.push({ label: "Filename", value: filename });
|
|
558
|
-
if (typeof filesize === "number") metaRows.push({ label: "File size", value: formatFileSize(filesize) });
|
|
559
|
-
if (typeof width === "number" && typeof height === "number") metaRows.push({ label: "Dimensions", value: `${width} \xD7 ${height} px` });
|
|
560
|
-
if (mimeType) metaRows.push({ label: "Type", value: mimeType });
|
|
561
|
-
if (createdAt) {
|
|
562
|
-
try {
|
|
563
|
-
metaRows.push({ label: "Uploaded", value: new Date(createdAt).toLocaleDateString() });
|
|
564
|
-
} catch {
|
|
565
|
-
metaRows.push({ label: "Uploaded", value: createdAt });
|
|
566
|
-
}
|
|
567
|
-
}
|
|
568
|
-
return /* @__PURE__ */ jsxs4("div", { className: "orion-admin-grid", style: { alignItems: "start" }, children: [
|
|
569
|
-
/* @__PURE__ */ jsxs4("div", { children: [
|
|
570
|
-
/* @__PURE__ */ jsx4("div", { className: "orion-admin-card", children: url ? /* @__PURE__ */ jsx4("img", { alt: alt || filename || "Media", src: url, style: { borderRadius: 12, width: "100%" } }) : /* @__PURE__ */ jsx4("span", { children: "No preview available." }) }),
|
|
571
|
-
url ? /* @__PURE__ */ jsx4(
|
|
572
|
-
"button",
|
|
573
|
-
{
|
|
574
|
-
className: "orion-admin-action-button",
|
|
575
|
-
onClick: copyUrl,
|
|
576
|
-
style: { marginTop: "0.6rem", width: "100%" },
|
|
577
|
-
type: "button",
|
|
578
|
-
children: copied ? "Copied!" : "Copy URL"
|
|
579
|
-
}
|
|
580
|
-
) : null
|
|
581
|
-
] }),
|
|
582
|
-
/* @__PURE__ */ jsxs4("div", { style: { display: "grid", gap: "0.8rem" }, children: [
|
|
583
|
-
metaRows.length > 0 ? /* @__PURE__ */ jsx4("div", { className: "orion-admin-card orion-admin-meta-table", children: metaRows.map((row) => /* @__PURE__ */ jsxs4("div", { className: "orion-admin-meta-row", children: [
|
|
584
|
-
/* @__PURE__ */ jsx4("span", { className: "orion-admin-meta-label", children: row.label }),
|
|
585
|
-
/* @__PURE__ */ jsx4("span", { className: "orion-admin-meta-value", children: row.value })
|
|
586
|
-
] }, row.label)) }) : null,
|
|
587
|
-
/* @__PURE__ */ jsxs4("form", { action: updateAction, className: "orion-admin-form", children: [
|
|
588
|
-
/* @__PURE__ */ jsx4("input", { name: "id", type: "hidden", value: id }),
|
|
589
|
-
/* @__PURE__ */ jsxs4("label", { children: [
|
|
590
|
-
"Alt text",
|
|
591
|
-
/* @__PURE__ */ jsx4("input", { defaultValue: alt || "", name: "alt", required: true, type: "text" })
|
|
592
|
-
] }),
|
|
593
|
-
/* @__PURE__ */ jsx4("button", { type: "submit", children: "Save" })
|
|
594
|
-
] }),
|
|
595
|
-
confirmDelete ? /* @__PURE__ */ jsxs4("div", { className: "orion-admin-form", style: { borderColor: "#b42318" }, children: [
|
|
596
|
-
/* @__PURE__ */ jsx4("p", { style: { fontWeight: 700, margin: 0 }, children: "Are you sure you want to delete this asset?" }),
|
|
597
|
-
/* @__PURE__ */ jsx4("p", { style: { color: "var(--orion-admin-muted)", fontSize: "0.9rem", margin: 0 }, children: "This action cannot be undone." }),
|
|
598
|
-
/* @__PURE__ */ jsxs4("div", { style: { display: "flex", gap: "0.5rem" }, children: [
|
|
599
|
-
/* @__PURE__ */ jsxs4("form", { action: deleteAction, style: { flex: 1 }, children: [
|
|
600
|
-
/* @__PURE__ */ jsx4("input", { name: "id", type: "hidden", value: id }),
|
|
601
|
-
/* @__PURE__ */ jsx4("button", { style: { background: "#b42318", border: 0, borderRadius: 10, color: "#fff", cursor: "pointer", fontWeight: 800, padding: "0.55rem 0.8rem", width: "100%" }, type: "submit", children: "Yes, Delete" })
|
|
602
|
-
] }),
|
|
603
|
-
/* @__PURE__ */ jsx4(
|
|
604
|
-
"button",
|
|
605
|
-
{
|
|
606
|
-
onClick: () => setConfirmDelete(false),
|
|
607
|
-
style: { background: "transparent", border: "1px solid var(--orion-admin-border)", borderRadius: 10, cursor: "pointer", flex: 1, fontWeight: 700, padding: "0.55rem 0.8rem" },
|
|
608
|
-
type: "button",
|
|
609
|
-
children: "Cancel"
|
|
610
|
-
}
|
|
611
|
-
)
|
|
612
|
-
] })
|
|
613
|
-
] }) : /* @__PURE__ */ jsx4(
|
|
614
|
-
"button",
|
|
615
|
-
{
|
|
616
|
-
className: "orion-admin-action-button",
|
|
617
|
-
onClick: () => setConfirmDelete(true),
|
|
618
|
-
style: { background: "#b42318" },
|
|
619
|
-
type: "button",
|
|
620
|
-
children: "Delete Asset"
|
|
621
|
-
}
|
|
622
|
-
)
|
|
623
|
-
] })
|
|
624
|
-
] });
|
|
625
|
-
}
|
|
626
|
-
|
|
627
|
-
// src/admin-app/components/MediaListItem.tsx
|
|
628
|
-
import { jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
629
|
-
function formatFileSize2(bytes) {
|
|
630
|
-
if (bytes < 1024) return `${bytes} B`;
|
|
631
|
-
if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
|
|
632
|
-
return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
|
|
633
|
-
}
|
|
634
|
-
function MediaListItem({
|
|
635
|
-
id,
|
|
636
|
-
filename,
|
|
637
|
-
alt,
|
|
638
|
-
url,
|
|
639
|
-
filesize,
|
|
640
|
-
width,
|
|
641
|
-
height,
|
|
642
|
-
mimeType,
|
|
643
|
-
href
|
|
644
|
-
}) {
|
|
645
|
-
const label = filename || `Media ${id}`;
|
|
646
|
-
const altText = alt || "";
|
|
647
|
-
const metaParts = [];
|
|
648
|
-
if (typeof filesize === "number") metaParts.push(formatFileSize2(filesize));
|
|
649
|
-
if (typeof width === "number" && typeof height === "number") metaParts.push(`${width}\xD7${height}`);
|
|
650
|
-
if (typeof mimeType === "string") metaParts.push(mimeType);
|
|
651
|
-
return /* @__PURE__ */ jsxs5("a", { className: "orion-admin-list-item", href, children: [
|
|
652
|
-
/* @__PURE__ */ jsxs5("div", { style: { alignItems: "center", display: "flex", gap: "0.8rem" }, children: [
|
|
653
|
-
url ? /* @__PURE__ */ jsx5("img", { alt: altText || label, className: "orion-admin-media-preview", src: url }) : null,
|
|
654
|
-
/* @__PURE__ */ jsxs5("div", { children: [
|
|
655
|
-
/* @__PURE__ */ jsx5("strong", { children: label }),
|
|
656
|
-
/* @__PURE__ */ jsx5("div", { className: "orion-admin-list-meta", children: altText || "No alt text" }),
|
|
657
|
-
metaParts.length > 0 ? /* @__PURE__ */ jsx5("div", { className: "orion-admin-list-meta", style: { marginTop: "0.15rem" }, children: metaParts.join(" \xB7 ") }) : null
|
|
658
|
-
] })
|
|
659
|
-
] }),
|
|
660
|
-
/* @__PURE__ */ jsx5("span", { className: "orion-admin-list-meta", children: "Edit" })
|
|
661
|
-
] });
|
|
662
|
-
}
|
|
663
|
-
|
|
664
|
-
// src/admin-app/components/MediaUploadForm.tsx
|
|
665
|
-
import { useState as useState5, useRef, useCallback } from "react";
|
|
666
|
-
import { useRouter } from "next/navigation";
|
|
667
|
-
import { jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
668
|
-
var MEDIA_LIBRARY_SYNC_EVENT = "orion-media-library-updated";
|
|
669
|
-
var notifyMediaLibraryUpdated = () => {
|
|
670
|
-
if (typeof window === "undefined") {
|
|
671
|
-
return;
|
|
672
|
-
}
|
|
673
|
-
const updatedAt = Date.now().toString();
|
|
674
|
-
window.dispatchEvent(
|
|
675
|
-
new CustomEvent(MEDIA_LIBRARY_SYNC_EVENT, {
|
|
676
|
-
detail: {
|
|
677
|
-
updatedAt
|
|
678
|
-
}
|
|
679
|
-
})
|
|
680
|
-
);
|
|
681
|
-
try {
|
|
682
|
-
window.localStorage.setItem(MEDIA_LIBRARY_SYNC_EVENT, updatedAt);
|
|
683
|
-
} catch {
|
|
684
|
-
}
|
|
685
|
-
};
|
|
686
|
-
var parseUploadError = async (response) => {
|
|
687
|
-
const fallback = "Upload failed. Please check the image and required fields, then try again.";
|
|
688
|
-
try {
|
|
689
|
-
const body = await response.json();
|
|
690
|
-
const nestedMessage = body.errors?.[0]?.data?.errors?.[0]?.message;
|
|
691
|
-
if (typeof nestedMessage === "string" && nestedMessage.trim().length > 0) {
|
|
692
|
-
return nestedMessage;
|
|
693
|
-
}
|
|
694
|
-
const topMessage = body.errors?.[0]?.message;
|
|
695
|
-
if (typeof topMessage === "string" && topMessage.trim().length > 0) {
|
|
696
|
-
return topMessage;
|
|
697
|
-
}
|
|
698
|
-
if (typeof body.message === "string" && body.message.trim().length > 0) {
|
|
699
|
-
return body.message;
|
|
700
|
-
}
|
|
701
|
-
} catch {
|
|
702
|
-
}
|
|
703
|
-
return fallback;
|
|
704
|
-
};
|
|
705
|
-
function MediaUploadForm() {
|
|
706
|
-
const router = useRouter();
|
|
707
|
-
const fileInputRef = useRef(null);
|
|
708
|
-
const [alt, setAlt] = useState5("");
|
|
709
|
-
const [file, setFile] = useState5(null);
|
|
710
|
-
const [preview, setPreview] = useState5(null);
|
|
711
|
-
const [dragging, setDragging] = useState5(false);
|
|
712
|
-
const [submitting, setSubmitting] = useState5(false);
|
|
713
|
-
const [error, setError] = useState5(null);
|
|
714
|
-
const handleFile = useCallback((selectedFile) => {
|
|
715
|
-
setFile(selectedFile);
|
|
716
|
-
if (preview) {
|
|
717
|
-
URL.revokeObjectURL(preview);
|
|
718
|
-
setPreview(null);
|
|
719
|
-
}
|
|
720
|
-
if (selectedFile && selectedFile.type.startsWith("image/")) {
|
|
721
|
-
setPreview(URL.createObjectURL(selectedFile));
|
|
722
|
-
}
|
|
723
|
-
}, [preview]);
|
|
724
|
-
const onDragOver = useCallback((e) => {
|
|
725
|
-
e.preventDefault();
|
|
726
|
-
setDragging(true);
|
|
727
|
-
}, []);
|
|
728
|
-
const onDragLeave = useCallback((e) => {
|
|
729
|
-
e.preventDefault();
|
|
730
|
-
setDragging(false);
|
|
731
|
-
}, []);
|
|
732
|
-
const onDrop = useCallback((e) => {
|
|
733
|
-
e.preventDefault();
|
|
734
|
-
setDragging(false);
|
|
735
|
-
const droppedFile = e.dataTransfer.files?.[0] || null;
|
|
736
|
-
if (droppedFile) {
|
|
737
|
-
handleFile(droppedFile);
|
|
738
|
-
}
|
|
739
|
-
}, [handleFile]);
|
|
740
|
-
const upload = async (event) => {
|
|
741
|
-
event.preventDefault();
|
|
742
|
-
if (!file) {
|
|
743
|
-
setError("Select an image to upload.");
|
|
744
|
-
return;
|
|
745
|
-
}
|
|
746
|
-
setSubmitting(true);
|
|
747
|
-
setError(null);
|
|
748
|
-
try {
|
|
749
|
-
const optimizedFile = await optimizeImageForUpload(file);
|
|
750
|
-
if (optimizedFile.size > MAX_DIRECT_UPLOAD_BYTES) {
|
|
751
|
-
throw new Error("Image is too large. Use an image under 4MB or lower-resolution export.");
|
|
752
|
-
}
|
|
753
|
-
const formData = new FormData();
|
|
754
|
-
const fallbackAlt = file.name.replace(/\.[^/.]+$/, "").trim();
|
|
755
|
-
const resolvedAlt = alt.trim() || fallbackAlt || "Uploaded image";
|
|
756
|
-
formData.set("_payload", JSON.stringify({ alt: resolvedAlt }));
|
|
757
|
-
formData.set("alt", resolvedAlt);
|
|
758
|
-
formData.set("file", optimizedFile);
|
|
759
|
-
const response = await fetch("/api/media", {
|
|
760
|
-
method: "POST",
|
|
761
|
-
credentials: "include",
|
|
762
|
-
body: formData
|
|
763
|
-
});
|
|
764
|
-
if (!response.ok) {
|
|
765
|
-
throw new Error(await parseUploadError(response));
|
|
766
|
-
}
|
|
767
|
-
setAlt("");
|
|
768
|
-
setFile(null);
|
|
769
|
-
if (preview) {
|
|
770
|
-
URL.revokeObjectURL(preview);
|
|
771
|
-
setPreview(null);
|
|
772
|
-
}
|
|
773
|
-
notifyMediaLibraryUpdated();
|
|
774
|
-
router.refresh();
|
|
775
|
-
} catch (err) {
|
|
776
|
-
setError(err instanceof Error ? err.message : "Upload failed");
|
|
777
|
-
} finally {
|
|
778
|
-
setSubmitting(false);
|
|
779
|
-
}
|
|
780
|
-
};
|
|
781
|
-
return /* @__PURE__ */ jsxs6("form", { className: "orion-admin-upload-form", onSubmit: upload, children: [
|
|
782
|
-
/* @__PURE__ */ jsxs6("label", { children: [
|
|
783
|
-
"Alt text",
|
|
784
|
-
/* @__PURE__ */ jsx6(
|
|
785
|
-
"input",
|
|
786
|
-
{
|
|
787
|
-
onChange: (event) => setAlt(event.target.value),
|
|
788
|
-
placeholder: "Describe the image",
|
|
789
|
-
type: "text",
|
|
790
|
-
value: alt
|
|
791
|
-
}
|
|
792
|
-
)
|
|
793
|
-
] }),
|
|
794
|
-
/* @__PURE__ */ jsxs6(
|
|
795
|
-
"div",
|
|
796
|
-
{
|
|
797
|
-
className: `orion-admin-dropzone${dragging ? " is-dragging" : ""}${file ? " has-file" : ""}`,
|
|
798
|
-
onClick: () => fileInputRef.current?.click(),
|
|
799
|
-
onDragLeave,
|
|
800
|
-
onDragOver,
|
|
801
|
-
onDrop,
|
|
802
|
-
children: [
|
|
803
|
-
preview ? /* @__PURE__ */ jsxs6("div", { className: "orion-admin-dropzone-preview", children: [
|
|
804
|
-
/* @__PURE__ */ jsx6("img", { alt: "Upload preview", src: preview }),
|
|
805
|
-
/* @__PURE__ */ jsx6("span", { children: file?.name })
|
|
806
|
-
] }) : /* @__PURE__ */ jsxs6("div", { className: "orion-admin-dropzone-label", children: [
|
|
807
|
-
/* @__PURE__ */ jsx6("strong", { children: "Drop an image here" }),
|
|
808
|
-
/* @__PURE__ */ jsx6("span", { children: "or click to browse" })
|
|
809
|
-
] }),
|
|
810
|
-
/* @__PURE__ */ jsx6(
|
|
811
|
-
"input",
|
|
812
|
-
{
|
|
813
|
-
accept: "image/*",
|
|
814
|
-
onChange: (event) => handleFile(event.target.files?.[0] || null),
|
|
815
|
-
ref: fileInputRef,
|
|
816
|
-
style: { display: "none" },
|
|
817
|
-
type: "file"
|
|
818
|
-
}
|
|
819
|
-
)
|
|
820
|
-
]
|
|
821
|
-
}
|
|
822
|
-
),
|
|
823
|
-
error ? /* @__PURE__ */ jsx6("div", { className: "orion-admin-upload-error", children: error }) : null,
|
|
824
|
-
/* @__PURE__ */ jsx6("button", { disabled: submitting, type: "submit", children: submitting ? "Uploading..." : "Upload" })
|
|
825
|
-
] });
|
|
826
|
-
}
|
|
3
|
+
AdminShellClient,
|
|
4
|
+
HeaderNavEditorWithPreview,
|
|
5
|
+
HeaderNavItemsEditor,
|
|
6
|
+
MediaDetailPanel,
|
|
7
|
+
MediaListItem,
|
|
8
|
+
MediaUploadForm,
|
|
9
|
+
SiteFooterPreview,
|
|
10
|
+
SiteHeaderPreview
|
|
11
|
+
} from "../chunk-KPIX7OSV.mjs";
|
|
12
|
+
import "../chunk-ROTPP5CU.mjs";
|
|
827
13
|
|
|
828
14
|
// src/admin-app/components/PageEditorFrame.tsx
|
|
829
|
-
import { useEffect
|
|
830
|
-
import { jsx
|
|
15
|
+
import { useEffect, useRef, useState } from "react";
|
|
16
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
831
17
|
var extractPageIDFromBuilderSrc = (value) => {
|
|
832
18
|
if (!value || typeof value !== "string") {
|
|
833
19
|
return null;
|
|
@@ -841,19 +27,19 @@ var extractPageIDFromBuilderSrc = (value) => {
|
|
|
841
27
|
}
|
|
842
28
|
};
|
|
843
29
|
function PageEditorFrame({ src }) {
|
|
844
|
-
const iframeRef =
|
|
845
|
-
const dirtyCheckTimerRef =
|
|
846
|
-
const [saving, setSaving] =
|
|
847
|
-
const [message, setMessage] =
|
|
848
|
-
const [error, setError] =
|
|
849
|
-
const [hasUnsavedChanges, setHasUnsavedChanges] =
|
|
850
|
-
const [awaitingDirtyCheck, setAwaitingDirtyCheck] =
|
|
851
|
-
const [pendingNavigationURL, setPendingNavigationURL] =
|
|
852
|
-
const [showUnsavedDialog, setShowUnsavedDialog] =
|
|
853
|
-
const [canUndo, setCanUndo] =
|
|
854
|
-
const [canRedo, setCanRedo] =
|
|
855
|
-
const [sessionExpired, setSessionExpired] =
|
|
856
|
-
const [hasUnpublishedChanges, setHasUnpublishedChanges] =
|
|
30
|
+
const iframeRef = useRef(null);
|
|
31
|
+
const dirtyCheckTimerRef = useRef(null);
|
|
32
|
+
const [saving, setSaving] = useState(null);
|
|
33
|
+
const [message, setMessage] = useState("");
|
|
34
|
+
const [error, setError] = useState("");
|
|
35
|
+
const [hasUnsavedChanges, setHasUnsavedChanges] = useState(false);
|
|
36
|
+
const [awaitingDirtyCheck, setAwaitingDirtyCheck] = useState(false);
|
|
37
|
+
const [pendingNavigationURL, setPendingNavigationURL] = useState(null);
|
|
38
|
+
const [showUnsavedDialog, setShowUnsavedDialog] = useState(false);
|
|
39
|
+
const [canUndo, setCanUndo] = useState(false);
|
|
40
|
+
const [canRedo, setCanRedo] = useState(false);
|
|
41
|
+
const [sessionExpired, setSessionExpired] = useState(false);
|
|
42
|
+
const [hasUnpublishedChanges, setHasUnpublishedChanges] = useState(false);
|
|
857
43
|
const pageID = extractPageIDFromBuilderSrc(src);
|
|
858
44
|
const refreshUnpublishedChanges = async () => {
|
|
859
45
|
if (!pageID) {
|
|
@@ -934,7 +120,7 @@ function PageEditorFrame({ src }) {
|
|
|
934
120
|
"*"
|
|
935
121
|
);
|
|
936
122
|
};
|
|
937
|
-
|
|
123
|
+
useEffect(() => {
|
|
938
124
|
const onMessage = (event) => {
|
|
939
125
|
const data = event.data;
|
|
940
126
|
if (!data || data.source !== "payload-visual-builder-child") {
|
|
@@ -986,10 +172,10 @@ function PageEditorFrame({ src }) {
|
|
|
986
172
|
window.addEventListener("message", onMessage);
|
|
987
173
|
return () => window.removeEventListener("message", onMessage);
|
|
988
174
|
}, [awaitingDirtyCheck, pendingNavigationURL]);
|
|
989
|
-
|
|
175
|
+
useEffect(() => {
|
|
990
176
|
void refreshUnpublishedChanges();
|
|
991
177
|
}, [pageID]);
|
|
992
|
-
|
|
178
|
+
useEffect(() => {
|
|
993
179
|
const onDocumentClick = (event) => {
|
|
994
180
|
if (!hasUnsavedChanges) {
|
|
995
181
|
return;
|
|
@@ -1052,7 +238,7 @@ function PageEditorFrame({ src }) {
|
|
|
1052
238
|
document.addEventListener("click", onDocumentClick, true);
|
|
1053
239
|
return () => document.removeEventListener("click", onDocumentClick, true);
|
|
1054
240
|
}, [hasUnsavedChanges]);
|
|
1055
|
-
|
|
241
|
+
useEffect(() => {
|
|
1056
242
|
if (!hasUnsavedChanges) {
|
|
1057
243
|
return;
|
|
1058
244
|
}
|
|
@@ -1063,14 +249,14 @@ function PageEditorFrame({ src }) {
|
|
|
1063
249
|
window.addEventListener("beforeunload", onBeforeUnload);
|
|
1064
250
|
return () => window.removeEventListener("beforeunload", onBeforeUnload);
|
|
1065
251
|
}, [hasUnsavedChanges]);
|
|
1066
|
-
|
|
252
|
+
useEffect(
|
|
1067
253
|
() => () => {
|
|
1068
254
|
clearDirtyCheckTimer();
|
|
1069
255
|
},
|
|
1070
256
|
[]
|
|
1071
257
|
);
|
|
1072
|
-
return /* @__PURE__ */
|
|
1073
|
-
/* @__PURE__ */
|
|
258
|
+
return /* @__PURE__ */ jsxs("div", { style: { display: "grid", gap: "0.8rem" }, children: [
|
|
259
|
+
/* @__PURE__ */ jsxs(
|
|
1074
260
|
"div",
|
|
1075
261
|
{
|
|
1076
262
|
style: {
|
|
@@ -1085,17 +271,17 @@ function PageEditorFrame({ src }) {
|
|
|
1085
271
|
padding: "0.7rem 0.8rem"
|
|
1086
272
|
},
|
|
1087
273
|
children: [
|
|
1088
|
-
/* @__PURE__ */
|
|
1089
|
-
/* @__PURE__ */
|
|
1090
|
-
/* @__PURE__ */
|
|
274
|
+
/* @__PURE__ */ jsxs("div", { style: { display: "grid", gap: "0.2rem" }, children: [
|
|
275
|
+
/* @__PURE__ */ jsx("div", { style: { color: "var(--orion-admin-muted)", fontSize: "0.9rem" }, children: "Save changes to update the page layout and content." }),
|
|
276
|
+
/* @__PURE__ */ jsx(
|
|
1091
277
|
"div",
|
|
1092
278
|
{
|
|
1093
279
|
style: {
|
|
1094
280
|
alignItems: "center",
|
|
1095
|
-
background: hasUnpublishedChanges ? "#fff3cd" : "
|
|
1096
|
-
border: `1px solid ${hasUnpublishedChanges ? "#f0c36d" : "
|
|
281
|
+
background: hasUnpublishedChanges ? "#fff3cd" : "var(--orion-admin-accent-subtle)",
|
|
282
|
+
border: `1px solid ${hasUnpublishedChanges ? "#f0c36d" : "color-mix(in srgb, var(--orion-admin-accent) 36%, transparent)"}`,
|
|
1097
283
|
borderRadius: 999,
|
|
1098
|
-
color: hasUnpublishedChanges ? "#6a4a00" : "
|
|
284
|
+
color: hasUnpublishedChanges ? "#6a4a00" : "var(--orion-admin-accent)",
|
|
1099
285
|
display: "inline-flex",
|
|
1100
286
|
fontSize: "0.75rem",
|
|
1101
287
|
fontWeight: 800,
|
|
@@ -1107,8 +293,8 @@ function PageEditorFrame({ src }) {
|
|
|
1107
293
|
}
|
|
1108
294
|
)
|
|
1109
295
|
] }),
|
|
1110
|
-
/* @__PURE__ */
|
|
1111
|
-
/* @__PURE__ */
|
|
296
|
+
/* @__PURE__ */ jsxs("div", { style: { alignItems: "center", display: "flex", flexWrap: "wrap", gap: "0.5rem" }, children: [
|
|
297
|
+
/* @__PURE__ */ jsx(
|
|
1112
298
|
"button",
|
|
1113
299
|
{
|
|
1114
300
|
className: "orion-admin-action-button",
|
|
@@ -1119,7 +305,7 @@ function PageEditorFrame({ src }) {
|
|
|
1119
305
|
children: "Undo"
|
|
1120
306
|
}
|
|
1121
307
|
),
|
|
1122
|
-
/* @__PURE__ */
|
|
308
|
+
/* @__PURE__ */ jsx(
|
|
1123
309
|
"button",
|
|
1124
310
|
{
|
|
1125
311
|
className: "orion-admin-action-button",
|
|
@@ -1130,7 +316,7 @@ function PageEditorFrame({ src }) {
|
|
|
1130
316
|
children: "Redo"
|
|
1131
317
|
}
|
|
1132
318
|
),
|
|
1133
|
-
/* @__PURE__ */
|
|
319
|
+
/* @__PURE__ */ jsx(
|
|
1134
320
|
"button",
|
|
1135
321
|
{
|
|
1136
322
|
className: "orion-admin-action-button",
|
|
@@ -1140,13 +326,13 @@ function PageEditorFrame({ src }) {
|
|
|
1140
326
|
children: saving === "draft" ? "Saving..." : "Save Draft"
|
|
1141
327
|
}
|
|
1142
328
|
),
|
|
1143
|
-
/* @__PURE__ */
|
|
329
|
+
/* @__PURE__ */ jsx(
|
|
1144
330
|
"button",
|
|
1145
331
|
{
|
|
1146
332
|
className: "orion-admin-action-button",
|
|
1147
333
|
disabled: saving !== null,
|
|
1148
334
|
onClick: () => sendSave("published"),
|
|
1149
|
-
style: { background: "
|
|
335
|
+
style: { background: "var(--orion-admin-accent)" },
|
|
1150
336
|
type: "button",
|
|
1151
337
|
children: saving === "published" ? "Publishing..." : "Publish"
|
|
1152
338
|
}
|
|
@@ -1155,9 +341,9 @@ function PageEditorFrame({ src }) {
|
|
|
1155
341
|
]
|
|
1156
342
|
}
|
|
1157
343
|
),
|
|
1158
|
-
message ? /* @__PURE__ */
|
|
1159
|
-
error ? /* @__PURE__ */
|
|
1160
|
-
sessionExpired ? /* @__PURE__ */
|
|
344
|
+
message ? /* @__PURE__ */ jsx("div", { style: { color: "var(--orion-admin-accent)", fontSize: "0.9rem", fontWeight: 700 }, children: message }) : null,
|
|
345
|
+
error ? /* @__PURE__ */ jsx("div", { className: "orion-admin-error", children: error }) : null,
|
|
346
|
+
sessionExpired ? /* @__PURE__ */ jsx(
|
|
1161
347
|
"div",
|
|
1162
348
|
{
|
|
1163
349
|
style: {
|
|
@@ -1172,7 +358,7 @@ function PageEditorFrame({ src }) {
|
|
|
1172
358
|
children: "Session expired. Log in again in a new tab, then save your changes."
|
|
1173
359
|
}
|
|
1174
360
|
) : null,
|
|
1175
|
-
/* @__PURE__ */
|
|
361
|
+
/* @__PURE__ */ jsx(
|
|
1176
362
|
"iframe",
|
|
1177
363
|
{
|
|
1178
364
|
ref: iframeRef,
|
|
@@ -1192,7 +378,7 @@ function PageEditorFrame({ src }) {
|
|
|
1192
378
|
}
|
|
1193
379
|
}
|
|
1194
380
|
),
|
|
1195
|
-
pendingNavigationURL && showUnsavedDialog ? /* @__PURE__ */
|
|
381
|
+
pendingNavigationURL && showUnsavedDialog ? /* @__PURE__ */ jsx(
|
|
1196
382
|
"div",
|
|
1197
383
|
{
|
|
1198
384
|
"data-orion-unsaved-dialog": "true",
|
|
@@ -1206,7 +392,7 @@ function PageEditorFrame({ src }) {
|
|
|
1206
392
|
position: "fixed",
|
|
1207
393
|
zIndex: 2e3
|
|
1208
394
|
},
|
|
1209
|
-
children: /* @__PURE__ */
|
|
395
|
+
children: /* @__PURE__ */ jsxs(
|
|
1210
396
|
"div",
|
|
1211
397
|
{
|
|
1212
398
|
style: {
|
|
@@ -1221,12 +407,12 @@ function PageEditorFrame({ src }) {
|
|
|
1221
407
|
width: "100%"
|
|
1222
408
|
},
|
|
1223
409
|
children: [
|
|
1224
|
-
/* @__PURE__ */
|
|
1225
|
-
/* @__PURE__ */
|
|
1226
|
-
/* @__PURE__ */
|
|
410
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
411
|
+
/* @__PURE__ */ jsx("div", { style: { color: "var(--orion-admin-text)", fontSize: "1rem", fontWeight: 700 }, children: "Unsaved changes" }),
|
|
412
|
+
/* @__PURE__ */ jsx("div", { style: { color: "var(--orion-admin-muted)", fontSize: "0.9rem", marginTop: "0.4rem" }, children: "You have unsaved edits in the page builder. Save before leaving this page?" })
|
|
1227
413
|
] }),
|
|
1228
|
-
/* @__PURE__ */
|
|
1229
|
-
/* @__PURE__ */
|
|
414
|
+
/* @__PURE__ */ jsxs("div", { style: { display: "flex", gap: "0.6rem", justifyContent: "flex-end" }, children: [
|
|
415
|
+
/* @__PURE__ */ jsx(
|
|
1230
416
|
"button",
|
|
1231
417
|
{
|
|
1232
418
|
className: "orion-admin-action-button",
|
|
@@ -1238,7 +424,7 @@ function PageEditorFrame({ src }) {
|
|
|
1238
424
|
children: "Stay"
|
|
1239
425
|
}
|
|
1240
426
|
),
|
|
1241
|
-
/* @__PURE__ */
|
|
427
|
+
/* @__PURE__ */ jsx(
|
|
1242
428
|
"button",
|
|
1243
429
|
{
|
|
1244
430
|
className: "orion-admin-action-button",
|
|
@@ -1268,5 +454,7 @@ export {
|
|
|
1268
454
|
MediaDetailPanel,
|
|
1269
455
|
MediaListItem,
|
|
1270
456
|
MediaUploadForm,
|
|
1271
|
-
PageEditorFrame
|
|
457
|
+
PageEditorFrame,
|
|
458
|
+
SiteFooterPreview,
|
|
459
|
+
SiteHeaderPreview
|
|
1272
460
|
};
|