@orion-studios/payload-studio 0.6.0-beta.133 → 0.6.0-beta.135

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.
@@ -9,7 +9,7 @@ import {
9
9
  SiteFooterPreview,
10
10
  adminNavIcons,
11
11
  buildAdminPageLinkOptions
12
- } from "../chunk-KOBQX2HL.mjs";
12
+ } from "../chunk-NF37A575.mjs";
13
13
  import "../chunk-ROTPP5CU.mjs";
14
14
  import {
15
15
  BlockPicker,
@@ -8,7 +8,7 @@ import {
8
8
  MediaUploadForm,
9
9
  SiteFooterPreview,
10
10
  SiteHeaderPreview
11
- } from "../chunk-KOBQX2HL.mjs";
11
+ } from "../chunk-NF37A575.mjs";
12
12
  import "../chunk-ROTPP5CU.mjs";
13
13
 
14
14
  // src/admin-app/components/PageEditorFrame.tsx
@@ -1314,7 +1314,7 @@ var decorateBuilderSettingHelp = (root = document) => {
1314
1314
  trigger.className = "orion-builder-v2-help-trigger";
1315
1315
  trigger.dataset.builderHelpText = help;
1316
1316
  trigger.role = "button";
1317
- trigger.tabIndex = 0;
1317
+ trigger.tabIndex = -1;
1318
1318
  trigger.textContent = "?";
1319
1319
  element.appendChild(trigger);
1320
1320
  }
@@ -1356,6 +1356,7 @@ var decorateBuilderColorEyeDroppers = (root = document) => {
1356
1356
  button.dataset.orionColorEyedropper = "true";
1357
1357
  button.setAttribute("aria-label", "Pick color from screen");
1358
1358
  button.setAttribute("title", "Pick color from screen");
1359
+ button.tabIndex = -1;
1359
1360
  button.innerHTML = '<svg viewBox="0 0 24 24" aria-hidden="true"><path d="M14.7 4.3a2.4 2.4 0 0 1 3.4 0l1.6 1.6a2.4 2.4 0 0 1 0 3.4l-1.2 1.2 1 1a1 1 0 1 1-1.4 1.4l-1-1-8.9 8.9H4v-4.2l8.9-8.9-1-1a1 1 0 0 1 1.4-1.4l1 1 1.4-1.4Zm-.4 4.8-8.3 8.3V19h1.6l8.3-8.3-1.6-1.6Z" fill="currentColor"/></svg>';
1360
1361
  swatch.insertAdjacentElement("afterend", button);
1361
1362
  });
@@ -1373,6 +1374,7 @@ var decorateBuilderNumericSteppers = (root = document) => {
1373
1374
  return;
1374
1375
  }
1375
1376
  field.classList.add("has-orion-builder-stepper");
1377
+ field.querySelector("select")?.setAttribute("tabindex", "-1");
1376
1378
  const stepper = document.createElement("span");
1377
1379
  stepper.className = "orion-builder-v2-stepper";
1378
1380
  const updateValue = (direction) => {
@@ -1390,6 +1392,7 @@ var decorateBuilderNumericSteppers = (root = document) => {
1390
1392
  button.type = "button";
1391
1393
  button.className = `orion-builder-v2-stepper-button ${step.className}`;
1392
1394
  button.setAttribute("aria-label", `${step.label} ${property.replace(/-/g, " ")}`);
1395
+ button.tabIndex = -1;
1393
1396
  button.textContent = step.text;
1394
1397
  button.addEventListener("click", (event) => {
1395
1398
  event.preventDefault();
@@ -2142,6 +2145,7 @@ function GrapesPageEditor({
2142
2145
  const stylePanelEditActiveRef = (0, import_react.useRef)(false);
2143
2146
  const historyRestoreActiveRef = (0, import_react.useRef)(false);
2144
2147
  const stylePanelHistoryBeforeRef = (0, import_react.useRef)(null);
2148
+ const historyReadyRef = (0, import_react.useRef)(false);
2145
2149
  const lastComponentSnapshotRef = (0, import_react.useRef)(/* @__PURE__ */ new WeakMap());
2146
2150
  const customUndoStackRef = (0, import_react.useRef)([]);
2147
2151
  const customRedoStackRef = (0, import_react.useRef)([]);
@@ -2761,6 +2765,12 @@ function GrapesPageEditor({
2761
2765
  }
2762
2766
  callback();
2763
2767
  };
2768
+ const clearNativeUndoHistory = () => {
2769
+ const undoManager = editorRef.current?.UndoManager;
2770
+ if (typeof undoManager?.clear === "function") {
2771
+ undoManager.clear();
2772
+ }
2773
+ };
2764
2774
  const isComponentAttached = (component) => Boolean(component.parent?.());
2765
2775
  const addComponentFromSnapshot = (snapshot) => {
2766
2776
  const parent = snapshot.parent;
@@ -2830,6 +2840,7 @@ function GrapesPageEditor({
2830
2840
  }
2831
2841
  customUndoStackRef.current.push({ after, before });
2832
2842
  customRedoStackRef.current = [];
2843
+ clearNativeUndoHistory();
2833
2844
  if (after) {
2834
2845
  lastComponentSnapshotRef.current.set(after.component, after);
2835
2846
  }
@@ -3095,8 +3106,18 @@ function GrapesPageEditor({
3095
3106
  registerOrionBuilderV2Blocks(editor);
3096
3107
  }
3097
3108
  registerProjectDynamicComponents(editor, adapter);
3109
+ historyReadyRef.current = false;
3098
3110
  editor.loadProjectData(projectData);
3099
3111
  void loadPayloadMediaAssets(editor);
3112
+ window.setTimeout(() => {
3113
+ customUndoStackRef.current = [];
3114
+ customRedoStackRef.current = [];
3115
+ lastComponentSnapshotRef.current = /* @__PURE__ */ new WeakMap();
3116
+ clearNativeUndoHistory();
3117
+ editor.clearDirtyCount?.();
3118
+ updateHistoryState(editor);
3119
+ historyReadyRef.current = true;
3120
+ }, 0);
3100
3121
  editor.on("update", () => {
3101
3122
  const hasDirtyChanges = editor.getDirtyCount() > 0;
3102
3123
  refreshSelectedState(selectedComponentRef.current);
@@ -3115,6 +3136,9 @@ function GrapesPageEditor({
3115
3136
  }, autosaveIntervalMs);
3116
3137
  });
3117
3138
  editor.on("orion:component-history", (entry) => {
3139
+ if (!historyReadyRef.current) {
3140
+ return;
3141
+ }
3118
3142
  if (!entry || typeof entry !== "object" || !("component" in entry) || !("before" in entry) || !("after" in entry)) {
3119
3143
  return;
3120
3144
  }
@@ -3136,7 +3160,7 @@ function GrapesPageEditor({
3136
3160
  );
3137
3161
  });
3138
3162
  editor.on("component:add", (component) => {
3139
- if (historyRestoreActiveRef.current) {
3163
+ if (!historyReadyRef.current || historyRestoreActiveRef.current) {
3140
3164
  return;
3141
3165
  }
3142
3166
  const typed = component;
@@ -3144,7 +3168,7 @@ function GrapesPageEditor({
3144
3168
  return;
3145
3169
  }
3146
3170
  window.setTimeout(() => {
3147
- if (historyRestoreActiveRef.current) {
3171
+ if (!historyReadyRef.current || historyRestoreActiveRef.current) {
3148
3172
  return;
3149
3173
  }
3150
3174
  pushCustomHistoryEntry(null, snapshotComponent(typed));
@@ -1190,7 +1190,7 @@ var decorateBuilderSettingHelp = (root = document) => {
1190
1190
  trigger.className = "orion-builder-v2-help-trigger";
1191
1191
  trigger.dataset.builderHelpText = help;
1192
1192
  trigger.role = "button";
1193
- trigger.tabIndex = 0;
1193
+ trigger.tabIndex = -1;
1194
1194
  trigger.textContent = "?";
1195
1195
  element.appendChild(trigger);
1196
1196
  }
@@ -1232,6 +1232,7 @@ var decorateBuilderColorEyeDroppers = (root = document) => {
1232
1232
  button.dataset.orionColorEyedropper = "true";
1233
1233
  button.setAttribute("aria-label", "Pick color from screen");
1234
1234
  button.setAttribute("title", "Pick color from screen");
1235
+ button.tabIndex = -1;
1235
1236
  button.innerHTML = '<svg viewBox="0 0 24 24" aria-hidden="true"><path d="M14.7 4.3a2.4 2.4 0 0 1 3.4 0l1.6 1.6a2.4 2.4 0 0 1 0 3.4l-1.2 1.2 1 1a1 1 0 1 1-1.4 1.4l-1-1-8.9 8.9H4v-4.2l8.9-8.9-1-1a1 1 0 0 1 1.4-1.4l1 1 1.4-1.4Zm-.4 4.8-8.3 8.3V19h1.6l8.3-8.3-1.6-1.6Z" fill="currentColor"/></svg>';
1236
1237
  swatch.insertAdjacentElement("afterend", button);
1237
1238
  });
@@ -1249,6 +1250,7 @@ var decorateBuilderNumericSteppers = (root = document) => {
1249
1250
  return;
1250
1251
  }
1251
1252
  field.classList.add("has-orion-builder-stepper");
1253
+ field.querySelector("select")?.setAttribute("tabindex", "-1");
1252
1254
  const stepper = document.createElement("span");
1253
1255
  stepper.className = "orion-builder-v2-stepper";
1254
1256
  const updateValue = (direction) => {
@@ -1266,6 +1268,7 @@ var decorateBuilderNumericSteppers = (root = document) => {
1266
1268
  button.type = "button";
1267
1269
  button.className = `orion-builder-v2-stepper-button ${step.className}`;
1268
1270
  button.setAttribute("aria-label", `${step.label} ${property.replace(/-/g, " ")}`);
1271
+ button.tabIndex = -1;
1269
1272
  button.textContent = step.text;
1270
1273
  button.addEventListener("click", (event) => {
1271
1274
  event.preventDefault();
@@ -2018,6 +2021,7 @@ function GrapesPageEditor({
2018
2021
  const stylePanelEditActiveRef = useRef(false);
2019
2022
  const historyRestoreActiveRef = useRef(false);
2020
2023
  const stylePanelHistoryBeforeRef = useRef(null);
2024
+ const historyReadyRef = useRef(false);
2021
2025
  const lastComponentSnapshotRef = useRef(/* @__PURE__ */ new WeakMap());
2022
2026
  const customUndoStackRef = useRef([]);
2023
2027
  const customRedoStackRef = useRef([]);
@@ -2637,6 +2641,12 @@ function GrapesPageEditor({
2637
2641
  }
2638
2642
  callback();
2639
2643
  };
2644
+ const clearNativeUndoHistory = () => {
2645
+ const undoManager = editorRef.current?.UndoManager;
2646
+ if (typeof undoManager?.clear === "function") {
2647
+ undoManager.clear();
2648
+ }
2649
+ };
2640
2650
  const isComponentAttached = (component) => Boolean(component.parent?.());
2641
2651
  const addComponentFromSnapshot = (snapshot) => {
2642
2652
  const parent = snapshot.parent;
@@ -2706,6 +2716,7 @@ function GrapesPageEditor({
2706
2716
  }
2707
2717
  customUndoStackRef.current.push({ after, before });
2708
2718
  customRedoStackRef.current = [];
2719
+ clearNativeUndoHistory();
2709
2720
  if (after) {
2710
2721
  lastComponentSnapshotRef.current.set(after.component, after);
2711
2722
  }
@@ -2971,8 +2982,18 @@ function GrapesPageEditor({
2971
2982
  registerOrionBuilderV2Blocks(editor);
2972
2983
  }
2973
2984
  registerProjectDynamicComponents(editor, adapter);
2985
+ historyReadyRef.current = false;
2974
2986
  editor.loadProjectData(projectData);
2975
2987
  void loadPayloadMediaAssets(editor);
2988
+ window.setTimeout(() => {
2989
+ customUndoStackRef.current = [];
2990
+ customRedoStackRef.current = [];
2991
+ lastComponentSnapshotRef.current = /* @__PURE__ */ new WeakMap();
2992
+ clearNativeUndoHistory();
2993
+ editor.clearDirtyCount?.();
2994
+ updateHistoryState(editor);
2995
+ historyReadyRef.current = true;
2996
+ }, 0);
2976
2997
  editor.on("update", () => {
2977
2998
  const hasDirtyChanges = editor.getDirtyCount() > 0;
2978
2999
  refreshSelectedState(selectedComponentRef.current);
@@ -2991,6 +3012,9 @@ function GrapesPageEditor({
2991
3012
  }, autosaveIntervalMs);
2992
3013
  });
2993
3014
  editor.on("orion:component-history", (entry) => {
3015
+ if (!historyReadyRef.current) {
3016
+ return;
3017
+ }
2994
3018
  if (!entry || typeof entry !== "object" || !("component" in entry) || !("before" in entry) || !("after" in entry)) {
2995
3019
  return;
2996
3020
  }
@@ -3012,7 +3036,7 @@ function GrapesPageEditor({
3012
3036
  );
3013
3037
  });
3014
3038
  editor.on("component:add", (component) => {
3015
- if (historyRestoreActiveRef.current) {
3039
+ if (!historyReadyRef.current || historyRestoreActiveRef.current) {
3016
3040
  return;
3017
3041
  }
3018
3042
  const typed = component;
@@ -3020,7 +3044,7 @@ function GrapesPageEditor({
3020
3044
  return;
3021
3045
  }
3022
3046
  window.setTimeout(() => {
3023
- if (historyRestoreActiveRef.current) {
3047
+ if (!historyReadyRef.current || historyRestoreActiveRef.current) {
3024
3048
  return;
3025
3049
  }
3026
3050
  pushCustomHistoryEntry(null, snapshotComponent(typed));
@@ -734,124 +734,13 @@ function HeaderNavEditorWithPreview({
734
734
  ] });
735
735
  }
736
736
 
737
- // src/admin-app/components/MediaDetailPanel.tsx
738
- import { useState as useState4 } from "react";
737
+ // src/admin-app/components/MediaListItem.tsx
739
738
  import { jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
740
739
  function formatFileSize(bytes) {
741
740
  if (bytes < 1024) return `${bytes} B`;
742
741
  if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
743
742
  return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
744
743
  }
745
- function MediaDetailPanel({
746
- id,
747
- filename,
748
- alt,
749
- url,
750
- filesize,
751
- width,
752
- height,
753
- mimeType,
754
- createdAt,
755
- updateAction,
756
- deleteAction
757
- }) {
758
- const [copied, setCopied] = useState4(false);
759
- const [confirmDelete, setConfirmDelete] = useState4(false);
760
- const copyUrl = async () => {
761
- if (!url) return;
762
- try {
763
- await navigator.clipboard.writeText(url);
764
- setCopied(true);
765
- setTimeout(() => setCopied(false), 2e3);
766
- } catch {
767
- const input = document.createElement("input");
768
- input.value = url;
769
- document.body.appendChild(input);
770
- input.select();
771
- document.execCommand("copy");
772
- document.body.removeChild(input);
773
- setCopied(true);
774
- setTimeout(() => setCopied(false), 2e3);
775
- }
776
- };
777
- const metaRows = [];
778
- if (filename) metaRows.push({ label: "Filename", value: filename });
779
- if (typeof filesize === "number") metaRows.push({ label: "File size", value: formatFileSize(filesize) });
780
- if (typeof width === "number" && typeof height === "number") metaRows.push({ label: "Dimensions", value: `${width} \xD7 ${height} px` });
781
- if (mimeType) metaRows.push({ label: "Type", value: mimeType });
782
- if (createdAt) {
783
- try {
784
- metaRows.push({ label: "Uploaded", value: new Date(createdAt).toLocaleDateString() });
785
- } catch {
786
- metaRows.push({ label: "Uploaded", value: createdAt });
787
- }
788
- }
789
- return /* @__PURE__ */ jsxs5("div", { className: "orion-admin-grid", style: { alignItems: "start" }, children: [
790
- /* @__PURE__ */ jsxs5("div", { children: [
791
- /* @__PURE__ */ jsx5("div", { className: "orion-admin-card", children: url ? /* @__PURE__ */ jsx5("img", { alt: alt || filename || "Media", src: url, style: { borderRadius: 12, width: "100%" } }) : /* @__PURE__ */ jsx5("span", { children: "No preview available." }) }),
792
- url ? /* @__PURE__ */ jsx5(
793
- "button",
794
- {
795
- className: "orion-admin-action-button",
796
- onClick: copyUrl,
797
- style: { marginTop: "0.6rem", width: "100%" },
798
- type: "button",
799
- children: copied ? "Copied!" : "Copy URL"
800
- }
801
- ) : null
802
- ] }),
803
- /* @__PURE__ */ jsxs5("div", { style: { display: "grid", gap: "0.8rem" }, children: [
804
- metaRows.length > 0 ? /* @__PURE__ */ jsx5("div", { className: "orion-admin-card orion-admin-meta-table", children: metaRows.map((row) => /* @__PURE__ */ jsxs5("div", { className: "orion-admin-meta-row", children: [
805
- /* @__PURE__ */ jsx5("span", { className: "orion-admin-meta-label", children: row.label }),
806
- /* @__PURE__ */ jsx5("span", { className: "orion-admin-meta-value", children: row.value })
807
- ] }, row.label)) }) : null,
808
- /* @__PURE__ */ jsxs5("form", { action: updateAction, className: "orion-admin-form", children: [
809
- /* @__PURE__ */ jsx5("input", { name: "id", type: "hidden", value: id }),
810
- /* @__PURE__ */ jsxs5("label", { children: [
811
- "Alt text",
812
- /* @__PURE__ */ jsx5("input", { defaultValue: alt || "", name: "alt", required: true, type: "text" })
813
- ] }),
814
- /* @__PURE__ */ jsx5("button", { type: "submit", children: "Save" })
815
- ] }),
816
- confirmDelete ? /* @__PURE__ */ jsxs5("div", { className: "orion-admin-form", style: { borderColor: "#b42318" }, children: [
817
- /* @__PURE__ */ jsx5("p", { style: { fontWeight: 700, margin: 0 }, children: "Are you sure you want to delete this asset?" }),
818
- /* @__PURE__ */ jsx5("p", { style: { color: "var(--orion-admin-muted)", fontSize: "0.9rem", margin: 0 }, children: "This action cannot be undone." }),
819
- /* @__PURE__ */ jsxs5("div", { style: { display: "flex", gap: "0.5rem" }, children: [
820
- /* @__PURE__ */ jsxs5("form", { action: deleteAction, style: { flex: 1 }, children: [
821
- /* @__PURE__ */ jsx5("input", { name: "id", type: "hidden", value: id }),
822
- /* @__PURE__ */ jsx5("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" })
823
- ] }),
824
- /* @__PURE__ */ jsx5(
825
- "button",
826
- {
827
- onClick: () => setConfirmDelete(false),
828
- style: { background: "transparent", border: "1px solid var(--orion-admin-border)", borderRadius: 10, cursor: "pointer", flex: 1, fontWeight: 700, padding: "0.55rem 0.8rem" },
829
- type: "button",
830
- children: "Cancel"
831
- }
832
- )
833
- ] })
834
- ] }) : /* @__PURE__ */ jsx5(
835
- "button",
836
- {
837
- className: "orion-admin-action-button",
838
- onClick: () => setConfirmDelete(true),
839
- style: { background: "#b42318" },
840
- type: "button",
841
- children: "Delete Asset"
842
- }
843
- )
844
- ] })
845
- ] });
846
- }
847
-
848
- // src/admin-app/components/MediaListItem.tsx
849
- import { jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
850
- function formatFileSize2(bytes) {
851
- if (bytes < 1024) return `${bytes} B`;
852
- if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
853
- return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
854
- }
855
744
  function MediaListItem({
856
745
  id,
857
746
  filename,
@@ -866,26 +755,26 @@ function MediaListItem({
866
755
  const label = filename || `Media ${id}`;
867
756
  const altText = alt || "";
868
757
  const metaParts = [];
869
- if (typeof filesize === "number") metaParts.push(formatFileSize2(filesize));
758
+ if (typeof filesize === "number") metaParts.push(formatFileSize(filesize));
870
759
  if (typeof width === "number" && typeof height === "number") metaParts.push(`${width}\xD7${height}`);
871
760
  if (typeof mimeType === "string") metaParts.push(mimeType);
872
- return /* @__PURE__ */ jsxs6("a", { className: "orion-admin-list-item", href, children: [
873
- /* @__PURE__ */ jsxs6("div", { style: { alignItems: "center", display: "flex", gap: "0.8rem" }, children: [
874
- url ? /* @__PURE__ */ jsx6("img", { alt: altText || label, className: "orion-admin-media-preview", src: url }) : null,
875
- /* @__PURE__ */ jsxs6("div", { children: [
876
- /* @__PURE__ */ jsx6("strong", { children: label }),
877
- /* @__PURE__ */ jsx6("div", { className: "orion-admin-list-meta", children: altText || "No alt text" }),
878
- metaParts.length > 0 ? /* @__PURE__ */ jsx6("div", { className: "orion-admin-list-meta", style: { marginTop: "0.15rem" }, children: metaParts.join(" \xB7 ") }) : null
761
+ return /* @__PURE__ */ jsxs5("a", { className: "orion-admin-list-item", href, children: [
762
+ /* @__PURE__ */ jsxs5("div", { style: { alignItems: "center", display: "flex", gap: "0.8rem" }, children: [
763
+ url ? /* @__PURE__ */ jsx5("img", { alt: altText || label, className: "orion-admin-media-preview", src: url }) : null,
764
+ /* @__PURE__ */ jsxs5("div", { children: [
765
+ /* @__PURE__ */ jsx5("strong", { children: label }),
766
+ /* @__PURE__ */ jsx5("div", { className: "orion-admin-list-meta", children: altText || "No alt text" }),
767
+ metaParts.length > 0 ? /* @__PURE__ */ jsx5("div", { className: "orion-admin-list-meta", style: { marginTop: "0.15rem" }, children: metaParts.join(" \xB7 ") }) : null
879
768
  ] })
880
769
  ] }),
881
- /* @__PURE__ */ jsx6("span", { className: "orion-admin-list-meta", children: "Edit" })
770
+ /* @__PURE__ */ jsx5("span", { className: "orion-admin-list-meta", children: "Edit" })
882
771
  ] });
883
772
  }
884
773
 
885
774
  // src/admin-app/components/MediaUploadForm.tsx
886
- import { useState as useState5, useRef, useCallback } from "react";
775
+ import { useState as useState4, useRef, useCallback } from "react";
887
776
  import { useRouter } from "next/navigation";
888
- import { jsx as jsx7, jsxs as jsxs7 } from "react/jsx-runtime";
777
+ import { jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
889
778
  var MEDIA_LIBRARY_SYNC_EVENT = "orion-media-library-updated";
890
779
  var notifyMediaLibraryUpdated = () => {
891
780
  if (typeof window === "undefined") {
@@ -926,12 +815,12 @@ var parseUploadError = async (response) => {
926
815
  function MediaUploadForm() {
927
816
  const router = useRouter();
928
817
  const fileInputRef = useRef(null);
929
- const [alt, setAlt] = useState5("");
930
- const [file, setFile] = useState5(null);
931
- const [preview, setPreview] = useState5(null);
932
- const [dragging, setDragging] = useState5(false);
933
- const [submitting, setSubmitting] = useState5(false);
934
- const [error, setError] = useState5(null);
818
+ const [alt, setAlt] = useState4("");
819
+ const [file, setFile] = useState4(null);
820
+ const [preview, setPreview] = useState4(null);
821
+ const [dragging, setDragging] = useState4(false);
822
+ const [submitting, setSubmitting] = useState4(false);
823
+ const [error, setError] = useState4(null);
935
824
  const handleFile = useCallback((selectedFile) => {
936
825
  setFile(selectedFile);
937
826
  if (preview) {
@@ -999,10 +888,10 @@ function MediaUploadForm() {
999
888
  setSubmitting(false);
1000
889
  }
1001
890
  };
1002
- return /* @__PURE__ */ jsxs7("form", { className: "orion-admin-upload-form", onSubmit: upload, children: [
1003
- /* @__PURE__ */ jsxs7("label", { children: [
891
+ return /* @__PURE__ */ jsxs6("form", { className: "orion-admin-upload-form", onSubmit: upload, children: [
892
+ /* @__PURE__ */ jsxs6("label", { children: [
1004
893
  "Alt text",
1005
- /* @__PURE__ */ jsx7(
894
+ /* @__PURE__ */ jsx6(
1006
895
  "input",
1007
896
  {
1008
897
  onChange: (event) => setAlt(event.target.value),
@@ -1012,7 +901,7 @@ function MediaUploadForm() {
1012
901
  }
1013
902
  )
1014
903
  ] }),
1015
- /* @__PURE__ */ jsxs7(
904
+ /* @__PURE__ */ jsxs6(
1016
905
  "div",
1017
906
  {
1018
907
  className: `orion-admin-dropzone${dragging ? " is-dragging" : ""}${file ? " has-file" : ""}`,
@@ -1021,14 +910,14 @@ function MediaUploadForm() {
1021
910
  onDragOver,
1022
911
  onDrop,
1023
912
  children: [
1024
- preview ? /* @__PURE__ */ jsxs7("div", { className: "orion-admin-dropzone-preview", children: [
1025
- /* @__PURE__ */ jsx7("img", { alt: "Upload preview", src: preview }),
1026
- /* @__PURE__ */ jsx7("span", { children: file?.name })
1027
- ] }) : /* @__PURE__ */ jsxs7("div", { className: "orion-admin-dropzone-label", children: [
1028
- /* @__PURE__ */ jsx7("strong", { children: "Drop an image here" }),
1029
- /* @__PURE__ */ jsx7("span", { children: "or click to browse" })
913
+ preview ? /* @__PURE__ */ jsxs6("div", { className: "orion-admin-dropzone-preview", children: [
914
+ /* @__PURE__ */ jsx6("img", { alt: "Upload preview", src: preview }),
915
+ /* @__PURE__ */ jsx6("span", { children: file?.name })
916
+ ] }) : /* @__PURE__ */ jsxs6("div", { className: "orion-admin-dropzone-label", children: [
917
+ /* @__PURE__ */ jsx6("strong", { children: "Drop an image here" }),
918
+ /* @__PURE__ */ jsx6("span", { children: "or click to browse" })
1030
919
  ] }),
1031
- /* @__PURE__ */ jsx7(
920
+ /* @__PURE__ */ jsx6(
1032
921
  "input",
1033
922
  {
1034
923
  accept: "image/*",
@@ -1041,8 +930,119 @@ function MediaUploadForm() {
1041
930
  ]
1042
931
  }
1043
932
  ),
1044
- error ? /* @__PURE__ */ jsx7("div", { className: "orion-admin-upload-error", children: error }) : null,
1045
- /* @__PURE__ */ jsx7("button", { disabled: submitting, type: "submit", children: submitting ? "Uploading..." : "Upload" })
933
+ error ? /* @__PURE__ */ jsx6("div", { className: "orion-admin-upload-error", children: error }) : null,
934
+ /* @__PURE__ */ jsx6("button", { disabled: submitting, type: "submit", children: submitting ? "Uploading..." : "Upload" })
935
+ ] });
936
+ }
937
+
938
+ // src/admin-app/components/MediaDetailPanel.tsx
939
+ import { useState as useState5 } from "react";
940
+ import { jsx as jsx7, jsxs as jsxs7 } from "react/jsx-runtime";
941
+ function formatFileSize2(bytes) {
942
+ if (bytes < 1024) return `${bytes} B`;
943
+ if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
944
+ return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
945
+ }
946
+ function MediaDetailPanel({
947
+ id,
948
+ filename,
949
+ alt,
950
+ url,
951
+ filesize,
952
+ width,
953
+ height,
954
+ mimeType,
955
+ createdAt,
956
+ updateAction,
957
+ deleteAction
958
+ }) {
959
+ const [copied, setCopied] = useState5(false);
960
+ const [confirmDelete, setConfirmDelete] = useState5(false);
961
+ const copyUrl = async () => {
962
+ if (!url) return;
963
+ try {
964
+ await navigator.clipboard.writeText(url);
965
+ setCopied(true);
966
+ setTimeout(() => setCopied(false), 2e3);
967
+ } catch {
968
+ const input = document.createElement("input");
969
+ input.value = url;
970
+ document.body.appendChild(input);
971
+ input.select();
972
+ document.execCommand("copy");
973
+ document.body.removeChild(input);
974
+ setCopied(true);
975
+ setTimeout(() => setCopied(false), 2e3);
976
+ }
977
+ };
978
+ const metaRows = [];
979
+ if (filename) metaRows.push({ label: "Filename", value: filename });
980
+ if (typeof filesize === "number") metaRows.push({ label: "File size", value: formatFileSize2(filesize) });
981
+ if (typeof width === "number" && typeof height === "number") metaRows.push({ label: "Dimensions", value: `${width} \xD7 ${height} px` });
982
+ if (mimeType) metaRows.push({ label: "Type", value: mimeType });
983
+ if (createdAt) {
984
+ try {
985
+ metaRows.push({ label: "Uploaded", value: new Date(createdAt).toLocaleDateString() });
986
+ } catch {
987
+ metaRows.push({ label: "Uploaded", value: createdAt });
988
+ }
989
+ }
990
+ return /* @__PURE__ */ jsxs7("div", { className: "orion-admin-grid", style: { alignItems: "start" }, children: [
991
+ /* @__PURE__ */ jsxs7("div", { children: [
992
+ /* @__PURE__ */ jsx7("div", { className: "orion-admin-card", children: url ? /* @__PURE__ */ jsx7("img", { alt: alt || filename || "Media", src: url, style: { borderRadius: 12, width: "100%" } }) : /* @__PURE__ */ jsx7("span", { children: "No preview available." }) }),
993
+ url ? /* @__PURE__ */ jsx7(
994
+ "button",
995
+ {
996
+ className: "orion-admin-action-button",
997
+ onClick: copyUrl,
998
+ style: { marginTop: "0.6rem", width: "100%" },
999
+ type: "button",
1000
+ children: copied ? "Copied!" : "Copy URL"
1001
+ }
1002
+ ) : null
1003
+ ] }),
1004
+ /* @__PURE__ */ jsxs7("div", { style: { display: "grid", gap: "0.8rem" }, children: [
1005
+ metaRows.length > 0 ? /* @__PURE__ */ jsx7("div", { className: "orion-admin-card orion-admin-meta-table", children: metaRows.map((row) => /* @__PURE__ */ jsxs7("div", { className: "orion-admin-meta-row", children: [
1006
+ /* @__PURE__ */ jsx7("span", { className: "orion-admin-meta-label", children: row.label }),
1007
+ /* @__PURE__ */ jsx7("span", { className: "orion-admin-meta-value", children: row.value })
1008
+ ] }, row.label)) }) : null,
1009
+ /* @__PURE__ */ jsxs7("form", { action: updateAction, className: "orion-admin-form", children: [
1010
+ /* @__PURE__ */ jsx7("input", { name: "id", type: "hidden", value: id }),
1011
+ /* @__PURE__ */ jsxs7("label", { children: [
1012
+ "Alt text",
1013
+ /* @__PURE__ */ jsx7("input", { defaultValue: alt || "", name: "alt", required: true, type: "text" })
1014
+ ] }),
1015
+ /* @__PURE__ */ jsx7("button", { type: "submit", children: "Save" })
1016
+ ] }),
1017
+ confirmDelete ? /* @__PURE__ */ jsxs7("div", { className: "orion-admin-form", style: { borderColor: "#b42318" }, children: [
1018
+ /* @__PURE__ */ jsx7("p", { style: { fontWeight: 700, margin: 0 }, children: "Are you sure you want to delete this asset?" }),
1019
+ /* @__PURE__ */ jsx7("p", { style: { color: "var(--orion-admin-muted)", fontSize: "0.9rem", margin: 0 }, children: "This action cannot be undone." }),
1020
+ /* @__PURE__ */ jsxs7("div", { style: { display: "flex", gap: "0.5rem" }, children: [
1021
+ /* @__PURE__ */ jsxs7("form", { action: deleteAction, style: { flex: 1 }, children: [
1022
+ /* @__PURE__ */ jsx7("input", { name: "id", type: "hidden", value: id }),
1023
+ /* @__PURE__ */ jsx7("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" })
1024
+ ] }),
1025
+ /* @__PURE__ */ jsx7(
1026
+ "button",
1027
+ {
1028
+ onClick: () => setConfirmDelete(false),
1029
+ style: { background: "transparent", border: "1px solid var(--orion-admin-border)", borderRadius: 10, cursor: "pointer", flex: 1, fontWeight: 700, padding: "0.55rem 0.8rem" },
1030
+ type: "button",
1031
+ children: "Cancel"
1032
+ }
1033
+ )
1034
+ ] })
1035
+ ] }) : /* @__PURE__ */ jsx7(
1036
+ "button",
1037
+ {
1038
+ className: "orion-admin-action-button",
1039
+ onClick: () => setConfirmDelete(true),
1040
+ style: { background: "#b42318" },
1041
+ type: "button",
1042
+ children: "Delete Asset"
1043
+ }
1044
+ )
1045
+ ] })
1046
1046
  ] });
1047
1047
  }
1048
1048
 
@@ -1054,7 +1054,7 @@ export {
1054
1054
  SiteHeaderPreview,
1055
1055
  SiteFooterPreview,
1056
1056
  HeaderNavEditorWithPreview,
1057
- MediaDetailPanel,
1058
1057
  MediaListItem,
1059
- MediaUploadForm
1058
+ MediaUploadForm,
1059
+ MediaDetailPanel
1060
1060
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@orion-studios/payload-studio",
3
- "version": "0.6.0-beta.133",
3
+ "version": "0.6.0-beta.135",
4
4
  "description": "Base CMS, builder, and custom admin toolkit for Orion Studios websites",
5
5
  "types": "./dist/index.d.ts",
6
6
  "main": "./dist/index.js",