@burdenoff/microfe-files 2026.1014.11 → 2026.1016.1
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/README.md +37 -0
- package/dist/config/index.js.map +1 -1
- package/dist/files/FilesRoot.js +17 -10
- package/dist/files/FilesRoot.js.map +1 -1
- package/dist/files/FilesRoutes.d.ts +1 -1
- package/dist/files/FilesRoutes.js.map +1 -1
- package/dist/files/components/ActionMenu.js.map +1 -1
- package/dist/files/components/ConfirmDialog.d.ts +1 -1
- package/dist/files/components/ConfirmDialog.js.map +1 -1
- package/dist/files/components/ContextMenu.d.ts +1 -1
- package/dist/files/components/ContextMenu.js.map +1 -1
- package/dist/files/components/CopyDialog.js.map +1 -1
- package/dist/files/components/EmptyState.d.ts +1 -1
- package/dist/files/components/EmptyState.js.map +1 -1
- package/dist/files/components/FileBrowser.js +2 -1
- package/dist/files/components/FileBrowser.js.map +1 -1
- package/dist/files/components/FileCard.d.ts.map +1 -1
- package/dist/files/components/FileCard.js +150 -142
- package/dist/files/components/FileCard.js.map +1 -1
- package/dist/files/components/FileInfoPanel.d.ts +1 -1
- package/dist/files/components/FileInfoPanel.d.ts.map +1 -1
- package/dist/files/components/FileInfoPanel.js +3 -7
- package/dist/files/components/FileInfoPanel.js.map +1 -1
- package/dist/files/components/FileListItem.d.ts.map +1 -1
- package/dist/files/components/FileListItem.js +1 -1
- package/dist/files/components/FileListItem.js.map +1 -1
- package/dist/files/components/FilePreviewModal.d.ts +1 -1
- package/dist/files/components/FilePreviewModal.d.ts.map +1 -1
- package/dist/files/components/FilePreviewModal.js +5 -0
- package/dist/files/components/FilePreviewModal.js.map +1 -1
- package/dist/files/components/FileVersionPanel.d.ts.map +1 -1
- package/dist/files/components/FileVersionPanel.js +122 -121
- package/dist/files/components/FileVersionPanel.js.map +1 -1
- package/dist/files/components/FolderCard.d.ts.map +1 -1
- package/dist/files/components/FolderCard.js +1 -1
- package/dist/files/components/FolderCard.js.map +1 -1
- package/dist/files/components/MoveDialog.js +2 -2
- package/dist/files/components/MoveDialog.js.map +1 -1
- package/dist/files/components/SearchBar.d.ts +1 -1
- package/dist/files/components/SearchBar.d.ts.map +1 -1
- package/dist/files/components/SearchBar.js +132 -128
- package/dist/files/components/SearchBar.js.map +1 -1
- package/dist/files/components/ShareDialog.d.ts +1 -1
- package/dist/files/components/ShareDialog.js.map +1 -1
- package/dist/files/components/StorageBanner.js.map +1 -1
- package/dist/files/components/TabBar.d.ts +1 -1
- package/dist/files/components/TabBar.js.map +1 -1
- package/dist/files/components/Toast.d.ts +1 -1
- package/dist/files/components/Toast.js.map +1 -1
- package/dist/files/components/UploadQueue.d.ts +1 -1
- package/dist/files/components/UploadQueue.js +1 -1
- package/dist/files/components/UploadQueue.js.map +1 -1
- package/dist/files/components/contextMenuItems.d.ts +4 -4
- package/dist/files/components/contextMenuItems.js.map +1 -1
- package/dist/files/components/viewers/AudioPlayer.d.ts +1 -1
- package/dist/files/components/viewers/AudioPlayer.js.map +1 -1
- package/dist/files/components/viewers/CodeViewer.d.ts +1 -1
- package/dist/files/components/viewers/CodeViewer.js.map +1 -1
- package/dist/files/components/viewers/ImageViewer.d.ts +1 -1
- package/dist/files/components/viewers/ImageViewer.js.map +1 -1
- package/dist/files/components/viewers/PDFViewer.d.ts +1 -1
- package/dist/files/components/viewers/PDFViewer.js.map +1 -1
- package/dist/files/components/viewers/TextViewer.d.ts +1 -1
- package/dist/files/components/viewers/TextViewer.js.map +1 -1
- package/dist/files/components/viewers/VideoPlayer.d.ts +1 -1
- package/dist/files/components/viewers/VideoPlayer.js.map +1 -1
- package/dist/files/graphql-types.d.ts +2 -17
- package/dist/files/graphql-types.d.ts.map +1 -1
- package/dist/files/hooks/useBatchOperations.d.ts +6 -1
- package/dist/files/hooks/useBatchOperations.d.ts.map +1 -1
- package/dist/files/hooks/useBatchOperations.js +8 -7
- package/dist/files/hooks/useBatchOperations.js.map +1 -1
- package/dist/files/hooks/useBinItems.d.ts.map +1 -1
- package/dist/files/hooks/useBinItems.js +14 -12
- package/dist/files/hooks/useBinItems.js.map +1 -1
- package/dist/files/hooks/useBrowsePage.d.ts +131 -8
- package/dist/files/hooks/useBrowsePage.d.ts.map +1 -1
- package/dist/files/hooks/useBrowsePage.js +23 -22
- package/dist/files/hooks/useBrowsePage.js.map +1 -1
- package/dist/files/hooks/useCopyFile.d.ts +22 -1
- package/dist/files/hooks/useCopyFile.d.ts.map +1 -1
- package/dist/files/hooks/useCopyFile.js +9 -8
- package/dist/files/hooks/useCopyFile.js.map +1 -1
- package/dist/files/hooks/useCreateFolder.d.ts +23 -1
- package/dist/files/hooks/useCreateFolder.d.ts.map +1 -1
- package/dist/files/hooks/useCreateFolder.js +16 -9
- package/dist/files/hooks/useCreateFolder.js.map +1 -1
- package/dist/files/hooks/useCreateFolderShare.d.ts +20 -1
- package/dist/files/hooks/useCreateFolderShare.d.ts.map +1 -1
- package/dist/files/hooks/useCreateFolderShare.js +22 -7
- package/dist/files/hooks/useCreateFolderShare.js.map +1 -1
- package/dist/files/hooks/useCreateShare.d.ts +19 -1
- package/dist/files/hooks/useCreateShare.d.ts.map +1 -1
- package/dist/files/hooks/useCreateShare.js +22 -7
- package/dist/files/hooks/useCreateShare.js.map +1 -1
- package/dist/files/hooks/useDeleteFile.d.ts +1 -1
- package/dist/files/hooks/useDeleteFile.d.ts.map +1 -1
- package/dist/files/hooks/useDeleteFile.js +8 -7
- package/dist/files/hooks/useDeleteFile.js.map +1 -1
- package/dist/files/hooks/useDeleteFolder.d.ts +1 -1
- package/dist/files/hooks/useDeleteFolder.d.ts.map +1 -1
- package/dist/files/hooks/useDeleteFolder.js +9 -8
- package/dist/files/hooks/useDeleteFolder.js.map +1 -1
- package/dist/files/hooks/useDragDrop.js.map +1 -1
- package/dist/files/hooks/useFileVersions.d.ts +36 -9
- package/dist/files/hooks/useFileVersions.d.ts.map +1 -1
- package/dist/files/hooks/useFileVersions.js +14 -13
- package/dist/files/hooks/useFileVersions.js.map +1 -1
- package/dist/files/hooks/useFoldersQuery.d.ts +8 -4
- package/dist/files/hooks/useFoldersQuery.d.ts.map +1 -1
- package/dist/files/hooks/useFoldersQuery.js +7 -6
- package/dist/files/hooks/useFoldersQuery.js.map +1 -1
- package/dist/files/hooks/useKeyboardNavigation.js +7 -8
- package/dist/files/hooks/useKeyboardNavigation.js.map +1 -1
- package/dist/files/hooks/useMoveFile.d.ts +22 -1
- package/dist/files/hooks/useMoveFile.d.ts.map +1 -1
- package/dist/files/hooks/useMoveFile.js +9 -8
- package/dist/files/hooks/useMoveFile.js.map +1 -1
- package/dist/files/hooks/useMoveFolder.d.ts +22 -1
- package/dist/files/hooks/useMoveFolder.d.ts.map +1 -1
- package/dist/files/hooks/useMoveFolder.js +9 -8
- package/dist/files/hooks/useMoveFolder.js.map +1 -1
- package/dist/files/hooks/usePermanentlyDeleteFile.d.ts +1 -1
- package/dist/files/hooks/usePermanentlyDeleteFile.d.ts.map +1 -1
- package/dist/files/hooks/usePermanentlyDeleteFile.js +8 -7
- package/dist/files/hooks/usePermanentlyDeleteFile.js.map +1 -1
- package/dist/files/hooks/usePermanentlyDeleteFolder.d.ts +1 -1
- package/dist/files/hooks/usePermanentlyDeleteFolder.d.ts.map +1 -1
- package/dist/files/hooks/usePermanentlyDeleteFolder.js +8 -7
- package/dist/files/hooks/usePermanentlyDeleteFolder.js.map +1 -1
- package/dist/files/hooks/useRecentFiles.d.ts.map +1 -1
- package/dist/files/hooks/useRecentFiles.js +13 -11
- package/dist/files/hooks/useRecentFiles.js.map +1 -1
- package/dist/files/hooks/useRenameFile.d.ts +22 -1
- package/dist/files/hooks/useRenameFile.d.ts.map +1 -1
- package/dist/files/hooks/useRenameFile.js +9 -8
- package/dist/files/hooks/useRenameFile.js.map +1 -1
- package/dist/files/hooks/useRenameFolder.d.ts +22 -1
- package/dist/files/hooks/useRenameFolder.d.ts.map +1 -1
- package/dist/files/hooks/useRenameFolder.js +9 -8
- package/dist/files/hooks/useRenameFolder.js.map +1 -1
- package/dist/files/hooks/useRestoreFile.d.ts +22 -1
- package/dist/files/hooks/useRestoreFile.d.ts.map +1 -1
- package/dist/files/hooks/useRestoreFile.js +8 -7
- package/dist/files/hooks/useRestoreFile.js.map +1 -1
- package/dist/files/hooks/useRestoreFolder.d.ts +22 -1
- package/dist/files/hooks/useRestoreFolder.d.ts.map +1 -1
- package/dist/files/hooks/useRestoreFolder.js +8 -7
- package/dist/files/hooks/useRestoreFolder.js.map +1 -1
- package/dist/files/hooks/useSearch.d.ts +2 -3
- package/dist/files/hooks/useSearch.d.ts.map +1 -1
- package/dist/files/hooks/useSearch.js +14 -12
- package/dist/files/hooks/useSearch.js.map +1 -1
- package/dist/files/hooks/useStarredItems.d.ts +2 -3
- package/dist/files/hooks/useStarredItems.d.ts.map +1 -1
- package/dist/files/hooks/useStarredItems.js +12 -10
- package/dist/files/hooks/useStarredItems.js.map +1 -1
- package/dist/files/hooks/useStorageQuota.d.ts.map +1 -1
- package/dist/files/hooks/useStorageQuota.js +17 -16
- package/dist/files/hooks/useStorageQuota.js.map +1 -1
- package/dist/files/hooks/useToast.js.map +1 -1
- package/dist/files/hooks/useToggleStar.d.ts +43 -1
- package/dist/files/hooks/useToggleStar.d.ts.map +1 -1
- package/dist/files/hooks/useToggleStar.js +9 -8
- package/dist/files/hooks/useToggleStar.js.map +1 -1
- package/dist/files/hooks/useUploadFile.d.ts +23 -1
- package/dist/files/hooks/useUploadFile.d.ts.map +1 -1
- package/dist/files/hooks/useUploadFile.js +28 -27
- package/dist/files/hooks/useUploadFile.js.map +1 -1
- package/dist/files/hooks/useUploadQueueState.d.ts +32 -0
- package/dist/files/hooks/useUploadQueueState.d.ts.map +1 -0
- package/dist/files/hooks/useUploadQueueState.js +61 -0
- package/dist/files/hooks/useUploadQueueState.js.map +1 -0
- package/dist/files/index.js +4 -3
- package/dist/files/pages/BrowserPage.d.ts +1 -1
- package/dist/files/pages/BrowserPage.d.ts.map +1 -1
- package/dist/files/pages/BrowserPage.js +383 -387
- package/dist/files/pages/BrowserPage.js.map +1 -1
- package/dist/files/pages/ShareAccessPage.d.ts +1 -1
- package/dist/files/pages/ShareAccessPage.js.map +1 -1
- package/dist/files/providers/FilesProvider.js.map +1 -1
- package/dist/files/store/filesStore.js.map +1 -1
- package/dist/files/types.d.ts.map +1 -1
- package/dist/files/utils/events.js.map +1 -1
- package/dist/files/utils/fileViewModel.d.ts +7 -0
- package/dist/files/utils/fileViewModel.d.ts.map +1 -0
- package/dist/files/utils/fileViewModel.js +34 -0
- package/dist/files/utils/fileViewModel.js.map +1 -0
- package/dist/files/utils/i18n.js.map +1 -1
- package/dist/files/utils/index.js +19 -19
- package/dist/files/utils/index.js.map +1 -1
- package/dist/files/utils/quotaUtils.js +1 -2
- package/dist/files/utils/thumbnail.js +19 -23
- package/dist/files/utils/thumbnail.js.map +1 -1
- package/dist/files/utils/uploadDigest.js +1 -1
- package/dist/files/utils/uploadDigest.js.map +1 -1
- package/dist/generated/global-operations.d.ts +4 -1
- package/dist/generated/global-operations.d.ts.map +1 -1
- package/dist/generated/global-types.d.ts +16 -21
- package/dist/generated/global-types.d.ts.map +1 -1
- package/dist/generated/wspace-operations.d.ts +503 -1784
- package/dist/generated/wspace-operations.d.ts.map +1 -1
- package/dist/generated/wspace-operations.js +15278 -1110
- package/dist/generated/wspace-operations.js.map +1 -1
- package/dist/generated/wspace-types.d.ts +90013 -24889
- package/dist/generated/wspace-types.d.ts.map +1 -1
- package/dist/generated/wspace-types.js +16 -0
- package/dist/generated/wspace-types.js.map +1 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/shared/hooks/useTr.js.map +1 -1
- package/dist/translations/en.js.map +1 -1
- package/dist/utils/nativeBridge.js +1 -2
- package/package.json +24 -22
- package/dist/files.d.ts +0 -2
|
@@ -1,231 +1,232 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
1
|
+
import { browserFileSize as e } from "../utils/fileViewModel.js";
|
|
2
|
+
import { useToast as t } from "../hooks/useToast.js";
|
|
3
|
+
import { formatFileDate as n, formatFileSize as r } from "../utils/index.js";
|
|
4
|
+
import { tWithFallback as i } from "../utils/i18n.js";
|
|
5
|
+
import { ConfirmDialog as a } from "./ConfirmDialog.js";
|
|
6
|
+
import { useDeleteFileVersion as o, useFileVersions as s, useRestoreFileVersion as c, useVersionDownloadUrl as l } from "../hooks/useFileVersions.js";
|
|
7
|
+
import { useState as u } from "react";
|
|
8
|
+
import { AlertCircle as d, CheckCircle2 as f, Clock as p, Download as m, Loader2 as h, RotateCcw as g, Tag as _, Trash2 as v, X as y } from "lucide-react";
|
|
9
|
+
import { Fragment as b, jsx as x, jsxs as S } from "react/jsx-runtime";
|
|
10
|
+
import { useI18n as C } from "@burdenoff/fe-libs/shared/providers/shell/I18nProvider";
|
|
11
|
+
import { IllustratedEmptyState as w } from "@burdenoff/fe-libs/ui";
|
|
11
12
|
//#region src/files/components/FileVersionPanel.tsx
|
|
12
|
-
var
|
|
13
|
-
let { t:
|
|
14
|
-
|
|
15
|
-
title: `${
|
|
16
|
-
description:
|
|
17
|
-
confirmLabel:
|
|
13
|
+
var T = ({ file: T, onClose: E }) => {
|
|
14
|
+
let { t: D } = C(), [O, k] = u(null), [A, j] = u(null), M = t(), { data: N, isLoading: P, error: F } = s(T.id), I = N?.versions || [], L = c(), R = o(), z = l(), B = async (e, t) => {
|
|
15
|
+
j({
|
|
16
|
+
title: `${i(D, "files.version.restoreVersion", "Restore version")} ${t}`,
|
|
17
|
+
description: i(D, "files.version.restoreDescription", "This will create a new version with the restored content."),
|
|
18
|
+
confirmLabel: i(D, "files.version.restore", "Restore"),
|
|
18
19
|
onConfirm: async () => {
|
|
19
20
|
try {
|
|
20
|
-
await
|
|
21
|
+
await L.mutateAsync({
|
|
21
22
|
versionId: e,
|
|
22
23
|
createNewVersion: !0,
|
|
23
|
-
changeMessage: `${
|
|
24
|
-
}),
|
|
24
|
+
changeMessage: `${i(D, "files.version.restoredFrom", "Restored from version")} ${t}`
|
|
25
|
+
}), M.success(`${i(D, "files.version.versionRestored", "Version {{number}} restored successfully", { number: t })}`);
|
|
25
26
|
} catch {
|
|
26
|
-
|
|
27
|
+
M.error(i(D, "files.version.restoreFailed", "Failed to restore version"));
|
|
27
28
|
}
|
|
28
29
|
}
|
|
29
30
|
});
|
|
30
|
-
},
|
|
31
|
-
|
|
32
|
-
title: `${
|
|
33
|
-
description:
|
|
34
|
-
confirmLabel:
|
|
31
|
+
}, V = async (e, t) => {
|
|
32
|
+
j({
|
|
33
|
+
title: `${i(D, "files.version.deleteVersion", "Delete version")} ${t}`,
|
|
34
|
+
description: i(D, "files.version.deleteDescription", "This action cannot be undone."),
|
|
35
|
+
confirmLabel: i(D, "files.version.deleteVersionBtn", "Delete version"),
|
|
35
36
|
variant: "danger",
|
|
36
37
|
onConfirm: async () => {
|
|
37
38
|
try {
|
|
38
|
-
await
|
|
39
|
+
await R.mutateAsync(e), M.success(`${i(D, "files.version.versionDeleted", "Version {{number}} deleted", { number: t })}`);
|
|
39
40
|
} catch {
|
|
40
|
-
|
|
41
|
+
M.error(i(D, "files.version.deleteFailed", "Failed to delete version"));
|
|
41
42
|
}
|
|
42
43
|
}
|
|
43
44
|
});
|
|
44
|
-
},
|
|
45
|
-
if (!
|
|
46
|
-
let e =
|
|
47
|
-
|
|
48
|
-
...
|
|
45
|
+
}, H = async () => {
|
|
46
|
+
if (!A || A.loading) return;
|
|
47
|
+
let e = A.onConfirm;
|
|
48
|
+
j({
|
|
49
|
+
...A,
|
|
49
50
|
loading: !0
|
|
50
|
-
}), await e(),
|
|
51
|
-
},
|
|
51
|
+
}), await e(), j(null);
|
|
52
|
+
}, U = async (e) => {
|
|
52
53
|
try {
|
|
53
|
-
let t = await
|
|
54
|
-
if (!t) throw Error(
|
|
54
|
+
let t = await z.getDownloadUrl(e);
|
|
55
|
+
if (!t) throw Error(i(D, "files.version.downloadUnavailable", "Version download URL is unavailable"));
|
|
55
56
|
window.open(t, "_blank", "noopener,noreferrer");
|
|
56
57
|
} catch (e) {
|
|
57
|
-
|
|
58
|
+
M.error(e instanceof Error ? e.message : i(D, "files.version.downloadFailed", "Failed to download version"));
|
|
58
59
|
}
|
|
59
60
|
};
|
|
60
|
-
return /* @__PURE__ */
|
|
61
|
+
return /* @__PURE__ */ S("div", {
|
|
61
62
|
className: "fixed inset-0 z-[110] bg-bg-overlay flex items-center justify-center p-4 animate-in fade-in duration-200",
|
|
62
63
|
role: "dialog",
|
|
63
64
|
"aria-modal": "true",
|
|
64
|
-
"aria-label":
|
|
65
|
-
children: [/* @__PURE__ */
|
|
65
|
+
"aria-label": i(D, "files.version.historyFor", "Version history for {{name}}", { name: T.name }),
|
|
66
|
+
children: [/* @__PURE__ */ S("div", {
|
|
66
67
|
className: "bg-bg-surface rounded-lg shadow-xl max-w-3xl w-full max-h-[90vh] overflow-hidden flex flex-col animate-in zoom-in-95 duration-200",
|
|
67
68
|
children: [
|
|
68
|
-
/* @__PURE__ */
|
|
69
|
+
/* @__PURE__ */ S("div", {
|
|
69
70
|
className: "flex items-center justify-between p-6 border-b border-border-seam",
|
|
70
|
-
children: [/* @__PURE__ */
|
|
71
|
+
children: [/* @__PURE__ */ S("div", {
|
|
71
72
|
className: "flex items-center gap-3",
|
|
72
|
-
children: [/* @__PURE__ */
|
|
73
|
+
children: [/* @__PURE__ */ x(p, { className: "size-6 text-text-link" }), /* @__PURE__ */ S("div", { children: [/* @__PURE__ */ x("h2", {
|
|
73
74
|
className: "text-lg font-semibold text-text-primary",
|
|
74
|
-
children:
|
|
75
|
-
}), /* @__PURE__ */
|
|
75
|
+
children: i(D, "files.version.versionHistory", "Version History")
|
|
76
|
+
}), /* @__PURE__ */ x("p", {
|
|
76
77
|
className: "text-sm text-text-secondary",
|
|
77
|
-
children:
|
|
78
|
+
children: T.name
|
|
78
79
|
})] })]
|
|
79
|
-
}), /* @__PURE__ */
|
|
80
|
+
}), /* @__PURE__ */ x("button", {
|
|
80
81
|
type: "button",
|
|
81
|
-
onClick:
|
|
82
|
+
onClick: E,
|
|
82
83
|
className: "p-2 text-text-tertiary hover:text-text-secondary hover:bg-action-ghost-bg-hover rounded-lg transition-colors duration-200",
|
|
83
|
-
"aria-label":
|
|
84
|
-
children: /* @__PURE__ */
|
|
84
|
+
"aria-label": i(D, "files.version.closeHistory", "Close version history"),
|
|
85
|
+
children: /* @__PURE__ */ x(y, { className: "size-5" })
|
|
85
86
|
})]
|
|
86
87
|
}),
|
|
87
|
-
/* @__PURE__ */
|
|
88
|
+
/* @__PURE__ */ S("div", {
|
|
88
89
|
className: "flex-1 overflow-y-auto p-6",
|
|
89
90
|
children: [
|
|
90
|
-
|
|
91
|
+
P && /* @__PURE__ */ x("div", {
|
|
91
92
|
className: "flex items-center justify-center py-12",
|
|
92
|
-
children: /* @__PURE__ */
|
|
93
|
+
children: /* @__PURE__ */ x(h, { className: "size-8 text-text-link animate-spin" })
|
|
93
94
|
}),
|
|
94
|
-
|
|
95
|
+
F && /* @__PURE__ */ x("div", {
|
|
95
96
|
className: "flex items-center justify-center py-12",
|
|
96
|
-
children: /* @__PURE__ */
|
|
97
|
+
children: /* @__PURE__ */ S("div", {
|
|
97
98
|
className: "text-center",
|
|
98
|
-
children: [/* @__PURE__ */
|
|
99
|
+
children: [/* @__PURE__ */ x(d, { className: "size-12 text-status-error-text mx-auto mb-4" }), /* @__PURE__ */ x("p", {
|
|
99
100
|
className: "text-sm text-text-secondary",
|
|
100
|
-
children:
|
|
101
|
+
children: i(D, "files.version.loadFailed", "Failed to load version history")
|
|
101
102
|
})]
|
|
102
103
|
})
|
|
103
104
|
}),
|
|
104
|
-
!
|
|
105
|
+
!P && !F && I.length === 0 && /* @__PURE__ */ x(w, {
|
|
105
106
|
illustration: "empty-data",
|
|
106
|
-
title:
|
|
107
|
-
description:
|
|
107
|
+
title: i(D, "files.version.noHistory", "No version history available"),
|
|
108
|
+
description: i(D, "files.version.noHistoryDescription", "New versions appear here each time this file is re-uploaded or edited, so you can review and restore earlier copies.")
|
|
108
109
|
}),
|
|
109
|
-
!
|
|
110
|
+
!P && !F && I.length > 0 && /* @__PURE__ */ x("div", {
|
|
110
111
|
className: "space-y-3",
|
|
111
|
-
children:
|
|
112
|
-
className: `p-4 border rounded-lg transition-all duration-200 ${
|
|
113
|
-
onClick: () =>
|
|
114
|
-
children: /* @__PURE__ */
|
|
112
|
+
children: I.map((t) => /* @__PURE__ */ x("div", {
|
|
113
|
+
className: `p-4 border rounded-lg transition-all duration-200 ${t.isCurrentVersion ? "border-action-primary-border bg-bg-accent" : O === t.id ? "border-border-seam bg-bg-sunken" : "border-border-seam hover:border-border-strong hover:bg-action-ghost-bg-hover"}`,
|
|
114
|
+
onClick: () => k(t.id),
|
|
115
|
+
children: /* @__PURE__ */ S("div", {
|
|
115
116
|
className: "flex items-start justify-between gap-4",
|
|
116
|
-
children: [/* @__PURE__ */
|
|
117
|
+
children: [/* @__PURE__ */ S("div", {
|
|
117
118
|
className: "flex-1 min-w-0",
|
|
118
119
|
children: [
|
|
119
|
-
/* @__PURE__ */
|
|
120
|
+
/* @__PURE__ */ S("div", {
|
|
120
121
|
className: "flex items-center gap-2 mb-2",
|
|
121
122
|
children: [
|
|
122
|
-
/* @__PURE__ */
|
|
123
|
+
/* @__PURE__ */ S("span", {
|
|
123
124
|
className: "text-sm font-semibold text-text-primary",
|
|
124
125
|
children: [
|
|
125
|
-
|
|
126
|
+
i(D, "files.version.version", "Version"),
|
|
126
127
|
" ",
|
|
127
|
-
|
|
128
|
+
t.versionNumber
|
|
128
129
|
]
|
|
129
130
|
}),
|
|
130
|
-
|
|
131
|
+
t.isCurrentVersion && /* @__PURE__ */ S("span", {
|
|
131
132
|
className: "inline-flex items-center gap-1 px-2 py-0.5 bg-action-primary-bg text-text-inverse text-xs font-medium rounded",
|
|
132
|
-
children: [/* @__PURE__ */
|
|
133
|
+
children: [/* @__PURE__ */ x(f, { className: "size-3" }), i(D, "files.version.current", "Current")]
|
|
133
134
|
}),
|
|
134
|
-
|
|
135
|
+
t.isMajorVersion && /* @__PURE__ */ S("span", {
|
|
135
136
|
className: "inline-flex items-center gap-1 px-2 py-0.5 bg-status-info-bg-subtle text-status-info-text text-xs font-medium rounded",
|
|
136
|
-
children: [/* @__PURE__ */
|
|
137
|
+
children: [/* @__PURE__ */ x(_, { className: "size-3" }), i(D, "files.version.major", "Major")]
|
|
137
138
|
}),
|
|
138
|
-
|
|
139
|
+
t.versionLabel && /* @__PURE__ */ x("span", {
|
|
139
140
|
className: "inline-flex items-center px-2 py-0.5 bg-status-success-bg-subtle text-status-success-text text-xs font-medium rounded",
|
|
140
|
-
children:
|
|
141
|
+
children: t.versionLabel
|
|
141
142
|
})
|
|
142
143
|
]
|
|
143
144
|
}),
|
|
144
|
-
|
|
145
|
+
t.changeMessage && /* @__PURE__ */ x("p", {
|
|
145
146
|
className: "text-sm text-text-primary mb-2",
|
|
146
|
-
children:
|
|
147
|
+
children: t.changeMessage
|
|
147
148
|
}),
|
|
148
|
-
/* @__PURE__ */
|
|
149
|
+
/* @__PURE__ */ S("div", {
|
|
149
150
|
className: "flex items-center gap-4 text-xs text-text-secondary",
|
|
150
151
|
children: [
|
|
151
|
-
/* @__PURE__ */
|
|
152
|
+
/* @__PURE__ */ x("span", {
|
|
152
153
|
className: "tabular-nums",
|
|
153
|
-
children:
|
|
154
|
+
children: r(e(t.size))
|
|
154
155
|
}),
|
|
155
|
-
/* @__PURE__ */
|
|
156
|
-
/* @__PURE__ */
|
|
156
|
+
/* @__PURE__ */ x("span", { children: "•" }),
|
|
157
|
+
/* @__PURE__ */ x("span", { children: n(t.createdAt) })
|
|
157
158
|
]
|
|
158
159
|
})
|
|
159
160
|
]
|
|
160
|
-
}), /* @__PURE__ */
|
|
161
|
+
}), /* @__PURE__ */ S("div", {
|
|
161
162
|
className: "flex items-center gap-2",
|
|
162
|
-
children: [/* @__PURE__ */
|
|
163
|
+
children: [/* @__PURE__ */ x("button", {
|
|
163
164
|
type: "button",
|
|
164
|
-
onClick: (
|
|
165
|
-
|
|
165
|
+
onClick: (e) => {
|
|
166
|
+
e.stopPropagation(), U(t.id);
|
|
166
167
|
},
|
|
167
168
|
className: "p-2 text-text-secondary hover:text-text-link hover:bg-bg-accent rounded-lg transition-colors duration-200",
|
|
168
|
-
title:
|
|
169
|
-
children: /* @__PURE__ */
|
|
170
|
-
}), !
|
|
169
|
+
title: i(D, "files.version.downloadThisVersion", "Download this version"),
|
|
170
|
+
children: /* @__PURE__ */ x(m, { className: "size-4" })
|
|
171
|
+
}), !t.isCurrentVersion && /* @__PURE__ */ S(b, { children: [/* @__PURE__ */ x("button", {
|
|
171
172
|
type: "button",
|
|
172
|
-
onClick: (
|
|
173
|
-
|
|
173
|
+
onClick: (e) => {
|
|
174
|
+
e.stopPropagation(), B(t.id, t.versionNumber);
|
|
174
175
|
},
|
|
175
|
-
disabled:
|
|
176
|
+
disabled: L.isPending,
|
|
176
177
|
className: "p-2 text-text-secondary hover:text-status-success-text hover:bg-status-success-bg-subtle rounded-lg transition-colors duration-200 disabled:opacity-50 disabled:cursor-not-allowed",
|
|
177
|
-
title:
|
|
178
|
-
children:
|
|
179
|
-
}), /* @__PURE__ */
|
|
178
|
+
title: i(D, "files.version.restoreThisVersion", "Restore this version"),
|
|
179
|
+
children: L.isPending ? /* @__PURE__ */ x(h, { className: "size-4 animate-spin" }) : /* @__PURE__ */ x(g, { className: "size-4" })
|
|
180
|
+
}), /* @__PURE__ */ x("button", {
|
|
180
181
|
type: "button",
|
|
181
|
-
onClick: (
|
|
182
|
-
|
|
182
|
+
onClick: (e) => {
|
|
183
|
+
e.stopPropagation(), V(t.id, t.versionNumber);
|
|
183
184
|
},
|
|
184
|
-
disabled:
|
|
185
|
+
disabled: R.isPending,
|
|
185
186
|
className: "p-2 text-text-secondary hover:text-status-error-text hover:bg-status-error-bg-subtle rounded-lg transition-colors duration-200 disabled:opacity-50 disabled:cursor-not-allowed",
|
|
186
|
-
title:
|
|
187
|
-
children:
|
|
187
|
+
title: i(D, "files.version.deleteThisVersion", "Delete this version"),
|
|
188
|
+
children: R.isPending ? /* @__PURE__ */ x(h, { className: "size-4 animate-spin" }) : /* @__PURE__ */ x(v, { className: "size-4" })
|
|
188
189
|
})] })]
|
|
189
190
|
})]
|
|
190
191
|
})
|
|
191
|
-
},
|
|
192
|
+
}, t.id))
|
|
192
193
|
})
|
|
193
194
|
]
|
|
194
195
|
}),
|
|
195
|
-
/* @__PURE__ */
|
|
196
|
+
/* @__PURE__ */ x("div", {
|
|
196
197
|
className: "p-6 border-t border-border-seam bg-bg-sunken",
|
|
197
|
-
children: /* @__PURE__ */
|
|
198
|
+
children: /* @__PURE__ */ S("div", {
|
|
198
199
|
className: "flex items-center justify-between text-sm text-text-secondary",
|
|
199
|
-
children: [/* @__PURE__ */
|
|
200
|
-
|
|
200
|
+
children: [/* @__PURE__ */ S("span", { children: [
|
|
201
|
+
N?.total || 0,
|
|
201
202
|
" ",
|
|
202
|
-
|
|
203
|
+
N?.total === 1 ? i(D, "files.version.versionSingular", "version") : i(D, "files.version.versions", "versions"),
|
|
203
204
|
" ",
|
|
204
|
-
|
|
205
|
-
] }), /* @__PURE__ */
|
|
205
|
+
i(D, "files.version.total", "total")
|
|
206
|
+
] }), /* @__PURE__ */ x("button", {
|
|
206
207
|
type: "button",
|
|
207
|
-
onClick:
|
|
208
|
+
onClick: E,
|
|
208
209
|
className: "px-4 py-2 text-sm font-medium text-text-primary hover:bg-action-ghost-bg-hover rounded-lg transition-colors duration-200",
|
|
209
|
-
children:
|
|
210
|
+
children: i(D, "files.common.actions.close", "Close")
|
|
210
211
|
})]
|
|
211
212
|
})
|
|
212
213
|
})
|
|
213
214
|
]
|
|
214
|
-
}),
|
|
215
|
-
title:
|
|
216
|
-
description:
|
|
217
|
-
confirmLabel:
|
|
218
|
-
cancelLabel:
|
|
219
|
-
variant:
|
|
220
|
-
loading:
|
|
221
|
-
onConfirm:
|
|
215
|
+
}), A && /* @__PURE__ */ x(a, {
|
|
216
|
+
title: A.title,
|
|
217
|
+
description: A.description,
|
|
218
|
+
confirmLabel: A.confirmLabel,
|
|
219
|
+
cancelLabel: i(D, "files.common.actions.cancel", "Cancel"),
|
|
220
|
+
variant: A.variant,
|
|
221
|
+
loading: A.loading,
|
|
222
|
+
onConfirm: H,
|
|
222
223
|
onCancel: () => {
|
|
223
|
-
|
|
224
|
+
A.loading || j(null);
|
|
224
225
|
}
|
|
225
226
|
})]
|
|
226
227
|
});
|
|
227
228
|
};
|
|
228
229
|
//#endregion
|
|
229
|
-
export {
|
|
230
|
+
export { T as FileVersionPanel };
|
|
230
231
|
|
|
231
232
|
//# sourceMappingURL=FileVersionPanel.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FileVersionPanel.js","names":[],"sources":["../../../src/files/components/FileVersionPanel.tsx"],"sourcesContent":["import { type FC, useState } from \"react\";\nimport {\n Clock,\n Download,\n RotateCcw,\n Trash2,\n X,\n CheckCircle2,\n AlertCircle,\n Loader2,\n Tag,\n} from \"lucide-react\";\nimport { useI18n } from \"@burdenoff/fe-libs/shared/providers/shell/I18nProvider\";\nimport { IllustratedEmptyState } from \"@burdenoff/fe-libs/ui\";\nimport type { FileItem } from \"../types\";\nimport { formatFileSize, formatFileDate } from \"../utils\";\nimport { tWithFallback } from \"../utils/i18n\";\nimport {\n useFileVersions,\n useRestoreFileVersion,\n useDeleteFileVersion,\n useVersionDownloadUrl,\n} from \"../hooks/useFileVersions\";\nimport { useToast } from \"../hooks/useToast\";\nimport { ConfirmDialog } from \"./ConfirmDialog\";\n\ninterface FileVersionPanelProps {\n file: FileItem;\n onClose: () => void;\n}\n\nexport const FileVersionPanel: FC<FileVersionPanelProps> = ({\n file,\n onClose,\n}) => {\n const { t } = useI18n();\n const [selectedVersionId, setSelectedVersionId] = useState<string | null>(\n null,\n );\n const [confirmAction, setConfirmAction] = useState<{\n title: string;\n description: string;\n confirmLabel: string;\n variant?: \"danger\" | \"default\";\n onConfirm: () => Promise<void>;\n loading?: boolean;\n } | null>(null);\n const toast = useToast();\n\n // Fetch versions\n const { data: versionsData, isLoading, error } = useFileVersions(file.id);\n const versions = versionsData?.versions || [];\n\n // Mutations\n const restoreMutation = useRestoreFileVersion();\n const deleteMutation = useDeleteFileVersion();\n const versionDownload = useVersionDownloadUrl();\n\n const handleRestore = async (versionId: string, versionNumber: number) => {\n setConfirmAction({\n title: `${tWithFallback(t, \"files.version.restoreVersion\", \"Restore version\")} ${versionNumber}`,\n description: tWithFallback(\n t,\n \"files.version.restoreDescription\",\n \"This will create a new version with the restored content.\",\n ),\n confirmLabel: tWithFallback(t, \"files.version.restore\", \"Restore\"),\n onConfirm: async () => {\n try {\n await restoreMutation.mutateAsync({\n versionId,\n createNewVersion: true,\n changeMessage: `${tWithFallback(t, \"files.version.restoredFrom\", \"Restored from version\")} ${versionNumber}`,\n });\n toast.success(\n `${tWithFallback(t, \"files.version.versionRestored\", \"Version {{number}} restored successfully\", { number: versionNumber })}`,\n );\n } catch {\n toast.error(\n tWithFallback(\n t,\n \"files.version.restoreFailed\",\n \"Failed to restore version\",\n ),\n );\n }\n },\n });\n };\n\n const handleDelete = async (versionId: string, versionNumber: number) => {\n setConfirmAction({\n title: `${tWithFallback(t, \"files.version.deleteVersion\", \"Delete version\")} ${versionNumber}`,\n description: tWithFallback(\n t,\n \"files.version.deleteDescription\",\n \"This action cannot be undone.\",\n ),\n confirmLabel: tWithFallback(\n t,\n \"files.version.deleteVersionBtn\",\n \"Delete version\",\n ),\n variant: \"danger\",\n onConfirm: async () => {\n try {\n await deleteMutation.mutateAsync(versionId);\n toast.success(\n `${tWithFallback(t, \"files.version.versionDeleted\", \"Version {{number}} deleted\", { number: versionNumber })}`,\n );\n } catch {\n toast.error(\n tWithFallback(\n t,\n \"files.version.deleteFailed\",\n \"Failed to delete version\",\n ),\n );\n }\n },\n });\n };\n\n const runConfirmAction = async () => {\n if (!confirmAction || confirmAction.loading) return;\n\n const action = confirmAction.onConfirm;\n setConfirmAction({ ...confirmAction, loading: true });\n await action();\n setConfirmAction(null);\n };\n\n const handleDownload = async (versionId: string) => {\n try {\n const downloadUrl = await versionDownload.getDownloadUrl(versionId);\n\n if (!downloadUrl) {\n throw new Error(\n tWithFallback(\n t,\n \"files.version.downloadUnavailable\",\n \"Version download URL is unavailable\",\n ),\n );\n }\n\n window.open(downloadUrl, \"_blank\", \"noopener,noreferrer\");\n } catch (error) {\n toast.error(\n error instanceof Error\n ? error.message\n : tWithFallback(\n t,\n \"files.version.downloadFailed\",\n \"Failed to download version\",\n ),\n );\n }\n };\n\n return (\n <div\n className=\"fixed inset-0 z-[110] bg-bg-overlay flex items-center justify-center p-4 animate-in fade-in duration-200\"\n role=\"dialog\"\n aria-modal=\"true\"\n aria-label={tWithFallback(\n t,\n \"files.version.historyFor\",\n \"Version history for {{name}}\",\n { name: file.name },\n )}\n >\n <div className=\"bg-bg-surface rounded-lg shadow-xl max-w-3xl w-full max-h-[90vh] overflow-hidden flex flex-col animate-in zoom-in-95 duration-200\">\n {/* Header */}\n <div className=\"flex items-center justify-between p-6 border-b border-border-seam\">\n <div className=\"flex items-center gap-3\">\n <Clock className=\"size-6 text-text-link\" />\n <div>\n <h2 className=\"text-lg font-semibold text-text-primary\">\n {tWithFallback(\n t,\n \"files.version.versionHistory\",\n \"Version History\",\n )}\n </h2>\n <p className=\"text-sm text-text-secondary\">{file.name}</p>\n </div>\n </div>\n <button\n type=\"button\"\n onClick={onClose}\n className=\"p-2 text-text-tertiary hover:text-text-secondary hover:bg-action-ghost-bg-hover rounded-lg transition-colors duration-200\"\n aria-label={tWithFallback(\n t,\n \"files.version.closeHistory\",\n \"Close version history\",\n )}\n >\n <X className=\"size-5\" />\n </button>\n </div>\n\n {/* Content */}\n <div className=\"flex-1 overflow-y-auto p-6\">\n {isLoading && (\n <div className=\"flex items-center justify-center py-12\">\n <Loader2 className=\"size-8 text-text-link animate-spin\" />\n </div>\n )}\n\n {error && (\n <div className=\"flex items-center justify-center py-12\">\n <div className=\"text-center\">\n <AlertCircle className=\"size-12 text-status-error-text mx-auto mb-4\" />\n <p className=\"text-sm text-text-secondary\">\n {tWithFallback(\n t,\n \"files.version.loadFailed\",\n \"Failed to load version history\",\n )}\n </p>\n </div>\n </div>\n )}\n\n {!isLoading && !error && versions.length === 0 && (\n <IllustratedEmptyState\n illustration=\"empty-data\"\n title={tWithFallback(\n t,\n \"files.version.noHistory\",\n \"No version history available\",\n )}\n description={tWithFallback(\n t,\n \"files.version.noHistoryDescription\",\n \"New versions appear here each time this file is re-uploaded or edited, so you can review and restore earlier copies.\",\n )}\n />\n )}\n\n {!isLoading && !error && versions.length > 0 && (\n <div className=\"space-y-3\">\n {versions.map((version: (typeof versions)[number]) => (\n <div\n key={version.id}\n className={`p-4 border rounded-lg transition-all duration-200 ${\n version.isCurrentVersion\n ? \"border-action-primary-border bg-bg-accent\"\n : selectedVersionId === version.id\n ? \"border-border-seam bg-bg-sunken\"\n : \"border-border-seam hover:border-border-strong hover:bg-action-ghost-bg-hover\"\n }`}\n onClick={() => setSelectedVersionId(version.id)}\n >\n <div className=\"flex items-start justify-between gap-4\">\n {/* Version info */}\n <div className=\"flex-1 min-w-0\">\n <div className=\"flex items-center gap-2 mb-2\">\n <span className=\"text-sm font-semibold text-text-primary\">\n {tWithFallback(t, \"files.version.version\", \"Version\")}{\" \"}\n {version.versionNumber}\n </span>\n\n {version.isCurrentVersion && (\n <span className=\"inline-flex items-center gap-1 px-2 py-0.5 bg-action-primary-bg text-text-inverse text-xs font-medium rounded\">\n <CheckCircle2 className=\"size-3\" />\n {tWithFallback(\n t,\n \"files.version.current\",\n \"Current\",\n )}\n </span>\n )}\n\n {version.isMajorVersion && (\n <span className=\"inline-flex items-center gap-1 px-2 py-0.5 bg-status-info-bg-subtle text-status-info-text text-xs font-medium rounded\">\n <Tag className=\"size-3\" />\n {tWithFallback(t, \"files.version.major\", \"Major\")}\n </span>\n )}\n\n {version.versionLabel && (\n <span className=\"inline-flex items-center px-2 py-0.5 bg-status-success-bg-subtle text-status-success-text text-xs font-medium rounded\">\n {version.versionLabel}\n </span>\n )}\n </div>\n\n {version.changeMessage && (\n <p className=\"text-sm text-text-primary mb-2\">\n {version.changeMessage}\n </p>\n )}\n\n <div className=\"flex items-center gap-4 text-xs text-text-secondary\">\n <span className=\"tabular-nums\">\n {formatFileSize(version.size)}\n </span>\n <span>•</span>\n <span>{formatFileDate(version.createdAt)}</span>\n </div>\n </div>\n\n {/* Actions */}\n <div className=\"flex items-center gap-2\">\n <button\n type=\"button\"\n onClick={(e) => {\n e.stopPropagation();\n handleDownload(version.id);\n }}\n className=\"p-2 text-text-secondary hover:text-text-link hover:bg-bg-accent rounded-lg transition-colors duration-200\"\n title={tWithFallback(\n t,\n \"files.version.downloadThisVersion\",\n \"Download this version\",\n )}\n >\n <Download className=\"size-4\" />\n </button>\n\n {!version.isCurrentVersion && (\n <>\n <button\n type=\"button\"\n onClick={(e) => {\n e.stopPropagation();\n handleRestore(version.id, version.versionNumber);\n }}\n disabled={restoreMutation.isPending}\n className=\"p-2 text-text-secondary hover:text-status-success-text hover:bg-status-success-bg-subtle rounded-lg transition-colors duration-200 disabled:opacity-50 disabled:cursor-not-allowed\"\n title={tWithFallback(\n t,\n \"files.version.restoreThisVersion\",\n \"Restore this version\",\n )}\n >\n {restoreMutation.isPending ? (\n <Loader2 className=\"size-4 animate-spin\" />\n ) : (\n <RotateCcw className=\"size-4\" />\n )}\n </button>\n\n <button\n type=\"button\"\n onClick={(e) => {\n e.stopPropagation();\n handleDelete(version.id, version.versionNumber);\n }}\n disabled={deleteMutation.isPending}\n className=\"p-2 text-text-secondary hover:text-status-error-text hover:bg-status-error-bg-subtle rounded-lg transition-colors duration-200 disabled:opacity-50 disabled:cursor-not-allowed\"\n title={tWithFallback(\n t,\n \"files.version.deleteThisVersion\",\n \"Delete this version\",\n )}\n >\n {deleteMutation.isPending ? (\n <Loader2 className=\"size-4 animate-spin\" />\n ) : (\n <Trash2 className=\"size-4\" />\n )}\n </button>\n </>\n )}\n </div>\n </div>\n </div>\n ))}\n </div>\n )}\n </div>\n\n {/* Footer */}\n <div className=\"p-6 border-t border-border-seam bg-bg-sunken\">\n <div className=\"flex items-center justify-between text-sm text-text-secondary\">\n <span>\n {versionsData?.total || 0}{\" \"}\n {versionsData?.total !== 1\n ? tWithFallback(t, \"files.version.versions\", \"versions\")\n : tWithFallback(\n t,\n \"files.version.versionSingular\",\n \"version\",\n )}{\" \"}\n {tWithFallback(t, \"files.version.total\", \"total\")}\n </span>\n <button\n type=\"button\"\n onClick={onClose}\n className=\"px-4 py-2 text-sm font-medium text-text-primary hover:bg-action-ghost-bg-hover rounded-lg transition-colors duration-200\"\n >\n {tWithFallback(t, \"files.common.actions.close\", \"Close\")}\n </button>\n </div>\n </div>\n </div>\n\n {confirmAction && (\n <ConfirmDialog\n title={confirmAction.title}\n description={confirmAction.description}\n confirmLabel={confirmAction.confirmLabel}\n cancelLabel={tWithFallback(\n t,\n \"files.common.actions.cancel\",\n \"Cancel\",\n )}\n variant={confirmAction.variant}\n loading={confirmAction.loading}\n onConfirm={runConfirmAction}\n onCancel={() => {\n if (!confirmAction.loading) {\n setConfirmAction(null);\n }\n }}\n />\n )}\n </div>\n );\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"FileVersionPanel.js","names":["_Fragment","FileVersionPanel","useI18n","selectedVersionId","setSelectedVersionId","useState","confirmAction","setConfirmAction","toast","useToast","versionsData","useFileVersions","file","versions","restoreMutation","useRestoreFileVersion","deleteMutation","useDeleteFileVersion","versionDownload","useVersionDownloadUrl","handleRestore","tWithFallback","t","versionNumber","handleDelete","versionId","runConfirmAction","action","handleDownload","downloadUrl","error","Clock","onClose","X","isLoading","Loader2","AlertCircle","IllustratedEmptyState","version","CheckCircle2","Tag","formatFileSize","browserFileSize","formatFileDate","Download","Fragment","RotateCcw","Trash2","ConfirmDialog"],"sources":["../../../src/files/components/FileVersionPanel.tsx"],"sourcesContent":["import { browserFileSize } from \"../utils/fileViewModel\";\nimport { type FC, useState } from \"react\";\nimport {\n Clock,\n Download,\n RotateCcw,\n Trash2,\n X,\n CheckCircle2,\n AlertCircle,\n Loader2,\n Tag,\n} from \"lucide-react\";\nimport { useI18n } from \"@burdenoff/fe-libs/shared/providers/shell/I18nProvider\";\nimport { IllustratedEmptyState } from \"@burdenoff/fe-libs/ui\";\nimport type { FileItem } from \"../types\";\nimport { formatFileSize, formatFileDate } from \"../utils\";\nimport { tWithFallback } from \"../utils/i18n\";\nimport {\n useFileVersions,\n useRestoreFileVersion,\n useDeleteFileVersion,\n useVersionDownloadUrl,\n} from \"../hooks/useFileVersions\";\nimport { useToast } from \"../hooks/useToast\";\nimport { ConfirmDialog } from \"./ConfirmDialog\";\n\ninterface FileVersionPanelProps {\n file: FileItem;\n onClose: () => void;\n}\n\nexport const FileVersionPanel: FC<FileVersionPanelProps> = ({\n file,\n onClose,\n}) => {\n const { t } = useI18n();\n const [selectedVersionId, setSelectedVersionId] = useState<string | null>(\n null,\n );\n const [confirmAction, setConfirmAction] = useState<{\n title: string;\n description: string;\n confirmLabel: string;\n variant?: \"danger\" | \"default\";\n onConfirm: () => Promise<void>;\n loading?: boolean;\n } | null>(null);\n const toast = useToast();\n\n // Fetch versions\n const { data: versionsData, isLoading, error } = useFileVersions(file.id);\n const versions = versionsData?.versions || [];\n\n // Mutations\n const restoreMutation = useRestoreFileVersion();\n const deleteMutation = useDeleteFileVersion();\n const versionDownload = useVersionDownloadUrl();\n\n const handleRestore = async (versionId: string, versionNumber: number) => {\n setConfirmAction({\n title: `${tWithFallback(t, \"files.version.restoreVersion\", \"Restore version\")} ${versionNumber}`,\n description: tWithFallback(\n t,\n \"files.version.restoreDescription\",\n \"This will create a new version with the restored content.\",\n ),\n confirmLabel: tWithFallback(t, \"files.version.restore\", \"Restore\"),\n onConfirm: async () => {\n try {\n await restoreMutation.mutateAsync({\n versionId,\n createNewVersion: true,\n changeMessage: `${tWithFallback(t, \"files.version.restoredFrom\", \"Restored from version\")} ${versionNumber}`,\n });\n toast.success(\n `${tWithFallback(t, \"files.version.versionRestored\", \"Version {{number}} restored successfully\", { number: versionNumber })}`,\n );\n } catch {\n toast.error(\n tWithFallback(\n t,\n \"files.version.restoreFailed\",\n \"Failed to restore version\",\n ),\n );\n }\n },\n });\n };\n\n const handleDelete = async (versionId: string, versionNumber: number) => {\n setConfirmAction({\n title: `${tWithFallback(t, \"files.version.deleteVersion\", \"Delete version\")} ${versionNumber}`,\n description: tWithFallback(\n t,\n \"files.version.deleteDescription\",\n \"This action cannot be undone.\",\n ),\n confirmLabel: tWithFallback(\n t,\n \"files.version.deleteVersionBtn\",\n \"Delete version\",\n ),\n variant: \"danger\",\n onConfirm: async () => {\n try {\n await deleteMutation.mutateAsync(versionId);\n toast.success(\n `${tWithFallback(t, \"files.version.versionDeleted\", \"Version {{number}} deleted\", { number: versionNumber })}`,\n );\n } catch {\n toast.error(\n tWithFallback(\n t,\n \"files.version.deleteFailed\",\n \"Failed to delete version\",\n ),\n );\n }\n },\n });\n };\n\n const runConfirmAction = async () => {\n if (!confirmAction || confirmAction.loading) return;\n\n const action = confirmAction.onConfirm;\n setConfirmAction({ ...confirmAction, loading: true });\n await action();\n setConfirmAction(null);\n };\n\n const handleDownload = async (versionId: string) => {\n try {\n const downloadUrl = await versionDownload.getDownloadUrl(versionId);\n\n if (!downloadUrl) {\n throw new Error(\n tWithFallback(\n t,\n \"files.version.downloadUnavailable\",\n \"Version download URL is unavailable\",\n ),\n );\n }\n\n window.open(downloadUrl, \"_blank\", \"noopener,noreferrer\");\n } catch (error) {\n toast.error(\n error instanceof Error\n ? error.message\n : tWithFallback(\n t,\n \"files.version.downloadFailed\",\n \"Failed to download version\",\n ),\n );\n }\n };\n\n return (\n <div\n className=\"fixed inset-0 z-[110] bg-bg-overlay flex items-center justify-center p-4 animate-in fade-in duration-200\"\n role=\"dialog\"\n aria-modal=\"true\"\n aria-label={tWithFallback(\n t,\n \"files.version.historyFor\",\n \"Version history for {{name}}\",\n { name: file.name },\n )}\n >\n <div className=\"bg-bg-surface rounded-lg shadow-xl max-w-3xl w-full max-h-[90vh] overflow-hidden flex flex-col animate-in zoom-in-95 duration-200\">\n {/* Header */}\n <div className=\"flex items-center justify-between p-6 border-b border-border-seam\">\n <div className=\"flex items-center gap-3\">\n <Clock className=\"size-6 text-text-link\" />\n <div>\n <h2 className=\"text-lg font-semibold text-text-primary\">\n {tWithFallback(\n t,\n \"files.version.versionHistory\",\n \"Version History\",\n )}\n </h2>\n <p className=\"text-sm text-text-secondary\">{file.name}</p>\n </div>\n </div>\n <button\n type=\"button\"\n onClick={onClose}\n className=\"p-2 text-text-tertiary hover:text-text-secondary hover:bg-action-ghost-bg-hover rounded-lg transition-colors duration-200\"\n aria-label={tWithFallback(\n t,\n \"files.version.closeHistory\",\n \"Close version history\",\n )}\n >\n <X className=\"size-5\" />\n </button>\n </div>\n\n {/* Content */}\n <div className=\"flex-1 overflow-y-auto p-6\">\n {isLoading && (\n <div className=\"flex items-center justify-center py-12\">\n <Loader2 className=\"size-8 text-text-link animate-spin\" />\n </div>\n )}\n\n {error && (\n <div className=\"flex items-center justify-center py-12\">\n <div className=\"text-center\">\n <AlertCircle className=\"size-12 text-status-error-text mx-auto mb-4\" />\n <p className=\"text-sm text-text-secondary\">\n {tWithFallback(\n t,\n \"files.version.loadFailed\",\n \"Failed to load version history\",\n )}\n </p>\n </div>\n </div>\n )}\n\n {!isLoading && !error && versions.length === 0 && (\n <IllustratedEmptyState\n illustration=\"empty-data\"\n title={tWithFallback(\n t,\n \"files.version.noHistory\",\n \"No version history available\",\n )}\n description={tWithFallback(\n t,\n \"files.version.noHistoryDescription\",\n \"New versions appear here each time this file is re-uploaded or edited, so you can review and restore earlier copies.\",\n )}\n />\n )}\n\n {!isLoading && !error && versions.length > 0 && (\n <div className=\"space-y-3\">\n {versions.map((version: (typeof versions)[number]) => (\n <div\n key={version.id}\n className={`p-4 border rounded-lg transition-all duration-200 ${\n version.isCurrentVersion\n ? \"border-action-primary-border bg-bg-accent\"\n : selectedVersionId === version.id\n ? \"border-border-seam bg-bg-sunken\"\n : \"border-border-seam hover:border-border-strong hover:bg-action-ghost-bg-hover\"\n }`}\n onClick={() => setSelectedVersionId(version.id)}\n >\n <div className=\"flex items-start justify-between gap-4\">\n {/* Version info */}\n <div className=\"flex-1 min-w-0\">\n <div className=\"flex items-center gap-2 mb-2\">\n <span className=\"text-sm font-semibold text-text-primary\">\n {tWithFallback(t, \"files.version.version\", \"Version\")}{\" \"}\n {version.versionNumber}\n </span>\n\n {version.isCurrentVersion && (\n <span className=\"inline-flex items-center gap-1 px-2 py-0.5 bg-action-primary-bg text-text-inverse text-xs font-medium rounded\">\n <CheckCircle2 className=\"size-3\" />\n {tWithFallback(\n t,\n \"files.version.current\",\n \"Current\",\n )}\n </span>\n )}\n\n {version.isMajorVersion && (\n <span className=\"inline-flex items-center gap-1 px-2 py-0.5 bg-status-info-bg-subtle text-status-info-text text-xs font-medium rounded\">\n <Tag className=\"size-3\" />\n {tWithFallback(t, \"files.version.major\", \"Major\")}\n </span>\n )}\n\n {version.versionLabel && (\n <span className=\"inline-flex items-center px-2 py-0.5 bg-status-success-bg-subtle text-status-success-text text-xs font-medium rounded\">\n {version.versionLabel}\n </span>\n )}\n </div>\n\n {version.changeMessage && (\n <p className=\"text-sm text-text-primary mb-2\">\n {version.changeMessage}\n </p>\n )}\n\n <div className=\"flex items-center gap-4 text-xs text-text-secondary\">\n <span className=\"tabular-nums\">\n {formatFileSize(browserFileSize(version.size))}\n </span>\n <span>•</span>\n <span>{formatFileDate(version.createdAt)}</span>\n </div>\n </div>\n\n {/* Actions */}\n <div className=\"flex items-center gap-2\">\n <button\n type=\"button\"\n onClick={(e) => {\n e.stopPropagation();\n handleDownload(version.id);\n }}\n className=\"p-2 text-text-secondary hover:text-text-link hover:bg-bg-accent rounded-lg transition-colors duration-200\"\n title={tWithFallback(\n t,\n \"files.version.downloadThisVersion\",\n \"Download this version\",\n )}\n >\n <Download className=\"size-4\" />\n </button>\n\n {!version.isCurrentVersion && (\n <>\n <button\n type=\"button\"\n onClick={(e) => {\n e.stopPropagation();\n handleRestore(version.id, version.versionNumber);\n }}\n disabled={restoreMutation.isPending}\n className=\"p-2 text-text-secondary hover:text-status-success-text hover:bg-status-success-bg-subtle rounded-lg transition-colors duration-200 disabled:opacity-50 disabled:cursor-not-allowed\"\n title={tWithFallback(\n t,\n \"files.version.restoreThisVersion\",\n \"Restore this version\",\n )}\n >\n {restoreMutation.isPending ? (\n <Loader2 className=\"size-4 animate-spin\" />\n ) : (\n <RotateCcw className=\"size-4\" />\n )}\n </button>\n\n <button\n type=\"button\"\n onClick={(e) => {\n e.stopPropagation();\n handleDelete(version.id, version.versionNumber);\n }}\n disabled={deleteMutation.isPending}\n className=\"p-2 text-text-secondary hover:text-status-error-text hover:bg-status-error-bg-subtle rounded-lg transition-colors duration-200 disabled:opacity-50 disabled:cursor-not-allowed\"\n title={tWithFallback(\n t,\n \"files.version.deleteThisVersion\",\n \"Delete this version\",\n )}\n >\n {deleteMutation.isPending ? (\n <Loader2 className=\"size-4 animate-spin\" />\n ) : (\n <Trash2 className=\"size-4\" />\n )}\n </button>\n </>\n )}\n </div>\n </div>\n </div>\n ))}\n </div>\n )}\n </div>\n\n {/* Footer */}\n <div className=\"p-6 border-t border-border-seam bg-bg-sunken\">\n <div className=\"flex items-center justify-between text-sm text-text-secondary\">\n <span>\n {versionsData?.total || 0}{\" \"}\n {versionsData?.total !== 1\n ? tWithFallback(t, \"files.version.versions\", \"versions\")\n : tWithFallback(\n t,\n \"files.version.versionSingular\",\n \"version\",\n )}{\" \"}\n {tWithFallback(t, \"files.version.total\", \"total\")}\n </span>\n <button\n type=\"button\"\n onClick={onClose}\n className=\"px-4 py-2 text-sm font-medium text-text-primary hover:bg-action-ghost-bg-hover rounded-lg transition-colors duration-200\"\n >\n {tWithFallback(t, \"files.common.actions.close\", \"Close\")}\n </button>\n </div>\n </div>\n </div>\n\n {confirmAction && (\n <ConfirmDialog\n title={confirmAction.title}\n description={confirmAction.description}\n confirmLabel={confirmAction.confirmLabel}\n cancelLabel={tWithFallback(\n t,\n \"files.common.actions.cancel\",\n \"Cancel\",\n )}\n variant={confirmAction.variant}\n loading={confirmAction.loading}\n onConfirm={runConfirmAction}\n onCancel={() => {\n if (!confirmAction.loading) {\n setConfirmAction(null);\n }\n }}\n />\n )}\n </div>\n );\n};\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FolderCard.d.ts","sourceRoot":"","sources":["../../../src/files/components/FolderCard.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,EAAqB,MAAM,OAAO,CAAC;AAgBnD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAM3C,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAErD,UAAU,eAAe;IACvB,MAAM,EAAE,UAAU,CAAC;IACnB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,WAAW,CAAC,EAAE,QAAQ,GAAG,IAAI,CAAC;IAC9B,QAAQ,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAC;IACtC,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,UAAU,KAAK,IAAI,CAAC;IACtC,OAAO,CAAC,EAAE,CAAC,MAAM,EAAE,UAAU,KAAK,IAAI,CAAC;IACvC,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE,UAAU,KAAK,IAAI,CAAC;IACxC,SAAS,CAAC,EAAE,CAAC,MAAM,EAAE,UAAU,KAAK,IAAI,CAAC;IACzC,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE,UAAU,KAAK,IAAI,CAAC;IACxC,UAAU,CAAC,EAAE,CAAC,MAAM,EAAE,UAAU,KAAK,IAAI,CAAC;IAC1C,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,UAAU,KAAK,IAAI,CAAC;IACtC,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,UAAU,KAAK,IAAI,CAAC;IACtC,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,UAAU,KAAK,IAAI,CAAC;IACtC,UAAU,CAAC,EAAE,CAAC,MAAM,EAAE,UAAU,KAAK,IAAI,CAAC;IAC1C,WAAW,CAAC,EAAE,CAAC,MAAM,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,KAAK,IAAI,CAAC;IACvE,SAAS,CAAC,EAAE,MAAM,IAAI,CAAC;IACvB,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,UAAU,KAAK,IAAI,CAAC;IACtC,aAAa,CAAC,EAAE,CAAC,MAAM,EAAE,UAAU,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;CACpE;AAED,UAAU,wBAAyB,SAAQ,IAAI,CAC7C,eAAe,EACf,aAAa,GAAG,WAAW,GAAG,QAAQ,CACvC;IACC,WAAW,CAAC,EAAE,CAAC,MAAM,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,KAAK,IAAI,CAAC;IACvE,SAAS,CAAC,EAAE,MAAM,IAAI,CAAC;IACvB,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,UAAU,KAAK,IAAI,CAAC;IACtC,aAAa,CAAC,EAAE,CAAC,MAAM,EAAE,UAAU,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;CACpE;AAED,eAAO,MAAM,UAAU,EAAE,EAAE,CAAC,wBAAwB,
|
|
1
|
+
{"version":3,"file":"FolderCard.d.ts","sourceRoot":"","sources":["../../../src/files/components/FolderCard.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,EAAqB,MAAM,OAAO,CAAC;AAgBnD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAM3C,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAErD,UAAU,eAAe;IACvB,MAAM,EAAE,UAAU,CAAC;IACnB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,WAAW,CAAC,EAAE,QAAQ,GAAG,IAAI,CAAC;IAC9B,QAAQ,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAC;IACtC,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,UAAU,KAAK,IAAI,CAAC;IACtC,OAAO,CAAC,EAAE,CAAC,MAAM,EAAE,UAAU,KAAK,IAAI,CAAC;IACvC,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE,UAAU,KAAK,IAAI,CAAC;IACxC,SAAS,CAAC,EAAE,CAAC,MAAM,EAAE,UAAU,KAAK,IAAI,CAAC;IACzC,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE,UAAU,KAAK,IAAI,CAAC;IACxC,UAAU,CAAC,EAAE,CAAC,MAAM,EAAE,UAAU,KAAK,IAAI,CAAC;IAC1C,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,UAAU,KAAK,IAAI,CAAC;IACtC,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,UAAU,KAAK,IAAI,CAAC;IACtC,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,UAAU,KAAK,IAAI,CAAC;IACtC,UAAU,CAAC,EAAE,CAAC,MAAM,EAAE,UAAU,KAAK,IAAI,CAAC;IAC1C,WAAW,CAAC,EAAE,CAAC,MAAM,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,KAAK,IAAI,CAAC;IACvE,SAAS,CAAC,EAAE,MAAM,IAAI,CAAC;IACvB,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,UAAU,KAAK,IAAI,CAAC;IACtC,aAAa,CAAC,EAAE,CAAC,MAAM,EAAE,UAAU,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;CACpE;AAED,UAAU,wBAAyB,SAAQ,IAAI,CAC7C,eAAe,EACf,aAAa,GAAG,WAAW,GAAG,QAAQ,CACvC;IACC,WAAW,CAAC,EAAE,CAAC,MAAM,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,KAAK,IAAI,CAAC;IACvE,SAAS,CAAC,EAAE,MAAM,IAAI,CAAC;IACvB,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,UAAU,KAAK,IAAI,CAAC;IACtC,aAAa,CAAC,EAAE,CAAC,MAAM,EAAE,UAAU,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;CACpE;AAED,eAAO,MAAM,UAAU,EAAE,EAAE,CAAC,wBAAwB,CAsWnD,CAAC"}
|
|
@@ -100,7 +100,7 @@ var S = ({ folder: S, isSelected: C = !1, isDragging: w = !1, isDropTarget: T =
|
|
|
100
100
|
!e.currentTarget.contains(e.relatedTarget) && !W && U(!1);
|
|
101
101
|
},
|
|
102
102
|
onKeyDown: (e) => {
|
|
103
|
-
(e.key === "Enter" || e.key === " ") && (e.preventDefault(), Z());
|
|
103
|
+
e.target === e.currentTarget && (e.key === "Enter" || e.key === " ") && (e.preventDefault(), Z());
|
|
104
104
|
},
|
|
105
105
|
draggable: !!L,
|
|
106
106
|
onDragStart: ae,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FolderCard.js","names":[],"sources":["../../../src/files/components/FolderCard.tsx"],"sourcesContent":["import { type FC, useState, useMemo } from \"react\";\nimport {\n Folder,\n FolderOpen,\n Share2,\n Trash2,\n Edit,\n ChevronRight,\n FolderInput,\n Info,\n Activity,\n Star,\n RotateCcw,\n} from \"lucide-react\";\nimport { useI18n } from \"@burdenoff/fe-libs/shared/providers/shell/I18nProvider\";\nimport { GlassCard } from \"@burdenoff/fe-libs/ui\";\nimport type { FolderItem } from \"../types\";\nimport { formatFileDate } from \"../utils\";\nimport { useFilesStore } from \"../store/filesStore\";\nimport { ActionMenu } from \"./ActionMenu\";\nimport { getDragOperation, canDropOnFolder } from \"../hooks/useDragDrop\";\nimport { tWithFallback } from \"../utils/i18n\";\nimport type { DragData } from \"../hooks/useDragDrop\";\n\ninterface FolderCardProps {\n folder: FolderItem;\n isSelected?: boolean;\n isDragging?: boolean;\n isDropTarget?: boolean;\n draggedItem?: DragData | null;\n onSelect?: (folderId: string) => void;\n onOpen?: (folder: FolderItem) => void;\n onShare?: (folder: FolderItem) => void;\n onDelete?: (folder: FolderItem) => void;\n onRestore?: (folder: FolderItem) => void;\n onRename?: (folder: FolderItem) => void;\n onFavorite?: (folder: FolderItem) => void;\n onCopy?: (folder: FolderItem) => void;\n onMove?: (folder: FolderItem) => void;\n onInfo?: (folder: FolderItem) => void;\n onActivity?: (folder: FolderItem) => void;\n onDragStart?: (folder: FolderItem, operation: \"move\" | \"copy\") => void;\n onDragEnd?: () => void;\n onDrop?: (folder: FolderItem) => void;\n onContextMenu?: (folder: FolderItem, x: number, y: number) => void;\n}\n\ninterface DraggableFolderCardProps extends Omit<\n FolderCardProps,\n \"onDragStart\" | \"onDragEnd\" | \"onDrop\"\n> {\n onDragStart?: (folder: FolderItem, operation: \"move\" | \"copy\") => void;\n onDragEnd?: () => void;\n onDrop?: (folder: FolderItem) => void;\n onContextMenu?: (folder: FolderItem, x: number, y: number) => void;\n}\n\nexport const FolderCard: FC<DraggableFolderCardProps> = ({\n folder,\n isSelected = false,\n isDragging = false,\n isDropTarget = false,\n draggedItem = null,\n onSelect,\n onOpen,\n onShare,\n onDelete,\n onRestore,\n onRename,\n onFavorite,\n onCopy: _onCopy,\n onMove,\n onInfo,\n onActivity,\n onDragStart,\n onDragEnd,\n onDrop,\n onContextMenu,\n}) => {\n const { t } = useI18n();\n const [isHovered, setIsHovered] = useState(false);\n const [menuOpen, setMenuOpen] = useState(false);\n const { toggleFolderSelection } = useFilesStore();\n\n const canDrop = canDropOnFolder(draggedItem, folder);\n const isValidDropTarget = isDropTarget && canDrop;\n\n const filesCount = folder.filesCount ?? 0;\n const subfoldersCount = folder.subfoldersCount ?? 0;\n const totalItems = filesCount + subfoldersCount;\n\n const openFolder = () => {\n if (onOpen) {\n onOpen(folder);\n }\n };\n\n const handleCheckboxChange = (e: React.ChangeEvent<HTMLInputElement>) => {\n e.stopPropagation();\n if (onSelect) {\n onSelect(folder.id);\n } else {\n toggleFolderSelection(folder.id);\n }\n };\n\n const handleActionClick = (e: React.MouseEvent, action: () => void) => {\n e.stopPropagation();\n action();\n };\n\n const handleDragStart = (e: React.DragEvent<HTMLDivElement>) => {\n e.dataTransfer.effectAllowed = \"copyMove\";\n e.dataTransfer.setData(\"application/x-file-id\", folder.id);\n e.dataTransfer.setData(\"application/x-file-type\", \"folder\");\n const operation = getDragOperation(e);\n e.dataTransfer.setData(\"application/x-drag-operation\", operation);\n onDragStart?.(folder, operation);\n };\n\n const handleDragEnd = () => {\n onDragEnd?.();\n };\n\n const handleDragOver = (e: React.DragEvent<HTMLDivElement>) => {\n if (isValidDropTarget) {\n e.preventDefault();\n e.dataTransfer.dropEffect =\n draggedItem?.operation === \"copy\" ? \"copy\" : \"move\";\n }\n };\n\n const handleDragEnter = (e: React.DragEvent<HTMLDivElement>) => {\n if (isValidDropTarget) {\n e.preventDefault();\n }\n };\n\n const handleDragLeave = () => {};\n\n const handleDrop = (e: React.DragEvent<HTMLDivElement>) => {\n e.preventDefault();\n if (isValidDropTarget) {\n onDrop?.(folder);\n }\n };\n\n const handleContextMenu = (e: React.MouseEvent) => {\n e.preventDefault();\n e.stopPropagation();\n onContextMenu?.(folder, e.clientX, e.clientY);\n };\n\n const FolderIcon = isHovered ? FolderOpen : Folder;\n\n const menuItems = useMemo(\n () => [\n ...(onShare\n ? [\n {\n label: tWithFallback(t, \"files.card.share\", \"Share\"),\n icon: <Share2 className=\"size-4\" />,\n onClick: () => onShare(folder),\n },\n ]\n : []),\n ...(onMove\n ? [\n {\n label: tWithFallback(t, \"files.card.moveTo\", \"Move to\"),\n icon: <FolderInput className=\"size-4\" />,\n onClick: () => onMove(folder),\n },\n ]\n : []),\n ...(onRename\n ? [\n {\n label: tWithFallback(t, \"files.card.rename\", \"Rename\"),\n icon: <Edit className=\"size-4\" />,\n onClick: () => onRename(folder),\n divider: true,\n },\n ]\n : []),\n ...(onFavorite\n ? [\n {\n label: folder.starred\n ? tWithFallback(\n t,\n \"files.card.removeFromStarred\",\n \"Remove from starred\",\n )\n : tWithFallback(t, \"files.card.addToStarred\", \"Add to starred\"),\n icon: <Star className=\"size-4\" />,\n onClick: () => onFavorite(folder),\n },\n ]\n : []),\n ...(onInfo\n ? [\n {\n label: tWithFallback(t, \"files.card.details\", \"Details\"),\n icon: <Info className=\"size-4\" />,\n onClick: () => onInfo(folder),\n },\n ]\n : []),\n ...(onActivity\n ? [\n {\n label: tWithFallback(t, \"files.card.activity\", \"Activity\"),\n icon: <Activity className=\"size-4\" />,\n onClick: () => onActivity(folder),\n },\n ]\n : []),\n ...(onDelete\n ? [\n {\n label: tWithFallback(t, \"files.card.delete\", \"Delete\"),\n icon: <Trash2 className=\"size-4\" />,\n onClick: () => onDelete(folder),\n variant: \"danger\" as const,\n divider: true,\n },\n ]\n : []),\n ...(onRestore\n ? [\n {\n label: tWithFallback(t, \"files.card.restore\", \"Restore\"),\n icon: <RotateCcw className=\"size-4\" />,\n onClick: () => onRestore(folder),\n },\n ]\n : []),\n ],\n [\n folder,\n onShare,\n onMove,\n onRename,\n onFavorite,\n onInfo,\n onActivity,\n onDelete,\n onRestore,\n t,\n ],\n );\n\n return (\n <GlassCard\n treatment=\"insight\"\n className={`group cursor-pointer focus-within:shadow-elevation-2 ${\n isDragging ? \"opacity-50\" : \"\"\n } ${\n isValidDropTarget\n ? \"border-action-primary-bg ring-2 ring-action-primary-bg ring-offset-2\"\n : isSelected\n ? \"border-action-primary-bg bg-bg-accent\"\n : \"border-border-seam\"\n }`}\n onClick={openFolder}\n onContextMenu={handleContextMenu}\n onMouseEnter={() => setIsHovered(true)}\n onMouseLeave={() => {\n if (!menuOpen) setIsHovered(false);\n }}\n onFocus={() => setIsHovered(true)}\n onBlur={(event) => {\n if (!event.currentTarget.contains(event.relatedTarget) && !menuOpen) {\n setIsHovered(false);\n }\n }}\n onKeyDown={(event) => {\n if (event.key === \"Enter\" || event.key === \" \") {\n event.preventDefault();\n openFolder();\n }\n }}\n draggable={Boolean(onDragStart)}\n onDragStart={handleDragStart}\n onDragEnd={handleDragEnd}\n onDragOver={handleDragOver}\n onDragEnter={handleDragEnter}\n onDragLeave={handleDragLeave}\n onDrop={handleDrop}\n role=\"button\"\n tabIndex={0}\n aria-label={`${tWithFallback(t, \"files.browser.openFolder\", \"Open folder\")} ${folder.name}`}\n >\n <div className=\"flex items-center gap-3 p-3\">\n {/* Selection checkbox */}\n <div\n className={`flex-shrink-0 transition-opacity ${\n isSelected\n ? \"opacity-100\"\n : \"opacity-0 group-hover:opacity-100 group-focus-within:opacity-100\"\n }`}\n onClick={(e) => e.stopPropagation()}\n >\n <input\n type=\"checkbox\"\n checked={isSelected}\n onChange={handleCheckboxChange}\n className=\"size-4 rounded border-border-default bg-bg-surface text-action-primary-bg focus:ring-2 focus:ring-action-primary-bg focus:ring-offset-2\"\n aria-label={`Select ${folder.name}`}\n />\n </div>\n\n {/* Folder icon */}\n <div className=\"flex-shrink-0 flex items-center justify-center size-10 rounded-lg bg-action-primary-bg/10\">\n <FolderIcon className=\"size-5 text-action-primary-bg\" />\n </div>\n\n {/* Folder info */}\n <div className=\"flex-1 min-w-0 pr-1\">\n <div className=\"flex items-center gap-1.5\">\n <span className=\"text-sm font-medium text-text-primary truncate\">\n {folder.name}\n </span>\n {folder.starred && (\n <Star className=\"size-3 flex-shrink-0 fill-yellow-400 text-yellow-400\" />\n )}\n </div>\n <div className=\"flex items-center gap-1 mt-0.5 text-xs text-text-secondary\">\n {subfoldersCount > 0 && (\n <>\n <span>\n {subfoldersCount}{\" \"}\n {subfoldersCount === 1\n ? tWithFallback(t, \"files.folder.subfolder\", \"folder\")\n : tWithFallback(t, \"files.folder.subfolders\", \"folders\")}\n </span>\n {filesCount > 0 && (\n <span className=\"text-border-subtle\">·</span>\n )}\n </>\n )}\n {filesCount > 0 && (\n <span>\n {filesCount}{\" \"}\n {filesCount === 1\n ? tWithFallback(t, \"files.folder.file\", \"file\")\n : tWithFallback(t, \"files.folder.files\", \"files\")}\n </span>\n )}\n {totalItems === 0 && (\n <span>{tWithFallback(t, \"files.folder.empty\", \"Empty\")}</span>\n )}\n <span className=\"text-border-subtle\">·</span>\n <span className=\"truncate\">{formatFileDate(folder.updatedAt)}</span>\n </div>\n </div>\n\n {/* Right-side actions — always reserve space so layout is stable */}\n <div className=\"flex-shrink-0 flex items-center gap-1\">\n {isHovered && onRestore && (\n <button\n type=\"button\"\n onClick={(e) => handleActionClick(e, () => onRestore(folder))}\n className=\"p-1.5 hover:bg-status-success-bg-subtle rounded transition-colors\"\n aria-label={tWithFallback(t, \"files.card.restore\", \"Restore\")}\n title={tWithFallback(t, \"files.card.restore\", \"Restore\")}\n >\n <RotateCcw className=\"size-4 text-status-success-text\" />\n </button>\n )}\n {isHovered && onShare && (\n <button\n onClick={(e) => handleActionClick(e, () => onShare(folder))}\n className=\"p-1.5 hover:bg-action-ghost-bg-hover rounded transition-colors\"\n aria-label={tWithFallback(t, \"files.card.share\", \"Share\")}\n title={tWithFallback(t, \"files.card.share\", \"Share\")}\n >\n <Share2 className=\"size-4 text-text-secondary\" />\n </button>\n )}\n {isHovered && onRename && (\n <button\n onClick={(e) => handleActionClick(e, () => onRename(folder))}\n className=\"p-1.5 hover:bg-action-ghost-bg-hover rounded transition-colors\"\n aria-label={tWithFallback(t, \"files.card.rename\", \"Rename\")}\n title={tWithFallback(t, \"files.card.rename\", \"Rename\")}\n >\n <Edit className=\"size-4 text-text-secondary\" />\n </button>\n )}\n <div onClick={(e) => e.stopPropagation()}>\n <ActionMenu\n items={menuItems}\n align=\"right\"\n triggerClassName={\n !isHovered && !menuOpen\n ? \"opacity-0 group-hover:opacity-100\"\n : \"\"\n }\n isOpen={menuOpen}\n onToggle={(open) => {\n setMenuOpen(open);\n if (open) setIsHovered(true);\n }}\n />\n </div>\n </div>\n\n {/* Navigate-into arrow */}\n <ChevronRight className=\"flex-shrink-0 size-4 text-text-muted opacity-0 group-hover:opacity-100 transition-opacity\" />\n </div>\n </GlassCard>\n );\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"FolderCard.js","names":["_Fragment","FolderCard","_onCopy","useI18n","isHovered","setIsHovered","useState","menuOpen","setMenuOpen","useFilesStore","canDrop","canDropOnFolder","draggedItem","folder","isValidDropTarget","isDropTarget","filesCount","subfoldersCount","totalItems","openFolder","onOpen","handleCheckboxChange","onSelect","toggleFolderSelection","handleActionClick","action","handleDragStart","operation","getDragOperation","onDragStart","handleDragEnd","handleDragOver","handleDragEnter","handleDragLeave","handleDrop","onDrop","handleContextMenu","onContextMenu","FolderIcon","FolderOpen","Folder","menuItems","useMemo","onShare","tWithFallback","t","Share2","onMove","FolderInput","onRename","Edit","onFavorite","Star","onInfo","Info","onActivity","Activity","onDelete","Trash2","onRestore","RotateCcw","GlassCard","isDragging","isSelected","event","Fragment","formatFileDate","ActionMenu","open","ChevronRight"],"sources":["../../../src/files/components/FolderCard.tsx"],"sourcesContent":["import { type FC, useState, useMemo } from \"react\";\nimport {\n Folder,\n FolderOpen,\n Share2,\n Trash2,\n Edit,\n ChevronRight,\n FolderInput,\n Info,\n Activity,\n Star,\n RotateCcw,\n} from \"lucide-react\";\nimport { useI18n } from \"@burdenoff/fe-libs/shared/providers/shell/I18nProvider\";\nimport { GlassCard } from \"@burdenoff/fe-libs/ui\";\nimport type { FolderItem } from \"../types\";\nimport { formatFileDate } from \"../utils\";\nimport { useFilesStore } from \"../store/filesStore\";\nimport { ActionMenu } from \"./ActionMenu\";\nimport { getDragOperation, canDropOnFolder } from \"../hooks/useDragDrop\";\nimport { tWithFallback } from \"../utils/i18n\";\nimport type { DragData } from \"../hooks/useDragDrop\";\n\ninterface FolderCardProps {\n folder: FolderItem;\n isSelected?: boolean;\n isDragging?: boolean;\n isDropTarget?: boolean;\n draggedItem?: DragData | null;\n onSelect?: (folderId: string) => void;\n onOpen?: (folder: FolderItem) => void;\n onShare?: (folder: FolderItem) => void;\n onDelete?: (folder: FolderItem) => void;\n onRestore?: (folder: FolderItem) => void;\n onRename?: (folder: FolderItem) => void;\n onFavorite?: (folder: FolderItem) => void;\n onCopy?: (folder: FolderItem) => void;\n onMove?: (folder: FolderItem) => void;\n onInfo?: (folder: FolderItem) => void;\n onActivity?: (folder: FolderItem) => void;\n onDragStart?: (folder: FolderItem, operation: \"move\" | \"copy\") => void;\n onDragEnd?: () => void;\n onDrop?: (folder: FolderItem) => void;\n onContextMenu?: (folder: FolderItem, x: number, y: number) => void;\n}\n\ninterface DraggableFolderCardProps extends Omit<\n FolderCardProps,\n \"onDragStart\" | \"onDragEnd\" | \"onDrop\"\n> {\n onDragStart?: (folder: FolderItem, operation: \"move\" | \"copy\") => void;\n onDragEnd?: () => void;\n onDrop?: (folder: FolderItem) => void;\n onContextMenu?: (folder: FolderItem, x: number, y: number) => void;\n}\n\nexport const FolderCard: FC<DraggableFolderCardProps> = ({\n folder,\n isSelected = false,\n isDragging = false,\n isDropTarget = false,\n draggedItem = null,\n onSelect,\n onOpen,\n onShare,\n onDelete,\n onRestore,\n onRename,\n onFavorite,\n onCopy: _onCopy,\n onMove,\n onInfo,\n onActivity,\n onDragStart,\n onDragEnd,\n onDrop,\n onContextMenu,\n}) => {\n const { t } = useI18n();\n const [isHovered, setIsHovered] = useState(false);\n const [menuOpen, setMenuOpen] = useState(false);\n const { toggleFolderSelection } = useFilesStore();\n\n const canDrop = canDropOnFolder(draggedItem, folder);\n const isValidDropTarget = isDropTarget && canDrop;\n\n const filesCount = folder.filesCount ?? 0;\n const subfoldersCount = folder.subfoldersCount ?? 0;\n const totalItems = filesCount + subfoldersCount;\n\n const openFolder = () => {\n if (onOpen) {\n onOpen(folder);\n }\n };\n\n const handleCheckboxChange = (e: React.ChangeEvent<HTMLInputElement>) => {\n e.stopPropagation();\n if (onSelect) {\n onSelect(folder.id);\n } else {\n toggleFolderSelection(folder.id);\n }\n };\n\n const handleActionClick = (e: React.MouseEvent, action: () => void) => {\n e.stopPropagation();\n action();\n };\n\n const handleDragStart = (e: React.DragEvent<HTMLDivElement>) => {\n e.dataTransfer.effectAllowed = \"copyMove\";\n e.dataTransfer.setData(\"application/x-file-id\", folder.id);\n e.dataTransfer.setData(\"application/x-file-type\", \"folder\");\n const operation = getDragOperation(e);\n e.dataTransfer.setData(\"application/x-drag-operation\", operation);\n onDragStart?.(folder, operation);\n };\n\n const handleDragEnd = () => {\n onDragEnd?.();\n };\n\n const handleDragOver = (e: React.DragEvent<HTMLDivElement>) => {\n if (isValidDropTarget) {\n e.preventDefault();\n e.dataTransfer.dropEffect =\n draggedItem?.operation === \"copy\" ? \"copy\" : \"move\";\n }\n };\n\n const handleDragEnter = (e: React.DragEvent<HTMLDivElement>) => {\n if (isValidDropTarget) {\n e.preventDefault();\n }\n };\n\n const handleDragLeave = () => {};\n\n const handleDrop = (e: React.DragEvent<HTMLDivElement>) => {\n e.preventDefault();\n if (isValidDropTarget) {\n onDrop?.(folder);\n }\n };\n\n const handleContextMenu = (e: React.MouseEvent) => {\n e.preventDefault();\n e.stopPropagation();\n onContextMenu?.(folder, e.clientX, e.clientY);\n };\n\n const FolderIcon = isHovered ? FolderOpen : Folder;\n\n const menuItems = useMemo(\n () => [\n ...(onShare\n ? [\n {\n label: tWithFallback(t, \"files.card.share\", \"Share\"),\n icon: <Share2 className=\"size-4\" />,\n onClick: () => onShare(folder),\n },\n ]\n : []),\n ...(onMove\n ? [\n {\n label: tWithFallback(t, \"files.card.moveTo\", \"Move to\"),\n icon: <FolderInput className=\"size-4\" />,\n onClick: () => onMove(folder),\n },\n ]\n : []),\n ...(onRename\n ? [\n {\n label: tWithFallback(t, \"files.card.rename\", \"Rename\"),\n icon: <Edit className=\"size-4\" />,\n onClick: () => onRename(folder),\n divider: true,\n },\n ]\n : []),\n ...(onFavorite\n ? [\n {\n label: folder.starred\n ? tWithFallback(\n t,\n \"files.card.removeFromStarred\",\n \"Remove from starred\",\n )\n : tWithFallback(t, \"files.card.addToStarred\", \"Add to starred\"),\n icon: <Star className=\"size-4\" />,\n onClick: () => onFavorite(folder),\n },\n ]\n : []),\n ...(onInfo\n ? [\n {\n label: tWithFallback(t, \"files.card.details\", \"Details\"),\n icon: <Info className=\"size-4\" />,\n onClick: () => onInfo(folder),\n },\n ]\n : []),\n ...(onActivity\n ? [\n {\n label: tWithFallback(t, \"files.card.activity\", \"Activity\"),\n icon: <Activity className=\"size-4\" />,\n onClick: () => onActivity(folder),\n },\n ]\n : []),\n ...(onDelete\n ? [\n {\n label: tWithFallback(t, \"files.card.delete\", \"Delete\"),\n icon: <Trash2 className=\"size-4\" />,\n onClick: () => onDelete(folder),\n variant: \"danger\" as const,\n divider: true,\n },\n ]\n : []),\n ...(onRestore\n ? [\n {\n label: tWithFallback(t, \"files.card.restore\", \"Restore\"),\n icon: <RotateCcw className=\"size-4\" />,\n onClick: () => onRestore(folder),\n },\n ]\n : []),\n ],\n [\n folder,\n onShare,\n onMove,\n onRename,\n onFavorite,\n onInfo,\n onActivity,\n onDelete,\n onRestore,\n t,\n ],\n );\n\n return (\n <GlassCard\n treatment=\"insight\"\n className={`group cursor-pointer focus-within:shadow-elevation-2 ${\n isDragging ? \"opacity-50\" : \"\"\n } ${\n isValidDropTarget\n ? \"border-action-primary-bg ring-2 ring-action-primary-bg ring-offset-2\"\n : isSelected\n ? \"border-action-primary-bg bg-bg-accent\"\n : \"border-border-seam\"\n }`}\n onClick={openFolder}\n onContextMenu={handleContextMenu}\n onMouseEnter={() => setIsHovered(true)}\n onMouseLeave={() => {\n if (!menuOpen) setIsHovered(false);\n }}\n onFocus={() => setIsHovered(true)}\n onBlur={(event) => {\n if (!event.currentTarget.contains(event.relatedTarget) && !menuOpen) {\n setIsHovered(false);\n }\n }}\n onKeyDown={(event) => {\n if (event.target !== event.currentTarget) return;\n if (event.key === \"Enter\" || event.key === \" \") {\n event.preventDefault();\n openFolder();\n }\n }}\n draggable={Boolean(onDragStart)}\n onDragStart={handleDragStart}\n onDragEnd={handleDragEnd}\n onDragOver={handleDragOver}\n onDragEnter={handleDragEnter}\n onDragLeave={handleDragLeave}\n onDrop={handleDrop}\n role=\"button\"\n tabIndex={0}\n aria-label={`${tWithFallback(t, \"files.browser.openFolder\", \"Open folder\")} ${folder.name}`}\n >\n <div className=\"flex items-center gap-3 p-3\">\n {/* Selection checkbox */}\n <div\n className={`flex-shrink-0 transition-opacity ${\n isSelected\n ? \"opacity-100\"\n : \"opacity-0 group-hover:opacity-100 group-focus-within:opacity-100\"\n }`}\n onClick={(e) => e.stopPropagation()}\n >\n <input\n type=\"checkbox\"\n checked={isSelected}\n onChange={handleCheckboxChange}\n className=\"size-4 rounded border-border-default bg-bg-surface text-action-primary-bg focus:ring-2 focus:ring-action-primary-bg focus:ring-offset-2\"\n aria-label={`Select ${folder.name}`}\n />\n </div>\n\n {/* Folder icon */}\n <div className=\"flex-shrink-0 flex items-center justify-center size-10 rounded-lg bg-action-primary-bg/10\">\n <FolderIcon className=\"size-5 text-action-primary-bg\" />\n </div>\n\n {/* Folder info */}\n <div className=\"flex-1 min-w-0 pr-1\">\n <div className=\"flex items-center gap-1.5\">\n <span className=\"text-sm font-medium text-text-primary truncate\">\n {folder.name}\n </span>\n {folder.starred && (\n <Star className=\"size-3 flex-shrink-0 fill-yellow-400 text-yellow-400\" />\n )}\n </div>\n <div className=\"flex items-center gap-1 mt-0.5 text-xs text-text-secondary\">\n {subfoldersCount > 0 && (\n <>\n <span>\n {subfoldersCount}{\" \"}\n {subfoldersCount === 1\n ? tWithFallback(t, \"files.folder.subfolder\", \"folder\")\n : tWithFallback(t, \"files.folder.subfolders\", \"folders\")}\n </span>\n {filesCount > 0 && (\n <span className=\"text-border-subtle\">·</span>\n )}\n </>\n )}\n {filesCount > 0 && (\n <span>\n {filesCount}{\" \"}\n {filesCount === 1\n ? tWithFallback(t, \"files.folder.file\", \"file\")\n : tWithFallback(t, \"files.folder.files\", \"files\")}\n </span>\n )}\n {totalItems === 0 && (\n <span>{tWithFallback(t, \"files.folder.empty\", \"Empty\")}</span>\n )}\n <span className=\"text-border-subtle\">·</span>\n <span className=\"truncate\">{formatFileDate(folder.updatedAt)}</span>\n </div>\n </div>\n\n {/* Right-side actions — always reserve space so layout is stable */}\n <div className=\"flex-shrink-0 flex items-center gap-1\">\n {isHovered && onRestore && (\n <button\n type=\"button\"\n onClick={(e) => handleActionClick(e, () => onRestore(folder))}\n className=\"p-1.5 hover:bg-status-success-bg-subtle rounded transition-colors\"\n aria-label={tWithFallback(t, \"files.card.restore\", \"Restore\")}\n title={tWithFallback(t, \"files.card.restore\", \"Restore\")}\n >\n <RotateCcw className=\"size-4 text-status-success-text\" />\n </button>\n )}\n {isHovered && onShare && (\n <button\n onClick={(e) => handleActionClick(e, () => onShare(folder))}\n className=\"p-1.5 hover:bg-action-ghost-bg-hover rounded transition-colors\"\n aria-label={tWithFallback(t, \"files.card.share\", \"Share\")}\n title={tWithFallback(t, \"files.card.share\", \"Share\")}\n >\n <Share2 className=\"size-4 text-text-secondary\" />\n </button>\n )}\n {isHovered && onRename && (\n <button\n onClick={(e) => handleActionClick(e, () => onRename(folder))}\n className=\"p-1.5 hover:bg-action-ghost-bg-hover rounded transition-colors\"\n aria-label={tWithFallback(t, \"files.card.rename\", \"Rename\")}\n title={tWithFallback(t, \"files.card.rename\", \"Rename\")}\n >\n <Edit className=\"size-4 text-text-secondary\" />\n </button>\n )}\n <div onClick={(e) => e.stopPropagation()}>\n <ActionMenu\n items={menuItems}\n align=\"right\"\n triggerClassName={\n !isHovered && !menuOpen\n ? \"opacity-0 group-hover:opacity-100\"\n : \"\"\n }\n isOpen={menuOpen}\n onToggle={(open) => {\n setMenuOpen(open);\n if (open) setIsHovered(true);\n }}\n />\n </div>\n </div>\n\n {/* Navigate-into arrow */}\n <ChevronRight className=\"flex-shrink-0 size-4 text-text-muted opacity-0 group-hover:opacity-100 transition-opacity\" />\n </div>\n </GlassCard>\n );\n};\n"],"mappings":"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"}
|