camox 0.22.0 → 0.23.0

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.
@@ -1,14 +1,15 @@
1
1
  import { cn } from "../../../lib/utils.js";
2
+ import { transformImageUrl } from "../../../core/lib/imageTransform.js";
2
3
  import { c } from "react/compiler-runtime";
3
4
  import { jsx, jsxs } from "react/jsx-runtime";
4
5
  import { FileIcon } from "lucide-react";
5
6
 
6
7
  //#region src/features/content/components/AssetCard.tsx
7
8
  const AssetCard = (t0) => {
8
- const $ = c(26);
9
- if ($[0] !== "62dab0d9b73ffb903a48127d8b52340688d238c98cfa8a817c9ae69dc68148ec") {
10
- for (let $i = 0; $i < 26; $i += 1) $[$i] = Symbol.for("react.memo_cache_sentinel");
11
- $[0] = "62dab0d9b73ffb903a48127d8b52340688d238c98cfa8a817c9ae69dc68148ec";
9
+ const $ = c(27);
10
+ if ($[0] !== "9ecd8015db2f9718029c6f2952f71322cd0d4bdec949a22375db105de6ada5db") {
11
+ for (let $i = 0; $i < 27; $i += 1) $[$i] = Symbol.for("react.memo_cache_sentinel");
12
+ $[0] = "9ecd8015db2f9718029c6f2952f71322cd0d4bdec949a22375db105de6ada5db";
12
13
  }
13
14
  const { file, selected, onSelect, onOpen } = t0;
14
15
  let t1;
@@ -52,14 +53,17 @@ const AssetCard = (t0) => {
52
53
  $[10] = t7;
53
54
  } else t7 = $[10];
54
55
  let t8;
55
- if ($[11] !== extension || $[12] !== file.alt || $[13] !== file.filename || $[14] !== file.url || $[15] !== isImage) {
56
+ if ($[11] !== extension || $[12] !== file.alt || $[13] !== file.filename || $[14] !== file.mimeType || $[15] !== file.url || $[16] !== isImage) {
56
57
  t8 = /* @__PURE__ */ jsx("div", {
57
- className: "bg-muted flex aspect-4/3 w-full items-center justify-center overflow-hidden rounded-sm",
58
+ className: "checkered flex aspect-4/3 w-full items-center justify-center overflow-hidden rounded-sm p-1.5",
58
59
  children: isImage ? /* @__PURE__ */ jsx("img", {
59
- src: file.url,
60
+ src: transformImageUrl(file.url, {
61
+ width: 480,
62
+ mimeType: file.mimeType
63
+ }),
60
64
  alt: file.alt || file.filename,
61
65
  draggable: false,
62
- className: "pointer-events-none h-full w-full object-cover"
66
+ className: "pointer-events-none h-full w-full object-contain"
63
67
  }) : /* @__PURE__ */ jsxs("div", {
64
68
  className: "text-muted-foreground flex flex-col items-center gap-1",
65
69
  children: [/* @__PURE__ */ jsx(FileIcon, { className: "h-8 w-8" }), extension && /* @__PURE__ */ jsx("span", {
@@ -71,21 +75,22 @@ const AssetCard = (t0) => {
71
75
  $[11] = extension;
72
76
  $[12] = file.alt;
73
77
  $[13] = file.filename;
74
- $[14] = file.url;
75
- $[15] = isImage;
76
- $[16] = t8;
77
- } else t8 = $[16];
78
+ $[14] = file.mimeType;
79
+ $[15] = file.url;
80
+ $[16] = isImage;
81
+ $[17] = t8;
82
+ } else t8 = $[17];
78
83
  let t9;
79
- if ($[17] !== file.filename) {
84
+ if ($[18] !== file.filename) {
80
85
  t9 = /* @__PURE__ */ jsx("p", {
81
86
  className: "line-clamp-2 px-0.5 text-xs break-all",
82
87
  children: file.filename
83
88
  });
84
- $[17] = file.filename;
85
- $[18] = t9;
86
- } else t9 = $[18];
89
+ $[18] = file.filename;
90
+ $[19] = t9;
91
+ } else t9 = $[19];
87
92
  let t10;
88
- if ($[19] !== file.id || $[20] !== t5 || $[21] !== t6 || $[22] !== t7 || $[23] !== t8 || $[24] !== t9) {
93
+ if ($[20] !== file.id || $[21] !== t5 || $[22] !== t6 || $[23] !== t7 || $[24] !== t8 || $[25] !== t9) {
89
94
  t10 = /* @__PURE__ */ jsxs("button", {
90
95
  type: "button",
91
96
  "data-asset-id": t3,
@@ -94,14 +99,14 @@ const AssetCard = (t0) => {
94
99
  onDoubleClick: t7,
95
100
  children: [t8, t9]
96
101
  });
97
- $[19] = file.id;
98
- $[20] = t5;
99
- $[21] = t6;
100
- $[22] = t7;
101
- $[23] = t8;
102
- $[24] = t9;
103
- $[25] = t10;
104
- } else t10 = $[25];
102
+ $[20] = file.id;
103
+ $[21] = t5;
104
+ $[22] = t6;
105
+ $[23] = t7;
106
+ $[24] = t8;
107
+ $[25] = t9;
108
+ $[26] = t10;
109
+ } else t10 = $[26];
105
110
  return t10;
106
111
  };
107
112
 
@@ -1,5 +1,6 @@
1
1
  import { useProjectSlug } from "../../../lib/auth.js";
2
2
  import { projectQueries } from "../../../lib/queries.js";
3
+ import { transformImageUrl } from "../../../core/lib/imageTransform.js";
3
4
  import { UploadDropZone } from "../../content/components/UploadDropZone.js";
4
5
  import { UploadItemRow } from "../../content/components/UploadProgressDrawer.js";
5
6
  import { useFileUpload } from "../../../hooks/use-file-upload.js";
@@ -20,9 +21,9 @@ function assetLabel(isImage, multiple) {
20
21
  }
21
22
  const AssetActionButtons = (t0) => {
22
23
  const $ = c(27);
23
- if ($[0] !== "511bbc6572b1a9ed249b95be0b61223953390bf5d43cd01f6b380f115b1aadaa") {
24
+ if ($[0] !== "44259d77bb7c7c167ba0def21aa6d5d7b7d1115e4b30d38a3c3d829d0a76df91") {
24
25
  for (let $i = 0; $i < 27; $i += 1) $[$i] = Symbol.for("react.memo_cache_sentinel");
25
- $[0] = "511bbc6572b1a9ed249b95be0b61223953390bf5d43cd01f6b380f115b1aadaa";
26
+ $[0] = "44259d77bb7c7c167ba0def21aa6d5d7b7d1115e4b30d38a3c3d829d0a76df91";
26
27
  }
27
28
  const { isImage, multiple, fileInputRef, onPickerOpen, onFilesSelected, uploads } = t0;
28
29
  let t1;
@@ -125,9 +126,9 @@ const AssetActionButtons = (t0) => {
125
126
  };
126
127
  const SingleAssetFieldEditor = (t0) => {
127
128
  const $ = c(29);
128
- if ($[0] !== "511bbc6572b1a9ed249b95be0b61223953390bf5d43cd01f6b380f115b1aadaa") {
129
+ if ($[0] !== "44259d77bb7c7c167ba0def21aa6d5d7b7d1115e4b30d38a3c3d829d0a76df91") {
129
130
  for (let $i = 0; $i < 29; $i += 1) $[$i] = Symbol.for("react.memo_cache_sentinel");
130
- $[0] = "511bbc6572b1a9ed249b95be0b61223953390bf5d43cd01f6b380f115b1aadaa";
131
+ $[0] = "44259d77bb7c7c167ba0def21aa6d5d7b7d1115e4b30d38a3c3d829d0a76df91";
131
132
  }
132
133
  const { fieldName, assetType, currentData, onFieldChange } = t0;
133
134
  const asset = currentData[fieldName];
@@ -207,7 +208,10 @@ const SingleAssetFieldEditor = (t0) => {
207
208
  children: [isImage ? /* @__PURE__ */ jsx("div", {
208
209
  className: "border-border h-10 w-10 shrink-0 overflow-hidden rounded border",
209
210
  children: /* @__PURE__ */ jsx("img", {
210
- src: asset.url,
211
+ src: transformImageUrl(asset.url, {
212
+ width: 128,
213
+ mimeType: asset.mimeType
214
+ }),
211
215
  alt: asset.alt || asset.filename,
212
216
  className: "h-full w-full object-cover"
213
217
  })
@@ -2,6 +2,7 @@ import { trackClientEvent } from "../../../lib/telemetry-client.js";
2
2
  import { getAuthCookieHeader } from "../../../lib/auth.js";
3
3
  import { getApiUrl, getEnvironmentName } from "../../../lib/api-client.js";
4
4
  import { fileMutations, fileQueries } from "../../../lib/queries.js";
5
+ import { isRasterImage, transformImageUrl } from "../../../core/lib/imageTransform.js";
5
6
  import { DebouncedFieldEditor } from "./DebouncedFieldEditor.js";
6
7
  import { UploadDropZone } from "../../content/components/UploadDropZone.js";
7
8
  import { c } from "react/compiler-runtime";
@@ -9,10 +10,10 @@ import { Label } from "@camox/ui/label";
9
10
  import { toast } from "@camox/ui/toaster";
10
11
  import { useMutation, useQuery } from "@tanstack/react-query";
11
12
  import { useCallback, useEffect, useRef, useState } from "react";
12
- import { jsx, jsxs } from "react/jsx-runtime";
13
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
13
14
  import { Button } from "@camox/ui/button";
14
15
  import { Tooltip, TooltipContent, TooltipTrigger } from "@camox/ui/tooltip";
15
- import { Check, Download, FileIcon, Link, Loader2, Trash2, X } from "lucide-react";
16
+ import { Check, Download, FileIcon, Info, Link, Loader2, Trash2, X } from "lucide-react";
16
17
  import { Dialog, DialogContent, DialogTitle } from "@camox/ui/dialog";
17
18
  import { Switch } from "@camox/ui/switch";
18
19
  import { ButtonGroup } from "@camox/ui/button-group";
@@ -20,9 +21,9 @@ import { ButtonGroup } from "@camox/ui/button-group";
20
21
  //#region src/features/preview/components/AssetLightbox.tsx
21
22
  function MetadataRow(t0) {
22
23
  const $ = c(9);
23
- if ($[0] !== "37940925d91368c87c0e95d97da969b420d7241705fd90761ebca29def086c1e") {
24
+ if ($[0] !== "50fbf2f7ee8a6e8b4452e53c7c776c76cf2aa2926c13218fcc4664012d02ad9a") {
24
25
  for (let $i = 0; $i < 9; $i += 1) $[$i] = Symbol.for("react.memo_cache_sentinel");
25
- $[0] = "37940925d91368c87c0e95d97da969b420d7241705fd90761ebca29def086c1e";
26
+ $[0] = "50fbf2f7ee8a6e8b4452e53c7c776c76cf2aa2926c13218fcc4664012d02ad9a";
26
27
  }
27
28
  const { label, children } = t0;
28
29
  let t1;
@@ -64,6 +65,116 @@ function MetadataRow(t0) {
64
65
  } else t4 = $[8];
65
66
  return t4;
66
67
  }
68
+ function DeliveredSize(t0) {
69
+ const $ = c(16);
70
+ if ($[0] !== "50fbf2f7ee8a6e8b4452e53c7c776c76cf2aa2926c13218fcc4664012d02ad9a") {
71
+ for (let $i = 0; $i < 16; $i += 1) $[$i] = Symbol.for("react.memo_cache_sentinel");
72
+ $[0] = "50fbf2f7ee8a6e8b4452e53c7c776c76cf2aa2926c13218fcc4664012d02ad9a";
73
+ }
74
+ const { bytes, raw } = t0;
75
+ if (bytes == null) {
76
+ let t1;
77
+ if ($[1] === Symbol.for("react.memo_cache_sentinel")) {
78
+ t1 = /* @__PURE__ */ jsx(Fragment, { children: "…" });
79
+ $[1] = t1;
80
+ } else t1 = $[1];
81
+ return t1;
82
+ }
83
+ let t1;
84
+ if ($[2] !== bytes || $[3] !== raw) {
85
+ t1 = raw != null && raw > 0 ? Math.round((raw - bytes) / raw * 100) : null;
86
+ $[2] = bytes;
87
+ $[3] = raw;
88
+ $[4] = t1;
89
+ } else t1 = $[4];
90
+ const savingsPct = t1;
91
+ if (savingsPct == null || savingsPct <= 0) {
92
+ let t2;
93
+ if ($[5] !== bytes) {
94
+ t2 = formatFileSize(bytes);
95
+ $[5] = bytes;
96
+ $[6] = t2;
97
+ } else t2 = $[6];
98
+ let t3;
99
+ if ($[7] !== t2) {
100
+ t3 = /* @__PURE__ */ jsxs(Fragment, { children: ["≈", t2] });
101
+ $[7] = t2;
102
+ $[8] = t3;
103
+ } else t3 = $[8];
104
+ return t3;
105
+ }
106
+ let t2;
107
+ if ($[9] !== bytes) {
108
+ t2 = formatFileSize(bytes);
109
+ $[9] = bytes;
110
+ $[10] = t2;
111
+ } else t2 = $[10];
112
+ let t3;
113
+ if ($[11] !== savingsPct) {
114
+ t3 = /* @__PURE__ */ jsxs("span", {
115
+ className: "text-muted-foreground",
116
+ children: [
117
+ "(−",
118
+ savingsPct,
119
+ "%)"
120
+ ]
121
+ });
122
+ $[11] = savingsPct;
123
+ $[12] = t3;
124
+ } else t3 = $[12];
125
+ let t4;
126
+ if ($[13] !== t2 || $[14] !== t3) {
127
+ t4 = /* @__PURE__ */ jsxs(Fragment, { children: [
128
+ "≈",
129
+ t2,
130
+ " ",
131
+ t3
132
+ ] });
133
+ $[13] = t2;
134
+ $[14] = t3;
135
+ $[15] = t4;
136
+ } else t4 = $[15];
137
+ return t4;
138
+ }
139
+ function DeliveredLabel(t0) {
140
+ const $ = c(4);
141
+ if ($[0] !== "50fbf2f7ee8a6e8b4452e53c7c776c76cf2aa2926c13218fcc4664012d02ad9a") {
142
+ for (let $i = 0; $i < 4; $i += 1) $[$i] = Symbol.for("react.memo_cache_sentinel");
143
+ $[0] = "50fbf2f7ee8a6e8b4452e53c7c776c76cf2aa2926c13218fcc4664012d02ad9a";
144
+ }
145
+ const { children } = t0;
146
+ let t1;
147
+ if ($[1] === Symbol.for("react.memo_cache_sentinel")) {
148
+ t1 = /* @__PURE__ */ jsxs(Tooltip, { children: [/* @__PURE__ */ jsx(TooltipTrigger, {
149
+ render: /* @__PURE__ */ jsx("button", {
150
+ type: "button",
151
+ className: "text-muted-foreground hover:text-foreground",
152
+ "aria-label": "About image optimization"
153
+ }),
154
+ children: /* @__PURE__ */ jsx(Info, { className: "h-3.5 w-3.5" })
155
+ }), /* @__PURE__ */ jsxs(TooltipContent, {
156
+ className: "max-w-xs",
157
+ children: [
158
+ "Visitors automatically receive a compressed WebP/AVIF version sized to their device. Estimates use ",
159
+ DELIVERED_PHONE_WIDTH,
160
+ "px (phone) and ",
161
+ DELIVERED_LAPTOP_WIDTH,
162
+ "px (laptop) — the original is preserved."
163
+ ]
164
+ })] });
165
+ $[1] = t1;
166
+ } else t1 = $[1];
167
+ let t2;
168
+ if ($[2] !== children) {
169
+ t2 = /* @__PURE__ */ jsxs("span", {
170
+ className: "inline-flex items-center gap-1",
171
+ children: [children, t1]
172
+ });
173
+ $[2] = children;
174
+ $[3] = t2;
175
+ } else t2 = $[3];
176
+ return t2;
177
+ }
67
178
  function formatRelativeTime(epochMs) {
68
179
  const now = Temporal.Now.instant();
69
180
  const then = Temporal.Instant.fromEpochMilliseconds(epochMs);
@@ -86,6 +197,20 @@ function formatFileSize(bytes) {
86
197
  if (bytes < 1024 * 1024 * 1024) return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
87
198
  return `${(bytes / (1024 * 1024 * 1024)).toFixed(1)} GB`;
88
199
  }
200
+ const DELIVERED_PHONE_WIDTH = 640;
201
+ const DELIVERED_LAPTOP_WIDTH = 1280;
202
+ async function measureContentLength(url, signal) {
203
+ try {
204
+ const res = await fetch(url, { signal });
205
+ res.body?.cancel();
206
+ const cl = res.headers.get("content-length");
207
+ if (!cl) return null;
208
+ const parsed = Number.parseInt(cl, 10);
209
+ return Number.isFinite(parsed) ? parsed : null;
210
+ } catch {
211
+ return null;
212
+ }
213
+ }
89
214
  const AssetLightbox = ({ open, onOpenChange, fileId }) => {
90
215
  const replaceFile = useMutation(fileMutations.replace());
91
216
  const deleteFile = useMutation(fileMutations.delete());
@@ -100,12 +225,55 @@ const AssetLightbox = ({ open, onOpenChange, fileId }) => {
100
225
  const [zoomed, setZoomed] = useState(false);
101
226
  const [zoomedWidth, setZoomedWidth] = useState(null);
102
227
  const clickFractionRef = useRef(null);
228
+ const [deliveredSizes, setDeliveredSizes] = useState(null);
103
229
  useEffect(() => {
104
230
  if (!open) {
105
231
  setZoomed(false);
106
232
  setZoomedWidth(null);
107
233
  }
108
234
  }, [open]);
235
+ const isImage = file?.mimeType?.startsWith("image/") ?? false;
236
+ const canUseAiMetadata = isRasterImage(file?.mimeType);
237
+ const fileUrl = file?.url;
238
+ const fileMimeType = file?.mimeType;
239
+ useEffect(() => {
240
+ if (!open || !isImage || !fileUrl) {
241
+ setDeliveredSizes(null);
242
+ return;
243
+ }
244
+ const phoneUrl = transformImageUrl(fileUrl, {
245
+ width: DELIVERED_PHONE_WIDTH,
246
+ mimeType: fileMimeType
247
+ });
248
+ const laptopUrl = transformImageUrl(fileUrl, {
249
+ width: DELIVERED_LAPTOP_WIDTH,
250
+ mimeType: fileMimeType
251
+ });
252
+ if (phoneUrl === fileUrl && laptopUrl === fileUrl) {
253
+ setDeliveredSizes(null);
254
+ return;
255
+ }
256
+ setDeliveredSizes({
257
+ phone: null,
258
+ laptop: null,
259
+ measured: false
260
+ });
261
+ const controller = new AbortController();
262
+ Promise.all([measureContentLength(phoneUrl, controller.signal), measureContentLength(laptopUrl, controller.signal)]).then(([phone, laptop]) => {
263
+ if (controller.signal.aborted) return;
264
+ setDeliveredSizes({
265
+ phone,
266
+ laptop,
267
+ measured: true
268
+ });
269
+ });
270
+ return () => controller.abort();
271
+ }, [
272
+ open,
273
+ isImage,
274
+ fileUrl,
275
+ fileMimeType
276
+ ]);
109
277
  useEffect(() => {
110
278
  if (!zoomed || !zoomedWidth || !containerRef.current || !clickFractionRef.current) return;
111
279
  const container = containerRef.current;
@@ -194,7 +362,6 @@ const AssetLightbox = ({ open, onOpenChange, fileId }) => {
194
362
  onOpenChange(false);
195
363
  };
196
364
  if (!file) return null;
197
- const isImage = file.mimeType?.startsWith("image/");
198
365
  return /* @__PURE__ */ jsx(Dialog, {
199
366
  open,
200
367
  onOpenChange,
@@ -340,11 +507,12 @@ const AssetLightbox = ({ open, onOpenChange, fileId }) => {
340
507
  children: /* @__PURE__ */ jsx(Trash2, {})
341
508
  }), /* @__PURE__ */ jsx(TooltipContent, { children: "Delete" })] })
342
509
  ] }),
343
- /* @__PURE__ */ jsxs("div", {
344
- className: "flex items-center gap-2",
510
+ /* @__PURE__ */ jsxs(Tooltip, { children: [/* @__PURE__ */ jsxs(TooltipTrigger, {
511
+ render: /* @__PURE__ */ jsx("div", { className: `flex items-center gap-2 ${canUseAiMetadata ? "" : "cursor-not-allowed"}` }),
345
512
  children: [/* @__PURE__ */ jsx(Switch, {
346
513
  id: "ai-metadata",
347
- checked: file.aiMetadataEnabled !== false,
514
+ disabled: !canUseAiMetadata,
515
+ checked: canUseAiMetadata && file.aiMetadataEnabled !== false,
348
516
  onCheckedChange: (checked) => {
349
517
  setAiMetadata.mutate({
350
518
  id: fileId,
@@ -359,14 +527,15 @@ const AssetLightbox = ({ open, onOpenChange, fileId }) => {
359
527
  }
360
528
  }), /* @__PURE__ */ jsx(Label, {
361
529
  htmlFor: "ai-metadata",
530
+ className: canUseAiMetadata ? "" : "text-muted-foreground",
362
531
  children: "AI metadata"
363
532
  })]
364
- }),
533
+ }), !canUseAiMetadata && /* @__PURE__ */ jsx(TooltipContent, { children: "AI metadata is only available for raster images." })] }),
365
534
  /* @__PURE__ */ jsx(DebouncedFieldEditor, {
366
535
  label: "File name",
367
536
  placeholder: "File name...",
368
537
  initialValue: file.filename,
369
- disabled: file.aiMetadataEnabled !== false,
538
+ disabled: canUseAiMetadata && file.aiMetadataEnabled !== false,
370
539
  onSave: (value) => setFilename.mutate({
371
540
  id: fileId,
372
541
  filename: value
@@ -376,7 +545,7 @@ const AssetLightbox = ({ open, onOpenChange, fileId }) => {
376
545
  label: "Alt text",
377
546
  placeholder: "Describe this file...",
378
547
  initialValue: file.alt,
379
- disabled: file.aiMetadataEnabled !== false,
548
+ disabled: canUseAiMetadata && file.aiMetadataEnabled !== false,
380
549
  rows: 2,
381
550
  onSave: (value_0) => setAlt.mutate({
382
551
  id: fileId,
@@ -391,9 +560,22 @@ const AssetLightbox = ({ open, onOpenChange, fileId }) => {
391
560
  children: file.mimeType.split("/").pop()?.toUpperCase() ?? "Unknown"
392
561
  }),
393
562
  /* @__PURE__ */ jsx(MetadataRow, {
394
- label: "Size",
563
+ label: "Raw size",
395
564
  children: file.size != null ? formatFileSize(file.size) : "Unknown"
396
565
  }),
566
+ isImage && deliveredSizes && /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(MetadataRow, {
567
+ label: /* @__PURE__ */ jsx(DeliveredLabel, { children: "On phone" }),
568
+ children: /* @__PURE__ */ jsx(DeliveredSize, {
569
+ bytes: deliveredSizes.phone,
570
+ raw: file.size
571
+ })
572
+ }), /* @__PURE__ */ jsx(MetadataRow, {
573
+ label: /* @__PURE__ */ jsx(DeliveredLabel, { children: "On laptop" }),
574
+ children: /* @__PURE__ */ jsx(DeliveredSize, {
575
+ bytes: deliveredSizes.laptop,
576
+ raw: file.size
577
+ })
578
+ })] }),
397
579
  /* @__PURE__ */ jsx(MetadataRow, {
398
580
  label: "Created",
399
581
  children: formatRelativeTime(file.createdAt)
@@ -24,16 +24,15 @@ const getSchemaFieldsInOrder = (schema) => {
24
24
  fieldType: prop.fieldType,
25
25
  label: prop.title,
26
26
  minItems: prop.minItems,
27
- maxItems: prop.maxItems,
28
- arrayItemType: prop.arrayItemType
27
+ maxItems: prop.maxItems
29
28
  };
30
29
  });
31
30
  };
32
31
  const DrillRow = (t0) => {
33
32
  const $ = c(28);
34
- if ($[0] !== "15f9ee4a513b843fbbfefffb10bc5ae0ad53bad634945c9c8e78821de81003d0") {
33
+ if ($[0] !== "10d7e880adc2a5d4d4076a1bdf35fee064c2b42cd42d45b2991c5ebaf6c4d95d") {
35
34
  for (let $i = 0; $i < 28; $i += 1) $[$i] = Symbol.for("react.memo_cache_sentinel");
36
- $[0] = "15f9ee4a513b843fbbfefffb10bc5ae0ad53bad634945c9c8e78821de81003d0";
35
+ $[0] = "10d7e880adc2a5d4d4076a1bdf35fee064c2b42cd42d45b2991c5ebaf6c4d95d";
37
36
  }
38
37
  const { label, preview, Icon, onClick, hover, postToIframe } = t0;
39
38
  let t1;
@@ -136,9 +135,9 @@ const DrillRow = (t0) => {
136
135
  };
137
136
  const ItemFieldsEditor = (t0) => {
138
137
  const $ = c(47);
139
- if ($[0] !== "15f9ee4a513b843fbbfefffb10bc5ae0ad53bad634945c9c8e78821de81003d0") {
138
+ if ($[0] !== "10d7e880adc2a5d4d4076a1bdf35fee064c2b42cd42d45b2991c5ebaf6c4d95d") {
140
139
  for (let $i = 0; $i < 47; $i += 1) $[$i] = Symbol.for("react.memo_cache_sentinel");
141
- $[0] = "15f9ee4a513b843fbbfefffb10bc5ae0ad53bad634945c9c8e78821de81003d0";
140
+ $[0] = "10d7e880adc2a5d4d4076a1bdf35fee064c2b42cd42d45b2991c5ebaf6c4d95d";
142
141
  }
143
142
  const { schema, data, blockId, itemId, onFieldChange, postToIframe, filesMap, itemsMap, fieldIdPrefix, autoFocusFieldName } = t0;
144
143
  let t1;
@@ -384,10 +383,10 @@ const ItemFieldsEditor = (t0) => {
384
383
  postToIframe
385
384
  }, field.name);
386
385
  }
387
- if (field.fieldType === "MultipleAssets") {
386
+ if (field.fieldType === "ImageList" || field.fieldType === "FileList") {
388
387
  const value_1 = data[field.name];
389
388
  const count = Array.isArray(value_1) ? value_1.length : 0;
390
- const isImage = field.arrayItemType === "Image";
389
+ const isImage = field.fieldType === "ImageList";
391
390
  const noun = isImage ? "image" : "file";
392
391
  let preview_0;
393
392
  if (count === 0) preview_0 = isImage ? "No images" : "No files";
@@ -434,7 +433,7 @@ const ItemFieldsEditor = (t0) => {
434
433
  postToIframe
435
434
  }, field.name);
436
435
  }
437
- if (field.fieldType === "RepeatableItem") {
436
+ if (field.fieldType === "Repeater") {
438
437
  const items = (data[field.name] ?? []).map((item) => {
439
438
  if (isItemMarker(item)) return itemsMap.get(item._itemId) ?? null;
440
439
  return item;
@@ -1,6 +1,7 @@
1
1
  import { useProjectSlug } from "../../../lib/auth.js";
2
2
  import { projectQueries } from "../../../lib/queries.js";
3
3
  import { cn } from "../../../lib/utils.js";
4
+ import { transformImageUrl } from "../../../core/lib/imageTransform.js";
4
5
  import { UploadDropZone } from "../../content/components/UploadDropZone.js";
5
6
  import { useFileUpload } from "../../../hooks/use-file-upload.js";
6
7
  import { AssetLightbox } from "./AssetLightbox.js";
@@ -20,10 +21,10 @@ import { CSS } from "@dnd-kit/utilities";
20
21
 
21
22
  //#region src/features/preview/components/MultipleAssetFieldEditor.tsx
22
23
  const SortableAssetItem = (t0) => {
23
- const $ = c(43);
24
- if ($[0] !== "4a9a772ea33768d0b437f29310be43cbb00f08bde5995fde9df846193f68d652") {
25
- for (let $i = 0; $i < 43; $i += 1) $[$i] = Symbol.for("react.memo_cache_sentinel");
26
- $[0] = "4a9a772ea33768d0b437f29310be43cbb00f08bde5995fde9df846193f68d652";
24
+ const $ = c(44);
25
+ if ($[0] !== "2cded293bac7099a2f0d21d69f3d54cce48c76ba242f02366ecaa807b6b79b7d") {
26
+ for (let $i = 0; $i < 44; $i += 1) $[$i] = Symbol.for("react.memo_cache_sentinel");
27
+ $[0] = "2cded293bac7099a2f0d21d69f3d54cce48c76ba242f02366ecaa807b6b79b7d";
27
28
  }
28
29
  const { asset, assetType, onRemove, onAssetOpen } = t0;
29
30
  const t1 = String(asset._fileId);
@@ -89,11 +90,14 @@ const SortableAssetItem = (t0) => {
89
90
  $[17] = t10;
90
91
  } else t10 = $[17];
91
92
  let t11;
92
- if ($[18] !== asset.alt || $[19] !== asset.filename || $[20] !== asset.url || $[21] !== assetType) {
93
+ if ($[18] !== asset.alt || $[19] !== asset.filename || $[20] !== asset.mimeType || $[21] !== asset.url || $[22] !== assetType) {
93
94
  t11 = assetType === "Image" ? /* @__PURE__ */ jsx("div", {
94
95
  className: "border-border h-12 w-12 shrink-0 overflow-hidden rounded border",
95
96
  children: /* @__PURE__ */ jsx("img", {
96
- src: asset.url,
97
+ src: transformImageUrl(asset.url, {
98
+ width: 128,
99
+ mimeType: asset.mimeType
100
+ }),
97
101
  alt: asset.alt || asset.filename,
98
102
  className: "h-full w-full object-cover"
99
103
  })
@@ -103,55 +107,56 @@ const SortableAssetItem = (t0) => {
103
107
  });
104
108
  $[18] = asset.alt;
105
109
  $[19] = asset.filename;
106
- $[20] = asset.url;
107
- $[21] = assetType;
108
- $[22] = t11;
109
- } else t11 = $[22];
110
+ $[20] = asset.mimeType;
111
+ $[21] = asset.url;
112
+ $[22] = assetType;
113
+ $[23] = t11;
114
+ } else t11 = $[23];
110
115
  const t12 = asset.filename || "Untitled";
111
116
  let t13;
112
- if ($[23] !== asset.filename || $[24] !== t12) {
117
+ if ($[24] !== asset.filename || $[25] !== t12) {
113
118
  t13 = /* @__PURE__ */ jsx("p", {
114
119
  className: "flex-1 truncate text-left text-sm",
115
120
  title: asset.filename,
116
121
  children: t12
117
122
  });
118
- $[23] = asset.filename;
119
- $[24] = t12;
120
- $[25] = t13;
121
- } else t13 = $[25];
123
+ $[24] = asset.filename;
124
+ $[25] = t12;
125
+ $[26] = t13;
126
+ } else t13 = $[26];
122
127
  let t14;
123
- if ($[26] !== t10 || $[27] !== t11 || $[28] !== t13) {
128
+ if ($[27] !== t10 || $[28] !== t11 || $[29] !== t13) {
124
129
  t14 = /* @__PURE__ */ jsxs("button", {
125
130
  type: "button",
126
131
  className: "flex min-w-0 flex-1 cursor-zoom-in items-center gap-2",
127
132
  onClick: t10,
128
133
  children: [t11, t13]
129
134
  });
130
- $[26] = t10;
131
- $[27] = t11;
132
- $[28] = t13;
133
- $[29] = t14;
134
- } else t14 = $[29];
135
+ $[27] = t10;
136
+ $[28] = t11;
137
+ $[29] = t13;
138
+ $[30] = t14;
139
+ } else t14 = $[30];
135
140
  let t15;
136
- if ($[30] !== asset._fileId || $[31] !== onRemove) {
141
+ if ($[31] !== asset._fileId || $[32] !== onRemove) {
137
142
  t15 = () => onRemove(asset._fileId);
138
- $[30] = asset._fileId;
139
- $[31] = onRemove;
140
- $[32] = t15;
141
- } else t15 = $[32];
143
+ $[31] = asset._fileId;
144
+ $[32] = onRemove;
145
+ $[33] = t15;
146
+ } else t15 = $[33];
142
147
  let t16;
143
- if ($[33] !== asset._fileId || $[34] !== t15) {
148
+ if ($[34] !== asset._fileId || $[35] !== t15) {
144
149
  t16 = /* @__PURE__ */ jsx(UnlinkAssetButton, {
145
150
  fileId: asset._fileId,
146
151
  onUnlink: t15,
147
152
  className: "hidden group-focus-within:flex group-hover:flex"
148
153
  });
149
- $[33] = asset._fileId;
150
- $[34] = t15;
151
- $[35] = t16;
152
- } else t16 = $[35];
154
+ $[34] = asset._fileId;
155
+ $[35] = t15;
156
+ $[36] = t16;
157
+ } else t16 = $[36];
153
158
  let t17;
154
- if ($[36] !== setNodeRef || $[37] !== style || $[38] !== t14 || $[39] !== t16 || $[40] !== t7 || $[41] !== t9) {
159
+ if ($[37] !== setNodeRef || $[38] !== style || $[39] !== t14 || $[40] !== t16 || $[41] !== t7 || $[42] !== t9) {
155
160
  t17 = /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsxs("div", {
156
161
  ref: setNodeRef,
157
162
  style,
@@ -162,21 +167,21 @@ const SortableAssetItem = (t0) => {
162
167
  t16
163
168
  ]
164
169
  }) });
165
- $[36] = setNodeRef;
166
- $[37] = style;
167
- $[38] = t14;
168
- $[39] = t16;
169
- $[40] = t7;
170
- $[41] = t9;
171
- $[42] = t17;
172
- } else t17 = $[42];
170
+ $[37] = setNodeRef;
171
+ $[38] = style;
172
+ $[39] = t14;
173
+ $[40] = t16;
174
+ $[41] = t7;
175
+ $[42] = t9;
176
+ $[43] = t17;
177
+ } else t17 = $[43];
173
178
  return t17;
174
179
  };
175
180
  const MultipleAssetFieldEditor = (t0) => {
176
181
  const $ = c(12);
177
- if ($[0] !== "4a9a772ea33768d0b437f29310be43cbb00f08bde5995fde9df846193f68d652") {
182
+ if ($[0] !== "2cded293bac7099a2f0d21d69f3d54cce48c76ba242f02366ecaa807b6b79b7d") {
178
183
  for (let $i = 0; $i < 12; $i += 1) $[$i] = Symbol.for("react.memo_cache_sentinel");
179
- $[0] = "4a9a772ea33768d0b437f29310be43cbb00f08bde5995fde9df846193f68d652";
184
+ $[0] = "2cded293bac7099a2f0d21d69f3d54cce48c76ba242f02366ecaa807b6b79b7d";
180
185
  }
181
186
  const { fieldName, assetType, currentData, onFieldChange } = t0;
182
187
  const isImage = assetType === "Image";
@@ -35,8 +35,7 @@ const getSettingsFields = (schema) => {
35
35
  fieldType: prop.fieldType,
36
36
  label: prop.title,
37
37
  enumLabels: prop.enumLabels,
38
- enumValues: prop.enum,
39
- arrayItemType: prop.arrayItemType
38
+ enumValues: prop.enum
40
39
  };
41
40
  });
42
41
  };
@@ -211,7 +210,7 @@ const PageContentSheet = () => {
211
210
  const isMultipleAsset = React.useMemo(() => {
212
211
  if (!isViewingAsset || !assetFieldName) return false;
213
212
  const prop = currentSchema?.properties?.[assetFieldName];
214
- return prop?.arrayItemType === "Image" || prop?.arrayItemType === "File";
213
+ return prop?.fieldType === "ImageList" || prop?.fieldType === "FileList";
215
214
  }, [
216
215
  isViewingAsset,
217
216
  assetFieldName,