@thetechfossil/upfiles 1.0.11 → 1.0.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -1,15 +1,20 @@
1
+ import * as React4 from 'react';
2
+ import React4__default, { useRef, useMemo, useState, useCallback, useEffect } from 'react';
3
+ import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
4
+ import * as Dialog2 from '@radix-ui/react-dialog';
5
+
1
6
  // src/client.ts
2
7
  var UpfilesClient = class {
3
8
  constructor(opts) {
4
9
  this.baseUrl = opts.baseUrl?.replace(/\/$/, "");
5
- this.presignPath = opts.presignPath ?? "/api/plugin/upload/presigned-url";
10
+ this.presignPath = opts.presignPath ?? "/api/plugin/upload";
6
11
  this.presignUrl = opts.presignUrl;
7
12
  this.headers = opts.headers;
8
13
  this.withCredentials = opts.withCredentials;
9
14
  this.apiKey = opts.apiKey;
10
15
  this.apiKeyHeader = opts.apiKeyHeader ?? "authorization";
11
16
  this.thumbnailsPath = opts.thumbnailsPath ?? "/api/plugin/thumbnails";
12
- this.completionPath = opts.completionPath ?? "/api/plugin/upload/complete";
17
+ this.completionPath = opts.completionPath ?? "/api/plugin/files";
13
18
  this.foldersPath = opts.foldersPath ?? "/api/plugin/folders";
14
19
  this.callCompletionEndpoint = opts.callCompletionEndpoint ?? false;
15
20
  }
@@ -285,8 +290,7 @@ var UpfilesClient = class {
285
290
  };
286
291
  }
287
292
  getEventsUrl(projectId) {
288
- const basePath = this.thumbnailsPath.replace(/\/thumbnails$/, "");
289
- const eventsPath = `${basePath}/events`;
293
+ this.thumbnailsPath.replace(/\/thumbnails$/, "");
290
294
  const target = this.baseUrl ? `${this.baseUrl}/api/events` : "/api/events";
291
295
  const url = new URL(target, window.location.href);
292
296
  if (this.apiKey) {
@@ -298,10 +302,6 @@ var UpfilesClient = class {
298
302
  return url.toString();
299
303
  }
300
304
  };
301
-
302
- // src/Uploader.tsx
303
- import React, { useCallback, useMemo, useRef, useState } from "react";
304
- import { jsx, jsxs } from "react/jsx-runtime";
305
305
  var Uploader = ({
306
306
  clientOptions,
307
307
  multiple = true,
@@ -468,7 +468,7 @@ var Uploader = ({
468
468
  setIsUploading(false);
469
469
  }
470
470
  }, [files, onComplete, onError, uploadOne]);
471
- React.useEffect(() => {
471
+ React4__default.useEffect(() => {
472
472
  if (autoUpload && files.some((f2) => f2.status === "pending") && !isUploading) {
473
473
  const timer = setTimeout(() => {
474
474
  uploadAll();
@@ -626,10 +626,6 @@ var Uploader = ({
626
626
  ] })
627
627
  ] });
628
628
  };
629
-
630
- // src/ProjectFilesWidget.tsx
631
- import React2, { useEffect, useMemo as useMemo2, useState as useState2 } from "react";
632
- import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
633
629
  var ProjectFilesWidget = ({
634
630
  clientOptions,
635
631
  folderPath,
@@ -645,16 +641,16 @@ var ProjectFilesWidget = ({
645
641
  showDelete = false,
646
642
  refreshInterval = 5e3
647
643
  }) => {
648
- const client = useMemo2(() => new UpfilesClient(clientOptions ?? {}), [clientOptions]);
649
- const [files, setFiles] = useState2([]);
650
- const [loading, setLoading] = useState2(false);
651
- const [error, setError] = useState2(null);
652
- const [query, setQuery] = useState2("");
653
- const [savingKey, setSavingKey] = useState2(null);
654
- const [deletingKey, setDeletingKey] = useState2(null);
655
- const lastUpdatedRef = React2.useRef(null);
656
- const isFetchingRef = React2.useRef(false);
657
- const fetchFiles = React2.useCallback(async (isPolling = false) => {
644
+ const client = useMemo(() => new UpfilesClient(clientOptions ?? {}), [clientOptions]);
645
+ const [files, setFiles] = useState([]);
646
+ const [loading, setLoading] = useState(false);
647
+ const [error, setError] = useState(null);
648
+ const [query, setQuery] = useState("");
649
+ const [savingKey, setSavingKey] = useState(null);
650
+ const [deletingKey, setDeletingKey] = useState(null);
651
+ const lastUpdatedRef = React4__default.useRef(null);
652
+ const isFetchingRef = React4__default.useRef(false);
653
+ const fetchFiles = React4__default.useCallback(async (isPolling = false) => {
658
654
  if (isFetchingRef.current) return;
659
655
  isFetchingRef.current = true;
660
656
  if (!isPolling) setLoading(true);
@@ -722,9 +718,9 @@ var ProjectFilesWidget = ({
722
718
  setDeletingKey(null);
723
719
  }
724
720
  };
725
- return /* @__PURE__ */ jsxs2("div", { className, children: [
726
- /* @__PURE__ */ jsxs2("div", { style: { display: "flex", gap: 8, alignItems: "center", marginBottom: 8 }, children: [
727
- /* @__PURE__ */ jsx2(
721
+ return /* @__PURE__ */ jsxs("div", { className, children: [
722
+ /* @__PURE__ */ jsxs("div", { style: { display: "flex", gap: 8, alignItems: "center", marginBottom: 8 }, children: [
723
+ /* @__PURE__ */ jsx(
728
724
  "input",
729
725
  {
730
726
  type: "text",
@@ -734,7 +730,7 @@ var ProjectFilesWidget = ({
734
730
  style: { flex: 1, padding: 8, border: "1px solid #e5e7eb", borderRadius: 6 }
735
731
  }
736
732
  ),
737
- /* @__PURE__ */ jsx2(
733
+ /* @__PURE__ */ jsx(
738
734
  "button",
739
735
  {
740
736
  onClick: () => {
@@ -746,26 +742,26 @@ var ProjectFilesWidget = ({
746
742
  }
747
743
  )
748
744
  ] }),
749
- loading && /* @__PURE__ */ jsx2("div", { style: { fontSize: 12, color: "#666" }, children: "Loading files\u2026" }),
750
- error && /* @__PURE__ */ jsx2("div", { style: { fontSize: 12, color: "#b91c1c" }, children: error }),
751
- !loading && !error && /* @__PURE__ */ jsxs2("ul", { className: listClassName, style: { listStyle: "none", padding: 0, margin: 0, display: "grid", gap: 8 }, children: [
752
- visible.map((f2) => /* @__PURE__ */ jsxs2(
745
+ loading && /* @__PURE__ */ jsx("div", { style: { fontSize: 12, color: "#666" }, children: "Loading files\u2026" }),
746
+ error && /* @__PURE__ */ jsx("div", { style: { fontSize: 12, color: "#b91c1c" }, children: error }),
747
+ !loading && !error && /* @__PURE__ */ jsxs("ul", { className: listClassName, style: { listStyle: "none", padding: 0, margin: 0, display: "grid", gap: 8 }, children: [
748
+ visible.map((f2) => /* @__PURE__ */ jsxs(
753
749
  "li",
754
750
  {
755
751
  className: itemClassName,
756
752
  style: { border: "1px solid #e5e7eb", borderRadius: 8, padding: 10, display: "flex", justifyContent: "space-between", alignItems: "center" },
757
753
  children: [
758
- /* @__PURE__ */ jsxs2("div", { style: { minWidth: 0 }, children: [
759
- /* @__PURE__ */ jsx2("div", { style: { fontWeight: 500, overflow: "hidden", textOverflow: "ellipsis" }, children: f2.originalName }),
760
- /* @__PURE__ */ jsxs2("div", { style: { fontSize: 12, color: "#666" }, children: [
754
+ /* @__PURE__ */ jsxs("div", { style: { minWidth: 0 }, children: [
755
+ /* @__PURE__ */ jsx("div", { style: { fontWeight: 500, overflow: "hidden", textOverflow: "ellipsis" }, children: f2.originalName }),
756
+ /* @__PURE__ */ jsxs("div", { style: { fontSize: 12, color: "#666" }, children: [
761
757
  (f2.size / (1024 * 1024)).toFixed(2),
762
758
  " MB \u2022 ",
763
759
  f2.contentType
764
760
  ] })
765
761
  ] }),
766
- /* @__PURE__ */ jsxs2("div", { style: { display: "flex", gap: 8, alignItems: "center" }, children: [
767
- /* @__PURE__ */ jsx2("a", { href: f2.url, target: "_blank", rel: "noreferrer", style: { fontSize: 12, color: "#2563eb" }, children: "View" }),
768
- /* @__PURE__ */ jsx2(
762
+ /* @__PURE__ */ jsxs("div", { style: { display: "flex", gap: 8, alignItems: "center" }, children: [
763
+ /* @__PURE__ */ jsx("a", { href: f2.url, target: "_blank", rel: "noreferrer", style: { fontSize: 12, color: "#2563eb" }, children: "View" }),
764
+ /* @__PURE__ */ jsx(
769
765
  "button",
770
766
  {
771
767
  onClick: async () => {
@@ -802,7 +798,7 @@ var ProjectFilesWidget = ({
802
798
  children: savingKey === f2.key ? "Saving\u2026" : "Use"
803
799
  }
804
800
  ),
805
- showDelete && /* @__PURE__ */ jsx2(
801
+ showDelete && /* @__PURE__ */ jsx(
806
802
  "button",
807
803
  {
808
804
  onClick: () => handleDelete(f2.key),
@@ -816,15 +812,11 @@ var ProjectFilesWidget = ({
816
812
  },
817
813
  f2.key
818
814
  )),
819
- visible.length === 0 && /* @__PURE__ */ jsx2("li", { style: { fontSize: 12, color: "#666" }, children: "No files found" })
815
+ visible.length === 0 && /* @__PURE__ */ jsx("li", { style: { fontSize: 12, color: "#666" }, children: "No files found" })
820
816
  ] })
821
817
  ] });
822
818
  };
823
819
 
824
- // src/ConnectProjectDialog.tsx
825
- import * as React3 from "react";
826
- import * as Dialog from "@radix-ui/react-dialog";
827
-
828
820
  // src/projectConnect.ts
829
821
  var f = (globalThis.fetch || fetch).bind(globalThis);
830
822
  async function httpJson(input, init, useFetch) {
@@ -914,19 +906,16 @@ function connectUsingApiKey(opts) {
914
906
  const client = new UpfilesClient({ baseUrl, apiKey, apiKeyHeader: opts.apiKeyHeader ?? "authorization" });
915
907
  return { apiKey, client };
916
908
  }
917
-
918
- // src/ConnectProjectDialog.tsx
919
- import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
920
909
  function ConnectProjectDialog(props) {
921
910
  const { baseUrl, open, onOpenChange, onConnected, fetchImpl, title, description, className } = props;
922
- const [mode, setMode] = React3.useState("existing");
923
- const [loading, setLoading] = React3.useState(false);
924
- const [error, setError] = React3.useState(null);
925
- const [projects, setProjects] = React3.useState([]);
926
- const [selectedProjectId, setSelectedProjectId] = React3.useState("");
927
- const [manualKey, setManualKey] = React3.useState("");
928
- const [newProjectName, setNewProjectName] = React3.useState("");
929
- const resetState = React3.useCallback(() => {
911
+ const [mode, setMode] = React4.useState("existing");
912
+ const [loading, setLoading] = React4.useState(false);
913
+ const [error, setError] = React4.useState(null);
914
+ const [projects, setProjects] = React4.useState([]);
915
+ const [selectedProjectId, setSelectedProjectId] = React4.useState("");
916
+ const [manualKey, setManualKey] = React4.useState("");
917
+ const [newProjectName, setNewProjectName] = React4.useState("");
918
+ const resetState = React4.useCallback(() => {
930
919
  setMode("existing");
931
920
  setLoading(false);
932
921
  setError(null);
@@ -935,7 +924,7 @@ function ConnectProjectDialog(props) {
935
924
  setManualKey("");
936
925
  setNewProjectName("");
937
926
  }, []);
938
- React3.useEffect(() => {
927
+ React4.useEffect(() => {
939
928
  const run = async () => {
940
929
  if (!open || mode !== "existing") return;
941
930
  try {
@@ -997,8 +986,8 @@ function ConnectProjectDialog(props) {
997
986
  setLoading(false);
998
987
  }
999
988
  };
1000
- const ModeSwitcher = /* @__PURE__ */ jsxs3("div", { className: "grid grid-cols-3 gap-2", children: [
1001
- /* @__PURE__ */ jsx3(
989
+ const ModeSwitcher = /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-3 gap-2", children: [
990
+ /* @__PURE__ */ jsx(
1002
991
  "button",
1003
992
  {
1004
993
  type: "button",
@@ -1007,7 +996,7 @@ function ConnectProjectDialog(props) {
1007
996
  children: "Connect existing"
1008
997
  }
1009
998
  ),
1010
- /* @__PURE__ */ jsx3(
999
+ /* @__PURE__ */ jsx(
1011
1000
  "button",
1012
1001
  {
1013
1002
  type: "button",
@@ -1016,7 +1005,7 @@ function ConnectProjectDialog(props) {
1016
1005
  children: "Add API key"
1017
1006
  }
1018
1007
  ),
1019
- /* @__PURE__ */ jsx3(
1008
+ /* @__PURE__ */ jsx(
1020
1009
  "button",
1021
1010
  {
1022
1011
  type: "button",
@@ -1026,19 +1015,19 @@ function ConnectProjectDialog(props) {
1026
1015
  }
1027
1016
  )
1028
1017
  ] });
1029
- return /* @__PURE__ */ jsx3(Dialog.Root, { open, onOpenChange: (o) => {
1018
+ return /* @__PURE__ */ jsx(Dialog2.Root, { open, onOpenChange: (o) => {
1030
1019
  if (!o) resetState();
1031
1020
  onOpenChange(o);
1032
- }, children: /* @__PURE__ */ jsxs3(Dialog.Portal, { children: [
1033
- /* @__PURE__ */ jsx3(Dialog.Overlay, { className: "fixed inset-0 bg-black/40" }),
1034
- /* @__PURE__ */ jsx3(Dialog.Content, { className: `fixed left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2 w-[95vw] max-w-md rounded-lg border bg-white p-4 shadow-lg ${className ?? ""}`, children: /* @__PURE__ */ jsxs3("div", { className: "space-y-3", children: [
1035
- /* @__PURE__ */ jsx3(Dialog.Title, { className: "text-lg font-semibold", children: title ?? "Connect to Upfiles" }),
1036
- /* @__PURE__ */ jsx3(Dialog.Description, { className: "text-sm text-muted-foreground", children: description ?? "Choose how to connect your project to retrieve an API key." }),
1021
+ }, children: /* @__PURE__ */ jsxs(Dialog2.Portal, { children: [
1022
+ /* @__PURE__ */ jsx(Dialog2.Overlay, { className: "fixed inset-0 bg-black/40" }),
1023
+ /* @__PURE__ */ jsx(Dialog2.Content, { className: `fixed left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2 w-[95vw] max-w-md rounded-lg border bg-white p-4 shadow-lg ${className ?? ""}`, children: /* @__PURE__ */ jsxs("div", { className: "space-y-3", children: [
1024
+ /* @__PURE__ */ jsx(Dialog2.Title, { className: "text-lg font-semibold", children: title ?? "Connect to Upfiles" }),
1025
+ /* @__PURE__ */ jsx(Dialog2.Description, { className: "text-sm text-muted-foreground", children: description ?? "Choose how to connect your project to retrieve an API key." }),
1037
1026
  ModeSwitcher,
1038
- error && /* @__PURE__ */ jsx3("div", { className: "rounded border border-red-200 bg-red-50 px-3 py-2 text-sm text-red-700", children: error }),
1039
- mode === "existing" && /* @__PURE__ */ jsxs3("div", { className: "space-y-2", children: [
1040
- /* @__PURE__ */ jsx3("label", { className: "text-sm font-medium", children: "Project" }),
1041
- /* @__PURE__ */ jsxs3(
1027
+ error && /* @__PURE__ */ jsx("div", { className: "rounded border border-red-200 bg-red-50 px-3 py-2 text-sm text-red-700", children: error }),
1028
+ mode === "existing" && /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
1029
+ /* @__PURE__ */ jsx("label", { className: "text-sm font-medium", children: "Project" }),
1030
+ /* @__PURE__ */ jsxs(
1042
1031
  "select",
1043
1032
  {
1044
1033
  className: "w-full rounded border px-3 py-2 text-sm",
@@ -1046,14 +1035,14 @@ function ConnectProjectDialog(props) {
1046
1035
  onChange: (e) => setSelectedProjectId(e.target.value),
1047
1036
  disabled: loading,
1048
1037
  children: [
1049
- projects.length === 0 && /* @__PURE__ */ jsx3("option", { value: "", children: loading ? "Loading..." : "No projects found" }),
1050
- projects.map((p) => /* @__PURE__ */ jsx3("option", { value: p.id, children: p.name }, p.id))
1038
+ projects.length === 0 && /* @__PURE__ */ jsx("option", { value: "", children: loading ? "Loading..." : "No projects found" }),
1039
+ projects.map((p) => /* @__PURE__ */ jsx("option", { value: p.id, children: p.name }, p.id))
1051
1040
  ]
1052
1041
  }
1053
1042
  ),
1054
- /* @__PURE__ */ jsxs3("div", { className: "flex justify-end gap-2 pt-2", children: [
1055
- /* @__PURE__ */ jsx3(Dialog.Close, { asChild: true, children: /* @__PURE__ */ jsx3("button", { type: "button", className: "px-3 py-2 text-sm rounded border", children: "Cancel" }) }),
1056
- /* @__PURE__ */ jsx3(
1043
+ /* @__PURE__ */ jsxs("div", { className: "flex justify-end gap-2 pt-2", children: [
1044
+ /* @__PURE__ */ jsx(Dialog2.Close, { asChild: true, children: /* @__PURE__ */ jsx("button", { type: "button", className: "px-3 py-2 text-sm rounded border", children: "Cancel" }) }),
1045
+ /* @__PURE__ */ jsx(
1057
1046
  "button",
1058
1047
  {
1059
1048
  type: "button",
@@ -1065,9 +1054,9 @@ function ConnectProjectDialog(props) {
1065
1054
  )
1066
1055
  ] })
1067
1056
  ] }),
1068
- mode === "manual" && /* @__PURE__ */ jsxs3("div", { className: "space-y-2", children: [
1069
- /* @__PURE__ */ jsx3("label", { className: "text-sm font-medium", children: "API key" }),
1070
- /* @__PURE__ */ jsx3(
1057
+ mode === "manual" && /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
1058
+ /* @__PURE__ */ jsx("label", { className: "text-sm font-medium", children: "API key" }),
1059
+ /* @__PURE__ */ jsx(
1071
1060
  "input",
1072
1061
  {
1073
1062
  className: "w-full rounded border px-3 py-2 text-sm",
@@ -1077,9 +1066,9 @@ function ConnectProjectDialog(props) {
1077
1066
  disabled: loading
1078
1067
  }
1079
1068
  ),
1080
- /* @__PURE__ */ jsxs3("div", { className: "flex justify-end gap-2 pt-2", children: [
1081
- /* @__PURE__ */ jsx3(Dialog.Close, { asChild: true, children: /* @__PURE__ */ jsx3("button", { type: "button", className: "px-3 py-2 text-sm rounded border", children: "Cancel" }) }),
1082
- /* @__PURE__ */ jsx3(
1069
+ /* @__PURE__ */ jsxs("div", { className: "flex justify-end gap-2 pt-2", children: [
1070
+ /* @__PURE__ */ jsx(Dialog2.Close, { asChild: true, children: /* @__PURE__ */ jsx("button", { type: "button", className: "px-3 py-2 text-sm rounded border", children: "Cancel" }) }),
1071
+ /* @__PURE__ */ jsx(
1083
1072
  "button",
1084
1073
  {
1085
1074
  type: "button",
@@ -1091,9 +1080,9 @@ function ConnectProjectDialog(props) {
1091
1080
  )
1092
1081
  ] })
1093
1082
  ] }),
1094
- mode === "new" && /* @__PURE__ */ jsxs3("div", { className: "space-y-2", children: [
1095
- /* @__PURE__ */ jsx3("label", { className: "text-sm font-medium", children: "Project name" }),
1096
- /* @__PURE__ */ jsx3(
1083
+ mode === "new" && /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
1084
+ /* @__PURE__ */ jsx("label", { className: "text-sm font-medium", children: "Project name" }),
1085
+ /* @__PURE__ */ jsx(
1097
1086
  "input",
1098
1087
  {
1099
1088
  className: "w-full rounded border px-3 py-2 text-sm",
@@ -1103,10 +1092,10 @@ function ConnectProjectDialog(props) {
1103
1092
  disabled: loading
1104
1093
  }
1105
1094
  ),
1106
- /* @__PURE__ */ jsx3("p", { className: "text-xs text-muted-foreground", children: "A project will be created in your Upfiles account and an API key generated." }),
1107
- /* @__PURE__ */ jsxs3("div", { className: "flex justify-end gap-2 pt-2", children: [
1108
- /* @__PURE__ */ jsx3(Dialog.Close, { asChild: true, children: /* @__PURE__ */ jsx3("button", { type: "button", className: "px-3 py-2 text-sm rounded border", children: "Cancel" }) }),
1109
- /* @__PURE__ */ jsx3(
1095
+ /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground", children: "A project will be created in your Upfiles account and an API key generated." }),
1096
+ /* @__PURE__ */ jsxs("div", { className: "flex justify-end gap-2 pt-2", children: [
1097
+ /* @__PURE__ */ jsx(Dialog2.Close, { asChild: true, children: /* @__PURE__ */ jsx("button", { type: "button", className: "px-3 py-2 text-sm rounded border", children: "Cancel" }) }),
1098
+ /* @__PURE__ */ jsx(
1110
1099
  "button",
1111
1100
  {
1112
1101
  type: "button",
@@ -1156,60 +1145,60 @@ async function fetchProjectImagesWithThumbs(clientOptions, opts) {
1156
1145
  results.sort((a, b) => (keyToIndex.get(a.key) ?? 0) - (keyToIndex.get(b.key) ?? 0));
1157
1146
  return { items: results, updatedAt };
1158
1147
  }
1159
-
1160
- // src/ImageManager.tsx
1161
- import * as React4 from "react";
1162
- import * as Dialog2 from "@radix-ui/react-dialog";
1163
- import { Fragment as Fragment2, jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
1164
- var IconGrid = ({ className }) => /* @__PURE__ */ jsxs4("svg", { xmlns: "http://www.w3.org/2000/svg", width: "24", height: "24", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className, children: [
1165
- /* @__PURE__ */ jsx4("rect", { width: "7", height: "7", x: "3", y: "3", rx: "1" }),
1166
- /* @__PURE__ */ jsx4("rect", { width: "7", height: "7", x: "14", y: "3", rx: "1" }),
1167
- /* @__PURE__ */ jsx4("rect", { width: "7", height: "7", x: "14", y: "14", rx: "1" }),
1168
- /* @__PURE__ */ jsx4("rect", { width: "7", height: "7", x: "3", y: "14", rx: "1" })
1148
+ var IconGrid = ({ className }) => /* @__PURE__ */ jsxs("svg", { xmlns: "http://www.w3.org/2000/svg", width: "24", height: "24", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className, children: [
1149
+ /* @__PURE__ */ jsx("rect", { width: "7", height: "7", x: "3", y: "3", rx: "1" }),
1150
+ /* @__PURE__ */ jsx("rect", { width: "7", height: "7", x: "14", y: "3", rx: "1" }),
1151
+ /* @__PURE__ */ jsx("rect", { width: "7", height: "7", x: "14", y: "14", rx: "1" }),
1152
+ /* @__PURE__ */ jsx("rect", { width: "7", height: "7", x: "3", y: "14", rx: "1" })
1153
+ ] });
1154
+ var IconUploadCloud = ({ className }) => /* @__PURE__ */ jsxs("svg", { xmlns: "http://www.w3.org/2000/svg", width: "24", height: "24", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className, children: [
1155
+ /* @__PURE__ */ jsx("path", { d: "M4 14.899A7 7 0 1 1 15.71 8h1.79a4.5 4.5 0 0 1 2.5 8.242" }),
1156
+ /* @__PURE__ */ jsx("path", { d: "M12 12v9" }),
1157
+ /* @__PURE__ */ jsx("path", { d: "m16 16-4-4-4 4" })
1169
1158
  ] });
1170
- var IconUploadCloud = ({ className }) => /* @__PURE__ */ jsxs4("svg", { xmlns: "http://www.w3.org/2000/svg", width: "24", height: "24", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className, children: [
1171
- /* @__PURE__ */ jsx4("path", { d: "M4 14.899A7 7 0 1 1 15.71 8h1.79a4.5 4.5 0 0 1 2.5 8.242" }),
1172
- /* @__PURE__ */ jsx4("path", { d: "M12 12v9" }),
1173
- /* @__PURE__ */ jsx4("path", { d: "m16 16-4-4-4 4" })
1159
+ var IconFolder = ({ className }) => /* @__PURE__ */ jsx("svg", { xmlns: "http://www.w3.org/2000/svg", width: "24", height: "24", viewBox: "0 0 24 24", fill: "currentColor", stroke: "currentColor", strokeWidth: "0", className, children: /* @__PURE__ */ jsx("path", { d: "M19.5 21a3 3 0 0 0 3-3v-4.5a3 3 0 0 0-3-3h-15a3 3 0 0 0-3 3V18a3 3 0 0 0 3 3h15ZM1.5 10.146V6a3 3 0 0 1 3-3h5.379a2.25 2.25 0 0 1 1.59.659l2.122 2.121c.14.141.331.22.53.22H19.5a3 3 0 0 1 3 3v1.146A4.483 4.483 0 0 0 19.5 9h-15a4.483 4.483 0 0 0-3 1.146Z" }) });
1160
+ var IconFolderPlus = ({ className }) => /* @__PURE__ */ jsxs("svg", { xmlns: "http://www.w3.org/2000/svg", width: "24", height: "24", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className, children: [
1161
+ /* @__PURE__ */ jsx("path", { d: "M4 20h16a2 2 0 0 0 2-2V8a2 2 0 0 0-2-2h-7.93a2 2 0 0 1-1.66-.9l-.82-1.2A2 2 0 0 0 7.93 2H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2Z" }),
1162
+ /* @__PURE__ */ jsx("line", { x1: "12", x2: "12", y1: "10", y2: "16" }),
1163
+ /* @__PURE__ */ jsx("line", { x1: "9", x2: "15", y1: "13", y2: "13" })
1174
1164
  ] });
1175
- var IconFolder = ({ className }) => /* @__PURE__ */ jsx4("svg", { xmlns: "http://www.w3.org/2000/svg", width: "24", height: "24", viewBox: "0 0 24 24", fill: "currentColor", stroke: "currentColor", strokeWidth: "0", className, children: /* @__PURE__ */ jsx4("path", { d: "M19.5 21a3 3 0 0 0 3-3v-4.5a3 3 0 0 0-3-3h-15a3 3 0 0 0-3 3V18a3 3 0 0 0 3 3h15ZM1.5 10.146V6a3 3 0 0 1 3-3h5.379a2.25 2.25 0 0 1 1.59.659l2.122 2.121c.14.141.331.22.53.22H19.5a3 3 0 0 1 3 3v1.146A4.483 4.483 0 0 0 19.5 9h-15a4.483 4.483 0 0 0-3 1.146Z" }) });
1176
- var IconFolderPlus = ({ className }) => /* @__PURE__ */ jsxs4("svg", { xmlns: "http://www.w3.org/2000/svg", width: "24", height: "24", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className, children: [
1177
- /* @__PURE__ */ jsx4("path", { d: "M4 20h16a2 2 0 0 0 2-2V8a2 2 0 0 0-2-2h-7.93a2 2 0 0 1-1.66-.9l-.82-1.2A2 2 0 0 0 7.93 2H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2Z" }),
1178
- /* @__PURE__ */ jsx4("line", { x1: "12", x2: "12", y1: "10", y2: "16" }),
1179
- /* @__PURE__ */ jsx4("line", { x1: "9", x2: "15", y1: "13", y2: "13" })
1165
+ var IconSearch = ({ className }) => /* @__PURE__ */ jsxs("svg", { xmlns: "http://www.w3.org/2000/svg", width: "24", height: "24", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className, children: [
1166
+ /* @__PURE__ */ jsx("circle", { cx: "11", cy: "11", r: "8" }),
1167
+ /* @__PURE__ */ jsx("path", { d: "m21 21-4.3-4.3" })
1180
1168
  ] });
1181
- var IconSearch = ({ className }) => /* @__PURE__ */ jsxs4("svg", { xmlns: "http://www.w3.org/2000/svg", width: "24", height: "24", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className, children: [
1182
- /* @__PURE__ */ jsx4("circle", { cx: "11", cy: "11", r: "8" }),
1183
- /* @__PURE__ */ jsx4("path", { d: "m21 21-4.3-4.3" })
1169
+ var IconRefresh = ({ className }) => /* @__PURE__ */ jsxs("svg", { xmlns: "http://www.w3.org/2000/svg", width: "24", height: "24", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className, children: [
1170
+ /* @__PURE__ */ jsx("path", { d: "M3 12a9 9 0 0 1 9-9 9.75 9.75 0 0 1 6.74 2.74L21 8" }),
1171
+ /* @__PURE__ */ jsx("path", { d: "M21 3v5h-5" }),
1172
+ /* @__PURE__ */ jsx("path", { d: "M21 12a9 9 0 0 1-9 9 9.75 9.75 0 0 1-6.74-2.74L3 16" }),
1173
+ /* @__PURE__ */ jsx("path", { d: "M8 16H3v5" })
1184
1174
  ] });
1185
- var IconRefresh = ({ className }) => /* @__PURE__ */ jsxs4("svg", { xmlns: "http://www.w3.org/2000/svg", width: "24", height: "24", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className, children: [
1186
- /* @__PURE__ */ jsx4("path", { d: "M3 12a9 9 0 0 1 9-9 9.75 9.75 0 0 1 6.74 2.74L21 8" }),
1187
- /* @__PURE__ */ jsx4("path", { d: "M21 3v5h-5" }),
1188
- /* @__PURE__ */ jsx4("path", { d: "M21 12a9 9 0 0 1-9 9 9.75 9.75 0 0 1-6.74-2.74L3 16" }),
1189
- /* @__PURE__ */ jsx4("path", { d: "M8 16H3v5" })
1175
+ var IconChevronRight = ({ className }) => /* @__PURE__ */ jsx("svg", { xmlns: "http://www.w3.org/2000/svg", width: "24", height: "24", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className, children: /* @__PURE__ */ jsx("path", { d: "m9 18 6-6-6-6" }) });
1176
+ var IconTrash = ({ className }) => /* @__PURE__ */ jsxs("svg", { xmlns: "http://www.w3.org/2000/svg", width: "24", height: "24", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className, children: [
1177
+ /* @__PURE__ */ jsx("path", { d: "M3 6h18" }),
1178
+ /* @__PURE__ */ jsx("path", { d: "M19 6v14c0 1-1 2-2 2H7c-1 0-2-1-2-2V6" }),
1179
+ /* @__PURE__ */ jsx("path", { d: "M8 6V4c0-1 1-2 2-2h4c1 0 2 1 2 2v2" }),
1180
+ /* @__PURE__ */ jsx("line", { x1: "10", x2: "10", y1: "11", y2: "17" }),
1181
+ /* @__PURE__ */ jsx("line", { x1: "14", x2: "14", y1: "11", y2: "17" })
1190
1182
  ] });
1191
- var IconChevronRight = ({ className }) => /* @__PURE__ */ jsx4("svg", { xmlns: "http://www.w3.org/2000/svg", width: "24", height: "24", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className, children: /* @__PURE__ */ jsx4("path", { d: "m9 18 6-6-6-6" }) });
1192
- var IconTrash = ({ className }) => /* @__PURE__ */ jsxs4("svg", { xmlns: "http://www.w3.org/2000/svg", width: "24", height: "24", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className, children: [
1193
- /* @__PURE__ */ jsx4("path", { d: "M3 6h18" }),
1194
- /* @__PURE__ */ jsx4("path", { d: "M19 6v14c0 1-1 2-2 2H7c-1 0-2-1-2-2V6" }),
1195
- /* @__PURE__ */ jsx4("path", { d: "M8 6V4c0-1 1-2 2-2h4c1 0 2 1 2 2v2" }),
1196
- /* @__PURE__ */ jsx4("line", { x1: "10", x2: "10", y1: "11", y2: "17" }),
1197
- /* @__PURE__ */ jsx4("line", { x1: "14", x2: "14", y1: "11", y2: "17" })
1183
+ var IconX = ({ className }) => /* @__PURE__ */ jsxs("svg", { xmlns: "http://www.w3.org/2000/svg", width: "24", height: "24", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className, children: [
1184
+ /* @__PURE__ */ jsx("path", { d: "M18 6 6 18" }),
1185
+ /* @__PURE__ */ jsx("path", { d: "m6 6 12 12" })
1198
1186
  ] });
1199
- var IconX = ({ className }) => /* @__PURE__ */ jsxs4("svg", { xmlns: "http://www.w3.org/2000/svg", width: "24", height: "24", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className, children: [
1200
- /* @__PURE__ */ jsx4("path", { d: "M18 6 6 18" }),
1201
- /* @__PURE__ */ jsx4("path", { d: "m6 6 12 12" })
1187
+ var IconHome = ({ className }) => /* @__PURE__ */ jsxs("svg", { xmlns: "http://www.w3.org/2000/svg", width: "24", height: "24", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className, children: [
1188
+ /* @__PURE__ */ jsx("path", { d: "m3 9 9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z" }),
1189
+ /* @__PURE__ */ jsx("polyline", { points: "9 22 9 12 15 12 15 22" })
1202
1190
  ] });
1203
- var IconHome = ({ className }) => /* @__PURE__ */ jsxs4("svg", { xmlns: "http://www.w3.org/2000/svg", width: "24", height: "24", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className, children: [
1204
- /* @__PURE__ */ jsx4("path", { d: "m3 9 9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z" }),
1205
- /* @__PURE__ */ jsx4("polyline", { points: "9 22 9 12 15 12 15 22" })
1191
+ var IconImage = ({ className }) => /* @__PURE__ */ jsxs("svg", { xmlns: "http://www.w3.org/2000/svg", width: "24", height: "24", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className, children: [
1192
+ /* @__PURE__ */ jsx("rect", { width: "18", height: "18", x: "3", y: "3", rx: "2", ry: "2" }),
1193
+ /* @__PURE__ */ jsx("circle", { cx: "9", cy: "9", r: "2" }),
1194
+ /* @__PURE__ */ jsx("path", { d: "m21 15-3.086-3.086a2 2 0 0 0-2.828 0L6 21" })
1206
1195
  ] });
1207
- var IconImage = ({ className }) => /* @__PURE__ */ jsxs4("svg", { xmlns: "http://www.w3.org/2000/svg", width: "24", height: "24", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className, children: [
1208
- /* @__PURE__ */ jsx4("rect", { width: "18", height: "18", x: "3", y: "3", rx: "2", ry: "2" }),
1209
- /* @__PURE__ */ jsx4("circle", { cx: "9", cy: "9", r: "2" }),
1210
- /* @__PURE__ */ jsx4("path", { d: "m21 15-3.086-3.086a2 2 0 0 0-2.828 0L6 21" })
1196
+ var IconLoader = ({ className }) => /* @__PURE__ */ jsx("svg", { xmlns: "http://www.w3.org/2000/svg", width: "24", height: "24", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className, children: /* @__PURE__ */ jsx("path", { d: "M21 12a9 9 0 1 1-6.219-8.56" }) });
1197
+ var IconLayers = ({ className }) => /* @__PURE__ */ jsxs("svg", { xmlns: "http://www.w3.org/2000/svg", width: "24", height: "24", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className, children: [
1198
+ /* @__PURE__ */ jsx("polygon", { points: "12 2 2 7 12 12 22 7 12 2" }),
1199
+ /* @__PURE__ */ jsx("polyline", { points: "2 17 12 22 22 17" }),
1200
+ /* @__PURE__ */ jsx("polyline", { points: "2 12 12 17 22 12" })
1211
1201
  ] });
1212
- var IconLoader = ({ className }) => /* @__PURE__ */ jsx4("svg", { xmlns: "http://www.w3.org/2000/svg", width: "24", height: "24", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className, children: /* @__PURE__ */ jsx4("path", { d: "M21 12a9 9 0 1 1-6.219-8.56" }) });
1213
1202
  function ImageManager(props) {
1214
1203
  const {
1215
1204
  open,
@@ -1246,8 +1235,20 @@ function ImageManager(props) {
1246
1235
  const [creatingFolder, setCreatingFolder] = React4.useState(false);
1247
1236
  const [fileToDelete, setFileToDelete] = React4.useState(null);
1248
1237
  const [thumbnailSelectorFile, setThumbnailSelectorFile] = React4.useState(null);
1238
+ const [selectedThumbnailForFile, setSelectedThumbnailForFile] = React4.useState(null);
1239
+ const [previewFile, setPreviewFile] = React4.useState(null);
1249
1240
  const lastUpdatedRef = React4.useRef(null);
1250
1241
  const isFetchingRef = React4.useRef(false);
1242
+ const deduplicateFiles = React4.useCallback((files2) => {
1243
+ const seen = /* @__PURE__ */ new Set();
1244
+ return files2.filter((file) => {
1245
+ if (seen.has(file.key)) {
1246
+ return false;
1247
+ }
1248
+ seen.add(file.key);
1249
+ return true;
1250
+ });
1251
+ }, []);
1251
1252
  const load = React4.useCallback(async (isPolling = false) => {
1252
1253
  if (isFetchingRef.current) return;
1253
1254
  isFetchingRef.current = true;
@@ -1264,7 +1265,7 @@ function ImageManager(props) {
1264
1265
  const { items: list, updatedAt } = filesData;
1265
1266
  if (isPolling && updatedAt && updatedAt === lastUpdatedRef.current) {
1266
1267
  }
1267
- setFiles(list);
1268
+ setFiles(deduplicateFiles(list));
1268
1269
  setFolders(foldersData);
1269
1270
  lastUpdatedRef.current = updatedAt;
1270
1271
  } catch (e) {
@@ -1299,7 +1300,7 @@ function ImageManager(props) {
1299
1300
  const newFile = payload.data.file;
1300
1301
  setFiles((prev) => {
1301
1302
  if (prev.find((f2) => f2.key === newFile.key)) return prev;
1302
- return [newFile, ...prev];
1303
+ return deduplicateFiles([newFile, ...prev]);
1303
1304
  });
1304
1305
  } else if (payload.type === "file:deleted") {
1305
1306
  const deletedKey = payload.data.fileKey || payload.data.file?.key;
@@ -1401,61 +1402,78 @@ function ImageManager(props) {
1401
1402
  const activeBreadcrumbPath = React4.useMemo(() => {
1402
1403
  return breadcrumbs.length > 1 ? breadcrumbs.slice(1).map((b) => b.name).join("/") + "/" : void 0;
1403
1404
  }, [breadcrumbs]);
1404
- return /* @__PURE__ */ jsxs4(Dialog2.Root, { open, onOpenChange, children: [
1405
- /* @__PURE__ */ jsxs4(Dialog2.Portal, { children: [
1406
- /* @__PURE__ */ jsx4(Dialog2.Overlay, { className: "fixed inset-0 bg-gray-900/50 backdrop-blur-sm z-50 transition-all duration-300" }),
1407
- /* @__PURE__ */ jsxs4(
1405
+ return /* @__PURE__ */ jsxs(Dialog2.Root, { open, onOpenChange, children: [
1406
+ /* @__PURE__ */ jsxs(Dialog2.Portal, { children: [
1407
+ /* @__PURE__ */ jsx(Dialog2.Overlay, { className: "fixed inset-0 bg-black/60 backdrop-blur-sm z-50 transition-all duration-300 flex items-center justify-center" }),
1408
+ /* @__PURE__ */ jsxs(
1408
1409
  Dialog2.Content,
1409
1410
  {
1410
- className: `fixed left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2 w-[90vw] h-[85vh] max-w-6xl rounded-2xl bg-white dark:bg-gray-950 shadow-2xl z-50 overflow-hidden flex flex-row ${className ?? ""}`,
1411
+ className: `fixed left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2 w-[95vw] h-[90vh] max-w-7xl min-w-[800px] min-h-[600px] rounded-2xl bg-white dark:bg-gray-950 shadow-2xl z-[51] overflow-hidden flex flex-row ${className ?? ""}`,
1411
1412
  children: [
1412
- /* @__PURE__ */ jsxs4("div", { className: "w-64 bg-gray-50 dark:bg-gray-900 border-r border-gray-200 dark:border-gray-800 flex flex-col flex-shrink-0", children: [
1413
- /* @__PURE__ */ jsxs4("div", { className: "p-6", children: [
1414
- /* @__PURE__ */ jsxs4("h2", { className: "text-lg font-bold text-gray-900 dark:text-white flex items-center gap-2", children: [
1415
- /* @__PURE__ */ jsx4(IconImage, { className: "text-blue-600" }),
1413
+ /* @__PURE__ */ jsx(
1414
+ Dialog2.Title,
1415
+ {
1416
+ style: {
1417
+ position: "absolute",
1418
+ width: "1px",
1419
+ height: "1px",
1420
+ padding: "0",
1421
+ margin: "-1px",
1422
+ overflow: "hidden",
1423
+ clip: "rect(0, 0, 0, 0)",
1424
+ whiteSpace: "nowrap",
1425
+ border: "0"
1426
+ },
1427
+ children: title ?? "Media Library"
1428
+ }
1429
+ ),
1430
+ /* @__PURE__ */ jsxs("div", { className: "w-64 min-w-[256px] bg-gray-50 dark:bg-gray-900 border-r border-gray-200 dark:border-gray-800 flex flex-col flex-shrink-0", children: [
1431
+ /* @__PURE__ */ jsxs("div", { className: "p-6", children: [
1432
+ /* @__PURE__ */ jsxs("h2", { className: "text-lg font-bold text-gray-900 dark:text-white flex items-center gap-2", children: [
1433
+ /* @__PURE__ */ jsx(IconImage, { className: "text-blue-600" }),
1416
1434
  title ?? "Media Library"
1417
1435
  ] }),
1418
- /* @__PURE__ */ jsx4("p", { className: "text-xs text-gray-500 mt-1", children: description ?? "Manage your assets" })
1436
+ /* @__PURE__ */ jsx("p", { className: "text-xs text-gray-500 mt-1", children: description ?? "Manage your assets" })
1419
1437
  ] }),
1420
- /* @__PURE__ */ jsxs4("nav", { className: "flex-1 px-3 space-y-1", children: [
1421
- /* @__PURE__ */ jsxs4(
1438
+ /* @__PURE__ */ jsxs("nav", { className: "flex-1 px-3 space-y-1", children: [
1439
+ /* @__PURE__ */ jsxs(
1422
1440
  "button",
1423
1441
  {
1424
1442
  onClick: () => setActiveView("browse"),
1425
1443
  className: `w-full flex items-center gap-3 px-3 py-2.5 text-sm font-medium rounded-lg transition-colors ${activeView === "browse" ? "bg-white dark:bg-gray-800 text-blue-600 dark:text-blue-400 shadow-sm" : "text-gray-600 dark:text-gray-400 hover:bg-gray-100 dark:hover:bg-gray-800"}`,
1426
1444
  children: [
1427
- /* @__PURE__ */ jsx4(IconGrid, { className: "w-4 h-4" }),
1445
+ /* @__PURE__ */ jsx(IconGrid, { className: "w-4 h-4" }),
1428
1446
  "All Files"
1429
1447
  ]
1430
1448
  }
1431
1449
  ),
1432
- mode === "full" && /* @__PURE__ */ jsxs4(
1450
+ mode === "full" && /* @__PURE__ */ jsxs(
1433
1451
  "button",
1434
1452
  {
1435
1453
  onClick: () => setActiveView("upload"),
1436
1454
  className: `w-full flex items-center gap-3 px-3 py-2.5 text-sm font-medium rounded-lg transition-colors ${activeView === "upload" ? "bg-white dark:bg-gray-800 text-blue-600 dark:text-blue-400 shadow-sm" : "text-gray-600 dark:text-gray-400 hover:bg-gray-100 dark:hover:bg-gray-800"}`,
1437
1455
  children: [
1438
- /* @__PURE__ */ jsx4(IconUploadCloud, { className: "w-4 h-4" }),
1456
+ /* @__PURE__ */ jsx(IconUploadCloud, { className: "w-4 h-4" }),
1439
1457
  "Upload New"
1440
1458
  ]
1441
1459
  }
1442
1460
  )
1443
1461
  ] }),
1444
- /* @__PURE__ */ jsx4("div", { className: "p-4 border-t border-gray-200 dark:border-gray-800", children: /* @__PURE__ */ jsxs4("div", { className: "text-xs text-center text-gray-400", children: [
1462
+ /* @__PURE__ */ jsx("div", { className: "p-4 border-t border-gray-200 dark:border-gray-800", children: /* @__PURE__ */ jsxs("div", { className: "text-xs text-center text-gray-400", children: [
1445
1463
  files.length,
1446
1464
  " files \u2022 ",
1447
1465
  folders.length,
1448
1466
  " folders"
1449
1467
  ] }) })
1450
1468
  ] }),
1451
- /* @__PURE__ */ jsxs4("div", { className: "flex-1 flex flex-col bg-white dark:bg-gray-950 relative", children: [
1452
- /* @__PURE__ */ jsxs4("div", { className: "h-16 border-b border-gray-100 dark:border-gray-800 flex items-center justify-between px-6 gap-4", children: [
1453
- /* @__PURE__ */ jsx4("div", { className: "flex items-center gap-4 flex-1", children: activeView === "browse" && /* @__PURE__ */ jsxs4(Fragment2, { children: [
1454
- /* @__PURE__ */ jsxs4("div", { className: "flex items-center text-sm text-gray-500 overflow-hidden whitespace-nowrap", children: [
1455
- /* @__PURE__ */ jsx4("button", { onClick: () => handleBreadcrumbClick(0), className: "hover:text-blue-600 transition-colors", children: /* @__PURE__ */ jsx4(IconHome, { className: "w-4 h-4" }) }),
1456
- breadcrumbs.slice(1).map((b, i) => /* @__PURE__ */ jsxs4(React4.Fragment, { children: [
1457
- /* @__PURE__ */ jsx4(IconChevronRight, { className: "w-4 h-4 text-gray-300 mx-1" }),
1458
- /* @__PURE__ */ jsx4(
1469
+ /* @__PURE__ */ jsxs("div", { className: "flex-1 flex flex-col bg-white dark:bg-gray-950 relative", children: [
1470
+ /* @__PURE__ */ jsxs("div", { className: "h-16 border-b border-gray-100 dark:border-gray-800 flex items-center justify-between px-6 gap-4", children: [
1471
+ /* @__PURE__ */ jsx("div", { className: "flex items-center gap-4 flex-1", children: activeView === "browse" && /* @__PURE__ */ jsxs(Fragment, { children: [
1472
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center text-sm text-gray-500 overflow-hidden whitespace-nowrap", children: [
1473
+ /* @__PURE__ */ jsx("button", { onClick: () => handleBreadcrumbClick(0), className: "hover:text-blue-600 transition-colors", children: /* @__PURE__ */ jsx(IconHome, { className: "w-4 h-4" }) }),
1474
+ breadcrumbs.slice(1).map((b, i) => /* @__PURE__ */ jsxs(React4.Fragment, { children: [
1475
+ /* @__PURE__ */ jsx(IconChevronRight, { className: "w-4 h-4 text-gray-300 mx-1" }),
1476
+ /* @__PURE__ */ jsx(
1459
1477
  "button",
1460
1478
  {
1461
1479
  onClick: () => handleBreadcrumbClick(i + 1),
@@ -1463,23 +1481,23 @@ function ImageManager(props) {
1463
1481
  children: b.name
1464
1482
  }
1465
1483
  )
1466
- ] }, b.id || i))
1484
+ ] }, `${b.id || "breadcrumb"}-${i}`))
1467
1485
  ] }),
1468
- /* @__PURE__ */ jsx4("div", { className: "h-4 w-px bg-gray-200 dark:bg-gray-700 mx-2" }),
1469
- /* @__PURE__ */ jsx4(
1486
+ /* @__PURE__ */ jsx("div", { className: "h-4 w-px bg-gray-200 dark:bg-gray-700 mx-2" }),
1487
+ /* @__PURE__ */ jsx(
1470
1488
  "button",
1471
1489
  {
1472
1490
  onClick: () => load(),
1473
1491
  disabled: loading,
1474
1492
  className: "p-1.5 text-gray-400 hover:text-blue-600 hover:bg-blue-50 dark:hover:bg-blue-900/20 rounded-md transition-all disabled:opacity-50",
1475
1493
  title: "Refresh",
1476
- children: /* @__PURE__ */ jsx4(IconRefresh, { className: `w-4 h-4 ${loading ? "animate-spin" : ""}` })
1494
+ children: /* @__PURE__ */ jsx(IconRefresh, { className: `w-4 h-4 ${loading ? "animate-spin" : ""}` })
1477
1495
  }
1478
1496
  ),
1479
- /* @__PURE__ */ jsx4("div", { className: "h-4 w-px bg-gray-200 dark:bg-gray-700 mx-2" }),
1480
- /* @__PURE__ */ jsxs4("div", { className: "relative flex-1 max-w-sm group", children: [
1481
- /* @__PURE__ */ jsx4(IconSearch, { className: "absolute left-3 top-1/2 -translate-y-1/2 w-4 h-4 text-gray-400 group-focus-within:text-blue-500 transition-colors" }),
1482
- /* @__PURE__ */ jsx4(
1497
+ /* @__PURE__ */ jsx("div", { className: "h-4 w-px bg-gray-200 dark:bg-gray-700 mx-2" }),
1498
+ /* @__PURE__ */ jsxs("div", { className: "relative flex-1 max-w-sm group", children: [
1499
+ /* @__PURE__ */ jsx(IconSearch, { className: "absolute left-3 top-1/2 -translate-y-1/2 w-4 h-4 text-gray-400 group-focus-within:text-blue-500 transition-colors" }),
1500
+ /* @__PURE__ */ jsx(
1483
1501
  "input",
1484
1502
  {
1485
1503
  value: query,
@@ -1490,26 +1508,26 @@ function ImageManager(props) {
1490
1508
  )
1491
1509
  ] })
1492
1510
  ] }) }),
1493
- /* @__PURE__ */ jsxs4("div", { className: "flex items-center gap-2", children: [
1494
- activeView === "browse" && /* @__PURE__ */ jsxs4(Fragment2, { children: [
1495
- /* @__PURE__ */ jsx4("button", { onClick: () => setShowCreateFolder(true), className: "p-2 text-gray-400 hover:text-blue-600 hover:bg-blue-50 dark:hover:bg-blue-900/10 rounded-lg transition-colors", title: "New Folder", children: /* @__PURE__ */ jsx4(IconFolderPlus, { className: "w-5 h-5" }) }),
1496
- /* @__PURE__ */ jsx4("button", { onClick: () => load(), className: `p-2 text-gray-400 hover:text-blue-600 hover:bg-blue-50 dark:hover:bg-blue-900/10 rounded-lg transition-colors ${loading ? "animate-spin text-blue-600" : ""}`, title: "Refresh", children: /* @__PURE__ */ jsx4(IconLoader, { className: "w-5 h-5" }) })
1511
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
1512
+ activeView === "browse" && /* @__PURE__ */ jsxs(Fragment, { children: [
1513
+ /* @__PURE__ */ jsx("button", { onClick: () => setShowCreateFolder(true), className: "p-2 text-gray-400 hover:text-blue-600 hover:bg-blue-50 dark:hover:bg-blue-900/10 rounded-lg transition-colors", title: "New Folder", children: /* @__PURE__ */ jsx(IconFolderPlus, { className: "w-5 h-5" }) }),
1514
+ /* @__PURE__ */ jsx("button", { onClick: () => load(), className: `p-2 text-gray-400 hover:text-blue-600 hover:bg-blue-50 dark:hover:bg-blue-900/10 rounded-lg transition-colors ${loading ? "animate-spin text-blue-600" : ""}`, title: "Refresh", children: /* @__PURE__ */ jsx(IconLoader, { className: "w-5 h-5" }) })
1497
1515
  ] }),
1498
- /* @__PURE__ */ jsx4(Dialog2.Close, { asChild: true, children: /* @__PURE__ */ jsx4("button", { className: "ml-2 p-2 text-gray-400 hover:text-red-500 hover:bg-red-50 dark:hover:bg-red-900/10 rounded-lg transition-colors", children: /* @__PURE__ */ jsx4(IconX, { className: "w-5 h-5" }) }) })
1516
+ /* @__PURE__ */ jsx(Dialog2.Close, { asChild: true, children: /* @__PURE__ */ jsx("button", { className: "ml-2 p-2 text-gray-400 hover:text-red-500 hover:bg-red-50 dark:hover:bg-red-900/10 rounded-lg transition-colors", children: /* @__PURE__ */ jsx(IconX, { className: "w-5 h-5" }) }) })
1499
1517
  ] })
1500
1518
  ] }),
1501
- /* @__PURE__ */ jsxs4("div", { className: "flex-1 overflow-y-auto p-6 bg-gray-50/30 dark:bg-gray-900/30", children: [
1502
- activeView === "browse" && /* @__PURE__ */ jsxs4(Fragment2, { children: [
1503
- error && /* @__PURE__ */ jsx4("div", { className: "mb-6 bg-red-50 text-red-600 p-4 rounded-lg text-sm border border-red-100 flex items-center gap-2", children: /* @__PURE__ */ jsx4("span", { children: error }) }),
1504
- /* @__PURE__ */ jsxs4("div", { className: gridClassName ?? "grid grid-cols-2 md:grid-cols-4 lg:grid-cols-5 xl:grid-cols-6 gap-6", children: [
1505
- visibleFolders.map((folder) => /* @__PURE__ */ jsxs4(
1519
+ /* @__PURE__ */ jsxs("div", { className: "flex-1 overflow-y-auto p-6 bg-gray-50/30 dark:bg-gray-900/30", children: [
1520
+ activeView === "browse" && /* @__PURE__ */ jsxs(Fragment, { children: [
1521
+ error && /* @__PURE__ */ jsx("div", { className: "mb-6 bg-red-50 text-red-600 p-4 rounded-lg text-sm border border-red-100 flex items-center gap-2", children: /* @__PURE__ */ jsx("span", { children: error }) }),
1522
+ /* @__PURE__ */ jsxs("div", { className: gridClassName ?? "grid grid-cols-2 md:grid-cols-4 lg:grid-cols-5 xl:grid-cols-6 gap-6", children: [
1523
+ visibleFolders.map((folder) => /* @__PURE__ */ jsxs(
1506
1524
  "div",
1507
1525
  {
1508
1526
  onClick: () => handleNavigate(folder),
1509
1527
  className: "group flex flex-col items-center gap-3 p-4 rounded-xl border border-gray-200/60 bg-white hover:border-blue-200 hover:shadow-lg hover:shadow-blue-500/5 hover:-translate-y-1 transition-all cursor-pointer",
1510
1528
  children: [
1511
- /* @__PURE__ */ jsx4("div", { className: "w-16 h-12 bg-blue-50 rounded-lg flex items-center justify-center text-blue-500 group-hover:scale-110 transition-transform", children: /* @__PURE__ */ jsx4(IconFolder, { className: "w-8 h-8 drop-shadow-sm" }) }),
1512
- /* @__PURE__ */ jsx4("span", { className: "text-sm font-medium text-gray-700 truncate w-full text-center", children: folder.name })
1529
+ /* @__PURE__ */ jsx("div", { className: "w-16 h-12 bg-blue-50 rounded-lg flex items-center justify-center text-blue-500 group-hover:scale-110 transition-transform", children: /* @__PURE__ */ jsx(IconFolder, { className: "w-8 h-8 drop-shadow-sm" }) }),
1530
+ /* @__PURE__ */ jsx("span", { className: "text-sm font-medium text-gray-700 truncate w-full text-center", children: folder.name })
1513
1531
  ]
1514
1532
  },
1515
1533
  folder.id
@@ -1518,17 +1536,19 @@ function ImageManager(props) {
1518
1536
  const fWithThumbs = f2;
1519
1537
  const bestThumb = fWithThumbs.thumbnails?.sort((a, b) => a.size - b.size).find((t) => t.size >= 300) || fWithThumbs.thumbnails?.[fWithThumbs.thumbnails?.length - 1];
1520
1538
  const thumbUrl = bestThumb?.url || f2.url;
1521
- return /* @__PURE__ */ jsxs4(
1539
+ return /* @__PURE__ */ jsxs(
1522
1540
  "div",
1523
1541
  {
1524
- className: "group relative aspect-[4/3] bg-white rounded-xl border border-gray-200 overflow-hidden shadow-sm hover:shadow-xl hover:shadow-gray-200/50 hover:border-blue-300 transition-all duration-300",
1542
+ onClick: () => setPreviewFile(f2),
1543
+ className: "group relative aspect-[4/3] bg-white rounded-xl border border-gray-200 overflow-hidden shadow-sm hover:shadow-xl hover:shadow-gray-200/50 hover:border-blue-300 transition-all duration-300 cursor-pointer",
1525
1544
  children: [
1526
- /* @__PURE__ */ jsx4("img", { src: thumbUrl, alt: "", className: "w-full h-full object-cover transition-transform duration-700 group-hover:scale-105" }),
1527
- /* @__PURE__ */ jsx4("div", { className: "absolute inset-0 bg-black/40 opacity-0 group-hover:opacity-100 transition-opacity duration-200 flex flex-col justify-end p-3", children: /* @__PURE__ */ jsxs4("div", { className: "flex gap-2 justify-center transform translate-y-2 group-hover:translate-y-0 transition-transform duration-300", children: [
1528
- /* @__PURE__ */ jsx4(
1545
+ /* @__PURE__ */ jsx("img", { src: thumbUrl, alt: f2.originalName, className: "w-full h-full object-cover transition-transform duration-700 group-hover:scale-105" }),
1546
+ /* @__PURE__ */ jsx("div", { className: "absolute inset-0 bg-black/40 opacity-0 group-hover:opacity-100 transition-opacity duration-200 flex flex-col justify-end p-3", children: /* @__PURE__ */ jsxs("div", { className: "flex gap-2 justify-center transform translate-y-2 group-hover:translate-y-0 transition-transform duration-300", children: [
1547
+ /* @__PURE__ */ jsx(
1529
1548
  "button",
1530
1549
  {
1531
- onClick: () => {
1550
+ onClick: (e) => {
1551
+ e.stopPropagation();
1532
1552
  onSelect({
1533
1553
  url: f2.url,
1534
1554
  key: f2.key,
@@ -1543,7 +1563,20 @@ function ImageManager(props) {
1543
1563
  children: "Select"
1544
1564
  }
1545
1565
  ),
1546
- showDelete && /* @__PURE__ */ jsx4(
1566
+ fWithThumbs.thumbnails && fWithThumbs.thumbnails.length > 0 && /* @__PURE__ */ jsx(
1567
+ "button",
1568
+ {
1569
+ onClick: (e) => {
1570
+ e.stopPropagation();
1571
+ setThumbnailSelectorFile(f2);
1572
+ setSelectedThumbnailForFile(null);
1573
+ },
1574
+ className: "p-1.5 bg-white/20 text-white text-xs font-semibold rounded-md hover:bg-purple-500 backdrop-blur-md transition-colors",
1575
+ title: "Select Thumbnail",
1576
+ children: /* @__PURE__ */ jsx(IconLayers, { className: "w-4 h-4" })
1577
+ }
1578
+ ),
1579
+ showDelete && /* @__PURE__ */ jsx(
1547
1580
  "button",
1548
1581
  {
1549
1582
  onClick: (e) => {
@@ -1551,44 +1584,44 @@ function ImageManager(props) {
1551
1584
  setFileToDelete(f2);
1552
1585
  },
1553
1586
  className: "p-1.5 bg-white/20 text-white text-xs font-semibold rounded-md hover:bg-red-500 backdrop-blur-md transition-colors",
1554
- children: /* @__PURE__ */ jsx4(IconTrash, { className: "w-4 h-4" })
1587
+ children: /* @__PURE__ */ jsx(IconTrash, { className: "w-4 h-4" })
1555
1588
  }
1556
1589
  )
1557
1590
  ] }) }),
1558
- /* @__PURE__ */ jsx4("div", { className: "absolute top-2 right-2 bg-black/50 backdrop-blur-md text-white text-[10px] px-1.5 py-0.5 rounded opacity-0 group-hover:opacity-100 transition-opacity", children: f2.originalName.split(".").pop()?.toUpperCase() })
1591
+ /* @__PURE__ */ jsx("div", { className: "absolute top-2 right-2 bg-black/50 backdrop-blur-md text-white text-[10px] px-1.5 py-0.5 rounded opacity-0 group-hover:opacity-100 transition-opacity", children: f2.originalName.split(".").pop()?.toUpperCase() })
1559
1592
  ]
1560
1593
  },
1561
1594
  f2.key
1562
1595
  );
1563
1596
  })
1564
1597
  ] }),
1565
- !loading && visibleFolders.length === 0 && visibleFiles.length === 0 && /* @__PURE__ */ jsxs4("div", { className: "h-full flex flex-col items-center justify-center text-gray-400", children: [
1566
- /* @__PURE__ */ jsx4("div", { className: "w-16 h-16 bg-gray-100 rounded-2xl flex items-center justify-center mb-4", children: /* @__PURE__ */ jsx4(IconSearch, { className: "w-8 h-8 opacity-40" }) }),
1567
- /* @__PURE__ */ jsx4("h3", { className: "text-gray-900 font-medium mb-1", children: "No Assets Found" }),
1568
- /* @__PURE__ */ jsx4("p", { className: "text-sm", children: "Try uploading a file or creating a new folder." })
1598
+ !loading && visibleFolders.length === 0 && visibleFiles.length === 0 && /* @__PURE__ */ jsxs("div", { className: "h-full flex flex-col items-center justify-center text-gray-400", children: [
1599
+ /* @__PURE__ */ jsx("div", { className: "w-16 h-16 bg-gray-100 rounded-2xl flex items-center justify-center mb-4", children: /* @__PURE__ */ jsx(IconSearch, { className: "w-8 h-8 opacity-40" }) }),
1600
+ /* @__PURE__ */ jsx("h3", { className: "text-gray-900 font-medium mb-1", children: "No Assets Found" }),
1601
+ /* @__PURE__ */ jsx("p", { className: "text-sm", children: "Try uploading a file or creating a new folder." })
1569
1602
  ] })
1570
1603
  ] }),
1571
- activeView === "upload" && /* @__PURE__ */ jsx4("div", { className: "h-full flex flex-col items-center justify-center max-w-2xl mx-auto", children: /* @__PURE__ */ jsxs4("div", { className: "w-full bg-white rounded-2xl border border-gray-200 p-8 shadow-sm", children: [
1572
- /* @__PURE__ */ jsxs4("h3", { className: "text-lg font-semibold text-gray-900 mb-6 flex items-center gap-2", children: [
1573
- /* @__PURE__ */ jsx4(IconUploadCloud, { className: "text-blue-500" }),
1604
+ activeView === "upload" && /* @__PURE__ */ jsx("div", { className: "h-full flex flex-col items-center justify-center max-w-2xl mx-auto", children: /* @__PURE__ */ jsxs("div", { className: "w-full bg-white rounded-2xl border border-gray-200 p-8 shadow-sm", children: [
1605
+ /* @__PURE__ */ jsxs("h3", { className: "text-lg font-semibold text-gray-900 mb-6 flex items-center gap-2", children: [
1606
+ /* @__PURE__ */ jsx(IconUploadCloud, { className: "text-blue-500" }),
1574
1607
  "Upload Files"
1575
1608
  ] }),
1576
- /* @__PURE__ */ jsxs4("div", { className: "mb-6", children: [
1577
- /* @__PURE__ */ jsx4("label", { className: "block text-sm font-medium text-gray-700 mb-2", children: "Target Folder" }),
1578
- /* @__PURE__ */ jsxs4("div", { className: "flex gap-2", children: [
1579
- /* @__PURE__ */ jsx4(
1609
+ /* @__PURE__ */ jsxs("div", { className: "mb-6", children: [
1610
+ /* @__PURE__ */ jsx("label", { className: "block text-sm font-medium text-gray-700 mb-2", children: "Target Folder" }),
1611
+ /* @__PURE__ */ jsxs("div", { className: "flex gap-2", children: [
1612
+ /* @__PURE__ */ jsx(
1580
1613
  "select",
1581
1614
  {
1582
1615
  value: selectedUploadFolder,
1583
1616
  onChange: (e) => setSelectedUploadFolder(e.target.value),
1584
1617
  className: "block w-full rounded-lg border-gray-200 bg-gray-50 text-gray-900 text-sm focus:ring-blue-500 focus:border-blue-500 p-2.5",
1585
- children: uploadFoldersList.map((opt) => /* @__PURE__ */ jsx4("option", { value: opt.id, children: opt.name }, opt.id))
1618
+ children: uploadFoldersList.map((opt) => /* @__PURE__ */ jsx("option", { value: opt.id, children: opt.name }, opt.id))
1586
1619
  }
1587
1620
  ),
1588
- /* @__PURE__ */ jsx4("button", { onClick: () => setShowCreateFolder(true), className: "px-3 bg-gray-100 hover:bg-gray-200 rounded-lg text-gray-600 transition-colors", children: /* @__PURE__ */ jsx4(IconFolderPlus, { className: "w-5 h-5" }) })
1621
+ /* @__PURE__ */ jsx("button", { onClick: () => setShowCreateFolder(true), className: "px-3 bg-gray-100 hover:bg-gray-200 rounded-lg text-gray-600 transition-colors", children: /* @__PURE__ */ jsx(IconFolderPlus, { className: "w-5 h-5" }) })
1589
1622
  ] })
1590
1623
  ] }),
1591
- /* @__PURE__ */ jsx4(
1624
+ /* @__PURE__ */ jsx(
1592
1625
  Uploader,
1593
1626
  {
1594
1627
  clientOptions,
@@ -1611,7 +1644,10 @@ function ImageManager(props) {
1611
1644
  url: file.publicUrl,
1612
1645
  thumbnails: file.thumbnails
1613
1646
  };
1614
- setFiles((prev) => [newItem, ...prev]);
1647
+ setFiles((prev) => {
1648
+ if (prev.find((f2) => f2.key === newItem.key)) return prev;
1649
+ return deduplicateFiles([newItem, ...prev]);
1650
+ });
1615
1651
  }
1616
1652
  },
1617
1653
  onComplete: () => {
@@ -1624,11 +1660,11 @@ function ImageManager(props) {
1624
1660
  },
1625
1661
  dropzoneClassName: "border-2 border-dashed border-gray-300 bg-gray-50 rounded-xl p-12 text-center cursor-pointer hover:border-blue-500 hover:bg-blue-50/50 transition-all",
1626
1662
  buttonClassName: "hidden",
1627
- children: /* @__PURE__ */ jsxs4("div", { className: "flex flex-col items-center gap-4", children: [
1628
- /* @__PURE__ */ jsx4("div", { className: "w-12 h-12 bg-blue-100 text-blue-600 rounded-full flex items-center justify-center", children: /* @__PURE__ */ jsx4(IconUploadCloud, { className: "w-6 h-6" }) }),
1629
- /* @__PURE__ */ jsxs4("div", { children: [
1630
- /* @__PURE__ */ jsx4("p", { className: "text-gray-900 font-medium", children: "Click to upload or drag and drop" }),
1631
- /* @__PURE__ */ jsxs4("p", { className: "text-xs text-gray-500 mt-1", children: [
1663
+ children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center gap-4", children: [
1664
+ /* @__PURE__ */ jsx("div", { className: "w-12 h-12 bg-blue-100 text-blue-600 rounded-full flex items-center justify-center", children: /* @__PURE__ */ jsx(IconUploadCloud, { className: "w-6 h-6" }) }),
1665
+ /* @__PURE__ */ jsxs("div", { children: [
1666
+ /* @__PURE__ */ jsx("p", { className: "text-gray-900 font-medium", children: "Click to upload or drag and drop" }),
1667
+ /* @__PURE__ */ jsxs("p", { className: "text-xs text-gray-500 mt-1", children: [
1632
1668
  "Supports PNG, JPG, GIF up to ",
1633
1669
  Math.round(maxFileSize / 1024 / 1024),
1634
1670
  "MB"
@@ -1644,11 +1680,12 @@ function ImageManager(props) {
1644
1680
  }
1645
1681
  )
1646
1682
  ] }),
1647
- /* @__PURE__ */ jsx4(Dialog2.Root, { open: showCreateFolder, onOpenChange: setShowCreateFolder, children: /* @__PURE__ */ jsxs4(Dialog2.Portal, { children: [
1648
- /* @__PURE__ */ jsx4(Dialog2.Overlay, { className: "fixed inset-0 bg-black/40 z-[60]" }),
1649
- /* @__PURE__ */ jsxs4(Dialog2.Content, { className: "fixed left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2 w-full max-w-sm rounded-xl bg-white p-6 shadow-2xl z-[61] outline-none", children: [
1650
- /* @__PURE__ */ jsx4(Dialog2.Title, { className: "text-lg font-semibold text-gray-900 mb-4", children: "New Folder" }),
1651
- /* @__PURE__ */ jsx4(
1683
+ /* @__PURE__ */ jsx(Dialog2.Root, { open: showCreateFolder, onOpenChange: setShowCreateFolder, children: /* @__PURE__ */ jsxs(Dialog2.Portal, { children: [
1684
+ /* @__PURE__ */ jsx(Dialog2.Overlay, { className: "fixed inset-0 bg-black/40 z-[60]" }),
1685
+ /* @__PURE__ */ jsxs(Dialog2.Content, { className: "fixed left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2 w-full max-w-sm rounded-xl bg-white p-6 shadow-2xl z-[61] outline-none", "aria-describedby": "new-folder-description", children: [
1686
+ /* @__PURE__ */ jsx(Dialog2.Title, { className: "text-lg font-semibold text-gray-900 mb-4", children: "New Folder" }),
1687
+ /* @__PURE__ */ jsx(Dialog2.Description, { id: "new-folder-description", className: "sr-only", children: "Create a new folder to organize your files" }),
1688
+ /* @__PURE__ */ jsx(
1652
1689
  "input",
1653
1690
  {
1654
1691
  autoFocus: true,
@@ -1659,9 +1696,9 @@ function ImageManager(props) {
1659
1696
  onKeyDown: (e) => e.key === "Enter" && handleCreateFolder()
1660
1697
  }
1661
1698
  ),
1662
- /* @__PURE__ */ jsxs4("div", { className: "flex justify-end gap-3", children: [
1663
- /* @__PURE__ */ jsx4("button", { onClick: () => setShowCreateFolder(false), className: "px-4 py-2 text-sm font-medium text-gray-600 hover:bg-gray-100 rounded-lg", children: "Cancel" }),
1664
- /* @__PURE__ */ jsx4(
1699
+ /* @__PURE__ */ jsxs("div", { className: "flex justify-end gap-3", children: [
1700
+ /* @__PURE__ */ jsx("button", { onClick: () => setShowCreateFolder(false), className: "px-4 py-2 text-sm font-medium text-gray-600 hover:bg-gray-100 rounded-lg", children: "Cancel" }),
1701
+ /* @__PURE__ */ jsx(
1665
1702
  "button",
1666
1703
  {
1667
1704
  onClick: handleCreateFolder,
@@ -1673,21 +1710,21 @@ function ImageManager(props) {
1673
1710
  ] })
1674
1711
  ] })
1675
1712
  ] }) }),
1676
- /* @__PURE__ */ jsx4(Dialog2.Root, { open: !!fileToDelete, onOpenChange: (open2) => !open2 && setFileToDelete(null), children: /* @__PURE__ */ jsxs4(Dialog2.Portal, { children: [
1677
- /* @__PURE__ */ jsx4(Dialog2.Overlay, { className: "fixed inset-0 bg-black/40 z-[80]" }),
1678
- /* @__PURE__ */ jsxs4(Dialog2.Content, { className: "fixed left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2 w-full max-w-md rounded-xl bg-white p-6 shadow-2xl z-[81]", children: [
1679
- /* @__PURE__ */ jsx4(Dialog2.Title, { className: "text-xl font-semibold text-gray-900 mb-2", children: "Delete File" }),
1680
- /* @__PURE__ */ jsxs4(Dialog2.Description, { className: "text-gray-600 mb-6", children: [
1713
+ /* @__PURE__ */ jsx(Dialog2.Root, { open: !!fileToDelete, onOpenChange: (open2) => !open2 && setFileToDelete(null), children: /* @__PURE__ */ jsxs(Dialog2.Portal, { children: [
1714
+ /* @__PURE__ */ jsx(Dialog2.Overlay, { className: "fixed inset-0 bg-black/40 z-[80]" }),
1715
+ /* @__PURE__ */ jsxs(Dialog2.Content, { className: "fixed left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2 w-full max-w-md rounded-xl bg-white p-6 shadow-2xl z-[81]", "aria-describedby": "delete-file-description", children: [
1716
+ /* @__PURE__ */ jsx(Dialog2.Title, { className: "text-xl font-semibold text-gray-900 mb-2", children: "Delete File" }),
1717
+ /* @__PURE__ */ jsxs(Dialog2.Description, { id: "delete-file-description", className: "text-gray-600 mb-6", children: [
1681
1718
  "Are you sure you want to delete ",
1682
- /* @__PURE__ */ jsxs4("span", { className: "font-semibold text-gray-900", children: [
1719
+ /* @__PURE__ */ jsxs("span", { className: "font-semibold text-gray-900", children: [
1683
1720
  '"',
1684
1721
  fileToDelete?.originalName,
1685
1722
  '"'
1686
1723
  ] }),
1687
1724
  "?"
1688
1725
  ] }),
1689
- /* @__PURE__ */ jsxs4("div", { className: "flex justify-end gap-3", children: [
1690
- /* @__PURE__ */ jsx4(
1726
+ /* @__PURE__ */ jsxs("div", { className: "flex justify-end gap-3", children: [
1727
+ /* @__PURE__ */ jsx(
1691
1728
  "button",
1692
1729
  {
1693
1730
  onClick: () => setFileToDelete(null),
@@ -1695,7 +1732,7 @@ function ImageManager(props) {
1695
1732
  children: "Cancel"
1696
1733
  }
1697
1734
  ),
1698
- /* @__PURE__ */ jsx4(
1735
+ /* @__PURE__ */ jsx(
1699
1736
  "button",
1700
1737
  {
1701
1738
  onClick: handleDelete,
@@ -1706,22 +1743,208 @@ function ImageManager(props) {
1706
1743
  )
1707
1744
  ] })
1708
1745
  ] })
1746
+ ] }) }),
1747
+ /* @__PURE__ */ jsx(Dialog2.Root, { open: !!thumbnailSelectorFile, onOpenChange: (open2) => !open2 && setThumbnailSelectorFile(null), children: /* @__PURE__ */ jsxs(Dialog2.Portal, { children: [
1748
+ /* @__PURE__ */ jsx(Dialog2.Overlay, { className: "fixed inset-0 bg-black/50 z-[90]" }),
1749
+ /* @__PURE__ */ jsxs(Dialog2.Content, { className: "fixed left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2 w-full max-w-4xl max-h-[80vh] rounded-xl bg-white shadow-2xl z-[91] overflow-hidden", "aria-describedby": "thumbnail-selector-description", children: [
1750
+ /* @__PURE__ */ jsxs("div", { className: "p-6 border-b border-gray-200", children: [
1751
+ /* @__PURE__ */ jsx(Dialog2.Title, { className: "text-xl font-semibold text-gray-900 mb-2", children: "Select Thumbnail" }),
1752
+ /* @__PURE__ */ jsxs(Dialog2.Description, { id: "thumbnail-selector-description", className: "text-gray-600", children: [
1753
+ "Choose a thumbnail size for ",
1754
+ /* @__PURE__ */ jsxs("span", { className: "font-semibold text-gray-900", children: [
1755
+ '"',
1756
+ thumbnailSelectorFile?.originalName,
1757
+ '"'
1758
+ ] })
1759
+ ] })
1760
+ ] }),
1761
+ /* @__PURE__ */ jsx("div", { className: "p-6 overflow-y-auto max-h-[60vh]", children: /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-2 md:grid-cols-3 lg:grid-cols-4 gap-4", children: [
1762
+ /* @__PURE__ */ jsxs(
1763
+ "div",
1764
+ {
1765
+ onClick: () => setSelectedThumbnailForFile(null),
1766
+ className: `group cursor-pointer rounded-lg border-2 overflow-hidden transition-all ${selectedThumbnailForFile === null ? "border-blue-500 ring-2 ring-blue-200" : "border-gray-200 hover:border-blue-300"}`,
1767
+ children: [
1768
+ /* @__PURE__ */ jsxs("div", { className: "aspect-square bg-gray-100 flex items-center justify-center relative", children: [
1769
+ /* @__PURE__ */ jsx(
1770
+ "img",
1771
+ {
1772
+ src: thumbnailSelectorFile?.url,
1773
+ alt: "Original",
1774
+ className: "w-full h-full object-cover"
1775
+ }
1776
+ ),
1777
+ selectedThumbnailForFile === null && /* @__PURE__ */ jsx("div", { className: "absolute inset-0 bg-blue-500/20 flex items-center justify-center", children: /* @__PURE__ */ jsx("div", { className: "w-6 h-6 bg-blue-500 rounded-full flex items-center justify-center", children: /* @__PURE__ */ jsx("svg", { className: "w-4 h-4 text-white", fill: "currentColor", viewBox: "0 0 20 20", children: /* @__PURE__ */ jsx("path", { fillRule: "evenodd", d: "M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z", clipRule: "evenodd" }) }) }) })
1778
+ ] }),
1779
+ /* @__PURE__ */ jsxs("div", { className: "p-3 bg-white", children: [
1780
+ /* @__PURE__ */ jsx("div", { className: "font-medium text-sm text-gray-900", children: "Original" }),
1781
+ /* @__PURE__ */ jsx("div", { className: "text-xs text-gray-500", children: "Full size" })
1782
+ ] })
1783
+ ]
1784
+ }
1785
+ ),
1786
+ thumbnailSelectorFile?.thumbnails?.map((thumbnail) => /* @__PURE__ */ jsxs(
1787
+ "div",
1788
+ {
1789
+ onClick: () => setSelectedThumbnailForFile(thumbnail),
1790
+ className: `group cursor-pointer rounded-lg border-2 overflow-hidden transition-all ${selectedThumbnailForFile?.id === thumbnail.id ? "border-blue-500 ring-2 ring-blue-200" : "border-gray-200 hover:border-blue-300"}`,
1791
+ children: [
1792
+ /* @__PURE__ */ jsxs("div", { className: "aspect-square bg-gray-100 flex items-center justify-center relative", children: [
1793
+ /* @__PURE__ */ jsx(
1794
+ "img",
1795
+ {
1796
+ src: thumbnail.url,
1797
+ alt: `${thumbnail.size}px thumbnail`,
1798
+ className: "w-full h-full object-cover"
1799
+ }
1800
+ ),
1801
+ selectedThumbnailForFile?.id === thumbnail.id && /* @__PURE__ */ jsx("div", { className: "absolute inset-0 bg-blue-500/20 flex items-center justify-center", children: /* @__PURE__ */ jsx("div", { className: "w-6 h-6 bg-blue-500 rounded-full flex items-center justify-center", children: /* @__PURE__ */ jsx("svg", { className: "w-4 h-4 text-white", fill: "currentColor", viewBox: "0 0 20 20", children: /* @__PURE__ */ jsx("path", { fillRule: "evenodd", d: "M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z", clipRule: "evenodd" }) }) }) })
1802
+ ] }),
1803
+ /* @__PURE__ */ jsxs("div", { className: "p-3 bg-white", children: [
1804
+ /* @__PURE__ */ jsxs("div", { className: "font-medium text-sm text-gray-900", children: [
1805
+ thumbnail.size,
1806
+ "px"
1807
+ ] }),
1808
+ /* @__PURE__ */ jsx("div", { className: "text-xs text-gray-500", children: thumbnail.sizeType || "Thumbnail" })
1809
+ ] })
1810
+ ]
1811
+ },
1812
+ thumbnail.id
1813
+ ))
1814
+ ] }) }),
1815
+ /* @__PURE__ */ jsxs("div", { className: "p-6 border-t border-gray-200 flex justify-end gap-3", children: [
1816
+ /* @__PURE__ */ jsx(
1817
+ "button",
1818
+ {
1819
+ onClick: () => setThumbnailSelectorFile(null),
1820
+ className: "px-4 py-2 text-sm font-medium text-gray-700 hover:bg-gray-100 rounded-lg",
1821
+ children: "Cancel"
1822
+ }
1823
+ ),
1824
+ /* @__PURE__ */ jsxs(
1825
+ "button",
1826
+ {
1827
+ onClick: () => {
1828
+ if (thumbnailSelectorFile) {
1829
+ onSelect({
1830
+ url: selectedThumbnailForFile?.url || thumbnailSelectorFile.url,
1831
+ key: thumbnailSelectorFile.key,
1832
+ originalName: thumbnailSelectorFile.originalName,
1833
+ size: thumbnailSelectorFile.size,
1834
+ contentType: thumbnailSelectorFile.contentType,
1835
+ thumbnails: thumbnailSelectorFile.thumbnails,
1836
+ selectedThumbnail: selectedThumbnailForFile || void 0
1837
+ });
1838
+ onOpenChange(false);
1839
+ setThumbnailSelectorFile(null);
1840
+ }
1841
+ },
1842
+ className: "px-4 py-2 text-sm font-medium rounded-lg bg-blue-600 text-white hover:bg-blue-700",
1843
+ children: [
1844
+ "Select ",
1845
+ selectedThumbnailForFile ? `${selectedThumbnailForFile.size}px Thumbnail` : "Original"
1846
+ ]
1847
+ }
1848
+ )
1849
+ ] })
1850
+ ] })
1851
+ ] }) }),
1852
+ /* @__PURE__ */ jsx(Dialog2.Root, { open: !!previewFile, onOpenChange: (open2) => !open2 && setPreviewFile(null), children: /* @__PURE__ */ jsxs(Dialog2.Portal, { children: [
1853
+ /* @__PURE__ */ jsx(Dialog2.Overlay, { className: "fixed inset-0 bg-black/90 z-[100]", onClick: () => setPreviewFile(null) }),
1854
+ /* @__PURE__ */ jsx(Dialog2.Content, { className: "fixed left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2 w-[90vw] h-[90vh] z-[101] outline-none", "aria-describedby": "image-preview-description", children: /* @__PURE__ */ jsxs("div", { className: "relative w-full h-full flex flex-col", children: [
1855
+ /* @__PURE__ */ jsx("div", { className: "absolute top-0 left-0 right-0 z-10 bg-gradient-to-b from-black/70 to-transparent p-6", children: /* @__PURE__ */ jsxs("div", { className: "flex items-start justify-between", children: [
1856
+ /* @__PURE__ */ jsxs("div", { className: "text-white", children: [
1857
+ /* @__PURE__ */ jsx(Dialog2.Title, { className: "text-xl font-semibold mb-1", children: previewFile?.originalName }),
1858
+ /* @__PURE__ */ jsxs(Dialog2.Description, { id: "image-preview-description", className: "text-sm text-gray-300", children: [
1859
+ previewFile?.size ? `${(previewFile.size / 1024).toFixed(1)} KB` : "",
1860
+ " \u2022 ",
1861
+ previewFile?.contentType
1862
+ ] })
1863
+ ] }),
1864
+ /* @__PURE__ */ jsx(
1865
+ "button",
1866
+ {
1867
+ onClick: () => setPreviewFile(null),
1868
+ className: "p-2 bg-white/10 hover:bg-white/20 rounded-lg backdrop-blur-md transition-colors",
1869
+ children: /* @__PURE__ */ jsx(IconX, { className: "w-6 h-6 text-white" })
1870
+ }
1871
+ )
1872
+ ] }) }),
1873
+ /* @__PURE__ */ jsx("div", { className: "flex-1 flex items-center justify-center p-6", children: /* @__PURE__ */ jsx(
1874
+ "img",
1875
+ {
1876
+ src: previewFile?.url,
1877
+ alt: previewFile?.originalName,
1878
+ className: "max-w-full max-h-full object-contain",
1879
+ onError: (e) => {
1880
+ const target = e.target;
1881
+ target.style.display = "none";
1882
+ const errorDiv = document.createElement("div");
1883
+ errorDiv.className = "text-white text-center";
1884
+ errorDiv.innerHTML = `
1885
+ <div class="text-red-400 mb-2">Failed to load image</div>
1886
+ <div class="text-sm text-gray-400">URL: ${previewFile?.url}</div>
1887
+ `;
1888
+ target.parentElement?.appendChild(errorDiv);
1889
+ }
1890
+ }
1891
+ ) }),
1892
+ /* @__PURE__ */ jsx("div", { className: "absolute bottom-0 left-0 right-0 z-10 bg-gradient-to-t from-black/70 to-transparent p-6", children: /* @__PURE__ */ jsxs("div", { className: "flex gap-3 justify-center", children: [
1893
+ /* @__PURE__ */ jsx(
1894
+ "button",
1895
+ {
1896
+ onClick: (e) => {
1897
+ e.stopPropagation();
1898
+ if (previewFile) {
1899
+ onSelect({
1900
+ url: previewFile.url,
1901
+ key: previewFile.key,
1902
+ originalName: previewFile.originalName,
1903
+ size: previewFile.size,
1904
+ contentType: previewFile.contentType,
1905
+ thumbnails: previewFile.thumbnails
1906
+ });
1907
+ onOpenChange(false);
1908
+ setPreviewFile(null);
1909
+ }
1910
+ },
1911
+ className: "px-6 py-2.5 bg-blue-600 text-white font-semibold rounded-lg hover:bg-blue-500 shadow-lg",
1912
+ children: "Select Image"
1913
+ }
1914
+ ),
1915
+ /* @__PURE__ */ jsx(
1916
+ "a",
1917
+ {
1918
+ href: previewFile?.url,
1919
+ target: "_blank",
1920
+ rel: "noopener noreferrer",
1921
+ onClick: (e) => e.stopPropagation(),
1922
+ className: "px-6 py-2.5 bg-white/10 text-white font-semibold rounded-lg hover:bg-white/20 backdrop-blur-md transition-colors",
1923
+ children: "Open in New Tab"
1924
+ }
1925
+ ),
1926
+ previewFile?.thumbnails && previewFile.thumbnails.length > 0 && /* @__PURE__ */ jsxs(
1927
+ "button",
1928
+ {
1929
+ onClick: (e) => {
1930
+ e.stopPropagation();
1931
+ setThumbnailSelectorFile(previewFile);
1932
+ setSelectedThumbnailForFile(null);
1933
+ setPreviewFile(null);
1934
+ },
1935
+ className: "px-6 py-2.5 bg-purple-600 text-white font-semibold rounded-lg hover:bg-purple-500 shadow-lg flex items-center gap-2",
1936
+ children: [
1937
+ /* @__PURE__ */ jsx(IconLayers, { className: "w-5 h-5" }),
1938
+ "Select Thumbnail"
1939
+ ]
1940
+ }
1941
+ )
1942
+ ] }) })
1943
+ ] }) })
1709
1944
  ] }) })
1710
1945
  ] });
1711
1946
  }
1712
- export {
1713
- ConnectProjectDialog,
1714
- ImageManager,
1715
- ProjectFilesWidget,
1716
- UpfilesClient,
1717
- Uploader,
1718
- addApiKeyManually,
1719
- connectProject,
1720
- connectUsingApiKey,
1721
- createClientWithKey,
1722
- createProject,
1723
- fetchFileThumbnails,
1724
- fetchProjectFiles,
1725
- fetchProjectImagesWithThumbs,
1726
- listProjects
1727
- };
1947
+
1948
+ export { ConnectProjectDialog, ImageManager, ProjectFilesWidget, UpfilesClient, Uploader, addApiKeyManually, connectProject, connectUsingApiKey, createClientWithKey, createProject, fetchFileThumbnails, fetchProjectFiles, fetchProjectImagesWithThumbs, listProjects };
1949
+ //# sourceMappingURL=index.mjs.map
1950
+ //# sourceMappingURL=index.mjs.map