@orion-studios/payload-studio 0.5.0-beta.50 → 0.5.0-beta.52
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/admin-app/client.js +377 -38
- package/dist/admin-app/client.mjs +371 -35
- package/dist/admin-app/index.d.mts +1 -1
- package/dist/admin-app/index.d.ts +1 -1
- package/dist/admin-app/styles.css +102 -0
- package/dist/{index-BBvk9b9i.d.mts → index-ZbOx4OCF.d.mts} +33 -2
- package/dist/{index-BBvk9b9i.d.ts → index-ZbOx4OCF.d.ts} +33 -2
- package/dist/index.d.mts +1 -1
- package/dist/index.d.ts +1 -1
- package/package.json +1 -1
package/dist/admin-app/client.js
CHANGED
|
@@ -24,6 +24,9 @@ __export(client_exports, {
|
|
|
24
24
|
AdminShellClient: () => AdminShellClient,
|
|
25
25
|
HeaderNavEditorWithPreview: () => HeaderNavEditorWithPreview,
|
|
26
26
|
HeaderNavItemsEditor: () => HeaderNavItemsEditor,
|
|
27
|
+
MediaDetailPanel: () => MediaDetailPanel,
|
|
28
|
+
MediaListItem: () => MediaListItem,
|
|
29
|
+
MediaUploadForm: () => MediaUploadForm,
|
|
27
30
|
PageEditorFrame: () => PageEditorFrame
|
|
28
31
|
});
|
|
29
32
|
module.exports = __toCommonJS(client_exports);
|
|
@@ -50,6 +53,47 @@ var navItemIsActive = (pathname, item) => {
|
|
|
50
53
|
|
|
51
54
|
// src/admin-app/components/AdminShellClient.tsx
|
|
52
55
|
var import_jsx_runtime = require("react/jsx-runtime");
|
|
56
|
+
var iconSize = 20;
|
|
57
|
+
var iconStyle = { display: "block", flexShrink: 0 };
|
|
58
|
+
function NavIcon({ name }) {
|
|
59
|
+
const props = { width: iconSize, height: iconSize, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2, strokeLinecap: "round", strokeLinejoin: "round", style: iconStyle };
|
|
60
|
+
switch (name) {
|
|
61
|
+
case "dashboard":
|
|
62
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("svg", { ...props, children: [
|
|
63
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("rect", { x: "3", y: "3", width: "7", height: "9", rx: "1" }),
|
|
64
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("rect", { x: "14", y: "3", width: "7", height: "5", rx: "1" }),
|
|
65
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("rect", { x: "14", y: "12", width: "7", height: "9", rx: "1" }),
|
|
66
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("rect", { x: "3", y: "16", width: "7", height: "5", rx: "1" })
|
|
67
|
+
] });
|
|
68
|
+
case "pages":
|
|
69
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("svg", { ...props, children: [
|
|
70
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8Z" }),
|
|
71
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("polyline", { points: "14 2 14 8 20 8" }),
|
|
72
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("line", { x1: "8", y1: "13", x2: "16", y2: "13" }),
|
|
73
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("line", { x1: "8", y1: "17", x2: "12", y2: "17" })
|
|
74
|
+
] });
|
|
75
|
+
case "globals":
|
|
76
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("svg", { ...props, children: [
|
|
77
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("circle", { cx: "12", cy: "12", r: "3" }),
|
|
78
|
+
/* @__PURE__ */ (0, import_jsx_runtime.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" })
|
|
79
|
+
] });
|
|
80
|
+
case "media":
|
|
81
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("svg", { ...props, children: [
|
|
82
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("rect", { x: "3", y: "3", width: "18", height: "18", rx: "2", ry: "2" }),
|
|
83
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("circle", { cx: "8.5", cy: "8.5", r: "1.5" }),
|
|
84
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("polyline", { points: "21 15 16 10 5 21" })
|
|
85
|
+
] });
|
|
86
|
+
case "tools":
|
|
87
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("svg", { ...props, children: /* @__PURE__ */ (0, import_jsx_runtime.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" }) });
|
|
88
|
+
case "account":
|
|
89
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("svg", { ...props, children: [
|
|
90
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2" }),
|
|
91
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("circle", { cx: "12", cy: "7", r: "4" })
|
|
92
|
+
] });
|
|
93
|
+
default:
|
|
94
|
+
return null;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
53
97
|
function AdminShellClient({
|
|
54
98
|
children,
|
|
55
99
|
brandName,
|
|
@@ -117,7 +161,10 @@ function AdminShellClient({
|
|
|
117
161
|
className: `orion-admin-nav-link ${active ? "is-active" : ""}`,
|
|
118
162
|
href: item.href,
|
|
119
163
|
title: item.label,
|
|
120
|
-
children: collapsed ? item.
|
|
164
|
+
children: item.icon ? collapsed ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(NavIcon, { name: item.icon }) : /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { style: { alignItems: "center", display: "flex", gap: "0.6rem" }, children: [
|
|
165
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(NavIcon, { name: item.icon }),
|
|
166
|
+
item.label
|
|
167
|
+
] }) : collapsed ? item.label.slice(0, 1) : item.label
|
|
121
168
|
},
|
|
122
169
|
item.href
|
|
123
170
|
);
|
|
@@ -493,22 +540,311 @@ function HeaderNavEditorWithPreview({
|
|
|
493
540
|
] });
|
|
494
541
|
}
|
|
495
542
|
|
|
496
|
-
// src/admin-app/components/
|
|
543
|
+
// src/admin-app/components/MediaDetailPanel.tsx
|
|
497
544
|
var import_react4 = require("react");
|
|
498
545
|
var import_jsx_runtime4 = require("react/jsx-runtime");
|
|
546
|
+
function formatFileSize(bytes) {
|
|
547
|
+
if (bytes < 1024) return `${bytes} B`;
|
|
548
|
+
if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
|
|
549
|
+
return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
|
|
550
|
+
}
|
|
551
|
+
function MediaDetailPanel({
|
|
552
|
+
id,
|
|
553
|
+
filename,
|
|
554
|
+
alt,
|
|
555
|
+
url,
|
|
556
|
+
filesize,
|
|
557
|
+
width,
|
|
558
|
+
height,
|
|
559
|
+
mimeType,
|
|
560
|
+
createdAt,
|
|
561
|
+
updateAction,
|
|
562
|
+
deleteAction
|
|
563
|
+
}) {
|
|
564
|
+
const [copied, setCopied] = (0, import_react4.useState)(false);
|
|
565
|
+
const [confirmDelete, setConfirmDelete] = (0, import_react4.useState)(false);
|
|
566
|
+
const copyUrl = async () => {
|
|
567
|
+
if (!url) return;
|
|
568
|
+
try {
|
|
569
|
+
await navigator.clipboard.writeText(url);
|
|
570
|
+
setCopied(true);
|
|
571
|
+
setTimeout(() => setCopied(false), 2e3);
|
|
572
|
+
} catch {
|
|
573
|
+
const input = document.createElement("input");
|
|
574
|
+
input.value = url;
|
|
575
|
+
document.body.appendChild(input);
|
|
576
|
+
input.select();
|
|
577
|
+
document.execCommand("copy");
|
|
578
|
+
document.body.removeChild(input);
|
|
579
|
+
setCopied(true);
|
|
580
|
+
setTimeout(() => setCopied(false), 2e3);
|
|
581
|
+
}
|
|
582
|
+
};
|
|
583
|
+
const metaRows = [];
|
|
584
|
+
if (filename) metaRows.push({ label: "Filename", value: filename });
|
|
585
|
+
if (typeof filesize === "number") metaRows.push({ label: "File size", value: formatFileSize(filesize) });
|
|
586
|
+
if (typeof width === "number" && typeof height === "number") metaRows.push({ label: "Dimensions", value: `${width} \xD7 ${height} px` });
|
|
587
|
+
if (mimeType) metaRows.push({ label: "Type", value: mimeType });
|
|
588
|
+
if (createdAt) {
|
|
589
|
+
try {
|
|
590
|
+
metaRows.push({ label: "Uploaded", value: new Date(createdAt).toLocaleDateString() });
|
|
591
|
+
} catch {
|
|
592
|
+
metaRows.push({ label: "Uploaded", value: createdAt });
|
|
593
|
+
}
|
|
594
|
+
}
|
|
595
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "orion-admin-grid", style: { alignItems: "start" }, children: [
|
|
596
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { children: [
|
|
597
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "orion-admin-card", children: url ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("img", { alt: alt || filename || "Media", src: url, style: { borderRadius: 12, width: "100%" } }) : /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { children: "No preview available." }) }),
|
|
598
|
+
url ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
599
|
+
"button",
|
|
600
|
+
{
|
|
601
|
+
className: "orion-admin-action-button",
|
|
602
|
+
onClick: copyUrl,
|
|
603
|
+
style: { marginTop: "0.6rem", width: "100%" },
|
|
604
|
+
type: "button",
|
|
605
|
+
children: copied ? "Copied!" : "Copy URL"
|
|
606
|
+
}
|
|
607
|
+
) : null
|
|
608
|
+
] }),
|
|
609
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: { display: "grid", gap: "0.8rem" }, children: [
|
|
610
|
+
metaRows.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "orion-admin-card orion-admin-meta-table", children: metaRows.map((row) => /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "orion-admin-meta-row", children: [
|
|
611
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "orion-admin-meta-label", children: row.label }),
|
|
612
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "orion-admin-meta-value", children: row.value })
|
|
613
|
+
] }, row.label)) }) : null,
|
|
614
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("form", { action: updateAction, className: "orion-admin-form", children: [
|
|
615
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("input", { name: "id", type: "hidden", value: id }),
|
|
616
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("label", { children: [
|
|
617
|
+
"Alt text",
|
|
618
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("input", { defaultValue: alt || "", name: "alt", required: true, type: "text" })
|
|
619
|
+
] }),
|
|
620
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("button", { type: "submit", children: "Save" })
|
|
621
|
+
] }),
|
|
622
|
+
confirmDelete ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "orion-admin-form", style: { borderColor: "#b42318" }, children: [
|
|
623
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { style: { fontWeight: 700, margin: 0 }, children: "Are you sure you want to delete this asset?" }),
|
|
624
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { style: { color: "var(--orion-admin-muted)", fontSize: "0.9rem", margin: 0 }, children: "This action cannot be undone." }),
|
|
625
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: { display: "flex", gap: "0.5rem" }, children: [
|
|
626
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("form", { action: deleteAction, style: { flex: 1 }, children: [
|
|
627
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("input", { name: "id", type: "hidden", value: id }),
|
|
628
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("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" })
|
|
629
|
+
] }),
|
|
630
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
631
|
+
"button",
|
|
632
|
+
{
|
|
633
|
+
onClick: () => setConfirmDelete(false),
|
|
634
|
+
style: { background: "transparent", border: "1px solid var(--orion-admin-border)", borderRadius: 10, cursor: "pointer", flex: 1, fontWeight: 700, padding: "0.55rem 0.8rem" },
|
|
635
|
+
type: "button",
|
|
636
|
+
children: "Cancel"
|
|
637
|
+
}
|
|
638
|
+
)
|
|
639
|
+
] })
|
|
640
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
641
|
+
"button",
|
|
642
|
+
{
|
|
643
|
+
className: "orion-admin-action-button",
|
|
644
|
+
onClick: () => setConfirmDelete(true),
|
|
645
|
+
style: { background: "#b42318" },
|
|
646
|
+
type: "button",
|
|
647
|
+
children: "Delete Asset"
|
|
648
|
+
}
|
|
649
|
+
)
|
|
650
|
+
] })
|
|
651
|
+
] });
|
|
652
|
+
}
|
|
653
|
+
|
|
654
|
+
// src/admin-app/components/MediaListItem.tsx
|
|
655
|
+
var import_jsx_runtime5 = require("react/jsx-runtime");
|
|
656
|
+
function formatFileSize2(bytes) {
|
|
657
|
+
if (bytes < 1024) return `${bytes} B`;
|
|
658
|
+
if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
|
|
659
|
+
return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
|
|
660
|
+
}
|
|
661
|
+
function MediaListItem({
|
|
662
|
+
id,
|
|
663
|
+
filename,
|
|
664
|
+
alt,
|
|
665
|
+
url,
|
|
666
|
+
filesize,
|
|
667
|
+
width,
|
|
668
|
+
height,
|
|
669
|
+
mimeType,
|
|
670
|
+
href
|
|
671
|
+
}) {
|
|
672
|
+
const label = filename || `Media ${id}`;
|
|
673
|
+
const altText = alt || "";
|
|
674
|
+
const metaParts = [];
|
|
675
|
+
if (typeof filesize === "number") metaParts.push(formatFileSize2(filesize));
|
|
676
|
+
if (typeof width === "number" && typeof height === "number") metaParts.push(`${width}\xD7${height}`);
|
|
677
|
+
if (typeof mimeType === "string") metaParts.push(mimeType);
|
|
678
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("a", { className: "orion-admin-list-item", href, children: [
|
|
679
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { style: { alignItems: "center", display: "flex", gap: "0.8rem" }, children: [
|
|
680
|
+
url ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("img", { alt: altText || label, className: "orion-admin-media-preview", src: url }) : null,
|
|
681
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { children: [
|
|
682
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("strong", { children: label }),
|
|
683
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "orion-admin-list-meta", children: altText || "No alt text" }),
|
|
684
|
+
metaParts.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "orion-admin-list-meta", style: { marginTop: "0.15rem" }, children: metaParts.join(" \xB7 ") }) : null
|
|
685
|
+
] })
|
|
686
|
+
] }),
|
|
687
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "orion-admin-list-meta", children: "Edit" })
|
|
688
|
+
] });
|
|
689
|
+
}
|
|
690
|
+
|
|
691
|
+
// src/admin-app/components/MediaUploadForm.tsx
|
|
692
|
+
var import_react5 = require("react");
|
|
693
|
+
var import_navigation = require("next/navigation");
|
|
694
|
+
var import_jsx_runtime6 = require("react/jsx-runtime");
|
|
695
|
+
var parseUploadError = async (response) => {
|
|
696
|
+
const fallback = "Upload failed. Please check the image and required fields, then try again.";
|
|
697
|
+
try {
|
|
698
|
+
const body = await response.json();
|
|
699
|
+
const nestedMessage = body.errors?.[0]?.data?.errors?.[0]?.message;
|
|
700
|
+
if (typeof nestedMessage === "string" && nestedMessage.trim().length > 0) {
|
|
701
|
+
return nestedMessage;
|
|
702
|
+
}
|
|
703
|
+
const topMessage = body.errors?.[0]?.message;
|
|
704
|
+
if (typeof topMessage === "string" && topMessage.trim().length > 0) {
|
|
705
|
+
return topMessage;
|
|
706
|
+
}
|
|
707
|
+
if (typeof body.message === "string" && body.message.trim().length > 0) {
|
|
708
|
+
return body.message;
|
|
709
|
+
}
|
|
710
|
+
} catch {
|
|
711
|
+
}
|
|
712
|
+
return fallback;
|
|
713
|
+
};
|
|
714
|
+
function MediaUploadForm() {
|
|
715
|
+
const router = (0, import_navigation.useRouter)();
|
|
716
|
+
const fileInputRef = (0, import_react5.useRef)(null);
|
|
717
|
+
const [alt, setAlt] = (0, import_react5.useState)("");
|
|
718
|
+
const [file, setFile] = (0, import_react5.useState)(null);
|
|
719
|
+
const [preview, setPreview] = (0, import_react5.useState)(null);
|
|
720
|
+
const [dragging, setDragging] = (0, import_react5.useState)(false);
|
|
721
|
+
const [submitting, setSubmitting] = (0, import_react5.useState)(false);
|
|
722
|
+
const [error, setError] = (0, import_react5.useState)(null);
|
|
723
|
+
const handleFile = (0, import_react5.useCallback)((selectedFile) => {
|
|
724
|
+
setFile(selectedFile);
|
|
725
|
+
if (preview) {
|
|
726
|
+
URL.revokeObjectURL(preview);
|
|
727
|
+
setPreview(null);
|
|
728
|
+
}
|
|
729
|
+
if (selectedFile && selectedFile.type.startsWith("image/")) {
|
|
730
|
+
setPreview(URL.createObjectURL(selectedFile));
|
|
731
|
+
}
|
|
732
|
+
}, [preview]);
|
|
733
|
+
const onDragOver = (0, import_react5.useCallback)((e) => {
|
|
734
|
+
e.preventDefault();
|
|
735
|
+
setDragging(true);
|
|
736
|
+
}, []);
|
|
737
|
+
const onDragLeave = (0, import_react5.useCallback)((e) => {
|
|
738
|
+
e.preventDefault();
|
|
739
|
+
setDragging(false);
|
|
740
|
+
}, []);
|
|
741
|
+
const onDrop = (0, import_react5.useCallback)((e) => {
|
|
742
|
+
e.preventDefault();
|
|
743
|
+
setDragging(false);
|
|
744
|
+
const droppedFile = e.dataTransfer.files?.[0] || null;
|
|
745
|
+
if (droppedFile) {
|
|
746
|
+
handleFile(droppedFile);
|
|
747
|
+
}
|
|
748
|
+
}, [handleFile]);
|
|
749
|
+
const upload = async (event) => {
|
|
750
|
+
event.preventDefault();
|
|
751
|
+
if (!file) {
|
|
752
|
+
setError("Select an image to upload.");
|
|
753
|
+
return;
|
|
754
|
+
}
|
|
755
|
+
setSubmitting(true);
|
|
756
|
+
setError(null);
|
|
757
|
+
try {
|
|
758
|
+
const formData = new FormData();
|
|
759
|
+
const fallbackAlt = file.name.replace(/\.[^/.]+$/, "").trim();
|
|
760
|
+
const resolvedAlt = alt.trim() || fallbackAlt || "Uploaded image";
|
|
761
|
+
formData.set("_payload", JSON.stringify({ alt: resolvedAlt }));
|
|
762
|
+
formData.set("alt", resolvedAlt);
|
|
763
|
+
formData.set("file", file);
|
|
764
|
+
const response = await fetch("/api/media", {
|
|
765
|
+
method: "POST",
|
|
766
|
+
credentials: "include",
|
|
767
|
+
body: formData
|
|
768
|
+
});
|
|
769
|
+
if (!response.ok) {
|
|
770
|
+
throw new Error(await parseUploadError(response));
|
|
771
|
+
}
|
|
772
|
+
setAlt("");
|
|
773
|
+
setFile(null);
|
|
774
|
+
if (preview) {
|
|
775
|
+
URL.revokeObjectURL(preview);
|
|
776
|
+
setPreview(null);
|
|
777
|
+
}
|
|
778
|
+
router.refresh();
|
|
779
|
+
} catch (err) {
|
|
780
|
+
setError(err instanceof Error ? err.message : "Upload failed");
|
|
781
|
+
} finally {
|
|
782
|
+
setSubmitting(false);
|
|
783
|
+
}
|
|
784
|
+
};
|
|
785
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("form", { className: "orion-admin-upload-form", onSubmit: upload, children: [
|
|
786
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("label", { children: [
|
|
787
|
+
"Alt text",
|
|
788
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
789
|
+
"input",
|
|
790
|
+
{
|
|
791
|
+
onChange: (event) => setAlt(event.target.value),
|
|
792
|
+
placeholder: "Describe the image",
|
|
793
|
+
type: "text",
|
|
794
|
+
value: alt
|
|
795
|
+
}
|
|
796
|
+
)
|
|
797
|
+
] }),
|
|
798
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
|
|
799
|
+
"div",
|
|
800
|
+
{
|
|
801
|
+
className: `orion-admin-dropzone${dragging ? " is-dragging" : ""}${file ? " has-file" : ""}`,
|
|
802
|
+
onClick: () => fileInputRef.current?.click(),
|
|
803
|
+
onDragLeave,
|
|
804
|
+
onDragOver,
|
|
805
|
+
onDrop,
|
|
806
|
+
children: [
|
|
807
|
+
preview ? /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "orion-admin-dropzone-preview", children: [
|
|
808
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("img", { alt: "Upload preview", src: preview }),
|
|
809
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { children: file?.name })
|
|
810
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "orion-admin-dropzone-label", children: [
|
|
811
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("strong", { children: "Drop an image here" }),
|
|
812
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { children: "or click to browse" })
|
|
813
|
+
] }),
|
|
814
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
815
|
+
"input",
|
|
816
|
+
{
|
|
817
|
+
accept: "image/*",
|
|
818
|
+
onChange: (event) => handleFile(event.target.files?.[0] || null),
|
|
819
|
+
ref: fileInputRef,
|
|
820
|
+
style: { display: "none" },
|
|
821
|
+
type: "file"
|
|
822
|
+
}
|
|
823
|
+
)
|
|
824
|
+
]
|
|
825
|
+
}
|
|
826
|
+
),
|
|
827
|
+
error ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "orion-admin-upload-error", children: error }) : null,
|
|
828
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("button", { disabled: submitting, type: "submit", children: submitting ? "Uploading..." : "Upload" })
|
|
829
|
+
] });
|
|
830
|
+
}
|
|
831
|
+
|
|
832
|
+
// src/admin-app/components/PageEditorFrame.tsx
|
|
833
|
+
var import_react6 = require("react");
|
|
834
|
+
var import_jsx_runtime7 = require("react/jsx-runtime");
|
|
499
835
|
function PageEditorFrame({ src }) {
|
|
500
|
-
const iframeRef = (0,
|
|
501
|
-
const dirtyCheckTimerRef = (0,
|
|
502
|
-
const [saving, setSaving] = (0,
|
|
503
|
-
const [message, setMessage] = (0,
|
|
504
|
-
const [error, setError] = (0,
|
|
505
|
-
const [hasUnsavedChanges, setHasUnsavedChanges] = (0,
|
|
506
|
-
const [awaitingDirtyCheck, setAwaitingDirtyCheck] = (0,
|
|
507
|
-
const [pendingNavigationURL, setPendingNavigationURL] = (0,
|
|
508
|
-
const [showUnsavedDialog, setShowUnsavedDialog] = (0,
|
|
509
|
-
const [canUndo, setCanUndo] = (0,
|
|
510
|
-
const [canRedo, setCanRedo] = (0,
|
|
511
|
-
const [sessionExpired, setSessionExpired] = (0,
|
|
836
|
+
const iframeRef = (0, import_react6.useRef)(null);
|
|
837
|
+
const dirtyCheckTimerRef = (0, import_react6.useRef)(null);
|
|
838
|
+
const [saving, setSaving] = (0, import_react6.useState)(null);
|
|
839
|
+
const [message, setMessage] = (0, import_react6.useState)("");
|
|
840
|
+
const [error, setError] = (0, import_react6.useState)("");
|
|
841
|
+
const [hasUnsavedChanges, setHasUnsavedChanges] = (0, import_react6.useState)(false);
|
|
842
|
+
const [awaitingDirtyCheck, setAwaitingDirtyCheck] = (0, import_react6.useState)(false);
|
|
843
|
+
const [pendingNavigationURL, setPendingNavigationURL] = (0, import_react6.useState)(null);
|
|
844
|
+
const [showUnsavedDialog, setShowUnsavedDialog] = (0, import_react6.useState)(false);
|
|
845
|
+
const [canUndo, setCanUndo] = (0, import_react6.useState)(false);
|
|
846
|
+
const [canRedo, setCanRedo] = (0, import_react6.useState)(false);
|
|
847
|
+
const [sessionExpired, setSessionExpired] = (0, import_react6.useState)(false);
|
|
512
848
|
const clearDirtyCheckTimer = () => {
|
|
513
849
|
if (dirtyCheckTimerRef.current) {
|
|
514
850
|
window.clearTimeout(dirtyCheckTimerRef.current);
|
|
@@ -554,7 +890,7 @@ function PageEditorFrame({ src }) {
|
|
|
554
890
|
"*"
|
|
555
891
|
);
|
|
556
892
|
};
|
|
557
|
-
(0,
|
|
893
|
+
(0, import_react6.useEffect)(() => {
|
|
558
894
|
const onMessage = (event) => {
|
|
559
895
|
const data = event.data;
|
|
560
896
|
if (!data || data.source !== "payload-visual-builder-child") {
|
|
@@ -599,7 +935,7 @@ function PageEditorFrame({ src }) {
|
|
|
599
935
|
window.addEventListener("message", onMessage);
|
|
600
936
|
return () => window.removeEventListener("message", onMessage);
|
|
601
937
|
}, [awaitingDirtyCheck, pendingNavigationURL]);
|
|
602
|
-
(0,
|
|
938
|
+
(0, import_react6.useEffect)(() => {
|
|
603
939
|
const onDocumentClick = (event) => {
|
|
604
940
|
if (!hasUnsavedChanges) {
|
|
605
941
|
return;
|
|
@@ -662,7 +998,7 @@ function PageEditorFrame({ src }) {
|
|
|
662
998
|
document.addEventListener("click", onDocumentClick, true);
|
|
663
999
|
return () => document.removeEventListener("click", onDocumentClick, true);
|
|
664
1000
|
}, [hasUnsavedChanges]);
|
|
665
|
-
(0,
|
|
1001
|
+
(0, import_react6.useEffect)(() => {
|
|
666
1002
|
if (!hasUnsavedChanges) {
|
|
667
1003
|
return;
|
|
668
1004
|
}
|
|
@@ -673,14 +1009,14 @@ function PageEditorFrame({ src }) {
|
|
|
673
1009
|
window.addEventListener("beforeunload", onBeforeUnload);
|
|
674
1010
|
return () => window.removeEventListener("beforeunload", onBeforeUnload);
|
|
675
1011
|
}, [hasUnsavedChanges]);
|
|
676
|
-
(0,
|
|
1012
|
+
(0, import_react6.useEffect)(
|
|
677
1013
|
() => () => {
|
|
678
1014
|
clearDirtyCheckTimer();
|
|
679
1015
|
},
|
|
680
1016
|
[]
|
|
681
1017
|
);
|
|
682
|
-
return /* @__PURE__ */ (0,
|
|
683
|
-
/* @__PURE__ */ (0,
|
|
1018
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { style: { display: "grid", gap: "0.8rem" }, children: [
|
|
1019
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
|
|
684
1020
|
"div",
|
|
685
1021
|
{
|
|
686
1022
|
style: {
|
|
@@ -695,9 +1031,9 @@ function PageEditorFrame({ src }) {
|
|
|
695
1031
|
padding: "0.7rem 0.8rem"
|
|
696
1032
|
},
|
|
697
1033
|
children: [
|
|
698
|
-
/* @__PURE__ */ (0,
|
|
699
|
-
/* @__PURE__ */ (0,
|
|
700
|
-
/* @__PURE__ */ (0,
|
|
1034
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { style: { color: "var(--orion-admin-muted)", fontSize: "0.9rem" }, children: "Save changes to update the page layout and content." }),
|
|
1035
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { style: { alignItems: "center", display: "flex", flexWrap: "wrap", gap: "0.5rem" }, children: [
|
|
1036
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
701
1037
|
"button",
|
|
702
1038
|
{
|
|
703
1039
|
className: "orion-admin-action-button",
|
|
@@ -708,7 +1044,7 @@ function PageEditorFrame({ src }) {
|
|
|
708
1044
|
children: "Undo"
|
|
709
1045
|
}
|
|
710
1046
|
),
|
|
711
|
-
/* @__PURE__ */ (0,
|
|
1047
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
712
1048
|
"button",
|
|
713
1049
|
{
|
|
714
1050
|
className: "orion-admin-action-button",
|
|
@@ -719,7 +1055,7 @@ function PageEditorFrame({ src }) {
|
|
|
719
1055
|
children: "Redo"
|
|
720
1056
|
}
|
|
721
1057
|
),
|
|
722
|
-
/* @__PURE__ */ (0,
|
|
1058
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
723
1059
|
"button",
|
|
724
1060
|
{
|
|
725
1061
|
className: "orion-admin-action-button",
|
|
@@ -729,7 +1065,7 @@ function PageEditorFrame({ src }) {
|
|
|
729
1065
|
children: saving === "draft" ? "Saving..." : "Save Draft"
|
|
730
1066
|
}
|
|
731
1067
|
),
|
|
732
|
-
/* @__PURE__ */ (0,
|
|
1068
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
733
1069
|
"button",
|
|
734
1070
|
{
|
|
735
1071
|
className: "orion-admin-action-button",
|
|
@@ -744,9 +1080,9 @@ function PageEditorFrame({ src }) {
|
|
|
744
1080
|
]
|
|
745
1081
|
}
|
|
746
1082
|
),
|
|
747
|
-
message ? /* @__PURE__ */ (0,
|
|
748
|
-
error ? /* @__PURE__ */ (0,
|
|
749
|
-
sessionExpired ? /* @__PURE__ */ (0,
|
|
1083
|
+
message ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { style: { color: "#0f7d52", fontSize: "0.9rem", fontWeight: 700 }, children: message }) : null,
|
|
1084
|
+
error ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "orion-admin-error", children: error }) : null,
|
|
1085
|
+
sessionExpired ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
750
1086
|
"div",
|
|
751
1087
|
{
|
|
752
1088
|
style: {
|
|
@@ -761,7 +1097,7 @@ function PageEditorFrame({ src }) {
|
|
|
761
1097
|
children: "Session expired. Log in again in a new tab, then save your changes."
|
|
762
1098
|
}
|
|
763
1099
|
) : null,
|
|
764
|
-
/* @__PURE__ */ (0,
|
|
1100
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
765
1101
|
"iframe",
|
|
766
1102
|
{
|
|
767
1103
|
ref: iframeRef,
|
|
@@ -781,7 +1117,7 @@ function PageEditorFrame({ src }) {
|
|
|
781
1117
|
}
|
|
782
1118
|
}
|
|
783
1119
|
),
|
|
784
|
-
pendingNavigationURL && showUnsavedDialog ? /* @__PURE__ */ (0,
|
|
1120
|
+
pendingNavigationURL && showUnsavedDialog ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
785
1121
|
"div",
|
|
786
1122
|
{
|
|
787
1123
|
"data-orion-unsaved-dialog": "true",
|
|
@@ -795,7 +1131,7 @@ function PageEditorFrame({ src }) {
|
|
|
795
1131
|
position: "fixed",
|
|
796
1132
|
zIndex: 2e3
|
|
797
1133
|
},
|
|
798
|
-
children: /* @__PURE__ */ (0,
|
|
1134
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
|
|
799
1135
|
"div",
|
|
800
1136
|
{
|
|
801
1137
|
style: {
|
|
@@ -810,12 +1146,12 @@ function PageEditorFrame({ src }) {
|
|
|
810
1146
|
width: "100%"
|
|
811
1147
|
},
|
|
812
1148
|
children: [
|
|
813
|
-
/* @__PURE__ */ (0,
|
|
814
|
-
/* @__PURE__ */ (0,
|
|
815
|
-
/* @__PURE__ */ (0,
|
|
1149
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { children: [
|
|
1150
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { style: { color: "var(--orion-admin-text)", fontSize: "1rem", fontWeight: 700 }, children: "Unsaved changes" }),
|
|
1151
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.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?" })
|
|
816
1152
|
] }),
|
|
817
|
-
/* @__PURE__ */ (0,
|
|
818
|
-
/* @__PURE__ */ (0,
|
|
1153
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { style: { display: "flex", gap: "0.6rem", justifyContent: "flex-end" }, children: [
|
|
1154
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
819
1155
|
"button",
|
|
820
1156
|
{
|
|
821
1157
|
className: "orion-admin-action-button",
|
|
@@ -827,7 +1163,7 @@ function PageEditorFrame({ src }) {
|
|
|
827
1163
|
children: "Stay"
|
|
828
1164
|
}
|
|
829
1165
|
),
|
|
830
|
-
/* @__PURE__ */ (0,
|
|
1166
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
831
1167
|
"button",
|
|
832
1168
|
{
|
|
833
1169
|
className: "orion-admin-action-button",
|
|
@@ -855,5 +1191,8 @@ function PageEditorFrame({ src }) {
|
|
|
855
1191
|
AdminShellClient,
|
|
856
1192
|
HeaderNavEditorWithPreview,
|
|
857
1193
|
HeaderNavItemsEditor,
|
|
1194
|
+
MediaDetailPanel,
|
|
1195
|
+
MediaListItem,
|
|
1196
|
+
MediaUploadForm,
|
|
858
1197
|
PageEditorFrame
|
|
859
1198
|
});
|