@muhgholy/next-drive 2.2.0 → 2.2.2

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.
Files changed (35) hide show
  1. package/README.md +222 -346
  2. package/dist/{chunk-5C6YUPCM.js → chunk-F5SLCUJ5.js} +26 -8
  3. package/dist/chunk-F5SLCUJ5.js.map +1 -0
  4. package/dist/client/components/dialog.d.ts.map +1 -1
  5. package/dist/client/components/drive/dnd-provider.d.ts +2 -2
  6. package/dist/client/components/drive/dnd-provider.d.ts.map +1 -1
  7. package/dist/client/components/drive/explorer.d.ts.map +1 -1
  8. package/dist/client/components/drive/file-grid.d.ts.map +1 -1
  9. package/dist/client/components/drive/header.d.ts +4 -1
  10. package/dist/client/components/drive/header.d.ts.map +1 -1
  11. package/dist/client/components/drive/path-bar.d.ts +3 -1
  12. package/dist/client/components/drive/path-bar.d.ts.map +1 -1
  13. package/dist/client/components/drive/sidebar.d.ts +3 -1
  14. package/dist/client/components/drive/sidebar.d.ts.map +1 -1
  15. package/dist/client/components/drive/storage/indicator.d.ts.map +1 -1
  16. package/dist/client/components/drive/upload.d.ts.map +1 -1
  17. package/dist/client/components/ui/progress.d.ts +2 -1
  18. package/dist/client/components/ui/progress.d.ts.map +1 -1
  19. package/dist/client/components/ui/sheet.d.ts.map +1 -1
  20. package/dist/client/context.d.ts +4 -0
  21. package/dist/client/context.d.ts.map +1 -1
  22. package/dist/client/file-chooser.d.ts.map +1 -1
  23. package/dist/client/index.d.ts +0 -1
  24. package/dist/client/index.d.ts.map +1 -1
  25. package/dist/client/index.js +487 -281
  26. package/dist/client/index.js.map +1 -1
  27. package/dist/client/styles.css +57 -40
  28. package/dist/server/express.js +2 -2
  29. package/dist/server/index.d.ts.map +1 -1
  30. package/dist/server/index.js +1 -1
  31. package/dist/server/providers/google.d.ts.map +1 -1
  32. package/package.json +5 -1
  33. package/dist/chunk-5C6YUPCM.js.map +0 -1
  34. package/dist/client/index.css +0 -48
  35. package/dist/client/index.css.map +0 -1
@@ -7,15 +7,15 @@ import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
7
7
  import { Slot } from '@radix-ui/react-slot';
8
8
  import { cva } from 'class-variance-authority';
9
9
  import * as SheetPrimitive from '@radix-ui/react-dialog';
10
- import { X, ChevronRight, Check, Circle, Loader2, Folder, FolderPlus, Menu, RotateCcw, Trash2, Group, ArrowUpDown, Calendar, ArrowDownAZ, ArrowUpAZ, ArrowDown01, ArrowUp01, LayoutGrid, List, Upload, Cloud, AlertCircle, Pencil, Database, HardDrive, ChevronsUpDown, Settings2, Trash, Plus, FolderOpen, Clock, CheckCircle2 } from 'lucide-react';
10
+ import { X, ChevronRight, Check, Circle, Loader2, Folder, FolderPlus, Menu, RotateCcw, Trash2, Group, ArrowUpDown, Calendar, ArrowDownAZ, ArrowUpAZ, ArrowDown01, ArrowUp01, LayoutGrid, List, RefreshCw, Upload, CheckCircle2, Cloud, AlertCircle, Pencil, HardDrive, Database, ChevronsUpDown, Plus, Settings2, Trash, FolderOpen, Clock } from 'lucide-react';
11
11
  import * as DropdownMenuPrimitive from '@radix-ui/react-dropdown-menu';
12
12
  import * as LabelPrimitive from '@radix-ui/react-label';
13
13
  import { useSensors, useSensor, PointerSensor, KeyboardSensor, DndContext, pointerWithin, closestCenter, useDroppable } from '@dnd-kit/core';
14
14
  import { sortableKeyboardCoordinates, arrayMove, SortableContext, rectSortingStrategy, useSortable } from '@dnd-kit/sortable';
15
+ import * as ProgressPrimitive from '@radix-ui/react-progress';
15
16
  import { startOfWeek, subWeeks, isToday, isYesterday, isAfter } from 'date-fns';
16
17
  import * as ContextMenuPrimitive from '@radix-ui/react-context-menu';
17
18
  import { CSS } from '@dnd-kit/utilities';
18
- import * as ProgressPrimitive from '@radix-ui/react-progress';
19
19
 
20
20
  var DriveContext = createContext(null);
21
21
  var DriveProvider = (props) => {
@@ -34,6 +34,7 @@ var DriveProvider = (props) => {
34
34
  const [path, setPath] = useState([{ id: null, name: "Home" }]);
35
35
  const [accounts, setAccounts] = useState([]);
36
36
  const [activeAccountId, setActiveAccountIdState] = useState(initialActiveAccountId);
37
+ const [availableProviders, setAvailableProviders] = useState({ google: false });
37
38
  const [quota, setQuota] = useState(null);
38
39
  const [viewMode, setViewMode] = useState(() => {
39
40
  if (typeof window !== "undefined") return window.innerWidth < 768 ? "LIST" : "GRID";
@@ -105,6 +106,8 @@ var DriveProvider = (props) => {
105
106
  const refreshAccounts = useCallback(async () => {
106
107
  const res = await callAPI("listAccounts");
107
108
  if (res.status === 200 && res.data) setAccounts(res.data.accounts);
109
+ const infoRes = await callAPI("information");
110
+ if (infoRes.status === 200 && infoRes.data) setAvailableProviders(infoRes.data.providers);
108
111
  }, [callAPI]);
109
112
  const refreshQuota = useCallback(async () => {
110
113
  const res = await callAPI("quota");
@@ -123,6 +126,7 @@ var DriveProvider = (props) => {
123
126
  setCurrentView("BROWSE");
124
127
  setSearchQuery("");
125
128
  setSelectedFileIds([]);
129
+ setIsLoading(true);
126
130
  if (!item) {
127
131
  setCurrentFolderId(null);
128
132
  setPath([{ id: null, name: "Home" }]);
@@ -139,6 +143,7 @@ var DriveProvider = (props) => {
139
143
  setCurrentView("BROWSE");
140
144
  setSearchQuery("");
141
145
  setSelectedFileIds([]);
146
+ setIsLoading(true);
142
147
  const newPath = path.slice(0, -1);
143
148
  setPath(newPath);
144
149
  setCurrentFolderId(newPath[newPath.length - 1]?.id || null);
@@ -225,11 +230,13 @@ var DriveProvider = (props) => {
225
230
  setItems,
226
231
  isLoading,
227
232
  error,
233
+ fetchItems,
228
234
  // Accounts
229
235
  accounts,
230
236
  activeAccountId,
231
237
  setActiveAccountId,
232
238
  refreshAccounts,
239
+ availableProviders,
233
240
  // Storage
234
241
  quota,
235
242
  refreshQuota,
@@ -1029,6 +1036,7 @@ var DialogConfirmation = (props) => {
1029
1036
  return /* @__PURE__ */ jsx(Dialog, { open, onOpenChange: handleOpenChange, children: /* @__PURE__ */ jsxs(
1030
1037
  DialogContent,
1031
1038
  {
1039
+ showCloseButton: false,
1032
1040
  onInteractOutside: (e) => {
1033
1041
  if (disableEscapeKeyDown) {
1034
1042
  e.preventDefault();
@@ -1082,7 +1090,8 @@ var DriveDndContext = createContext({
1082
1090
  draggingItemId: null
1083
1091
  });
1084
1092
  var useDriveDnd = () => useContext(DriveDndContext);
1085
- var DriveDndProvider = ({ children }) => {
1093
+ var DriveDndProvider = (props) => {
1094
+ const { children } = props;
1086
1095
  const { items, setItems, sortBy, setSortBy, moveItem, callAPI, currentView } = useDrive();
1087
1096
  const [dragOverFolderId, setDragOverFolderId] = useState(null);
1088
1097
  const [draggingItemId, setDraggingItemId] = useState(null);
@@ -1149,6 +1158,39 @@ var DriveDndProvider = ({ children }) => {
1149
1158
  }
1150
1159
  ) : children });
1151
1160
  };
1161
+ function Progress({
1162
+ className,
1163
+ value,
1164
+ indicatorClassName,
1165
+ indeterminate = false,
1166
+ ...props
1167
+ }) {
1168
+ const isIndeterminate = indeterminate || value === void 0;
1169
+ return /* @__PURE__ */ jsx(
1170
+ ProgressPrimitive.Root,
1171
+ {
1172
+ "data-slot": "progress",
1173
+ className: cn(
1174
+ "bg-primary/20 relative h-2 w-full overflow-hidden rounded-full",
1175
+ className
1176
+ ),
1177
+ ...props,
1178
+ children: /* @__PURE__ */ jsx(
1179
+ ProgressPrimitive.Indicator,
1180
+ {
1181
+ "data-slot": "progress-indicator",
1182
+ className: cn(
1183
+ "bg-primary h-full flex-1 transition-all",
1184
+ isIndeterminate && "w-1/3 animate-indeterminate",
1185
+ !isIndeterminate && "w-full",
1186
+ indicatorClassName
1187
+ ),
1188
+ style: isIndeterminate ? void 0 : { transform: `translateX(-${100 - (value || 0)}%)` }
1189
+ }
1190
+ )
1191
+ }
1192
+ );
1193
+ }
1152
1194
  var ContextMenu = ContextMenuPrimitive.Root;
1153
1195
  var ContextMenuTrigger = ContextMenuPrimitive.Trigger;
1154
1196
  var ContextMenuSubTrigger = React3.forwardRef(({ className, inset, children, ...props }, ref) => /* @__PURE__ */ jsxs(
@@ -1260,7 +1302,8 @@ var ContextMenuSeparator = React3.forwardRef(({ className, ...props }, ref) => /
1260
1302
  }
1261
1303
  ));
1262
1304
  ContextMenuSeparator.displayName = ContextMenuPrimitive.Separator.displayName;
1263
- var SortableItem = ({ id, children, disabled, isDragOverTarget }) => {
1305
+ var SortableItem = (props) => {
1306
+ const { id, children, disabled, isDragOverTarget } = props;
1264
1307
  const { attributes, listeners, setNodeRef, transform, transition, isDragging } = useSortable({ id, disabled });
1265
1308
  const style = {
1266
1309
  transform: isDragOverTarget ? void 0 : CSS.Transform.toString(transform),
@@ -1271,7 +1314,8 @@ var SortableItem = ({ id, children, disabled, isDragOverTarget }) => {
1271
1314
  };
1272
1315
  return /* @__PURE__ */ jsx("div", { ref: setNodeRef, style, ...attributes, ...listeners, children });
1273
1316
  };
1274
- var FileItem = ({ item, isSelected, isDragOver, onSelect, onDoubleClick, onRename, onDelete, onRestore }) => {
1317
+ var FileItem = (props) => {
1318
+ const { item, isSelected, isDragOver, onSelect, onDoubleClick, onRename, onDelete, onRestore } = props;
1275
1319
  const { apiEndpoint, viewMode, currentView } = useDrive();
1276
1320
  const isFolder = item.information.type === "FOLDER";
1277
1321
  const tokenParam = item.token ? `&token=${item.token}` : "";
@@ -1460,34 +1504,36 @@ var DriveFileGrid = (props) => {
1460
1504
  };
1461
1505
  const enableDrag = currentView === "BROWSE";
1462
1506
  if (isLoading && items.length === 0) {
1463
- return /* @__PURE__ */ jsx("div", { className: cn("flex-1 flex items-center justify-center", className), children: /* @__PURE__ */ jsx(Loader2, { className: "size-8 animate-spin text-muted-foreground" }) });
1507
+ return /* @__PURE__ */ jsxs("div", { className: cn("flex-1 flex flex-col", className), children: [
1508
+ /* @__PURE__ */ jsx("div", { className: "h-1 w-full shrink-0", children: /* @__PURE__ */ jsx(
1509
+ Progress,
1510
+ {
1511
+ indeterminate: true,
1512
+ className: "h-full rounded-none bg-primary/10",
1513
+ indicatorClassName: "bg-primary"
1514
+ }
1515
+ ) }),
1516
+ /* @__PURE__ */ jsx("div", { className: "flex-1 flex items-center justify-center", children: /* @__PURE__ */ jsx(Loader2, { className: "size-8 animate-spin text-muted-foreground" }) })
1517
+ ] });
1464
1518
  }
1465
1519
  if (error) {
1466
- return /* @__PURE__ */ jsx("div", { className: cn("flex-1 flex items-center justify-center p-8", className), children: /* @__PURE__ */ jsx("div", { className: "text-center", children: /* @__PURE__ */ jsx("p", { className: "text-destructive font-medium", children: error }) }) });
1520
+ return /* @__PURE__ */ jsx("div", { className: cn("flex-1 flex items-center justify-center p-8", className), children: /* @__PURE__ */ jsx("p", { className: "text-destructive font-medium text-center", children: error }) });
1467
1521
  }
1468
1522
  if (processedItems.length === 0) {
1469
- return /* @__PURE__ */ jsxs(Fragment, { children: [
1470
- /* @__PURE__ */ jsxs("div", { className: cn("flex-1 flex flex-col items-center justify-center p-8 text-center", className), children: [
1471
- /* @__PURE__ */ jsx("div", { className: "size-16 rounded-2xl bg-muted/50 dark:bg-muted/30 flex items-center justify-center mb-4", children: /* @__PURE__ */ jsx(Folder, { className: "size-8 text-muted-foreground/60" }) }),
1472
- /* @__PURE__ */ jsx("p", { className: "text-sm font-medium text-muted-foreground", children: currentView === "SEARCH" ? "No files match your search" : currentView === "TRASH" ? "Trash is empty" : "This folder is empty" })
1473
- ] }),
1474
- /* @__PURE__ */ jsx(
1475
- DialogConfirmation,
1476
- {
1477
- open: dialogs.newFolder,
1478
- onClose: () => setDialogs((prev) => ({ ...prev, newFolder: false })),
1479
- title: "Create New Folder",
1480
- description: "Enter a name for the new folder",
1481
- inputs: [{ type: "INPUT", id: "name", name: "Folder name", required: true }],
1482
- onConfirm: async (inputs) => {
1483
- await createFolder(inputs.name);
1484
- return [true];
1485
- }
1486
- }
1487
- )
1523
+ return /* @__PURE__ */ jsxs("div", { className: cn("flex-1 flex flex-col items-center justify-center p-8 text-center", className), children: [
1524
+ /* @__PURE__ */ jsx("div", { className: "size-16 rounded-2xl bg-muted/50 dark:bg-muted/30 flex items-center justify-center mb-4", children: /* @__PURE__ */ jsx(Folder, { className: "size-8 text-muted-foreground/60" }) }),
1525
+ /* @__PURE__ */ jsx("p", { className: "text-sm font-medium text-muted-foreground", children: currentView === "SEARCH" ? "No files match your search" : currentView === "TRASH" ? "Trash is empty" : "This folder is empty" })
1488
1526
  ] });
1489
1527
  }
1490
1528
  return /* @__PURE__ */ jsxs(Fragment, { children: [
1529
+ isLoading && /* @__PURE__ */ jsx("div", { className: "h-1 w-full shrink-0", children: /* @__PURE__ */ jsx(
1530
+ Progress,
1531
+ {
1532
+ indeterminate: true,
1533
+ className: "h-full rounded-none bg-primary/10",
1534
+ indicatorClassName: "bg-primary"
1535
+ }
1536
+ ) }),
1491
1537
  /* @__PURE__ */ jsxs("div", { className: cn("flex-1 overflow-y-auto min-h-0 p-2 sm:p-3 md:p-4", className), children: [
1492
1538
  /* @__PURE__ */ jsx("div", { className: "space-y-4 sm:space-y-6", children: Object.entries(groupedItems).map(([groupName, groupItems]) => /* @__PURE__ */ jsxs("div", { children: [
1493
1539
  groupBy !== "NONE" && /* @__PURE__ */ jsxs("h3", { className: "text-xs font-semibold text-muted-foreground uppercase tracking-wide mb-2 sm:mb-3 px-1", children: [
@@ -1585,7 +1631,7 @@ var DriveFileGrid = (props) => {
1585
1631
  )
1586
1632
  ] });
1587
1633
  };
1588
- var DriveHeader = () => {
1634
+ var DriveHeader = ({ className }) => {
1589
1635
  const {
1590
1636
  viewMode,
1591
1637
  setViewMode,
@@ -1608,7 +1654,7 @@ var DriveHeader = () => {
1608
1654
  createFolder
1609
1655
  } = useDrive();
1610
1656
  const [dialogs, setDialogs] = useState({ delete: false, emptyTrash: false, newFolder: false });
1611
- return /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center gap-2 border-b bg-muted/30 dark:bg-muted/20 p-2", children: [
1657
+ return /* @__PURE__ */ jsxs("div", { className: cn("flex flex-wrap items-center gap-2 bg-muted/30 dark:bg-muted/20 p-2", className), children: [
1612
1658
  currentView === "BROWSE" && /* @__PURE__ */ jsxs(
1613
1659
  Button,
1614
1660
  {
@@ -1878,6 +1924,18 @@ var DriveHeader = () => {
1878
1924
  )
1879
1925
  ] });
1880
1926
  };
1927
+ var DriveContentProgress = () => {
1928
+ const { isLoading } = useDrive();
1929
+ if (!isLoading) return null;
1930
+ return /* @__PURE__ */ jsx("div", { className: "h-1 w-full shrink-0", children: /* @__PURE__ */ jsx(
1931
+ Progress,
1932
+ {
1933
+ indeterminate: true,
1934
+ className: "h-full rounded-none bg-primary/10",
1935
+ indicatorClassName: "bg-primary"
1936
+ }
1937
+ ) });
1938
+ };
1881
1939
  var DroppablePathItem = (props) => {
1882
1940
  const { id, name, isLast, onClick } = props;
1883
1941
  const { currentFolderId } = useDrive();
@@ -1909,7 +1967,7 @@ var DroppablePathItem = (props) => {
1909
1967
  variant: "ghost",
1910
1968
  size: "sm",
1911
1969
  className: cn(
1912
- "h-auto font-normal text-xs sm:text-sm px-1.5 sm:px-2 py-0.5 sm:py-1 truncate max-w-25 sm:max-w-37.5",
1970
+ "h-6 font-normal text-xs sm:text-sm px-1.5 sm:px-2 truncate max-w-25 sm:max-w-37.5",
1913
1971
  isOver && !isCurrentFolder && "ring-2 ring-primary bg-primary/10 scale-105"
1914
1972
  ),
1915
1973
  onClick,
@@ -1919,9 +1977,9 @@ var DroppablePathItem = (props) => {
1919
1977
  }
1920
1978
  );
1921
1979
  };
1922
- var DrivePathBar = () => {
1980
+ var DrivePathBar = ({ className }) => {
1923
1981
  const { path, navigateToFolder } = useDrive();
1924
- return /* @__PURE__ */ jsx("ol", { className: "flex items-center gap-1 sm:gap-1.5 text-sm text-muted-foreground bg-muted/30 px-2 sm:px-3 py-1.5 sm:py-2 rounded-md border w-full overflow-x-auto flex-nowrap min-w-0", "aria-label": "Breadcrumb", role: "navigation", children: path.map((item, index) => {
1982
+ return /* @__PURE__ */ jsx("ol", { className: cn("flex items-center gap-1 sm:gap-1.5 text-sm text-muted-foreground overflow-x-auto flex-nowrap min-w-0", className), "aria-label": "Breadcrumb", role: "navigation", children: path.map((item, index) => {
1925
1983
  const isLast = index === path.length - 1;
1926
1984
  return /* @__PURE__ */ jsxs("li", { className: "flex items-center gap-1 sm:gap-1.5 shrink-0", children: [
1927
1985
  index > 0 && /* @__PURE__ */ jsx("span", { className: "text-muted-foreground/50 text-xs", "aria-hidden": "true", children: "/" }),
@@ -1937,33 +1995,8 @@ var DrivePathBar = () => {
1937
1995
  ] }, item.id ?? "root");
1938
1996
  }) });
1939
1997
  };
1940
- function Progress({
1941
- className,
1942
- value,
1943
- indicatorClassName,
1944
- ...props
1945
- }) {
1946
- return /* @__PURE__ */ jsx(
1947
- ProgressPrimitive.Root,
1948
- {
1949
- "data-slot": "progress",
1950
- className: cn(
1951
- "bg-primary/20 relative h-2 w-full overflow-hidden rounded-full",
1952
- className
1953
- ),
1954
- ...props,
1955
- children: /* @__PURE__ */ jsx(
1956
- ProgressPrimitive.Indicator,
1957
- {
1958
- "data-slot": "progress-indicator",
1959
- className: cn("bg-primary h-full w-full flex-1 transition-all", indicatorClassName),
1960
- style: { transform: `translateX(-${100 - (value || 0)}%)` }
1961
- }
1962
- )
1963
- }
1964
- );
1965
- }
1966
- var UploadStatusIcon = ({ status }) => {
1998
+ var UploadStatusIcon = (props) => {
1999
+ const { status } = props;
1967
2000
  switch (status) {
1968
2001
  case "complete":
1969
2002
  return /* @__PURE__ */ jsx(CheckCircle2, { className: "size-4 text-emerald-500" });
@@ -1982,7 +2015,7 @@ var DriveUpload = (props) => {
1982
2015
  const [isDragging, setIsDragging] = useState(false);
1983
2016
  const [showUploadsDialog, setShowUploadsDialog] = useState(false);
1984
2017
  const inputRef = useRef(null);
1985
- const { currentFolderId, setItems, apiEndpoint, activeAccountId, withCredentials } = useDrive();
2018
+ const { currentFolderId, setItems, apiEndpoint, activeAccountId, withCredentials, fetchItems, isLoading } = useDrive();
1986
2019
  const { uploads, uploadFiles, cancelUpload, cancelAllUploads } = useUpload(apiEndpoint, activeAccountId, withCredentials, (uploadedItem) => {
1987
2020
  if (uploadedItem) {
1988
2021
  setItems((prev) => [uploadedItem, ...prev]);
@@ -2102,6 +2135,18 @@ var DriveUpload = (props) => {
2102
2135
  "aria-hidden": "true"
2103
2136
  }
2104
2137
  ),
2138
+ activeAccountId && /* @__PURE__ */ jsx(
2139
+ Button,
2140
+ {
2141
+ onClick: () => fetchItems(),
2142
+ type: "button",
2143
+ variant: "outline",
2144
+ size: "sm",
2145
+ disabled: isLoading,
2146
+ title: "Refresh",
2147
+ children: /* @__PURE__ */ jsx(RefreshCw, { className: cn("!size-4 shrink-0", isLoading && "animate-spin") })
2148
+ }
2149
+ ),
2105
2150
  /* @__PURE__ */ jsxs(
2106
2151
  Button,
2107
2152
  {
@@ -2110,8 +2155,8 @@ var DriveUpload = (props) => {
2110
2155
  size: "sm",
2111
2156
  disabled: hasUploadsInProgress,
2112
2157
  children: [
2113
- /* @__PURE__ */ jsx(Upload, { className: "size-4 mr-1.5" }),
2114
- " Upload"
2158
+ /* @__PURE__ */ jsx(Upload, { className: "!size-4 shrink-0" }),
2159
+ /* @__PURE__ */ jsx("span", { children: "Upload" })
2115
2160
  ]
2116
2161
  }
2117
2162
  ),
@@ -2123,8 +2168,8 @@ var DriveUpload = (props) => {
2123
2168
  size: "sm",
2124
2169
  onClick: () => setShowUploadsDialog(true),
2125
2170
  children: [
2126
- activeUploads.length > 0 && /* @__PURE__ */ jsx(Loader2, { className: "size-3.5 mr-1.5 animate-spin" }),
2127
- activeUploads.length > 0 ? `(${activeUploads.length})` : "Status"
2171
+ activeUploads.length > 0 ? /* @__PURE__ */ jsx(Loader2, { className: "!size-4 shrink-0 animate-spin" }) : /* @__PURE__ */ jsx(CheckCircle2, { className: "!size-4 shrink-0" }),
2172
+ /* @__PURE__ */ jsx("span", { children: activeUploads.length > 0 ? `(${activeUploads.length})` : "Status" })
2128
2173
  ]
2129
2174
  }
2130
2175
  )
@@ -2235,7 +2280,8 @@ var DriveStorageIndicator = (props) => {
2235
2280
  ] })
2236
2281
  ] });
2237
2282
  };
2238
- var ChooserSidebar = () => {
2283
+ var ChooserSidebar = (props) => {
2284
+ const { onNavigate } = props;
2239
2285
  const {
2240
2286
  accounts,
2241
2287
  activeAccountId,
@@ -2243,14 +2289,20 @@ var ChooserSidebar = () => {
2243
2289
  callAPI,
2244
2290
  refreshAccounts,
2245
2291
  currentView,
2246
- setCurrentView
2292
+ setCurrentView,
2293
+ availableProviders
2247
2294
  } = useDrive();
2248
2295
  const [renameDialog, setRenameDialog] = useState({ open: false, account: null });
2249
2296
  const [deleteDialog, setDeleteDialog] = useState({ open: false, account: null });
2250
2297
  const [newName, setNewName] = useState("");
2298
+ const [oauthLoading, setOauthLoading] = useState(false);
2299
+ const [oauthAbort, setOauthAbort] = useState(null);
2300
+ const [dropdownOpen, setDropdownOpen] = useState(false);
2251
2301
  const currentAccount = activeAccountId ? accounts.find((a) => a.id === activeAccountId) : null;
2252
2302
  const currentAccountName = currentAccount?.name || "Local Storage";
2253
2303
  const currentAccountEmail = currentAccount?.email || "On this device";
2304
+ const hasAnyProvider = availableProviders.google;
2305
+ const isDropdownDisabled = accounts.length === 0 && !hasAnyProvider;
2254
2306
  const handleRename = async () => {
2255
2307
  if (!renameDialog.account || !newName.trim()) return;
2256
2308
  await callAPI("renameAccount", { method: "PATCH", query: { id: renameDialog.account.id }, body: JSON.stringify({ name: newName.trim() }) });
@@ -2266,90 +2318,157 @@ var ChooserSidebar = () => {
2266
2318
  setDeleteDialog({ open: false, account: null });
2267
2319
  return [true];
2268
2320
  };
2269
- const openOAuthPopup = async () => {
2270
- const res = await callAPI("getAuthUrl", { query: { provider: "GOOGLE" } });
2271
- if (res.status !== 200 || !res.data?.url) {
2272
- alert(res.message || "Failed");
2273
- return;
2274
- }
2321
+ const openOAuthPopup = () => {
2275
2322
  const width = 600, height = 600;
2276
2323
  const left = window.screen.width / 2 - width / 2;
2277
2324
  const top = window.screen.height / 2 - height / 2;
2278
- window.open(res.data.url, "Connect to Google Drive", `width=${width},height=${height},top=${top},left=${left}`);
2279
- const cleanup = () => {
2280
- window.removeEventListener("message", ml);
2281
- window.removeEventListener("storage", sl);
2282
- };
2283
- const ml = (e) => {
2284
- if (e.data === "oauth-success") {
2285
- cleanup();
2286
- refreshAccounts();
2287
- }
2288
- };
2289
- const sl = (e) => {
2290
- if (e.key === "next-drive-oauth-success") {
2291
- cleanup();
2292
- refreshAccounts();
2325
+ const popup = window.open("about:blank", "Connect to Google Drive", `width=${width},height=${height},top=${top},left=${left}`);
2326
+ if (!popup) {
2327
+ alert("Popup blocked. Please allow popups for this site.");
2328
+ return;
2329
+ }
2330
+ const controller = new AbortController();
2331
+ setOauthAbort(controller);
2332
+ setOauthLoading(true);
2333
+ (async () => {
2334
+ try {
2335
+ const res = await callAPI("getAuthUrl", { query: { provider: "GOOGLE" } });
2336
+ if (controller.signal.aborted) {
2337
+ popup.close();
2338
+ return;
2339
+ }
2340
+ if (res.status !== 200 || !res.data?.url) {
2341
+ popup.close();
2342
+ setOauthLoading(false);
2343
+ setOauthAbort(null);
2344
+ alert(res.message || "Failed to initialize account connection");
2345
+ return;
2346
+ }
2347
+ popup.location.href = res.data.url;
2348
+ const cleanup = () => {
2349
+ window.removeEventListener("message", ml);
2350
+ window.removeEventListener("storage", sl);
2351
+ setOauthLoading(false);
2352
+ setOauthAbort(null);
2353
+ };
2354
+ const ml = (e) => {
2355
+ if (e.data === "oauth-success") {
2356
+ cleanup();
2357
+ refreshAccounts();
2358
+ setDropdownOpen(true);
2359
+ }
2360
+ };
2361
+ const sl = (e) => {
2362
+ if (e.key === "next-drive-oauth-success") {
2363
+ cleanup();
2364
+ refreshAccounts();
2365
+ setDropdownOpen(true);
2366
+ }
2367
+ };
2368
+ window.addEventListener("message", ml);
2369
+ window.addEventListener("storage", sl);
2370
+ const checkPopupClosed = setInterval(() => {
2371
+ if (popup.closed) {
2372
+ clearInterval(checkPopupClosed);
2373
+ cleanup();
2374
+ }
2375
+ }, 500);
2376
+ } catch {
2377
+ popup.close();
2378
+ setOauthLoading(false);
2379
+ setOauthAbort(null);
2380
+ alert("Failed to connect. Please try again.");
2293
2381
  }
2294
- };
2295
- window.addEventListener("message", ml);
2296
- window.addEventListener("storage", sl);
2382
+ })();
2383
+ };
2384
+ const cancelOAuth = () => {
2385
+ oauthAbort?.abort();
2386
+ setOauthLoading(false);
2387
+ setOauthAbort(null);
2297
2388
  };
2298
2389
  return /* @__PURE__ */ jsxs("div", { className: "flex flex-col h-full w-full bg-muted/5 dark:bg-muted/10", children: [
2299
- /* @__PURE__ */ jsx("div", { className: "p-2 border-b border-border/50", children: /* @__PURE__ */ jsxs(DropdownMenu, { children: [
2300
- /* @__PURE__ */ jsx(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsxs(Button, { variant: "ghost", className: "w-full justify-between px-2 h-11 hover:bg-muted/50 dark:hover:bg-muted/30", children: [
2301
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 text-left min-w-0 flex-1", children: [
2302
- /* @__PURE__ */ jsx("div", { className: cn(
2303
- "size-7 rounded-md flex items-center justify-center shrink-0",
2304
- activeAccountId ? "bg-blue-500/10 text-blue-600 dark:bg-blue-500/20 dark:text-blue-400" : "bg-emerald-500/10 text-emerald-600 dark:bg-emerald-500/20 dark:text-emerald-400"
2305
- ), children: activeAccountId ? /* @__PURE__ */ jsx(Database, { className: "size-3.5" }) : /* @__PURE__ */ jsx(HardDrive, { className: "size-3.5" }) }),
2390
+ /* @__PURE__ */ jsx("div", { className: "p-2 border-b border-border/50", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1", children: [
2391
+ isDropdownDisabled ? (
2392
+ /* Static display when no accounts and no providers */
2393
+ /* @__PURE__ */ jsxs("div", { className: "flex-1 flex items-center gap-2 px-2 h-11 min-w-0", children: [
2394
+ /* @__PURE__ */ jsx("div", { className: "size-7 rounded-md flex items-center justify-center shrink-0 bg-emerald-500/10 text-emerald-600 dark:bg-emerald-500/20 dark:text-emerald-400", children: /* @__PURE__ */ jsx(HardDrive, { className: "size-3.5" }) }),
2306
2395
  /* @__PURE__ */ jsxs("div", { className: "flex flex-col min-w-0", children: [
2307
- /* @__PURE__ */ jsx("span", { className: "text-sm font-medium truncate", children: currentAccountName }),
2308
- /* @__PURE__ */ jsx("span", { className: "text-[11px] text-muted-foreground truncate", children: currentAccountEmail })
2396
+ /* @__PURE__ */ jsx("span", { className: "text-sm font-medium truncate", children: "Local Storage" }),
2397
+ /* @__PURE__ */ jsx("span", { className: "text-[11px] text-muted-foreground truncate", children: "On this device" })
2309
2398
  ] })
2310
- ] }),
2311
- /* @__PURE__ */ jsx(ChevronsUpDown, { className: "size-3.5 text-muted-foreground/60 shrink-0" })
2312
- ] }) }),
2313
- /* @__PURE__ */ jsxs(DropdownMenuContent, { className: "w-56", align: "start", children: [
2314
- /* @__PURE__ */ jsx(DropdownMenuLabel, { className: "text-[11px] font-medium text-muted-foreground uppercase tracking-wide", children: "Storage" }),
2315
- /* @__PURE__ */ jsxs(DropdownMenuItem, { onClick: () => setActiveAccountId(null), className: "gap-2 py-2", children: [
2316
- /* @__PURE__ */ jsx("span", { className: "flex-1 text-sm", children: "Local Storage" }),
2317
- activeAccountId === null && /* @__PURE__ */ jsx(Check, { className: "size-3.5 text-primary" })
2318
- ] }),
2319
- accounts.length > 0 && /* @__PURE__ */ jsx(DropdownMenuSeparator, {}),
2320
- accounts.map((account) => /* @__PURE__ */ jsxs("div", { className: "flex items-center group", children: [
2321
- /* @__PURE__ */ jsxs(DropdownMenuItem, { onClick: () => setActiveAccountId(account.id), className: "flex-1 gap-2 py-2 pr-1", children: [
2322
- /* @__PURE__ */ jsxs("div", { className: "flex-1 min-w-0", children: [
2323
- /* @__PURE__ */ jsx("p", { className: "text-sm truncate", children: account.name }),
2324
- /* @__PURE__ */ jsx("p", { className: "text-[10px] text-muted-foreground truncate", children: account.email })
2325
- ] }),
2326
- activeAccountId === account.id && /* @__PURE__ */ jsx(Check, { className: "size-3.5 text-primary" })
2399
+ ] })
2400
+ ) : /* @__PURE__ */ jsxs(DropdownMenu, { open: dropdownOpen, onOpenChange: setDropdownOpen, children: [
2401
+ /* @__PURE__ */ jsx(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsxs(Button, { variant: "ghost", className: "flex-1 min-w-0 justify-between px-2 h-11 hover:bg-muted/50 dark:hover:bg-muted/30", children: [
2402
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 text-left min-w-0 flex-1", children: [
2403
+ /* @__PURE__ */ jsx("div", { className: cn(
2404
+ "size-7 rounded-md flex items-center justify-center shrink-0",
2405
+ activeAccountId ? "bg-blue-500/10 text-blue-600 dark:bg-blue-500/20 dark:text-blue-400" : "bg-emerald-500/10 text-emerald-600 dark:bg-emerald-500/20 dark:text-emerald-400"
2406
+ ), children: activeAccountId ? /* @__PURE__ */ jsx(Database, { className: "size-3.5" }) : /* @__PURE__ */ jsx(HardDrive, { className: "size-3.5" }) }),
2407
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col min-w-0", children: [
2408
+ /* @__PURE__ */ jsx("span", { className: "text-sm font-medium truncate", children: currentAccountName }),
2409
+ /* @__PURE__ */ jsx("span", { className: "text-[11px] text-muted-foreground truncate", children: currentAccountEmail })
2410
+ ] })
2411
+ ] }),
2412
+ /* @__PURE__ */ jsx(ChevronsUpDown, { className: "size-3.5 text-muted-foreground/60 shrink-0" })
2413
+ ] }) }),
2414
+ /* @__PURE__ */ jsxs(DropdownMenuContent, { className: "w-56", align: "start", children: [
2415
+ /* @__PURE__ */ jsx(DropdownMenuLabel, { className: "text-[11px] font-medium text-muted-foreground uppercase tracking-wide", children: "Storage" }),
2416
+ /* @__PURE__ */ jsxs(DropdownMenuItem, { onClick: () => {
2417
+ setActiveAccountId(null);
2418
+ setCurrentView("BROWSE");
2419
+ onNavigate?.();
2420
+ }, className: "gap-2 py-2", children: [
2421
+ /* @__PURE__ */ jsx("span", { className: "flex-1 text-sm", children: "Local Storage" }),
2422
+ activeAccountId === null && /* @__PURE__ */ jsx(Check, { className: "size-3.5 text-primary" })
2327
2423
  ] }),
2328
- /* @__PURE__ */ jsxs(DropdownMenu, { children: [
2329
- /* @__PURE__ */ jsx(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsx(Button, { variant: "ghost", size: "icon", className: "size-7 mr-1 opacity-0 group-hover:opacity-100 transition-opacity", onClick: (e) => e.stopPropagation(), children: /* @__PURE__ */ jsx(Settings2, { className: "size-3.5 text-muted-foreground" }) }) }),
2330
- /* @__PURE__ */ jsxs(DropdownMenuContent, { align: "end", className: "w-36", children: [
2331
- /* @__PURE__ */ jsxs(DropdownMenuItem, { onClick: () => {
2332
- setNewName(account.name);
2333
- setRenameDialog({ open: true, account });
2334
- }, children: [
2335
- /* @__PURE__ */ jsx(Pencil, { className: "size-3.5 mr-2" }),
2336
- " Rename"
2424
+ accounts.length > 0 && /* @__PURE__ */ jsx(DropdownMenuSeparator, {}),
2425
+ accounts.map((account) => /* @__PURE__ */ jsxs(
2426
+ DropdownMenuItem,
2427
+ {
2428
+ onClick: () => {
2429
+ setActiveAccountId(account.id);
2430
+ setCurrentView("BROWSE");
2431
+ onNavigate?.();
2432
+ },
2433
+ className: "gap-2 py-2",
2434
+ children: [
2435
+ /* @__PURE__ */ jsxs("div", { className: "flex-1 min-w-0", children: [
2436
+ /* @__PURE__ */ jsx("p", { className: "text-sm truncate", children: account.name }),
2437
+ /* @__PURE__ */ jsx("p", { className: "text-[10px] text-muted-foreground truncate", children: account.email })
2438
+ ] }),
2439
+ activeAccountId === account.id && /* @__PURE__ */ jsx(Check, { className: "size-3.5 text-primary" })
2440
+ ]
2441
+ },
2442
+ account.id
2443
+ )),
2444
+ hasAnyProvider && /* @__PURE__ */ jsxs(Fragment, { children: [
2445
+ /* @__PURE__ */ jsx(DropdownMenuSeparator, {}),
2446
+ /* @__PURE__ */ jsxs(DropdownMenuSub, { children: [
2447
+ /* @__PURE__ */ jsxs(DropdownMenuSubTrigger, { className: "gap-2", children: [
2448
+ /* @__PURE__ */ jsx(Plus, { className: "size-3.5" }),
2449
+ /* @__PURE__ */ jsx("span", { className: "text-sm", children: "Add Account" })
2337
2450
  ] }),
2338
- /* @__PURE__ */ jsx(DropdownMenuSeparator, {}),
2339
- /* @__PURE__ */ jsxs(DropdownMenuItem, { className: "text-destructive focus:text-destructive", onClick: () => setDeleteDialog({ open: true, account }), children: [
2340
- /* @__PURE__ */ jsx(Trash, { className: "size-3.5 mr-2" }),
2341
- " Remove"
2342
- ] })
2451
+ /* @__PURE__ */ jsx(DropdownMenuSubContent, { children: availableProviders.google && /* @__PURE__ */ jsx(DropdownMenuItem, { onClick: openOAuthPopup, children: "Google Drive" }) })
2343
2452
  ] })
2344
2453
  ] })
2345
- ] }, account.id)),
2346
- /* @__PURE__ */ jsx(DropdownMenuSeparator, {}),
2347
- /* @__PURE__ */ jsxs(DropdownMenuSub, { children: [
2348
- /* @__PURE__ */ jsxs(DropdownMenuSubTrigger, { className: "gap-2", children: [
2349
- /* @__PURE__ */ jsx(Plus, { className: "size-3.5" }),
2350
- /* @__PURE__ */ jsx("span", { className: "text-sm", children: "Add Account" })
2454
+ ] })
2455
+ ] }),
2456
+ currentAccount && /* @__PURE__ */ jsxs(DropdownMenu, { children: [
2457
+ /* @__PURE__ */ jsx(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsx(Button, { variant: "ghost", size: "icon", className: "size-9 shrink-0 hover:bg-muted/50 dark:hover:bg-muted/30", children: /* @__PURE__ */ jsx(Settings2, { className: "size-4 text-muted-foreground" }) }) }),
2458
+ /* @__PURE__ */ jsxs(DropdownMenuContent, { align: "end", className: "w-40", children: [
2459
+ /* @__PURE__ */ jsx(DropdownMenuLabel, { className: "text-xs text-muted-foreground truncate", children: currentAccount.name }),
2460
+ /* @__PURE__ */ jsx(DropdownMenuSeparator, {}),
2461
+ /* @__PURE__ */ jsxs(DropdownMenuItem, { onClick: () => {
2462
+ setNewName(currentAccount.name);
2463
+ setRenameDialog({ open: true, account: currentAccount });
2464
+ }, children: [
2465
+ /* @__PURE__ */ jsx(Pencil, { className: "size-3.5 mr-2" }),
2466
+ " Rename"
2351
2467
  ] }),
2352
- /* @__PURE__ */ jsx(DropdownMenuSubContent, { children: /* @__PURE__ */ jsx(DropdownMenuItem, { onClick: openOAuthPopup, children: "Google Drive" }) })
2468
+ /* @__PURE__ */ jsxs(DropdownMenuItem, { className: "text-destructive focus:text-destructive", onClick: () => setDeleteDialog({ open: true, account: currentAccount }), children: [
2469
+ /* @__PURE__ */ jsx(Trash, { className: "size-3.5 mr-2" }),
2470
+ " Disconnect"
2471
+ ] })
2353
2472
  ] })
2354
2473
  ] })
2355
2474
  ] }) }),
@@ -2359,7 +2478,10 @@ var ChooserSidebar = () => {
2359
2478
  {
2360
2479
  variant: "ghost",
2361
2480
  className: cn("w-full justify-start gap-2.5 h-9 px-2.5 font-medium", currentView !== "TRASH" ? "bg-primary/10 text-primary hover:bg-primary/15" : "hover:bg-muted/50"),
2362
- onClick: () => setCurrentView("BROWSE"),
2481
+ onClick: () => {
2482
+ setCurrentView("BROWSE");
2483
+ onNavigate?.();
2484
+ },
2363
2485
  children: [
2364
2486
  /* @__PURE__ */ jsx(FolderOpen, { className: "size-4" }),
2365
2487
  " My Files"
@@ -2371,7 +2493,10 @@ var ChooserSidebar = () => {
2371
2493
  {
2372
2494
  variant: "ghost",
2373
2495
  className: cn("w-full justify-start gap-2.5 h-9 px-2.5 font-medium", currentView === "TRASH" ? "bg-destructive/10 text-destructive hover:bg-destructive/15" : "hover:bg-muted/50"),
2374
- onClick: () => setCurrentView("TRASH"),
2496
+ onClick: () => {
2497
+ setCurrentView("TRASH");
2498
+ onNavigate?.();
2499
+ },
2375
2500
  children: [
2376
2501
  /* @__PURE__ */ jsx(Trash2, { className: "size-4" }),
2377
2502
  " Trash"
@@ -2380,7 +2505,7 @@ var ChooserSidebar = () => {
2380
2505
  )
2381
2506
  ] }),
2382
2507
  /* @__PURE__ */ jsx("div", { className: "p-2.5 border-t border-border/50 bg-background/50 dark:bg-background/30", children: /* @__PURE__ */ jsx(DriveStorageIndicator, {}) }),
2383
- /* @__PURE__ */ jsx(Dialog, { open: renameDialog.open, onOpenChange: (open) => !open && setRenameDialog({ open: false, account: null }), children: /* @__PURE__ */ jsxs(DialogContent, { className: "sm:max-w-sm", children: [
2508
+ /* @__PURE__ */ jsx(Dialog, { open: renameDialog.open, onOpenChange: (open) => !open && setRenameDialog({ open: false, account: null }), children: /* @__PURE__ */ jsxs(DialogContent, { className: "sm:max-w-sm", showCloseButton: false, children: [
2384
2509
  /* @__PURE__ */ jsxs(DialogHeader, { children: [
2385
2510
  /* @__PURE__ */ jsx(DialogTitle, { children: "Rename Account" }),
2386
2511
  /* @__PURE__ */ jsx(DialogDescription, { children: "Enter a new display name." })
@@ -2396,21 +2521,32 @@ var ChooserSidebar = () => {
2396
2521
  {
2397
2522
  open: deleteDialog.open,
2398
2523
  onClose: () => setDeleteDialog({ open: false, account: null }),
2399
- title: "Remove Account",
2400
- description: `Disconnect "${deleteDialog.account?.name}"? Synced files will be removed.`,
2524
+ title: "Disconnect Account",
2525
+ description: `Disconnect "${deleteDialog.account?.name}"? Access will be revoked and synced files will be removed.`,
2401
2526
  onConfirm: handleDelete
2402
2527
  }
2403
- )
2528
+ ),
2529
+ /* @__PURE__ */ jsx(Dialog, { open: oauthLoading, onOpenChange: (open) => !open && cancelOAuth(), children: /* @__PURE__ */ jsx(DialogContent, { className: "sm:max-w-xs", showCloseButton: false, children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center gap-4 py-4", children: [
2530
+ /* @__PURE__ */ jsx(Loader2, { className: "size-8 text-primary animate-spin" }),
2531
+ /* @__PURE__ */ jsxs("div", { className: "text-center", children: [
2532
+ /* @__PURE__ */ jsx(DialogTitle, { className: "text-base", children: "Connecting..." }),
2533
+ /* @__PURE__ */ jsx(DialogDescription, { className: "text-sm mt-1", children: "Preparing Google authentication" })
2534
+ ] }),
2535
+ /* @__PURE__ */ jsx(Button, { variant: "outline", size: "sm", onClick: cancelOAuth, children: "Cancel" })
2536
+ ] }) }) })
2537
+ ] });
2538
+ };
2539
+ var MobileSidebarSheet = () => {
2540
+ const [sheetOpen, setSheetOpen] = useState(false);
2541
+ return /* @__PURE__ */ jsxs(Sheet, { open: sheetOpen, onOpenChange: setSheetOpen, children: [
2542
+ /* @__PURE__ */ jsx(SheetTrigger, { asChild: true, children: /* @__PURE__ */ jsx(Button, { variant: "ghost", size: "icon", className: "size-9 md:hidden shrink-0", children: /* @__PURE__ */ jsx(Menu, { className: "size-5" }) }) }),
2543
+ /* @__PURE__ */ jsxs(SheetContent, { side: "left", className: "w-72 p-0", hideCloseButton: true, children: [
2544
+ /* @__PURE__ */ jsx(SheetTitle, { className: "sr-only", children: "Navigation" }),
2545
+ /* @__PURE__ */ jsx(SheetDescription, { className: "sr-only", children: "Storage and navigation" }),
2546
+ /* @__PURE__ */ jsx(ChooserSidebar, { onNavigate: () => setSheetOpen(false) })
2547
+ ] })
2404
2548
  ] });
2405
2549
  };
2406
- var MobileSidebarSheet = () => /* @__PURE__ */ jsxs(Sheet, { children: [
2407
- /* @__PURE__ */ jsx(SheetTrigger, { asChild: true, children: /* @__PURE__ */ jsx(Button, { variant: "ghost", size: "icon", className: "size-9 md:hidden shrink-0", children: /* @__PURE__ */ jsx(Menu, { className: "size-5" }) }) }),
2408
- /* @__PURE__ */ jsxs(SheetContent, { side: "left", className: "w-72 p-0", children: [
2409
- /* @__PURE__ */ jsx(SheetTitle, { className: "sr-only", children: "Navigation" }),
2410
- /* @__PURE__ */ jsx(SheetDescription, { className: "sr-only", children: "Storage and navigation" }),
2411
- /* @__PURE__ */ jsx(ChooserSidebar, {})
2412
- ] })
2413
- ] });
2414
2550
  var DriveFileChooser = (props) => {
2415
2551
  const {
2416
2552
  value,
@@ -2522,9 +2658,9 @@ var DriveFileChooser = (props) => {
2522
2658
  /* @__PURE__ */ jsxs(Dialog2Body, { className: "flex flex-col md:flex-row", children: [
2523
2659
  /* @__PURE__ */ jsx("div", { className: "hidden md:flex w-52 lg:w-56 border-r shrink-0", children: /* @__PURE__ */ jsx(ChooserSidebar, {}) }),
2524
2660
  /* @__PURE__ */ jsx(DriveDndProvider, { children: /* @__PURE__ */ jsxs("div", { className: "flex-1 flex flex-col min-w-0 min-h-0", children: [
2525
- /* @__PURE__ */ jsx("div", { className: "shrink-0 border-b", children: /* @__PURE__ */ jsx(DriveHeader, {}) }),
2526
- /* @__PURE__ */ jsxs("div", { className: "shrink-0 flex items-center gap-2 px-3 py-2 border-b bg-muted/20 dark:bg-muted/10", children: [
2527
- /* @__PURE__ */ jsx("div", { className: "flex-1 min-w-0", children: /* @__PURE__ */ jsx(DrivePathBar, {}) }),
2661
+ /* @__PURE__ */ jsx(DriveHeader, { className: "border-b" }),
2662
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 px-3 py-2 border-b bg-muted/20 dark:bg-muted/10", children: [
2663
+ /* @__PURE__ */ jsx(DrivePathBar, { className: "flex-1" }),
2528
2664
  /* @__PURE__ */ jsx(DriveUpload, { compact: true, accept })
2529
2665
  ] }),
2530
2666
  /* @__PURE__ */ jsx(DriveFileGrid, { mimeFilter: accept, className: "flex-1" })
@@ -2540,7 +2676,8 @@ var DriveFileChooser = (props) => {
2540
2676
  ] }) })
2541
2677
  ] });
2542
2678
  };
2543
- var SidebarContent = ({ onNavigate }) => {
2679
+ var SidebarContent = (props) => {
2680
+ const { onNavigate } = props;
2544
2681
  const {
2545
2682
  accounts,
2546
2683
  activeAccountId,
@@ -2549,7 +2686,7 @@ var SidebarContent = ({ onNavigate }) => {
2549
2686
  refreshAccounts,
2550
2687
  currentView,
2551
2688
  setCurrentView,
2552
- isLoading
2689
+ availableProviders
2553
2690
  } = useDrive();
2554
2691
  const [renameDialog, setRenameDialog] = useState({
2555
2692
  open: false,
@@ -2560,9 +2697,14 @@ var SidebarContent = ({ onNavigate }) => {
2560
2697
  account: null
2561
2698
  });
2562
2699
  const [newName, setNewName] = useState("");
2700
+ const [oauthLoading, setOauthLoading] = useState(false);
2701
+ const [oauthAbort, setOauthAbort] = useState(null);
2702
+ const [dropdownOpen, setDropdownOpen] = useState(false);
2563
2703
  const currentAccount = activeAccountId ? accounts.find((a) => a.id === activeAccountId) : null;
2564
2704
  const currentAccountName = currentAccount?.name || "Local Storage";
2565
2705
  const currentAccountEmail = currentAccount?.email || "On this device";
2706
+ const hasAnyProvider = availableProviders.google;
2707
+ const isDropdownDisabled = accounts.length === 0 && !hasAnyProvider;
2566
2708
  const handleRename = async () => {
2567
2709
  if (!renameDialog.account || !newName.trim()) return;
2568
2710
  await callAPI("renameAccount", {
@@ -2582,68 +2724,111 @@ var SidebarContent = ({ onNavigate }) => {
2582
2724
  setDeleteDialog({ open: false, account: null });
2583
2725
  return [true];
2584
2726
  };
2585
- const openOAuthPopup = async () => {
2586
- const res = await callAPI("getAuthUrl", { query: { provider: "GOOGLE" } });
2587
- if (res.status !== 200 || !res.data?.url) {
2588
- alert(res.message || "Failed to initialize account connection");
2589
- return;
2590
- }
2727
+ const openOAuthPopup = () => {
2591
2728
  const width = 600, height = 600;
2592
2729
  const left = window.screen.width / 2 - width / 2;
2593
2730
  const top = window.screen.height / 2 - height / 2;
2594
- window.open(res.data.url, "Connect to Google Drive", `width=${width},height=${height},top=${top},left=${left}`);
2595
- const cleanup = () => {
2596
- window.removeEventListener("message", messageListener);
2597
- window.removeEventListener("storage", storageListener);
2598
- };
2599
- const messageListener = (event) => {
2600
- if (event.data === "oauth-success") {
2601
- cleanup();
2602
- refreshAccounts();
2603
- }
2604
- };
2605
- const storageListener = (event) => {
2606
- if (event.key === "next-drive-oauth-success") {
2607
- cleanup();
2608
- refreshAccounts();
2731
+ const popup = window.open("about:blank", "Connect to Google Drive", `width=${width},height=${height},top=${top},left=${left}`);
2732
+ if (!popup) {
2733
+ alert("Popup blocked. Please allow popups for this site.");
2734
+ return;
2735
+ }
2736
+ const controller = new AbortController();
2737
+ setOauthAbort(controller);
2738
+ setOauthLoading(true);
2739
+ (async () => {
2740
+ try {
2741
+ const res = await callAPI("getAuthUrl", { query: { provider: "GOOGLE" } });
2742
+ if (controller.signal.aborted) {
2743
+ popup.close();
2744
+ return;
2745
+ }
2746
+ if (res.status !== 200 || !res.data?.url) {
2747
+ popup.close();
2748
+ setOauthLoading(false);
2749
+ setOauthAbort(null);
2750
+ alert(res.message || "Failed to initialize account connection");
2751
+ return;
2752
+ }
2753
+ popup.location.href = res.data.url;
2754
+ const cleanup = () => {
2755
+ window.removeEventListener("message", messageListener);
2756
+ window.removeEventListener("storage", storageListener);
2757
+ setOauthLoading(false);
2758
+ setOauthAbort(null);
2759
+ };
2760
+ const messageListener = (event) => {
2761
+ if (event.data === "oauth-success") {
2762
+ cleanup();
2763
+ refreshAccounts();
2764
+ setDropdownOpen(true);
2765
+ }
2766
+ };
2767
+ const storageListener = (event) => {
2768
+ if (event.key === "next-drive-oauth-success") {
2769
+ cleanup();
2770
+ refreshAccounts();
2771
+ setDropdownOpen(true);
2772
+ }
2773
+ };
2774
+ window.addEventListener("message", messageListener);
2775
+ window.addEventListener("storage", storageListener);
2776
+ const checkPopupClosed = setInterval(() => {
2777
+ if (popup.closed) {
2778
+ clearInterval(checkPopupClosed);
2779
+ cleanup();
2780
+ }
2781
+ }, 500);
2782
+ } catch (err) {
2783
+ popup.close();
2784
+ setOauthLoading(false);
2785
+ setOauthAbort(null);
2786
+ alert("Failed to connect. Please try again.");
2609
2787
  }
2610
- };
2611
- window.addEventListener("message", messageListener);
2612
- window.addEventListener("storage", storageListener);
2788
+ })();
2789
+ };
2790
+ const cancelOAuth = () => {
2791
+ oauthAbort?.abort();
2792
+ setOauthLoading(false);
2793
+ setOauthAbort(null);
2613
2794
  };
2614
2795
  return /* @__PURE__ */ jsxs("div", { className: "w-full h-full flex flex-col bg-muted/5 dark:bg-muted/10", children: [
2615
- /* @__PURE__ */ jsx("div", { className: "h-1 w-full", children: isLoading && /* @__PURE__ */ jsx(
2616
- Progress,
2617
- {
2618
- value: void 0,
2619
- className: "h-full rounded-none bg-transparent",
2620
- indicatorClassName: "animate-pulse bg-primary/60"
2621
- }
2622
- ) }),
2623
- /* @__PURE__ */ jsx("div", { className: "p-2 border-b border-border/50", children: /* @__PURE__ */ jsxs(DropdownMenu, { children: [
2624
- /* @__PURE__ */ jsx(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsxs(Button, { variant: "ghost", className: "w-full justify-between px-2 h-11 hover:bg-muted/50 dark:hover:bg-muted/30", children: [
2625
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2.5 text-left min-w-0 flex-1", children: [
2626
- /* @__PURE__ */ jsx("div", { className: cn(
2627
- "size-7 rounded-md flex items-center justify-center shrink-0",
2628
- activeAccountId ? "bg-blue-500/10 text-blue-600 dark:bg-blue-500/20 dark:text-blue-400" : "bg-emerald-500/10 text-emerald-600 dark:bg-emerald-500/20 dark:text-emerald-400"
2629
- ), children: activeAccountId ? /* @__PURE__ */ jsx(Database, { className: "size-3.5" }) : /* @__PURE__ */ jsx(HardDrive, { className: "size-3.5" }) }),
2796
+ /* @__PURE__ */ jsx("div", { className: "p-2 border-b border-border/50", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1", children: [
2797
+ isDropdownDisabled ? (
2798
+ /* Static display when no accounts and no providers */
2799
+ /* @__PURE__ */ jsxs("div", { className: "flex-1 flex items-center gap-2.5 px-2 h-11 min-w-0", children: [
2800
+ /* @__PURE__ */ jsx("div", { className: "size-7 rounded-md flex items-center justify-center shrink-0 bg-emerald-500/10 text-emerald-600 dark:bg-emerald-500/20 dark:text-emerald-400", children: /* @__PURE__ */ jsx(HardDrive, { className: "size-3.5" }) }),
2630
2801
  /* @__PURE__ */ jsxs("div", { className: "flex flex-col min-w-0", children: [
2631
- /* @__PURE__ */ jsx("span", { className: "text-sm font-medium truncate", children: currentAccountName }),
2632
- /* @__PURE__ */ jsx("span", { className: "text-[11px] text-muted-foreground truncate", children: currentAccountEmail })
2802
+ /* @__PURE__ */ jsx("span", { className: "text-sm font-medium truncate", children: "Local Storage" }),
2803
+ /* @__PURE__ */ jsx("span", { className: "text-[11px] text-muted-foreground truncate", children: "On this device" })
2633
2804
  ] })
2634
- ] }),
2635
- /* @__PURE__ */ jsx(ChevronsUpDown, { className: "size-3.5 text-muted-foreground/60 shrink-0" })
2636
- ] }) }),
2637
- /* @__PURE__ */ jsxs(DropdownMenuContent, { className: "w-56", align: "start", children: [
2638
- /* @__PURE__ */ jsx(DropdownMenuLabel, { className: "text-[11px] font-medium text-muted-foreground uppercase tracking-wide", children: "Storage" }),
2639
- /* @__PURE__ */ jsx(DropdownMenuItem, { onClick: () => {
2640
- setActiveAccountId(null);
2641
- setCurrentView("BROWSE");
2642
- onNavigate?.();
2643
- }, className: "gap-2 py-2", children: activeAccountId === null && /* @__PURE__ */ jsx(Check, { className: "size-3.5 text-primary" }) }),
2644
- accounts.length > 0 && /* @__PURE__ */ jsx(DropdownMenuSeparator, {}),
2645
- accounts.map((account) => /* @__PURE__ */ jsxs("div", { className: "flex items-center group", children: [
2646
- /* @__PURE__ */ jsxs(
2805
+ ] })
2806
+ ) : /* @__PURE__ */ jsxs(DropdownMenu, { open: dropdownOpen, onOpenChange: setDropdownOpen, children: [
2807
+ /* @__PURE__ */ jsx(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsxs(Button, { variant: "ghost", className: "flex-1 min-w-0 justify-between px-2 h-11 hover:bg-muted/50 dark:hover:bg-muted/30", children: [
2808
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2.5 text-left min-w-0 flex-1", children: [
2809
+ /* @__PURE__ */ jsx("div", { className: cn(
2810
+ "size-7 rounded-md flex items-center justify-center shrink-0",
2811
+ activeAccountId ? "bg-blue-500/10 text-blue-600 dark:bg-blue-500/20 dark:text-blue-400" : "bg-emerald-500/10 text-emerald-600 dark:bg-emerald-500/20 dark:text-emerald-400"
2812
+ ), children: activeAccountId ? /* @__PURE__ */ jsx(Database, { className: "size-3.5" }) : /* @__PURE__ */ jsx(HardDrive, { className: "size-3.5" }) }),
2813
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col min-w-0", children: [
2814
+ /* @__PURE__ */ jsx("span", { className: "text-sm font-medium truncate", children: currentAccountName }),
2815
+ /* @__PURE__ */ jsx("span", { className: "text-[11px] text-muted-foreground truncate", children: currentAccountEmail })
2816
+ ] })
2817
+ ] }),
2818
+ /* @__PURE__ */ jsx(ChevronsUpDown, { className: "size-3.5 text-muted-foreground/60 shrink-0" })
2819
+ ] }) }),
2820
+ /* @__PURE__ */ jsxs(DropdownMenuContent, { className: "w-56", align: "start", children: [
2821
+ /* @__PURE__ */ jsx(DropdownMenuLabel, { className: "text-[11px] font-medium text-muted-foreground uppercase tracking-wide", children: "Storage" }),
2822
+ /* @__PURE__ */ jsxs(DropdownMenuItem, { onClick: () => {
2823
+ setActiveAccountId(null);
2824
+ setCurrentView("BROWSE");
2825
+ onNavigate?.();
2826
+ }, className: "gap-2 py-2", children: [
2827
+ /* @__PURE__ */ jsx("span", { className: "flex-1 text-sm", children: "Local Storage" }),
2828
+ activeAccountId === null && /* @__PURE__ */ jsx(Check, { className: "size-3.5 text-primary" })
2829
+ ] }),
2830
+ accounts.length > 0 && /* @__PURE__ */ jsx(DropdownMenuSeparator, {}),
2831
+ accounts.map((account) => /* @__PURE__ */ jsxs(
2647
2832
  DropdownMenuItem,
2648
2833
  {
2649
2834
  onClick: () => {
@@ -2651,7 +2836,7 @@ var SidebarContent = ({ onNavigate }) => {
2651
2836
  setCurrentView("BROWSE");
2652
2837
  onNavigate?.();
2653
2838
  },
2654
- className: "flex-1 gap-2 py-2 pr-1",
2839
+ className: "gap-2 py-2",
2655
2840
  children: [
2656
2841
  /* @__PURE__ */ jsxs("div", { className: "flex-1 min-w-0", children: [
2657
2842
  /* @__PURE__ */ jsx("p", { className: "text-sm truncate", children: account.name }),
@@ -2659,49 +2844,52 @@ var SidebarContent = ({ onNavigate }) => {
2659
2844
  ] }),
2660
2845
  activeAccountId === account.id && /* @__PURE__ */ jsx(Check, { className: "size-3.5 text-primary" })
2661
2846
  ]
2662
- }
2663
- ),
2664
- /* @__PURE__ */ jsxs(DropdownMenu, { children: [
2665
- /* @__PURE__ */ jsx(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsx(
2666
- Button,
2667
- {
2668
- variant: "ghost",
2669
- size: "icon",
2670
- className: "size-7 mr-1 opacity-0 group-hover:opacity-100 transition-opacity",
2671
- onClick: (e) => e.stopPropagation(),
2672
- children: /* @__PURE__ */ jsx(Settings2, { className: "size-3.5 text-muted-foreground" })
2673
- }
2674
- ) }),
2675
- /* @__PURE__ */ jsxs(DropdownMenuContent, { align: "end", className: "w-36", children: [
2676
- /* @__PURE__ */ jsxs(DropdownMenuItem, { onClick: () => {
2677
- setNewName(account.name);
2678
- setRenameDialog({ open: true, account });
2679
- }, children: [
2680
- /* @__PURE__ */ jsx(Pencil, { className: "size-3.5 mr-2" }),
2681
- "Rename"
2847
+ },
2848
+ account.id
2849
+ )),
2850
+ hasAnyProvider && /* @__PURE__ */ jsxs(Fragment, { children: [
2851
+ /* @__PURE__ */ jsx(DropdownMenuSeparator, {}),
2852
+ /* @__PURE__ */ jsxs(DropdownMenuSub, { children: [
2853
+ /* @__PURE__ */ jsxs(DropdownMenuSubTrigger, { className: "gap-2", children: [
2854
+ /* @__PURE__ */ jsx(Plus, { className: "size-3.5" }),
2855
+ /* @__PURE__ */ jsx("span", { className: "text-sm", children: "Add Account" })
2682
2856
  ] }),
2683
- /* @__PURE__ */ jsx(DropdownMenuSeparator, {}),
2684
- /* @__PURE__ */ jsxs(
2685
- DropdownMenuItem,
2686
- {
2687
- className: "text-destructive focus:text-destructive",
2688
- onClick: () => setDeleteDialog({ open: true, account }),
2689
- children: [
2690
- /* @__PURE__ */ jsx(Trash, { className: "size-3.5 mr-2" }),
2691
- "Remove"
2692
- ]
2693
- }
2694
- )
2857
+ /* @__PURE__ */ jsx(DropdownMenuSubContent, { children: availableProviders.google && /* @__PURE__ */ jsx(DropdownMenuItem, { onClick: openOAuthPopup, children: "Google Drive" }) })
2695
2858
  ] })
2696
2859
  ] })
2697
- ] }, account.id)),
2698
- /* @__PURE__ */ jsx(DropdownMenuSeparator, {}),
2699
- /* @__PURE__ */ jsxs(DropdownMenuSub, { children: [
2700
- /* @__PURE__ */ jsxs(DropdownMenuSubTrigger, { className: "gap-2", children: [
2701
- /* @__PURE__ */ jsx(Plus, { className: "size-3.5" }),
2702
- /* @__PURE__ */ jsx("span", { className: "text-sm", children: "Add Account" })
2860
+ ] })
2861
+ ] }),
2862
+ currentAccount && /* @__PURE__ */ jsxs(DropdownMenu, { children: [
2863
+ /* @__PURE__ */ jsx(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsx(
2864
+ Button,
2865
+ {
2866
+ variant: "ghost",
2867
+ size: "icon",
2868
+ className: "size-9 shrink-0 hover:bg-muted/50 dark:hover:bg-muted/30",
2869
+ children: /* @__PURE__ */ jsx(Settings2, { className: "size-4 text-muted-foreground" })
2870
+ }
2871
+ ) }),
2872
+ /* @__PURE__ */ jsxs(DropdownMenuContent, { align: "end", className: "w-40", children: [
2873
+ /* @__PURE__ */ jsx(DropdownMenuLabel, { className: "text-xs text-muted-foreground truncate", children: currentAccount.name }),
2874
+ /* @__PURE__ */ jsx(DropdownMenuSeparator, {}),
2875
+ /* @__PURE__ */ jsxs(DropdownMenuItem, { onClick: () => {
2876
+ setNewName(currentAccount.name);
2877
+ setRenameDialog({ open: true, account: currentAccount });
2878
+ }, children: [
2879
+ /* @__PURE__ */ jsx(Pencil, { className: "size-3.5 mr-2" }),
2880
+ "Rename"
2703
2881
  ] }),
2704
- /* @__PURE__ */ jsx(DropdownMenuSubContent, { children: /* @__PURE__ */ jsx(DropdownMenuItem, { onClick: openOAuthPopup, children: "Google Drive" }) })
2882
+ /* @__PURE__ */ jsxs(
2883
+ DropdownMenuItem,
2884
+ {
2885
+ className: "text-destructive focus:text-destructive",
2886
+ onClick: () => setDeleteDialog({ open: true, account: currentAccount }),
2887
+ children: [
2888
+ /* @__PURE__ */ jsx(Trash, { className: "size-3.5 mr-2" }),
2889
+ "Disconnect"
2890
+ ]
2891
+ }
2892
+ )
2705
2893
  ] })
2706
2894
  ] })
2707
2895
  ] }) }),
@@ -2744,7 +2932,7 @@ var SidebarContent = ({ onNavigate }) => {
2744
2932
  )
2745
2933
  ] }),
2746
2934
  /* @__PURE__ */ jsx("div", { className: "p-2.5 border-t border-border/50 bg-background/50 dark:bg-background/30", children: /* @__PURE__ */ jsx(DriveStorageIndicator, {}) }),
2747
- /* @__PURE__ */ jsx(Dialog, { open: renameDialog.open, onOpenChange: (open) => !open && setRenameDialog({ open: false, account: null }), children: /* @__PURE__ */ jsxs(DialogContent, { className: "sm:max-w-sm", children: [
2935
+ /* @__PURE__ */ jsx(Dialog, { open: renameDialog.open, onOpenChange: (open) => !open && setRenameDialog({ open: false, account: null }), children: /* @__PURE__ */ jsxs(DialogContent, { className: "sm:max-w-sm", showCloseButton: false, children: [
2748
2936
  /* @__PURE__ */ jsxs(DialogHeader, { children: [
2749
2937
  /* @__PURE__ */ jsx(DialogTitle, { children: "Rename Account" }),
2750
2938
  /* @__PURE__ */ jsx(DialogDescription, { children: "Enter a new display name for this storage account." })
@@ -2768,37 +2956,34 @@ var SidebarContent = ({ onNavigate }) => {
2768
2956
  {
2769
2957
  open: deleteDialog.open,
2770
2958
  onClose: () => setDeleteDialog({ open: false, account: null }),
2771
- title: "Remove Account",
2772
- description: `Are you sure you want to disconnect "${deleteDialog.account?.name}"? Synced files will be removed from local cache.`,
2959
+ title: "Disconnect Account",
2960
+ description: `Are you sure you want to disconnect "${deleteDialog.account?.name}"? Access will be revoked and synced files will be removed from local cache.`,
2773
2961
  onConfirm: handleDelete
2774
2962
  }
2775
- )
2963
+ ),
2964
+ /* @__PURE__ */ jsx(Dialog, { open: oauthLoading, onOpenChange: (open) => !open && cancelOAuth(), children: /* @__PURE__ */ jsx(DialogContent, { className: "sm:max-w-xs", showCloseButton: false, children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center gap-4 py-4", children: [
2965
+ /* @__PURE__ */ jsx(Loader2, { className: "size-8 text-primary animate-spin" }),
2966
+ /* @__PURE__ */ jsxs("div", { className: "text-center", children: [
2967
+ /* @__PURE__ */ jsx(DialogTitle, { className: "text-base", children: "Connecting..." }),
2968
+ /* @__PURE__ */ jsx(DialogDescription, { className: "text-sm mt-1", children: "Preparing Google authentication" })
2969
+ ] }),
2970
+ /* @__PURE__ */ jsx(Button, { variant: "outline", size: "sm", onClick: cancelOAuth, children: "Cancel" })
2971
+ ] }) }) })
2776
2972
  ] });
2777
2973
  };
2778
- var DriveSidebar = () => {
2974
+ var DriveSidebar = ({ className }) => {
2779
2975
  const [sheetOpen, setSheetOpen] = useState(false);
2780
- return /* @__PURE__ */ jsxs(Fragment, { children: [
2781
- /* @__PURE__ */ jsx("div", { className: "lg:hidden", children: /* @__PURE__ */ jsxs(Sheet, { open: sheetOpen, onOpenChange: setSheetOpen, children: [
2782
- /* @__PURE__ */ jsx(SheetTrigger, { asChild: true, children: /* @__PURE__ */ jsx(
2783
- Button,
2784
- {
2785
- variant: "ghost",
2786
- size: "icon",
2787
- className: "h-9 w-9",
2788
- "aria-label": "Open menu",
2789
- children: /* @__PURE__ */ jsx(Menu, { className: "h-5 w-5" })
2790
- }
2791
- ) }),
2792
- /* @__PURE__ */ jsxs(SheetContent, { side: "left", className: "w-70 sm:w-80 p-0", hideCloseButton: true, children: [
2793
- /* @__PURE__ */ jsx(SheetTitle, { className: "sr-only", children: "Navigation Menu" }),
2794
- /* @__PURE__ */ jsx(SheetDescription, { className: "sr-only", children: "Storage accounts and navigation" }),
2795
- /* @__PURE__ */ jsx(SidebarContent, { onNavigate: () => setSheetOpen(false) })
2796
- ] })
2797
- ] }) }),
2798
- /* @__PURE__ */ jsx("div", { className: "hidden lg:flex w-full h-full", children: /* @__PURE__ */ jsx(SidebarContent, {}) })
2799
- ] });
2976
+ return /* @__PURE__ */ jsx("div", { className, children: /* @__PURE__ */ jsxs(Sheet, { open: sheetOpen, onOpenChange: setSheetOpen, children: [
2977
+ /* @__PURE__ */ jsx(SheetTrigger, { asChild: true, children: /* @__PURE__ */ jsx(Button, { variant: "ghost", size: "icon", className: "size-9", "aria-label": "Open menu", children: /* @__PURE__ */ jsx(Menu, { className: "size-5" }) }) }),
2978
+ /* @__PURE__ */ jsxs(SheetContent, { side: "left", className: "w-70 sm:w-80 p-0", hideCloseButton: true, children: [
2979
+ /* @__PURE__ */ jsx(SheetTitle, { className: "sr-only", children: "Navigation Menu" }),
2980
+ /* @__PURE__ */ jsx(SheetDescription, { className: "sr-only", children: "Storage accounts and navigation" }),
2981
+ /* @__PURE__ */ jsx(SidebarContent, { onNavigate: () => setSheetOpen(false) })
2982
+ ] })
2983
+ ] }) });
2800
2984
  };
2801
- var SortableItem2 = ({ id, children, disabled, isDragOverTarget }) => {
2985
+ var SortableItem2 = (props) => {
2986
+ const { id, children, disabled, isDragOverTarget } = props;
2802
2987
  const {
2803
2988
  attributes,
2804
2989
  listeners,
@@ -3016,13 +3201,14 @@ var DriveExplorer = (props) => {
3016
3201
  }
3017
3202
  return null;
3018
3203
  })();
3019
- return /* @__PURE__ */ jsx(DndContext, { sensors, collisionDetection: closestCenter, onDragStart: handleDragStart, onDragOver: handleDragOver, onDragEnd: handleDragEnd, children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col h-full w-full overflow-hidden bg-background/50 dark:bg-background/30", children: [
3020
- /* @__PURE__ */ jsxs("div", { className: "h-14 px-3 sm:px-4 border-b bg-background/95 dark:bg-background/80 backdrop-blur-sm shrink-0 flex items-center gap-3", children: [
3021
- /* @__PURE__ */ jsx("div", { className: "lg:hidden", children: /* @__PURE__ */ jsx(DriveSidebar, {}) }),
3022
- /* @__PURE__ */ jsx("div", { className: "hidden lg:flex flex-1 min-w-0", children: /* @__PURE__ */ jsx(DrivePathBar, {}) }),
3204
+ return /* @__PURE__ */ jsx(DndContext, { sensors, collisionDetection: closestCenter, onDragStart: handleDragStart, onDragOver: handleDragOver, onDragEnd: handleDragEnd, children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col h-full w-full overflow-hidden bg-background/50 dark:bg-background/30 relative", children: [
3205
+ /* @__PURE__ */ jsx(DriveContentProgress, {}),
3206
+ /* @__PURE__ */ jsxs("div", { className: "h-12 px-3 sm:px-4 border-b bg-background/95 dark:bg-background/80 backdrop-blur-sm flex items-center gap-3", children: [
3207
+ /* @__PURE__ */ jsx(DriveSidebar, { className: "lg:hidden" }),
3208
+ /* @__PURE__ */ jsx(DrivePathBar, { className: "hidden lg:flex flex-1" }),
3023
3209
  /* @__PURE__ */ jsx(DriveUpload, { compact: true, accept: mimeFilter })
3024
3210
  ] }),
3025
- /* @__PURE__ */ jsx("div", { className: "lg:hidden px-3 py-2 border-b bg-background/95 dark:bg-background/80 backdrop-blur-sm shrink-0", children: /* @__PURE__ */ jsx(DrivePathBar, {}) }),
3211
+ /* @__PURE__ */ jsx("div", { className: "lg:hidden px-3 py-2 border-b bg-background/95 dark:bg-background/80 backdrop-blur-sm", children: /* @__PURE__ */ jsx(DrivePathBar, {}) }),
3026
3212
  stateContent || /* @__PURE__ */ jsxs(ContextMenu, { children: [
3027
3213
  /* @__PURE__ */ jsx(ContextMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsxs("div", { className: cn("flex-1 overflow-y-auto min-h-0 container mx-auto p-2 sm:p-3 md:p-4", className), children: [
3028
3214
  /* @__PURE__ */ jsx("div", { className: "space-y-4 sm:space-y-6 pb-8 sm:pb-12", children: Object.entries(groupedItems).map(([groupName, groupItems]) => /* @__PURE__ */ jsxs("div", { className: "space-y-3", children: [
@@ -3178,6 +3364,26 @@ var DriveExplorer = (props) => {
3178
3364
  ] }) });
3179
3365
  };
3180
3366
 
3181
- export { DriveDndProvider, DriveExplorer, DriveFileChooser, DriveFileGrid, DriveHeader, DrivePathBar, DriveProvider, DriveSidebar, DriveStorageIndicator, DriveUpload, useDrive, useDriveDnd, useUpload };
3367
+ // src/client/index.ts
3368
+ if (typeof document !== "undefined") {
3369
+ const STYLE_ID = "next-drive-styles";
3370
+ if (!document.getElementById(STYLE_ID)) {
3371
+ const style = document.createElement("style");
3372
+ style.id = STYLE_ID;
3373
+ style.textContent = `
3374
+ @keyframes indeterminate {
3375
+ 0% { transform: translateX(-100%); }
3376
+ 50% { transform: translateX(200%); }
3377
+ 100% { transform: translateX(-100%); }
3378
+ }
3379
+ .animate-indeterminate {
3380
+ animation: indeterminate 1.5s ease-in-out infinite;
3381
+ }
3382
+ `;
3383
+ document.head.appendChild(style);
3384
+ }
3385
+ }
3386
+
3387
+ export { DriveContentProgress, DriveDndProvider, DriveExplorer, DriveFileChooser, DriveFileGrid, DriveHeader, DrivePathBar, DriveProvider, DriveSidebar, DriveStorageIndicator, DriveUpload, useDrive, useDriveDnd, useUpload };
3182
3388
  //# sourceMappingURL=index.js.map
3183
3389
  //# sourceMappingURL=index.js.map