@lodashventure/medusa-media-manager 0.2.5 → 0.2.7
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.
|
@@ -2,7 +2,7 @@ import { jsxs, jsx } from "react/jsx-runtime";
|
|
|
2
2
|
import { useState, useMemo, useCallback, useRef, useEffect } from "react";
|
|
3
3
|
import { defineRouteConfig } from "@medusajs/admin-sdk";
|
|
4
4
|
import { SquaresPlus, ListBullet, ArrowPath, CloudArrowUp, Photo, ShieldCheck, DocumentText, PlaySolid, X, CircleArrowUp, ArrowDownTray, SquareTwoStack, Trash } from "@medusajs/icons";
|
|
5
|
-
import { Input, Select, TooltipProvider, Tooltip, IconButton, clx, Button, Badge, Skeleton, Table, StatusBadge, toast, Drawer, Textarea, Container, Heading, Alert } from "@medusajs/ui";
|
|
5
|
+
import { Input, Select, TooltipProvider, Tooltip, IconButton, clx, Button, Badge, Skeleton, Table, StatusBadge, toast, Drawer, FocusModal, Textarea, Container, Heading, Alert } from "@medusajs/ui";
|
|
6
6
|
import "@medusajs/admin-shared";
|
|
7
7
|
const ALL_OPTION_VALUE = "all";
|
|
8
8
|
const normalizeSelectValue = (value) => {
|
|
@@ -680,7 +680,7 @@ const STATUS_COLORS = {
|
|
|
680
680
|
archived: "warning"
|
|
681
681
|
};
|
|
682
682
|
const DEFAULT_LOCALE = "default";
|
|
683
|
-
const
|
|
683
|
+
const MediaAssetDialog = ({
|
|
684
684
|
assetId,
|
|
685
685
|
onClose,
|
|
686
686
|
onUpdated,
|
|
@@ -688,6 +688,7 @@ const MediaAssetDrawer = ({
|
|
|
688
688
|
}) => {
|
|
689
689
|
var _a;
|
|
690
690
|
const fileInputRef = useRef(null);
|
|
691
|
+
const modalContentRef = useRef(null);
|
|
691
692
|
const [asset, setAsset] = useState(null);
|
|
692
693
|
const [isLoading, setIsLoading] = useState(false);
|
|
693
694
|
const [isSaving, setIsSaving] = useState(false);
|
|
@@ -764,6 +765,11 @@ const MediaAssetDrawer = ({
|
|
|
764
765
|
isMounted = false;
|
|
765
766
|
};
|
|
766
767
|
}, [assetId]);
|
|
768
|
+
useEffect(() => {
|
|
769
|
+
if (modalContentRef.current) {
|
|
770
|
+
modalContentRef.current.scrollTop = 0;
|
|
771
|
+
}
|
|
772
|
+
}, [assetId]);
|
|
767
773
|
const tags = useMemo(() => parseTags(tagsInput), [tagsInput]);
|
|
768
774
|
const handleSave = async () => {
|
|
769
775
|
if (!asset || !assetId) {
|
|
@@ -852,290 +858,298 @@ const MediaAssetDrawer = ({
|
|
|
852
858
|
}
|
|
853
859
|
};
|
|
854
860
|
const assetRelations = (asset == null ? void 0 : asset.relations) ?? [];
|
|
855
|
-
return /* @__PURE__ */ jsx(
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
"
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
className: "
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
861
|
+
return /* @__PURE__ */ jsx(FocusModal, { open: Boolean(assetId), onOpenChange: (open) => !open && onClose(), children: /* @__PURE__ */ jsxs(
|
|
862
|
+
FocusModal.Content,
|
|
863
|
+
{
|
|
864
|
+
ref: modalContentRef,
|
|
865
|
+
className: "flex h-full w-full max-w-3xl flex-col overflow-y-auto p-6",
|
|
866
|
+
children: [
|
|
867
|
+
/* @__PURE__ */ jsxs(FocusModal.Header, { children: [
|
|
868
|
+
/* @__PURE__ */ jsx(FocusModal.Title, { className: "text-lg font-semibold", children: "Asset details" }),
|
|
869
|
+
/* @__PURE__ */ jsx(FocusModal.Description, { children: "Review and update metadata, copy delivery URLs, or replace the original file." })
|
|
870
|
+
] }),
|
|
871
|
+
isLoading ? /* @__PURE__ */ jsx("div", { className: "flex flex-1 items-center justify-center", children: /* @__PURE__ */ jsx("div", { className: "text-sm text-ui-fg-subtle", children: "Loading asset..." }) }) : asset ? /* @__PURE__ */ jsxs("div", { className: "flex flex-1 flex-col gap-y-6", children: [
|
|
872
|
+
/* @__PURE__ */ jsxs("section", { className: "flex flex-col gap-y-4", children: [
|
|
873
|
+
/* @__PURE__ */ jsx("div", { className: "aspect-video w-full overflow-hidden rounded-lg border border-ui-border-base bg-ui-bg-subtle", children: previewUrl ? /* @__PURE__ */ jsx(
|
|
874
|
+
"img",
|
|
875
|
+
{
|
|
876
|
+
src: previewUrl,
|
|
877
|
+
alt: asset.original_filename,
|
|
878
|
+
className: "h-full w-full object-contain"
|
|
879
|
+
}
|
|
880
|
+
) : /* @__PURE__ */ jsx("div", { className: "flex h-full w-full items-center justify-center text-ui-fg-muted", children: /* @__PURE__ */ jsx(Photo, { className: "size-8" }) }) }),
|
|
881
|
+
/* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center gap-2 text-xs text-ui-fg-subtle", children: [
|
|
882
|
+
/* @__PURE__ */ jsx("span", { children: asset.mime }),
|
|
883
|
+
/* @__PURE__ */ jsx("span", { children: "·" }),
|
|
884
|
+
/* @__PURE__ */ jsx("span", { children: formatFileSize(asset.size_bytes) }),
|
|
885
|
+
/* @__PURE__ */ jsx("span", { children: "·" }),
|
|
886
|
+
/* @__PURE__ */ jsxs("span", { children: [
|
|
887
|
+
"Updated ",
|
|
888
|
+
formatDateTime(asset.updated_at)
|
|
889
|
+
] }),
|
|
890
|
+
/* @__PURE__ */ jsx(
|
|
891
|
+
StatusBadge,
|
|
892
|
+
{
|
|
893
|
+
size: "small",
|
|
894
|
+
color: STATUS_COLORS[asset.status] ?? "default",
|
|
895
|
+
children: asset.status
|
|
896
|
+
}
|
|
897
|
+
),
|
|
898
|
+
/* @__PURE__ */ jsx(
|
|
899
|
+
Badge,
|
|
900
|
+
{
|
|
901
|
+
size: "small",
|
|
902
|
+
variant: asset.visibility === "public" ? "neutral" : "warning",
|
|
903
|
+
className: "capitalize",
|
|
904
|
+
children: asset.visibility
|
|
905
|
+
}
|
|
906
|
+
)
|
|
907
|
+
] }),
|
|
908
|
+
/* @__PURE__ */ jsxs("div", { className: "flex flex-wrap gap-2", children: [
|
|
909
|
+
/* @__PURE__ */ jsxs(
|
|
910
|
+
Button,
|
|
911
|
+
{
|
|
912
|
+
type: "button",
|
|
913
|
+
variant: "secondary",
|
|
914
|
+
onClick: () => {
|
|
915
|
+
var _a2;
|
|
916
|
+
return (_a2 = fileInputRef.current) == null ? void 0 : _a2.click();
|
|
917
|
+
},
|
|
918
|
+
isLoading: isReplacing,
|
|
919
|
+
children: [
|
|
920
|
+
/* @__PURE__ */ jsx(CircleArrowUp, { className: "mr-1 size-4" }),
|
|
921
|
+
"Replace file"
|
|
922
|
+
]
|
|
923
|
+
}
|
|
924
|
+
),
|
|
925
|
+
/* @__PURE__ */ jsxs(
|
|
926
|
+
Button,
|
|
927
|
+
{
|
|
928
|
+
type: "button",
|
|
929
|
+
variant: "secondary",
|
|
930
|
+
onClick: () => handleVariantCopy("medium"),
|
|
931
|
+
children: [
|
|
932
|
+
/* @__PURE__ */ jsx(ArrowDownTray, { className: "mr-1 size-4" }),
|
|
933
|
+
"Get URL"
|
|
934
|
+
]
|
|
935
|
+
}
|
|
936
|
+
)
|
|
937
|
+
] }),
|
|
938
|
+
/* @__PURE__ */ jsx(
|
|
939
|
+
"input",
|
|
940
|
+
{
|
|
941
|
+
type: "file",
|
|
942
|
+
ref: fileInputRef,
|
|
943
|
+
className: "hidden",
|
|
944
|
+
onChange: (event) => {
|
|
945
|
+
var _a2;
|
|
946
|
+
return handleReplace(((_a2 = event.target.files) == null ? void 0 : _a2[0]) ?? null);
|
|
947
|
+
}
|
|
948
|
+
}
|
|
949
|
+
)
|
|
878
950
|
] }),
|
|
879
|
-
/* @__PURE__ */
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
951
|
+
/* @__PURE__ */ jsxs("section", { className: "space-y-4", children: [
|
|
952
|
+
/* @__PURE__ */ jsxs("div", { className: "grid grid-cols-1 gap-4 md:grid-cols-2", children: [
|
|
953
|
+
/* @__PURE__ */ jsx(
|
|
954
|
+
Input,
|
|
955
|
+
{
|
|
956
|
+
label: "Title",
|
|
957
|
+
placeholder: "Hero banner",
|
|
958
|
+
value: title,
|
|
959
|
+
onChange: (event) => setTitle(event.target.value)
|
|
960
|
+
}
|
|
961
|
+
),
|
|
962
|
+
/* @__PURE__ */ jsx(
|
|
963
|
+
Input,
|
|
964
|
+
{
|
|
965
|
+
label: "Alt text",
|
|
966
|
+
placeholder: "Describe the media for accessibility",
|
|
967
|
+
value: altText,
|
|
968
|
+
onChange: (event) => setAltText(event.target.value)
|
|
969
|
+
}
|
|
970
|
+
)
|
|
971
|
+
] }),
|
|
972
|
+
/* @__PURE__ */ jsx(
|
|
973
|
+
Textarea,
|
|
974
|
+
{
|
|
975
|
+
label: "Caption",
|
|
976
|
+
placeholder: "Optional caption or notes",
|
|
977
|
+
value: caption,
|
|
978
|
+
onChange: (event) => setCaption(event.target.value)
|
|
979
|
+
}
|
|
980
|
+
),
|
|
981
|
+
/* @__PURE__ */ jsx(
|
|
982
|
+
Input,
|
|
983
|
+
{
|
|
984
|
+
label: "Tags",
|
|
985
|
+
placeholder: "summer, lookbook, hero",
|
|
986
|
+
value: tagsInput,
|
|
987
|
+
onChange: (event) => setTagsInput(event.target.value),
|
|
988
|
+
helperText: "Separate tags with commas"
|
|
989
|
+
}
|
|
990
|
+
),
|
|
991
|
+
/* @__PURE__ */ jsxs("div", { className: "grid grid-cols-1 gap-4 sm:grid-cols-2", children: [
|
|
992
|
+
/* @__PURE__ */ jsxs(
|
|
993
|
+
Select,
|
|
994
|
+
{
|
|
995
|
+
value: status,
|
|
996
|
+
onValueChange: (value) => setStatus(value),
|
|
997
|
+
children: [
|
|
998
|
+
/* @__PURE__ */ jsx(Select.Trigger, { children: /* @__PURE__ */ jsx(Select.Value, { placeholder: "Status" }) }),
|
|
999
|
+
/* @__PURE__ */ jsxs(Select.Content, { children: [
|
|
1000
|
+
/* @__PURE__ */ jsx(Select.Item, { value: "draft", children: "Draft" }),
|
|
1001
|
+
/* @__PURE__ */ jsx(Select.Item, { value: "published", children: "Published" }),
|
|
1002
|
+
/* @__PURE__ */ jsx(Select.Item, { value: "archived", children: "Archived" })
|
|
1003
|
+
] })
|
|
1004
|
+
]
|
|
1005
|
+
}
|
|
1006
|
+
),
|
|
1007
|
+
/* @__PURE__ */ jsxs(
|
|
1008
|
+
Select,
|
|
1009
|
+
{
|
|
1010
|
+
value: visibility,
|
|
1011
|
+
onValueChange: (value) => setVisibility(value),
|
|
1012
|
+
children: [
|
|
1013
|
+
/* @__PURE__ */ jsx(Select.Trigger, { children: /* @__PURE__ */ jsx(Select.Value, { placeholder: "Visibility" }) }),
|
|
1014
|
+
/* @__PURE__ */ jsxs(Select.Content, { children: [
|
|
1015
|
+
/* @__PURE__ */ jsx(Select.Item, { value: "public", children: "Public" }),
|
|
1016
|
+
/* @__PURE__ */ jsx(Select.Item, { value: "private", children: "Private" })
|
|
1017
|
+
] })
|
|
1018
|
+
]
|
|
1019
|
+
}
|
|
1020
|
+
)
|
|
1021
|
+
] })
|
|
1022
|
+
] }),
|
|
1023
|
+
((_a = asset.variants) == null ? void 0 : _a.length) ? /* @__PURE__ */ jsxs("section", { className: "space-y-3", children: [
|
|
1024
|
+
/* @__PURE__ */ jsx("h3", { className: "text-sm font-medium", children: "Variants" }),
|
|
1025
|
+
/* @__PURE__ */ jsxs(Table, { children: [
|
|
1026
|
+
/* @__PURE__ */ jsx(Table.Header, { children: /* @__PURE__ */ jsxs(Table.Row, { children: [
|
|
1027
|
+
/* @__PURE__ */ jsx(Table.HeaderCell, { children: "Name" }),
|
|
1028
|
+
/* @__PURE__ */ jsx(Table.HeaderCell, { children: "Format" }),
|
|
1029
|
+
/* @__PURE__ */ jsx(Table.HeaderCell, { children: "Dimensions" }),
|
|
1030
|
+
/* @__PURE__ */ jsx(Table.HeaderCell, { children: "Size" }),
|
|
1031
|
+
/* @__PURE__ */ jsx(Table.HeaderCell, { className: "text-right", children: "Actions" })
|
|
1032
|
+
] }) }),
|
|
1033
|
+
/* @__PURE__ */ jsx(Table.Body, { children: asset.variants.map((variant) => /* @__PURE__ */ jsxs(
|
|
1034
|
+
Table.Row,
|
|
1035
|
+
{
|
|
1036
|
+
children: [
|
|
1037
|
+
/* @__PURE__ */ jsx(Table.Cell, { className: "capitalize", children: variant.preset }),
|
|
1038
|
+
/* @__PURE__ */ jsx(Table.Cell, { children: variant.format }),
|
|
1039
|
+
/* @__PURE__ */ jsx(Table.Cell, { children: variant.width && variant.height ? `${variant.width}×${variant.height}` : "-" }),
|
|
1040
|
+
/* @__PURE__ */ jsx(Table.Cell, { children: formatFileSize(variant.size_bytes) }),
|
|
1041
|
+
/* @__PURE__ */ jsx(Table.Cell, { className: "flex justify-end gap-2", children: /* @__PURE__ */ jsxs(
|
|
1042
|
+
Button,
|
|
1043
|
+
{
|
|
1044
|
+
size: "small",
|
|
1045
|
+
variant: "secondary",
|
|
1046
|
+
onClick: () => handleVariantCopy(variant.preset),
|
|
1047
|
+
children: [
|
|
1048
|
+
/* @__PURE__ */ jsx(SquareTwoStack, { className: "mr-1 size-4" }),
|
|
1049
|
+
" Copy URL"
|
|
1050
|
+
]
|
|
1051
|
+
}
|
|
1052
|
+
) })
|
|
1053
|
+
]
|
|
1054
|
+
},
|
|
1055
|
+
variant.id ?? `${variant.preset}-${variant.format}`
|
|
1056
|
+
)) })
|
|
1057
|
+
] })
|
|
1058
|
+
] }) : null,
|
|
1059
|
+
/* @__PURE__ */ jsxs("section", { className: "space-y-3", children: [
|
|
1060
|
+
/* @__PURE__ */ jsx("h3", { className: "text-sm font-medium", children: "Usage" }),
|
|
1061
|
+
assetRelations.length ? /* @__PURE__ */ jsxs(Table, { children: [
|
|
1062
|
+
/* @__PURE__ */ jsx(Table.Header, { children: /* @__PURE__ */ jsxs(Table.Row, { children: [
|
|
1063
|
+
/* @__PURE__ */ jsx(Table.HeaderCell, { children: "Entity" }),
|
|
1064
|
+
/* @__PURE__ */ jsx(Table.HeaderCell, { children: "Reference" }),
|
|
1065
|
+
/* @__PURE__ */ jsx(Table.HeaderCell, { children: "Role" })
|
|
1066
|
+
] }) }),
|
|
1067
|
+
/* @__PURE__ */ jsx(Table.Body, { children: assetRelations.map((relation) => /* @__PURE__ */ jsxs(Table.Row, { children: [
|
|
1068
|
+
/* @__PURE__ */ jsx(Table.Cell, { className: "capitalize", children: relation.entity_type }),
|
|
1069
|
+
/* @__PURE__ */ jsx(Table.Cell, { className: "font-mono text-xs", children: relation.entity_id }),
|
|
1070
|
+
/* @__PURE__ */ jsx(Table.Cell, { children: relation.relation_role })
|
|
1071
|
+
] }, relation.id)) })
|
|
1072
|
+
] }) : /* @__PURE__ */ jsx("p", { className: "text-sm text-ui-fg-subtle", children: "This asset is not linked to any entities." })
|
|
1073
|
+
] })
|
|
1074
|
+
] }) : /* @__PURE__ */ jsx("div", { className: "flex flex-1 items-center justify-center text-sm text-ui-fg-subtle", children: "Select an asset to view details." }),
|
|
1075
|
+
/* @__PURE__ */ jsxs(FocusModal.Footer, { className: "mt-6 flex flex-wrap items-center justify-between gap-3", children: [
|
|
1076
|
+
/* @__PURE__ */ jsxs("div", { className: "flex gap-2", children: [
|
|
1077
|
+
/* @__PURE__ */ jsxs(
|
|
1078
|
+
Button,
|
|
1079
|
+
{
|
|
1080
|
+
type: "button",
|
|
1081
|
+
variant: "danger",
|
|
1082
|
+
onClick: () => {
|
|
1083
|
+
if (!asset) {
|
|
1084
|
+
return;
|
|
1085
|
+
}
|
|
1086
|
+
const confirmDelete = window.confirm(
|
|
1087
|
+
"Delete this asset and all generated variants?"
|
|
1088
|
+
);
|
|
1089
|
+
if (confirmDelete) {
|
|
1090
|
+
handleDelete(false);
|
|
1091
|
+
}
|
|
1092
|
+
},
|
|
1093
|
+
disabled: !asset,
|
|
1094
|
+
children: [
|
|
1095
|
+
/* @__PURE__ */ jsx(Trash, { className: "mr-1 size-4" }),
|
|
1096
|
+
" Delete"
|
|
1097
|
+
]
|
|
1098
|
+
}
|
|
1099
|
+
),
|
|
1100
|
+
/* @__PURE__ */ jsxs(
|
|
1101
|
+
Button,
|
|
1102
|
+
{
|
|
1103
|
+
type: "button",
|
|
1104
|
+
variant: "secondary",
|
|
1105
|
+
onClick: () => asset && handleVariantCopy("medium"),
|
|
1106
|
+
disabled: !asset,
|
|
1107
|
+
children: [
|
|
1108
|
+
/* @__PURE__ */ jsx(ArrowPath, { className: "mr-1 size-4" }),
|
|
1109
|
+
" Copy URL"
|
|
1110
|
+
]
|
|
1111
|
+
}
|
|
1112
|
+
)
|
|
1113
|
+
] }),
|
|
1114
|
+
/* @__PURE__ */ jsxs("div", { className: "flex gap-2", children: [
|
|
1115
|
+
/* @__PURE__ */ jsx(Button, { variant: "secondary", onClick: onClose, children: "Close" }),
|
|
1116
|
+
/* @__PURE__ */ jsx(
|
|
1117
|
+
Button,
|
|
1118
|
+
{
|
|
1119
|
+
onClick: handleSave,
|
|
1120
|
+
disabled: !asset || isSaving,
|
|
1121
|
+
isLoading: isSaving,
|
|
1122
|
+
children: "Save changes"
|
|
1123
|
+
}
|
|
1124
|
+
)
|
|
1125
|
+
] })
|
|
896
1126
|
] }),
|
|
897
|
-
/* @__PURE__ */ jsxs("div", { className: "
|
|
898
|
-
/* @__PURE__ */
|
|
1127
|
+
deleteAttempted && asset && /* @__PURE__ */ jsxs("div", { className: "mt-4 rounded-md border border-ui-border-base bg-ui-bg-subtle p-4 text-sm text-ui-fg-subtle", children: [
|
|
1128
|
+
/* @__PURE__ */ jsx("p", { className: "font-medium text-ui-fg-base", children: "Having trouble deleting?" }),
|
|
1129
|
+
/* @__PURE__ */ jsx("p", { className: "mt-1", children: "If the asset is still referenced, remove those relations first or attempt a force delete." }),
|
|
1130
|
+
/* @__PURE__ */ jsx(
|
|
899
1131
|
Button,
|
|
900
1132
|
{
|
|
901
|
-
|
|
902
|
-
variant: "
|
|
1133
|
+
className: "mt-3",
|
|
1134
|
+
variant: "danger",
|
|
1135
|
+
size: "small",
|
|
903
1136
|
onClick: () => {
|
|
904
|
-
|
|
905
|
-
|
|
1137
|
+
const confirmForce = window.confirm(
|
|
1138
|
+
"Force delete will remove the asset even if it is still referenced. Continue?"
|
|
1139
|
+
);
|
|
1140
|
+
if (confirmForce) {
|
|
1141
|
+
handleDelete(true);
|
|
1142
|
+
}
|
|
906
1143
|
},
|
|
907
|
-
|
|
908
|
-
children: [
|
|
909
|
-
/* @__PURE__ */ jsx(CircleArrowUp, { className: "mr-1 size-4" }),
|
|
910
|
-
"Replace file"
|
|
911
|
-
]
|
|
912
|
-
}
|
|
913
|
-
),
|
|
914
|
-
/* @__PURE__ */ jsxs(
|
|
915
|
-
Button,
|
|
916
|
-
{
|
|
917
|
-
type: "button",
|
|
918
|
-
variant: "secondary",
|
|
919
|
-
onClick: () => handleVariantCopy("medium"),
|
|
920
|
-
children: [
|
|
921
|
-
/* @__PURE__ */ jsx(ArrowDownTray, { className: "mr-1 size-4" }),
|
|
922
|
-
"Get URL"
|
|
923
|
-
]
|
|
924
|
-
}
|
|
925
|
-
)
|
|
926
|
-
] }),
|
|
927
|
-
/* @__PURE__ */ jsx(
|
|
928
|
-
"input",
|
|
929
|
-
{
|
|
930
|
-
type: "file",
|
|
931
|
-
ref: fileInputRef,
|
|
932
|
-
className: "hidden",
|
|
933
|
-
onChange: (event) => {
|
|
934
|
-
var _a2;
|
|
935
|
-
return handleReplace(((_a2 = event.target.files) == null ? void 0 : _a2[0]) ?? null);
|
|
936
|
-
}
|
|
937
|
-
}
|
|
938
|
-
)
|
|
939
|
-
] }),
|
|
940
|
-
/* @__PURE__ */ jsxs("section", { className: "space-y-4", children: [
|
|
941
|
-
/* @__PURE__ */ jsxs("div", { className: "grid grid-cols-1 gap-4 md:grid-cols-2", children: [
|
|
942
|
-
/* @__PURE__ */ jsx(
|
|
943
|
-
Input,
|
|
944
|
-
{
|
|
945
|
-
label: "Title",
|
|
946
|
-
placeholder: "Hero banner",
|
|
947
|
-
value: title,
|
|
948
|
-
onChange: (event) => setTitle(event.target.value)
|
|
949
|
-
}
|
|
950
|
-
),
|
|
951
|
-
/* @__PURE__ */ jsx(
|
|
952
|
-
Input,
|
|
953
|
-
{
|
|
954
|
-
label: "Alt text",
|
|
955
|
-
placeholder: "Describe the media for accessibility",
|
|
956
|
-
value: altText,
|
|
957
|
-
onChange: (event) => setAltText(event.target.value)
|
|
958
|
-
}
|
|
959
|
-
)
|
|
960
|
-
] }),
|
|
961
|
-
/* @__PURE__ */ jsx(
|
|
962
|
-
Textarea,
|
|
963
|
-
{
|
|
964
|
-
label: "Caption",
|
|
965
|
-
placeholder: "Optional caption or notes",
|
|
966
|
-
value: caption,
|
|
967
|
-
onChange: (event) => setCaption(event.target.value)
|
|
968
|
-
}
|
|
969
|
-
),
|
|
970
|
-
/* @__PURE__ */ jsx(
|
|
971
|
-
Input,
|
|
972
|
-
{
|
|
973
|
-
label: "Tags",
|
|
974
|
-
placeholder: "summer, lookbook, hero",
|
|
975
|
-
value: tagsInput,
|
|
976
|
-
onChange: (event) => setTagsInput(event.target.value),
|
|
977
|
-
helperText: "Separate tags with commas"
|
|
978
|
-
}
|
|
979
|
-
),
|
|
980
|
-
/* @__PURE__ */ jsxs("div", { className: "grid grid-cols-1 gap-4 sm:grid-cols-2", children: [
|
|
981
|
-
/* @__PURE__ */ jsxs(
|
|
982
|
-
Select,
|
|
983
|
-
{
|
|
984
|
-
value: status,
|
|
985
|
-
onValueChange: (value) => setStatus(value),
|
|
986
|
-
children: [
|
|
987
|
-
/* @__PURE__ */ jsx(Select.Trigger, { children: /* @__PURE__ */ jsx(Select.Value, { placeholder: "Status" }) }),
|
|
988
|
-
/* @__PURE__ */ jsxs(Select.Content, { children: [
|
|
989
|
-
/* @__PURE__ */ jsx(Select.Item, { value: "draft", children: "Draft" }),
|
|
990
|
-
/* @__PURE__ */ jsx(Select.Item, { value: "published", children: "Published" }),
|
|
991
|
-
/* @__PURE__ */ jsx(Select.Item, { value: "archived", children: "Archived" })
|
|
992
|
-
] })
|
|
993
|
-
]
|
|
994
|
-
}
|
|
995
|
-
),
|
|
996
|
-
/* @__PURE__ */ jsxs(
|
|
997
|
-
Select,
|
|
998
|
-
{
|
|
999
|
-
value: visibility,
|
|
1000
|
-
onValueChange: (value) => setVisibility(value),
|
|
1001
|
-
children: [
|
|
1002
|
-
/* @__PURE__ */ jsx(Select.Trigger, { children: /* @__PURE__ */ jsx(Select.Value, { placeholder: "Visibility" }) }),
|
|
1003
|
-
/* @__PURE__ */ jsxs(Select.Content, { children: [
|
|
1004
|
-
/* @__PURE__ */ jsx(Select.Item, { value: "public", children: "Public" }),
|
|
1005
|
-
/* @__PURE__ */ jsx(Select.Item, { value: "private", children: "Private" })
|
|
1006
|
-
] })
|
|
1007
|
-
]
|
|
1144
|
+
children: "Force delete"
|
|
1008
1145
|
}
|
|
1009
1146
|
)
|
|
1010
1147
|
] })
|
|
1011
|
-
]
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
/* @__PURE__ */ jsxs(Table, { children: [
|
|
1015
|
-
/* @__PURE__ */ jsx(Table.Header, { children: /* @__PURE__ */ jsxs(Table.Row, { children: [
|
|
1016
|
-
/* @__PURE__ */ jsx(Table.HeaderCell, { children: "Name" }),
|
|
1017
|
-
/* @__PURE__ */ jsx(Table.HeaderCell, { children: "Format" }),
|
|
1018
|
-
/* @__PURE__ */ jsx(Table.HeaderCell, { children: "Dimensions" }),
|
|
1019
|
-
/* @__PURE__ */ jsx(Table.HeaderCell, { children: "Size" }),
|
|
1020
|
-
/* @__PURE__ */ jsx(Table.HeaderCell, { className: "text-right", children: "Actions" })
|
|
1021
|
-
] }) }),
|
|
1022
|
-
/* @__PURE__ */ jsx(Table.Body, { children: asset.variants.map((variant) => /* @__PURE__ */ jsxs(
|
|
1023
|
-
Table.Row,
|
|
1024
|
-
{
|
|
1025
|
-
children: [
|
|
1026
|
-
/* @__PURE__ */ jsx(Table.Cell, { className: "capitalize", children: variant.preset }),
|
|
1027
|
-
/* @__PURE__ */ jsx(Table.Cell, { children: variant.format }),
|
|
1028
|
-
/* @__PURE__ */ jsx(Table.Cell, { children: variant.width && variant.height ? `${variant.width}×${variant.height}` : "-" }),
|
|
1029
|
-
/* @__PURE__ */ jsx(Table.Cell, { children: formatFileSize(variant.size_bytes) }),
|
|
1030
|
-
/* @__PURE__ */ jsx(Table.Cell, { className: "flex justify-end gap-2", children: /* @__PURE__ */ jsxs(
|
|
1031
|
-
Button,
|
|
1032
|
-
{
|
|
1033
|
-
size: "small",
|
|
1034
|
-
variant: "secondary",
|
|
1035
|
-
onClick: () => handleVariantCopy(variant.preset),
|
|
1036
|
-
children: [
|
|
1037
|
-
/* @__PURE__ */ jsx(SquareTwoStack, { className: "mr-1 size-4" }),
|
|
1038
|
-
" Copy URL"
|
|
1039
|
-
]
|
|
1040
|
-
}
|
|
1041
|
-
) })
|
|
1042
|
-
]
|
|
1043
|
-
},
|
|
1044
|
-
variant.id ?? `${variant.preset}-${variant.format}`
|
|
1045
|
-
)) })
|
|
1046
|
-
] })
|
|
1047
|
-
] }) : null,
|
|
1048
|
-
/* @__PURE__ */ jsxs("section", { className: "space-y-3", children: [
|
|
1049
|
-
/* @__PURE__ */ jsx("h3", { className: "text-sm font-medium", children: "Usage" }),
|
|
1050
|
-
assetRelations.length ? /* @__PURE__ */ jsxs(Table, { children: [
|
|
1051
|
-
/* @__PURE__ */ jsx(Table.Header, { children: /* @__PURE__ */ jsxs(Table.Row, { children: [
|
|
1052
|
-
/* @__PURE__ */ jsx(Table.HeaderCell, { children: "Entity" }),
|
|
1053
|
-
/* @__PURE__ */ jsx(Table.HeaderCell, { children: "Reference" }),
|
|
1054
|
-
/* @__PURE__ */ jsx(Table.HeaderCell, { children: "Role" })
|
|
1055
|
-
] }) }),
|
|
1056
|
-
/* @__PURE__ */ jsx(Table.Body, { children: assetRelations.map((relation) => /* @__PURE__ */ jsxs(Table.Row, { children: [
|
|
1057
|
-
/* @__PURE__ */ jsx(Table.Cell, { className: "capitalize", children: relation.entity_type }),
|
|
1058
|
-
/* @__PURE__ */ jsx(Table.Cell, { className: "font-mono text-xs", children: relation.entity_id }),
|
|
1059
|
-
/* @__PURE__ */ jsx(Table.Cell, { children: relation.relation_role })
|
|
1060
|
-
] }, relation.id)) })
|
|
1061
|
-
] }) : /* @__PURE__ */ jsx("p", { className: "text-sm text-ui-fg-subtle", children: "This asset is not linked to any entities." })
|
|
1062
|
-
] })
|
|
1063
|
-
] }) : /* @__PURE__ */ jsx("div", { className: "flex flex-1 items-center justify-center text-sm text-ui-fg-subtle", children: "Select an asset to view details." }),
|
|
1064
|
-
/* @__PURE__ */ jsxs(Drawer.Footer, { className: "mt-6 flex flex-wrap items-center justify-between gap-3", children: [
|
|
1065
|
-
/* @__PURE__ */ jsxs("div", { className: "flex gap-2", children: [
|
|
1066
|
-
/* @__PURE__ */ jsxs(
|
|
1067
|
-
Button,
|
|
1068
|
-
{
|
|
1069
|
-
type: "button",
|
|
1070
|
-
variant: "danger",
|
|
1071
|
-
onClick: () => {
|
|
1072
|
-
if (!asset) {
|
|
1073
|
-
return;
|
|
1074
|
-
}
|
|
1075
|
-
const confirmDelete = window.confirm(
|
|
1076
|
-
"Delete this asset and all generated variants?"
|
|
1077
|
-
);
|
|
1078
|
-
if (confirmDelete) {
|
|
1079
|
-
handleDelete(false);
|
|
1080
|
-
}
|
|
1081
|
-
},
|
|
1082
|
-
disabled: !asset,
|
|
1083
|
-
children: [
|
|
1084
|
-
/* @__PURE__ */ jsx(Trash, { className: "mr-1 size-4" }),
|
|
1085
|
-
" Delete"
|
|
1086
|
-
]
|
|
1087
|
-
}
|
|
1088
|
-
),
|
|
1089
|
-
/* @__PURE__ */ jsxs(
|
|
1090
|
-
Button,
|
|
1091
|
-
{
|
|
1092
|
-
type: "button",
|
|
1093
|
-
variant: "secondary",
|
|
1094
|
-
onClick: () => asset && handleVariantCopy("medium"),
|
|
1095
|
-
disabled: !asset,
|
|
1096
|
-
children: [
|
|
1097
|
-
/* @__PURE__ */ jsx(ArrowPath, { className: "mr-1 size-4" }),
|
|
1098
|
-
" Copy URL"
|
|
1099
|
-
]
|
|
1100
|
-
}
|
|
1101
|
-
)
|
|
1102
|
-
] }),
|
|
1103
|
-
/* @__PURE__ */ jsxs("div", { className: "flex gap-2", children: [
|
|
1104
|
-
/* @__PURE__ */ jsx(Button, { variant: "secondary", onClick: onClose, children: "Close" }),
|
|
1105
|
-
/* @__PURE__ */ jsx(
|
|
1106
|
-
Button,
|
|
1107
|
-
{
|
|
1108
|
-
onClick: handleSave,
|
|
1109
|
-
disabled: !asset || isSaving,
|
|
1110
|
-
isLoading: isSaving,
|
|
1111
|
-
children: "Save changes"
|
|
1112
|
-
}
|
|
1113
|
-
)
|
|
1114
|
-
] })
|
|
1115
|
-
] }),
|
|
1116
|
-
deleteAttempted && asset && /* @__PURE__ */ jsxs("div", { className: "mt-4 rounded-md border border-ui-border-base bg-ui-bg-subtle p-4 text-sm text-ui-fg-subtle", children: [
|
|
1117
|
-
/* @__PURE__ */ jsx("p", { className: "font-medium text-ui-fg-base", children: "Having trouble deleting?" }),
|
|
1118
|
-
/* @__PURE__ */ jsx("p", { className: "mt-1", children: "If the asset is still referenced, remove those relations first or attempt a force delete." }),
|
|
1119
|
-
/* @__PURE__ */ jsx(
|
|
1120
|
-
Button,
|
|
1121
|
-
{
|
|
1122
|
-
className: "mt-3",
|
|
1123
|
-
variant: "danger",
|
|
1124
|
-
size: "small",
|
|
1125
|
-
onClick: () => {
|
|
1126
|
-
const confirmForce = window.confirm(
|
|
1127
|
-
"Force delete will remove the asset even if it is still referenced. Continue?"
|
|
1128
|
-
);
|
|
1129
|
-
if (confirmForce) {
|
|
1130
|
-
handleDelete(true);
|
|
1131
|
-
}
|
|
1132
|
-
},
|
|
1133
|
-
children: "Force delete"
|
|
1134
|
-
}
|
|
1135
|
-
)
|
|
1136
|
-
] })
|
|
1137
|
-
] }) });
|
|
1148
|
+
]
|
|
1149
|
+
}
|
|
1150
|
+
) });
|
|
1138
1151
|
};
|
|
1152
|
+
const MediaAssetDrawer = MediaAssetDialog;
|
|
1139
1153
|
const PAGE_SIZE = 24;
|
|
1140
1154
|
const MediaLibraryPage = () => {
|
|
1141
1155
|
const [search, setSearch] = useState("");
|