@orion-studios/payload-studio 0.6.0-beta.121 → 0.6.0-beta.123

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-NF37A575.mjs";
12
+ } from "../chunk-KOBQX2HL.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-NF37A575.mjs";
11
+ } from "../chunk-KOBQX2HL.mjs";
12
12
  import "../chunk-ROTPP5CU.mjs";
13
13
 
14
14
  // src/admin-app/components/PageEditorFrame.tsx
@@ -823,10 +823,16 @@ var updateJsonListAttribute = ({
823
823
  [listAttr]: JSON.stringify(list)
824
824
  });
825
825
  };
826
- var snapshotModel = (model) => ({
827
- attributes: { ...model.getAttributes?.() || {} },
828
- style: { ...model.getStyle?.() || {} }
829
- });
826
+ var snapshotModel = (model, emptyListAttr) => {
827
+ const attributes = { ...model.getAttributes?.() || {} };
828
+ if (emptyListAttr && !attributes[emptyListAttr]) {
829
+ attributes[emptyListAttr] = "[]";
830
+ }
831
+ return {
832
+ attributes,
833
+ style: { ...model.getStyle?.() || {} }
834
+ };
835
+ };
830
836
  var pushModelHistory = ({
831
837
  after,
832
838
  before,
@@ -956,10 +962,10 @@ var bindEditablePreview = (view, editor) => {
956
962
  if (!listAttr) {
957
963
  return;
958
964
  }
959
- const before = snapshotModel(view.model);
965
+ const before = snapshotModel(view.model, listAttr);
960
966
  const runListMutation = (callback) => {
961
967
  withoutUndoTracking(editor, callback);
962
- const after = snapshotModel(view.model);
968
+ const after = snapshotModel(view.model, listAttr);
963
969
  if (JSON.stringify(before) !== JSON.stringify(after)) {
964
970
  pushModelHistory({
965
971
  after,
@@ -2115,7 +2121,7 @@ function GrapesPageEditor({
2115
2121
  }
2116
2122
  return null;
2117
2123
  };
2118
- const isOrionBlockComponent = (component) => Object.keys(parseOrionBlockAttribute(component?.getAttributes?.()?.["data-orion-block"])).length > 0;
2124
+ const isOrionBlockComponent = (component) => Boolean(component?.getAttributes?.()?.["data-orion-component"]) || Object.keys(parseOrionBlockAttribute(component?.getAttributes?.()?.["data-orion-block"])).length > 0;
2119
2125
  const findSelectedCanvasOrionBlock = () => {
2120
2126
  const editor = editorRef.current;
2121
2127
  const wrapper = editor?.DomComponents?.getWrapper?.() || null;
@@ -2171,16 +2177,19 @@ function GrapesPageEditor({
2171
2177
  const currentItems = parseItemsJson(attrs["data-orion-items-json"]);
2172
2178
  const nextItems = updater(currentItems);
2173
2179
  const block = parseOrionBlockAttribute(attrs["data-orion-block"]);
2174
- component.addAttributes?.({
2175
- "data-orion-items-json": JSON.stringify(nextItems),
2176
- ...Object.keys(block).length > 0 ? {
2177
- "data-orion-block": serializeOrionBlockAttribute({
2178
- ...block,
2179
- items: nextItems
2180
- })
2181
- } : {}
2180
+ const before = snapshotComponent(component);
2181
+ withoutUndoTracking2(() => {
2182
+ component.addAttributes?.({
2183
+ "data-orion-items-json": JSON.stringify(nextItems),
2184
+ ...Object.keys(block).length > 0 ? {
2185
+ "data-orion-block": serializeOrionBlockAttribute({
2186
+ ...block,
2187
+ items: nextItems
2188
+ })
2189
+ } : {}
2190
+ });
2182
2191
  });
2183
- rememberComponentSnapshot(component);
2192
+ pushCustomHistoryEntry(before, snapshotComponent(component));
2184
2193
  setSelectionSummary(summarizeSelectedComponent(component));
2185
2194
  };
2186
2195
  const refreshSelectedState = (component) => {
@@ -2617,6 +2626,23 @@ function GrapesPageEditor({
2617
2626
  return snapshot;
2618
2627
  };
2619
2628
  const getPreviousComponentSnapshot = (component) => component ? lastComponentSnapshotRef.current.get(component) || snapshotComponent(component) : null;
2629
+ const withoutUndoTracking2 = (callback) => {
2630
+ const undoManager = editorRef.current?.UndoManager;
2631
+ if (typeof undoManager?.skip === "function") {
2632
+ undoManager.skip(callback);
2633
+ return;
2634
+ }
2635
+ if (typeof undoManager?.stop === "function" && typeof undoManager?.start === "function") {
2636
+ undoManager.stop();
2637
+ try {
2638
+ callback();
2639
+ } finally {
2640
+ undoManager.start();
2641
+ }
2642
+ return;
2643
+ }
2644
+ callback();
2645
+ };
2620
2646
  const isComponentAttached = (component) => Boolean(component.parent?.());
2621
2647
  const addComponentFromSnapshot = (snapshot) => {
2622
2648
  const parent = snapshot.parent;
@@ -699,10 +699,16 @@ var updateJsonListAttribute = ({
699
699
  [listAttr]: JSON.stringify(list)
700
700
  });
701
701
  };
702
- var snapshotModel = (model) => ({
703
- attributes: { ...model.getAttributes?.() || {} },
704
- style: { ...model.getStyle?.() || {} }
705
- });
702
+ var snapshotModel = (model, emptyListAttr) => {
703
+ const attributes = { ...model.getAttributes?.() || {} };
704
+ if (emptyListAttr && !attributes[emptyListAttr]) {
705
+ attributes[emptyListAttr] = "[]";
706
+ }
707
+ return {
708
+ attributes,
709
+ style: { ...model.getStyle?.() || {} }
710
+ };
711
+ };
706
712
  var pushModelHistory = ({
707
713
  after,
708
714
  before,
@@ -832,10 +838,10 @@ var bindEditablePreview = (view, editor) => {
832
838
  if (!listAttr) {
833
839
  return;
834
840
  }
835
- const before = snapshotModel(view.model);
841
+ const before = snapshotModel(view.model, listAttr);
836
842
  const runListMutation = (callback) => {
837
843
  withoutUndoTracking(editor, callback);
838
- const after = snapshotModel(view.model);
844
+ const after = snapshotModel(view.model, listAttr);
839
845
  if (JSON.stringify(before) !== JSON.stringify(after)) {
840
846
  pushModelHistory({
841
847
  after,
@@ -1991,7 +1997,7 @@ function GrapesPageEditor({
1991
1997
  }
1992
1998
  return null;
1993
1999
  };
1994
- const isOrionBlockComponent = (component) => Object.keys(parseOrionBlockAttribute(component?.getAttributes?.()?.["data-orion-block"])).length > 0;
2000
+ const isOrionBlockComponent = (component) => Boolean(component?.getAttributes?.()?.["data-orion-component"]) || Object.keys(parseOrionBlockAttribute(component?.getAttributes?.()?.["data-orion-block"])).length > 0;
1995
2001
  const findSelectedCanvasOrionBlock = () => {
1996
2002
  const editor = editorRef.current;
1997
2003
  const wrapper = editor?.DomComponents?.getWrapper?.() || null;
@@ -2047,16 +2053,19 @@ function GrapesPageEditor({
2047
2053
  const currentItems = parseItemsJson(attrs["data-orion-items-json"]);
2048
2054
  const nextItems = updater(currentItems);
2049
2055
  const block = parseOrionBlockAttribute(attrs["data-orion-block"]);
2050
- component.addAttributes?.({
2051
- "data-orion-items-json": JSON.stringify(nextItems),
2052
- ...Object.keys(block).length > 0 ? {
2053
- "data-orion-block": serializeOrionBlockAttribute({
2054
- ...block,
2055
- items: nextItems
2056
- })
2057
- } : {}
2056
+ const before = snapshotComponent(component);
2057
+ withoutUndoTracking2(() => {
2058
+ component.addAttributes?.({
2059
+ "data-orion-items-json": JSON.stringify(nextItems),
2060
+ ...Object.keys(block).length > 0 ? {
2061
+ "data-orion-block": serializeOrionBlockAttribute({
2062
+ ...block,
2063
+ items: nextItems
2064
+ })
2065
+ } : {}
2066
+ });
2058
2067
  });
2059
- rememberComponentSnapshot(component);
2068
+ pushCustomHistoryEntry(before, snapshotComponent(component));
2060
2069
  setSelectionSummary(summarizeSelectedComponent(component));
2061
2070
  };
2062
2071
  const refreshSelectedState = (component) => {
@@ -2493,6 +2502,23 @@ function GrapesPageEditor({
2493
2502
  return snapshot;
2494
2503
  };
2495
2504
  const getPreviousComponentSnapshot = (component) => component ? lastComponentSnapshotRef.current.get(component) || snapshotComponent(component) : null;
2505
+ const withoutUndoTracking2 = (callback) => {
2506
+ const undoManager = editorRef.current?.UndoManager;
2507
+ if (typeof undoManager?.skip === "function") {
2508
+ undoManager.skip(callback);
2509
+ return;
2510
+ }
2511
+ if (typeof undoManager?.stop === "function" && typeof undoManager?.start === "function") {
2512
+ undoManager.stop();
2513
+ try {
2514
+ callback();
2515
+ } finally {
2516
+ undoManager.start();
2517
+ }
2518
+ return;
2519
+ }
2520
+ callback();
2521
+ };
2496
2522
  const isComponentAttached = (component) => Boolean(component.parent?.());
2497
2523
  const addComponentFromSnapshot = (snapshot) => {
2498
2524
  const parent = snapshot.parent;
@@ -734,13 +734,124 @@ function HeaderNavEditorWithPreview({
734
734
  ] });
735
735
  }
736
736
 
737
- // src/admin-app/components/MediaListItem.tsx
737
+ // src/admin-app/components/MediaDetailPanel.tsx
738
+ import { useState as useState4 } from "react";
738
739
  import { jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
739
740
  function formatFileSize(bytes) {
740
741
  if (bytes < 1024) return `${bytes} B`;
741
742
  if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
742
743
  return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
743
744
  }
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
+ }
744
855
  function MediaListItem({
745
856
  id,
746
857
  filename,
@@ -755,26 +866,26 @@ function MediaListItem({
755
866
  const label = filename || `Media ${id}`;
756
867
  const altText = alt || "";
757
868
  const metaParts = [];
758
- if (typeof filesize === "number") metaParts.push(formatFileSize(filesize));
869
+ if (typeof filesize === "number") metaParts.push(formatFileSize2(filesize));
759
870
  if (typeof width === "number" && typeof height === "number") metaParts.push(`${width}\xD7${height}`);
760
871
  if (typeof mimeType === "string") metaParts.push(mimeType);
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
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
768
879
  ] })
769
880
  ] }),
770
- /* @__PURE__ */ jsx5("span", { className: "orion-admin-list-meta", children: "Edit" })
881
+ /* @__PURE__ */ jsx6("span", { className: "orion-admin-list-meta", children: "Edit" })
771
882
  ] });
772
883
  }
773
884
 
774
885
  // src/admin-app/components/MediaUploadForm.tsx
775
- import { useState as useState4, useRef, useCallback } from "react";
886
+ import { useState as useState5, useRef, useCallback } from "react";
776
887
  import { useRouter } from "next/navigation";
777
- import { jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
888
+ import { jsx as jsx7, jsxs as jsxs7 } from "react/jsx-runtime";
778
889
  var MEDIA_LIBRARY_SYNC_EVENT = "orion-media-library-updated";
779
890
  var notifyMediaLibraryUpdated = () => {
780
891
  if (typeof window === "undefined") {
@@ -815,12 +926,12 @@ var parseUploadError = async (response) => {
815
926
  function MediaUploadForm() {
816
927
  const router = useRouter();
817
928
  const fileInputRef = useRef(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);
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);
824
935
  const handleFile = useCallback((selectedFile) => {
825
936
  setFile(selectedFile);
826
937
  if (preview) {
@@ -888,10 +999,10 @@ function MediaUploadForm() {
888
999
  setSubmitting(false);
889
1000
  }
890
1001
  };
891
- return /* @__PURE__ */ jsxs6("form", { className: "orion-admin-upload-form", onSubmit: upload, children: [
892
- /* @__PURE__ */ jsxs6("label", { children: [
1002
+ return /* @__PURE__ */ jsxs7("form", { className: "orion-admin-upload-form", onSubmit: upload, children: [
1003
+ /* @__PURE__ */ jsxs7("label", { children: [
893
1004
  "Alt text",
894
- /* @__PURE__ */ jsx6(
1005
+ /* @__PURE__ */ jsx7(
895
1006
  "input",
896
1007
  {
897
1008
  onChange: (event) => setAlt(event.target.value),
@@ -901,7 +1012,7 @@ function MediaUploadForm() {
901
1012
  }
902
1013
  )
903
1014
  ] }),
904
- /* @__PURE__ */ jsxs6(
1015
+ /* @__PURE__ */ jsxs7(
905
1016
  "div",
906
1017
  {
907
1018
  className: `orion-admin-dropzone${dragging ? " is-dragging" : ""}${file ? " has-file" : ""}`,
@@ -910,14 +1021,14 @@ function MediaUploadForm() {
910
1021
  onDragOver,
911
1022
  onDrop,
912
1023
  children: [
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" })
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" })
919
1030
  ] }),
920
- /* @__PURE__ */ jsx6(
1031
+ /* @__PURE__ */ jsx7(
921
1032
  "input",
922
1033
  {
923
1034
  accept: "image/*",
@@ -930,119 +1041,8 @@ function MediaUploadForm() {
930
1041
  ]
931
1042
  }
932
1043
  ),
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
- ] })
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" })
1046
1046
  ] });
1047
1047
  }
1048
1048
 
@@ -1054,7 +1054,7 @@ export {
1054
1054
  SiteHeaderPreview,
1055
1055
  SiteFooterPreview,
1056
1056
  HeaderNavEditorWithPreview,
1057
+ MediaDetailPanel,
1057
1058
  MediaListItem,
1058
- MediaUploadForm,
1059
- MediaDetailPanel
1059
+ MediaUploadForm
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.121",
3
+ "version": "0.6.0-beta.123",
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",