@burdenoff/microfe-files 2026.527.2 → 2026.527.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/files/components/ActionMenu.js +44 -40
- package/dist/files/components/ActionMenu.js.map +1 -1
- package/dist/files/components/ConfirmDialog.js +42 -40
- package/dist/files/components/ConfirmDialog.js.map +1 -1
- package/dist/files/components/CopyDialog.js +1 -0
- package/dist/files/components/CopyDialog.js.map +1 -1
- package/dist/files/components/FileCard.js.map +1 -1
- package/dist/files/components/FileInfoPanel.js +102 -102
- package/dist/files/components/FileInfoPanel.js.map +1 -1
- package/dist/files/components/FileListItem.js.map +1 -1
- package/dist/files/components/FolderCard.js.map +1 -1
- package/dist/files/components/SearchBar.js +125 -117
- package/dist/files/components/SearchBar.js.map +1 -1
- package/dist/files/components/ShareDialog.js +5 -0
- package/dist/files/components/ShareDialog.js.map +1 -1
- package/dist/files/components/Toast.js +27 -24
- package/dist/files/components/Toast.js.map +1 -1
- package/dist/files/components/UploadQueue.js +1 -1
- package/dist/files/components/UploadQueue.js.map +1 -1
- package/dist/files/components/viewers/AudioPlayer.js +3 -0
- package/dist/files/components/viewers/AudioPlayer.js.map +1 -1
- package/dist/files/components/viewers/TextViewer.js +1 -0
- package/dist/files/components/viewers/TextViewer.js.map +1 -1
- package/dist/files/components/viewers/VideoPlayer.js +3 -0
- package/dist/files/components/viewers/VideoPlayer.js.map +1 -1
- package/dist/files/hooks/useKeyboardNavigation.js +51 -51
- package/dist/files/hooks/useKeyboardNavigation.js.map +1 -1
- package/dist/files/pages/BrowserPage.js +210 -214
- package/dist/files/pages/BrowserPage.js.map +1 -1
- package/dist/files/pages/ShareAccessPage.js +1 -0
- package/dist/files/pages/ShareAccessPage.js.map +1 -1
- package/package.json +1 -1
|
@@ -1,226 +1,226 @@
|
|
|
1
1
|
import { tWithFallback as e } from "../utils/i18n.js";
|
|
2
|
-
import { Suspense as t, lazy as n, useEffect as r,
|
|
3
|
-
import { Calendar as
|
|
4
|
-
import { Fragment as
|
|
5
|
-
import { useI18n as
|
|
2
|
+
import { Suspense as t, lazy as n, useEffect as r, useEffectEvent as i, useState as a } from "react";
|
|
3
|
+
import { Calendar as o, Clock as s, FileText as c, HardDrive as l, Link as u, User as d, X as f } from "lucide-react";
|
|
4
|
+
import { Fragment as p, jsx as m, jsxs as h } from "react/jsx-runtime";
|
|
5
|
+
import { useI18n as g } from "@burdenoff/fe-libs/shared/providers/shell/I18nProvider";
|
|
6
6
|
//#region src/files/components/FileInfoPanel.tsx
|
|
7
|
-
var
|
|
8
|
-
function
|
|
9
|
-
let { t:
|
|
7
|
+
var _ = n(() => import("./FileVersionPanel.js").then((e) => ({ default: e.FileVersionPanel })));
|
|
8
|
+
function v({ item: n, type: v, onClose: y }) {
|
|
9
|
+
let { t: b } = g(), x = v === "file", S = x ? n : null, C = x ? null : n, [w, T] = a(!1), E = i(() => {
|
|
10
|
+
if (w) {
|
|
11
|
+
T(!1);
|
|
12
|
+
return;
|
|
13
|
+
}
|
|
14
|
+
y();
|
|
15
|
+
});
|
|
10
16
|
r(() => {
|
|
11
17
|
let e = (e) => {
|
|
12
|
-
|
|
13
|
-
if (C) {
|
|
14
|
-
w(!1);
|
|
15
|
-
return;
|
|
16
|
-
}
|
|
17
|
-
v();
|
|
18
|
-
}
|
|
18
|
+
e.key === "Escape" && E();
|
|
19
19
|
};
|
|
20
20
|
return document.addEventListener("keydown", e), () => document.removeEventListener("keydown", e);
|
|
21
|
-
}, [
|
|
22
|
-
let
|
|
21
|
+
}, []);
|
|
22
|
+
let D = (e) => new Date(e).toLocaleString("en-US", {
|
|
23
23
|
year: "numeric",
|
|
24
24
|
month: "long",
|
|
25
25
|
day: "numeric",
|
|
26
26
|
hour: "2-digit",
|
|
27
27
|
minute: "2-digit"
|
|
28
28
|
});
|
|
29
|
-
return /* @__PURE__ */
|
|
29
|
+
return /* @__PURE__ */ h("div", {
|
|
30
30
|
className: "fixed inset-y-0 right-0 z-[9999] w-full max-w-full overflow-y-auto border-l border-border-default bg-bg-surface shadow-2xl animate-in slide-in-from-right duration-300 sm:w-96 [&::-webkit-scrollbar]:hidden [-ms-overflow-style:none] [scrollbar-width:none]",
|
|
31
31
|
role: "dialog",
|
|
32
32
|
"aria-modal": "false",
|
|
33
|
-
"aria-label":
|
|
33
|
+
"aria-label": x ? e(b, "files.info.fileInfo", "File information") : e(b, "files.info.folderInfo", "Folder information"),
|
|
34
34
|
children: [
|
|
35
|
-
/* @__PURE__ */
|
|
35
|
+
/* @__PURE__ */ h("div", {
|
|
36
36
|
className: "sticky top-0 bg-bg-surface border-b border-border-default px-6 py-4 flex items-center justify-between",
|
|
37
|
-
children: [/* @__PURE__ */
|
|
37
|
+
children: [/* @__PURE__ */ m("h2", {
|
|
38
38
|
className: "text-lg font-semibold text-text-primary",
|
|
39
|
-
children:
|
|
40
|
-
}), /* @__PURE__ */
|
|
39
|
+
children: x ? e(b, "files.info.fileInfo", "File Information") : e(b, "files.info.folderInfo", "Folder Information")
|
|
40
|
+
}), /* @__PURE__ */ m("button", {
|
|
41
41
|
type: "button",
|
|
42
|
-
onClick:
|
|
42
|
+
onClick: y,
|
|
43
43
|
className: "p-1.5 rounded-md border border-border-default text-text-secondary bg-bg-elevated hover:bg-action-ghost-bg-hover hover:text-text-primary transition-colors shadow-sm",
|
|
44
|
-
"aria-label": e(
|
|
45
|
-
children: /* @__PURE__ */
|
|
44
|
+
"aria-label": e(b, "files.info.closePanel", "Close information panel"),
|
|
45
|
+
children: /* @__PURE__ */ m(f, { className: "size-5" })
|
|
46
46
|
})]
|
|
47
47
|
}),
|
|
48
|
-
/* @__PURE__ */
|
|
48
|
+
/* @__PURE__ */ h("div", {
|
|
49
49
|
className: "p-6 space-y-6",
|
|
50
50
|
children: [
|
|
51
|
-
/* @__PURE__ */
|
|
51
|
+
/* @__PURE__ */ m("div", {
|
|
52
52
|
className: "flex items-center justify-center py-8 bg-bg-muted rounded-lg",
|
|
53
|
-
children:
|
|
54
|
-
src:
|
|
53
|
+
children: x && S?.mimeType.startsWith("image/") ? /* @__PURE__ */ m("img", {
|
|
54
|
+
src: S.downloadUrl || S.url,
|
|
55
55
|
alt: n.name,
|
|
56
56
|
className: "max-w-full max-h-48 object-contain rounded"
|
|
57
|
-
}) : /* @__PURE__ */
|
|
57
|
+
}) : /* @__PURE__ */ m(c, { className: "size-20 text-text-muted" })
|
|
58
58
|
}),
|
|
59
|
-
/* @__PURE__ */
|
|
59
|
+
/* @__PURE__ */ h("div", { children: [/* @__PURE__ */ m("h3", {
|
|
60
60
|
className: "text-xl font-semibold text-text-primary break-words",
|
|
61
61
|
children: n.name
|
|
62
|
-
}), n.description && /* @__PURE__ */
|
|
62
|
+
}), n.description && /* @__PURE__ */ m("p", {
|
|
63
63
|
className: "mt-2 text-sm text-text-secondary",
|
|
64
64
|
children: n.description
|
|
65
65
|
})] }),
|
|
66
|
-
/* @__PURE__ */
|
|
66
|
+
/* @__PURE__ */ h("div", {
|
|
67
67
|
className: "space-y-4",
|
|
68
68
|
children: [
|
|
69
|
-
/* @__PURE__ */
|
|
69
|
+
/* @__PURE__ */ h("div", {
|
|
70
70
|
className: "flex items-start gap-3",
|
|
71
|
-
children: [/* @__PURE__ */
|
|
71
|
+
children: [/* @__PURE__ */ m(c, { className: "size-5 text-text-muted mt-0.5" }), /* @__PURE__ */ h("div", { children: [/* @__PURE__ */ m("p", {
|
|
72
72
|
className: "text-sm font-medium text-text-primary",
|
|
73
|
-
children: e(
|
|
74
|
-
}), /* @__PURE__ */
|
|
73
|
+
children: e(b, "files.info.type", "Type")
|
|
74
|
+
}), /* @__PURE__ */ m("p", {
|
|
75
75
|
className: "text-sm text-text-secondary",
|
|
76
|
-
children:
|
|
76
|
+
children: x ? S?.mimeType || e(b, "files.info.unknown", "Unknown") : e(b, "files.info.folder", "Folder")
|
|
77
77
|
})] })]
|
|
78
78
|
}),
|
|
79
|
-
|
|
79
|
+
x && S && /* @__PURE__ */ h("div", {
|
|
80
80
|
className: "flex items-start gap-3",
|
|
81
|
-
children: [/* @__PURE__ */
|
|
81
|
+
children: [/* @__PURE__ */ m(l, { className: "size-5 text-text-muted mt-0.5" }), /* @__PURE__ */ h("div", { children: [/* @__PURE__ */ m("p", {
|
|
82
82
|
className: "text-sm font-medium text-text-primary",
|
|
83
|
-
children: e(
|
|
84
|
-
}), /* @__PURE__ */
|
|
83
|
+
children: e(b, "files.info.size", "Size")
|
|
84
|
+
}), /* @__PURE__ */ m("p", {
|
|
85
85
|
className: "text-sm text-text-secondary",
|
|
86
|
-
children: ((e) => e < 1024 ? `${e} B` : e < 1024 * 1024 ? `${(e / 1024).toFixed(2)} KB` : e < 1024 * 1024 * 1024 ? `${(e / 1024 / 1024).toFixed(2)} MB` : `${(e / 1024 / 1024 / 1024).toFixed(2)} GB`)(
|
|
86
|
+
children: ((e) => e < 1024 ? `${e} B` : e < 1024 * 1024 ? `${(e / 1024).toFixed(2)} KB` : e < 1024 * 1024 * 1024 ? `${(e / 1024 / 1024).toFixed(2)} MB` : `${(e / 1024 / 1024 / 1024).toFixed(2)} GB`)(S.size)
|
|
87
87
|
})] })]
|
|
88
88
|
}),
|
|
89
|
-
!
|
|
89
|
+
!x && C && /* @__PURE__ */ h(p, { children: [/* @__PURE__ */ h("div", {
|
|
90
90
|
className: "flex items-start gap-3",
|
|
91
|
-
children: [/* @__PURE__ */
|
|
91
|
+
children: [/* @__PURE__ */ m(c, { className: "size-5 text-text-muted mt-0.5" }), /* @__PURE__ */ h("div", { children: [/* @__PURE__ */ m("p", {
|
|
92
92
|
className: "text-sm font-medium text-text-primary",
|
|
93
|
-
children: e(
|
|
94
|
-
}), /* @__PURE__ */
|
|
93
|
+
children: e(b, "files.info.contents", "Contents")
|
|
94
|
+
}), /* @__PURE__ */ h("p", {
|
|
95
95
|
className: "text-sm text-text-secondary",
|
|
96
96
|
children: [
|
|
97
|
-
|
|
97
|
+
C.filesCount,
|
|
98
98
|
" ",
|
|
99
|
-
e(
|
|
99
|
+
e(b, "files.info.files", "files"),
|
|
100
100
|
",",
|
|
101
101
|
" ",
|
|
102
|
-
|
|
102
|
+
C.subfoldersCount,
|
|
103
103
|
" ",
|
|
104
|
-
e(
|
|
104
|
+
e(b, "files.info.folders", "folders")
|
|
105
105
|
]
|
|
106
106
|
})] })]
|
|
107
|
-
}),
|
|
107
|
+
}), C.path && /* @__PURE__ */ h("div", {
|
|
108
108
|
className: "flex items-start gap-3",
|
|
109
|
-
children: [/* @__PURE__ */
|
|
109
|
+
children: [/* @__PURE__ */ m(u, { className: "size-5 text-text-muted mt-0.5" }), /* @__PURE__ */ h("div", { children: [/* @__PURE__ */ m("p", {
|
|
110
110
|
className: "text-sm font-medium text-text-primary",
|
|
111
|
-
children: e(
|
|
112
|
-
}), /* @__PURE__ */
|
|
111
|
+
children: e(b, "files.info.path", "Path")
|
|
112
|
+
}), /* @__PURE__ */ m("p", {
|
|
113
113
|
className: "text-sm text-text-secondary break-all",
|
|
114
|
-
children:
|
|
114
|
+
children: C.path
|
|
115
115
|
})] })]
|
|
116
116
|
})] }),
|
|
117
|
-
/* @__PURE__ */
|
|
117
|
+
/* @__PURE__ */ h("div", {
|
|
118
118
|
className: "flex items-start gap-3",
|
|
119
|
-
children: [/* @__PURE__ */
|
|
119
|
+
children: [/* @__PURE__ */ m(o, { className: "size-5 text-text-muted mt-0.5" }), /* @__PURE__ */ h("div", { children: [/* @__PURE__ */ m("p", {
|
|
120
120
|
className: "text-sm font-medium text-text-primary",
|
|
121
|
-
children: e(
|
|
122
|
-
}), /* @__PURE__ */
|
|
121
|
+
children: e(b, "files.info.created", "Created")
|
|
122
|
+
}), /* @__PURE__ */ m("p", {
|
|
123
123
|
className: "text-sm text-text-secondary",
|
|
124
|
-
children:
|
|
124
|
+
children: D(n.createdAt)
|
|
125
125
|
})] })]
|
|
126
126
|
}),
|
|
127
|
-
n.updatedAt && /* @__PURE__ */
|
|
127
|
+
n.updatedAt && /* @__PURE__ */ h("div", {
|
|
128
128
|
className: "flex items-start gap-3",
|
|
129
|
-
children: [/* @__PURE__ */
|
|
129
|
+
children: [/* @__PURE__ */ m(o, { className: "size-5 text-text-muted mt-0.5" }), /* @__PURE__ */ h("div", { children: [/* @__PURE__ */ m("p", {
|
|
130
130
|
className: "text-sm font-medium text-text-primary",
|
|
131
|
-
children: e(
|
|
132
|
-
}), /* @__PURE__ */
|
|
131
|
+
children: e(b, "files.info.modified", "Modified")
|
|
132
|
+
}), /* @__PURE__ */ m("p", {
|
|
133
133
|
className: "text-sm text-text-secondary",
|
|
134
|
-
children:
|
|
134
|
+
children: D(n.updatedAt)
|
|
135
135
|
})] })]
|
|
136
136
|
}),
|
|
137
|
-
/* @__PURE__ */
|
|
137
|
+
/* @__PURE__ */ h("div", {
|
|
138
138
|
className: "flex items-start gap-3",
|
|
139
|
-
children: [/* @__PURE__ */
|
|
139
|
+
children: [/* @__PURE__ */ m(d, { className: "size-5 text-text-muted mt-0.5" }), /* @__PURE__ */ h("div", { children: [/* @__PURE__ */ m("p", {
|
|
140
140
|
className: "text-sm font-medium text-text-primary",
|
|
141
|
-
children: e(
|
|
142
|
-
}), /* @__PURE__ */
|
|
141
|
+
children: e(b, "files.info.owner", "Owner")
|
|
142
|
+
}), /* @__PURE__ */ m("p", {
|
|
143
143
|
className: "text-sm text-text-secondary",
|
|
144
|
-
children: n.createdBy?.name || n.createdById || e(
|
|
144
|
+
children: n.createdBy?.name || n.createdById || e(b, "files.info.unknown", "Unknown")
|
|
145
145
|
})] })]
|
|
146
146
|
})
|
|
147
147
|
]
|
|
148
148
|
}),
|
|
149
|
-
/* @__PURE__ */
|
|
149
|
+
/* @__PURE__ */ h("div", {
|
|
150
150
|
className: "pt-6 border-t border-border-default",
|
|
151
|
-
children: [/* @__PURE__ */
|
|
151
|
+
children: [/* @__PURE__ */ m("h4", {
|
|
152
152
|
className: "text-sm font-semibold text-text-primary mb-3",
|
|
153
|
-
children: e(
|
|
154
|
-
}), /* @__PURE__ */
|
|
153
|
+
children: e(b, "files.info.properties", "Properties")
|
|
154
|
+
}), /* @__PURE__ */ h("dl", {
|
|
155
155
|
className: "space-y-2",
|
|
156
156
|
children: [
|
|
157
|
-
/* @__PURE__ */
|
|
157
|
+
/* @__PURE__ */ h("div", {
|
|
158
158
|
className: "flex justify-between",
|
|
159
|
-
children: [/* @__PURE__ */
|
|
159
|
+
children: [/* @__PURE__ */ m("dt", {
|
|
160
160
|
className: "text-sm text-text-secondary",
|
|
161
|
-
children: e(
|
|
162
|
-
}), /* @__PURE__ */
|
|
161
|
+
children: e(b, "files.info.status", "Status")
|
|
162
|
+
}), /* @__PURE__ */ m("dd", {
|
|
163
163
|
className: "text-sm font-medium text-text-primary",
|
|
164
164
|
children: n.status
|
|
165
165
|
})]
|
|
166
166
|
}),
|
|
167
|
-
/* @__PURE__ */
|
|
167
|
+
/* @__PURE__ */ h("div", {
|
|
168
168
|
className: "flex justify-between",
|
|
169
|
-
children: [/* @__PURE__ */
|
|
169
|
+
children: [/* @__PURE__ */ m("dt", {
|
|
170
170
|
className: "text-sm text-text-secondary",
|
|
171
|
-
children: e(
|
|
172
|
-
}), /* @__PURE__ */
|
|
171
|
+
children: e(b, "files.info.visibility", "Visibility")
|
|
172
|
+
}), /* @__PURE__ */ m("dd", {
|
|
173
173
|
className: "text-sm font-medium text-text-primary",
|
|
174
174
|
children: n.visibility
|
|
175
175
|
})]
|
|
176
176
|
}),
|
|
177
|
-
/* @__PURE__ */
|
|
177
|
+
/* @__PURE__ */ h("div", {
|
|
178
178
|
className: "flex justify-between",
|
|
179
|
-
children: [/* @__PURE__ */
|
|
179
|
+
children: [/* @__PURE__ */ m("dt", {
|
|
180
180
|
className: "text-sm text-text-secondary",
|
|
181
|
-
children: e(
|
|
182
|
-
}), /* @__PURE__ */
|
|
181
|
+
children: e(b, "files.info.starred", "Starred")
|
|
182
|
+
}), /* @__PURE__ */ m("dd", {
|
|
183
183
|
className: "text-sm font-medium text-text-primary",
|
|
184
|
-
children: n.starred ? e(
|
|
184
|
+
children: n.starred ? e(b, "files.info.yes", "Yes") : e(b, "files.info.no", "No")
|
|
185
185
|
})]
|
|
186
186
|
})
|
|
187
187
|
]
|
|
188
188
|
})]
|
|
189
189
|
}),
|
|
190
|
-
|
|
190
|
+
x && S && /* @__PURE__ */ m("div", {
|
|
191
191
|
className: "pt-6 border-t border-border-default",
|
|
192
|
-
children: /* @__PURE__ */
|
|
192
|
+
children: /* @__PURE__ */ h("button", {
|
|
193
193
|
type: "button",
|
|
194
|
-
onClick: () =>
|
|
194
|
+
onClick: () => T(!0),
|
|
195
195
|
className: "w-full flex items-center justify-center gap-2 px-4 py-3 text-sm font-medium text-action-primary-text bg-action-primary-bg/10 hover:bg-action-primary-bg/20 rounded-lg transition-all duration-200",
|
|
196
|
-
children: [/* @__PURE__ */
|
|
196
|
+
children: [/* @__PURE__ */ m(s, { className: "size-4" }), e(b, "files.info.viewVersionHistory", "View Version History")]
|
|
197
197
|
})
|
|
198
198
|
})
|
|
199
199
|
]
|
|
200
200
|
}),
|
|
201
|
-
|
|
202
|
-
fallback: /* @__PURE__ */
|
|
201
|
+
x && S && w && /* @__PURE__ */ m(t, {
|
|
202
|
+
fallback: /* @__PURE__ */ m("div", {
|
|
203
203
|
className: "fixed inset-0 z-50 bg-bg-overlay flex items-center justify-center",
|
|
204
|
-
children: /* @__PURE__ */
|
|
204
|
+
children: /* @__PURE__ */ m("div", {
|
|
205
205
|
className: "bg-bg-surface rounded-lg p-8 animate-in fade-in zoom-in duration-200",
|
|
206
|
-
children: /* @__PURE__ */
|
|
206
|
+
children: /* @__PURE__ */ h("div", {
|
|
207
207
|
className: "flex items-center gap-3",
|
|
208
|
-
children: [/* @__PURE__ */
|
|
208
|
+
children: [/* @__PURE__ */ m(s, { className: "size-6 text-action-primary-bg animate-spin" }), /* @__PURE__ */ m("span", {
|
|
209
209
|
className: "text-text-primary",
|
|
210
|
-
children: e(
|
|
210
|
+
children: e(b, "files.info.loadingVersionHistory", "Loading version history...")
|
|
211
211
|
})]
|
|
212
212
|
})
|
|
213
213
|
})
|
|
214
214
|
}),
|
|
215
|
-
children: /* @__PURE__ */
|
|
216
|
-
file:
|
|
217
|
-
onClose: () =>
|
|
215
|
+
children: /* @__PURE__ */ m(_, {
|
|
216
|
+
file: S,
|
|
217
|
+
onClose: () => T(!1)
|
|
218
218
|
})
|
|
219
219
|
})
|
|
220
220
|
]
|
|
221
221
|
});
|
|
222
222
|
}
|
|
223
223
|
//#endregion
|
|
224
|
-
export {
|
|
224
|
+
export { v as FileInfoPanel };
|
|
225
225
|
|
|
226
226
|
//# sourceMappingURL=FileInfoPanel.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FileInfoPanel.js","names":[],"sources":["../../../src/files/components/FileInfoPanel.tsx"],"sourcesContent":["import { useEffect, useState, lazy, Suspense } from \"react\";\nimport {\n X,\n FileText,\n Calendar,\n User,\n HardDrive,\n Link as LinkIcon,\n Clock,\n} from \"lucide-react\";\nimport { useI18n } from \"@burdenoff/fe-libs/shared/providers/shell/I18nProvider\";\nimport type { FileItem, FolderItem } from \"../types\";\nimport { tWithFallback } from \"../utils/i18n\";\n\n// Lazy load FileVersionPanel to avoid loading heavy dependencies until needed\nconst FileVersionPanel = lazy(() =>\n import(\"./FileVersionPanel\").then((m) => ({ default: m.FileVersionPanel })),\n);\n\ninterface FileInfoPanelProps {\n item: FileItem | FolderItem;\n type: \"file\" | \"folder\";\n onClose: () => void;\n}\n\nexport function FileInfoPanel({ item, type, onClose }: FileInfoPanelProps) {\n const { t } = useI18n();\n const isFile = type === \"file\";\n const file = isFile ? (item as FileItem) : null;\n const folder = !isFile ? (item as FolderItem) : null;\n const [showVersionHistory, setShowVersionHistory] = useState(false);\n\n useEffect(() => {\n const handleEscape = (event: KeyboardEvent) => {\n if (event.key === \"Escape\") {\n if (showVersionHistory) {\n setShowVersionHistory(false);\n return;\n }\n\n onClose();\n }\n };\n\n document.addEventListener(\"keydown\", handleEscape);\n return () => document.removeEventListener(\"keydown\", handleEscape);\n }, [onClose, showVersionHistory]);\n\n const formatDate = (date: string) => {\n return new Date(date).toLocaleString(\"en-US\", {\n year: \"numeric\",\n month: \"long\",\n day: \"numeric\",\n hour: \"2-digit\",\n minute: \"2-digit\",\n });\n };\n\n const formatSize = (bytes: number) => {\n if (bytes < 1024) return `${bytes} B`;\n if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(2)} KB`;\n if (bytes < 1024 * 1024 * 1024)\n return `${(bytes / 1024 / 1024).toFixed(2)} MB`;\n return `${(bytes / 1024 / 1024 / 1024).toFixed(2)} GB`;\n };\n\n return (\n <div\n className=\"fixed inset-y-0 right-0 z-[9999] w-full max-w-full overflow-y-auto border-l border-border-default bg-bg-surface shadow-2xl animate-in slide-in-from-right duration-300 sm:w-96 [&::-webkit-scrollbar]:hidden [-ms-overflow-style:none] [scrollbar-width:none]\"\n role=\"dialog\"\n aria-modal=\"false\"\n aria-label={\n isFile\n ? tWithFallback(t, \"files.info.fileInfo\", \"File information\")\n : tWithFallback(t, \"files.info.folderInfo\", \"Folder information\")\n }\n >\n {/* Header */}\n <div className=\"sticky top-0 bg-bg-surface border-b border-border-default px-6 py-4 flex items-center justify-between\">\n <h2 className=\"text-lg font-semibold text-text-primary\">\n {isFile\n ? tWithFallback(t, \"files.info.fileInfo\", \"File Information\")\n : tWithFallback(t, \"files.info.folderInfo\", \"Folder Information\")}\n </h2>\n <button\n type=\"button\"\n onClick={onClose}\n className=\"p-1.5 rounded-md border border-border-default text-text-secondary bg-bg-elevated hover:bg-action-ghost-bg-hover hover:text-text-primary transition-colors shadow-sm\"\n aria-label={tWithFallback(\n t,\n \"files.info.closePanel\",\n \"Close information panel\",\n )}\n >\n <X className=\"size-5\" />\n </button>\n </div>\n\n {/* Content */}\n <div className=\"p-6 space-y-6\">\n {/* Preview/Icon */}\n <div className=\"flex items-center justify-center py-8 bg-bg-muted rounded-lg\">\n {isFile && file?.mimeType.startsWith(\"image/\") ? (\n <img\n src={file.downloadUrl || file.url}\n alt={item.name}\n className=\"max-w-full max-h-48 object-contain rounded\"\n />\n ) : (\n <FileText className=\"size-20 text-text-muted\" />\n )}\n </div>\n\n {/* Name */}\n <div>\n <h3 className=\"text-xl font-semibold text-text-primary break-words\">\n {item.name}\n </h3>\n {item.description && (\n <p className=\"mt-2 text-sm text-text-secondary\">\n {item.description}\n </p>\n )}\n </div>\n\n {/* Details */}\n <div className=\"space-y-4\">\n <div className=\"flex items-start gap-3\">\n <FileText className=\"size-5 text-text-muted mt-0.5\" />\n <div>\n <p className=\"text-sm font-medium text-text-primary\">\n {tWithFallback(t, \"files.info.type\", \"Type\")}\n </p>\n <p className=\"text-sm text-text-secondary\">\n {isFile\n ? file?.mimeType ||\n tWithFallback(t, \"files.info.unknown\", \"Unknown\")\n : tWithFallback(t, \"files.info.folder\", \"Folder\")}\n </p>\n </div>\n </div>\n\n {isFile && file && (\n <div className=\"flex items-start gap-3\">\n <HardDrive className=\"size-5 text-text-muted mt-0.5\" />\n <div>\n <p className=\"text-sm font-medium text-text-primary\">\n {tWithFallback(t, \"files.info.size\", \"Size\")}\n </p>\n <p className=\"text-sm text-text-secondary\">\n {formatSize(file.size)}\n </p>\n </div>\n </div>\n )}\n\n {!isFile && folder && (\n <>\n <div className=\"flex items-start gap-3\">\n <FileText className=\"size-5 text-text-muted mt-0.5\" />\n <div>\n <p className=\"text-sm font-medium text-text-primary\">\n {tWithFallback(t, \"files.info.contents\", \"Contents\")}\n </p>\n <p className=\"text-sm text-text-secondary\">\n {folder.filesCount}{\" \"}\n {tWithFallback(t, \"files.info.files\", \"files\")},{\" \"}\n {folder.subfoldersCount}{\" \"}\n {tWithFallback(t, \"files.info.folders\", \"folders\")}\n </p>\n </div>\n </div>\n\n {folder.path && (\n <div className=\"flex items-start gap-3\">\n <LinkIcon className=\"size-5 text-text-muted mt-0.5\" />\n <div>\n <p className=\"text-sm font-medium text-text-primary\">\n {tWithFallback(t, \"files.info.path\", \"Path\")}\n </p>\n <p className=\"text-sm text-text-secondary break-all\">\n {folder.path}\n </p>\n </div>\n </div>\n )}\n </>\n )}\n\n <div className=\"flex items-start gap-3\">\n <Calendar className=\"size-5 text-text-muted mt-0.5\" />\n <div>\n <p className=\"text-sm font-medium text-text-primary\">\n {tWithFallback(t, \"files.info.created\", \"Created\")}\n </p>\n <p className=\"text-sm text-text-secondary\">\n {formatDate(item.createdAt)}\n </p>\n </div>\n </div>\n\n {item.updatedAt && (\n <div className=\"flex items-start gap-3\">\n <Calendar className=\"size-5 text-text-muted mt-0.5\" />\n <div>\n <p className=\"text-sm font-medium text-text-primary\">\n {tWithFallback(t, \"files.info.modified\", \"Modified\")}\n </p>\n <p className=\"text-sm text-text-secondary\">\n {formatDate(item.updatedAt)}\n </p>\n </div>\n </div>\n )}\n\n <div className=\"flex items-start gap-3\">\n <User className=\"size-5 text-text-muted mt-0.5\" />\n <div>\n <p className=\"text-sm font-medium text-text-primary\">\n {tWithFallback(t, \"files.info.owner\", \"Owner\")}\n </p>\n <p className=\"text-sm text-text-secondary\">\n {item.createdBy?.name ||\n item.createdById ||\n tWithFallback(t, \"files.info.unknown\", \"Unknown\")}\n </p>\n </div>\n </div>\n </div>\n\n {/* Additional Info */}\n <div className=\"pt-6 border-t border-border-default\">\n <h4 className=\"text-sm font-semibold text-text-primary mb-3\">\n {tWithFallback(t, \"files.info.properties\", \"Properties\")}\n </h4>\n <dl className=\"space-y-2\">\n <div className=\"flex justify-between\">\n <dt className=\"text-sm text-text-secondary\">\n {tWithFallback(t, \"files.info.status\", \"Status\")}\n </dt>\n <dd className=\"text-sm font-medium text-text-primary\">\n {item.status}\n </dd>\n </div>\n <div className=\"flex justify-between\">\n <dt className=\"text-sm text-text-secondary\">\n {tWithFallback(t, \"files.info.visibility\", \"Visibility\")}\n </dt>\n <dd className=\"text-sm font-medium text-text-primary\">\n {item.visibility}\n </dd>\n </div>\n <div className=\"flex justify-between\">\n <dt className=\"text-sm text-text-secondary\">\n {tWithFallback(t, \"files.info.starred\", \"Starred\")}\n </dt>\n <dd className=\"text-sm font-medium text-text-primary\">\n {item.starred\n ? tWithFallback(t, \"files.info.yes\", \"Yes\")\n : tWithFallback(t, \"files.info.no\", \"No\")}\n </dd>\n </div>\n </dl>\n </div>\n\n {/* Version History Button (Files only) */}\n {isFile && file && (\n <div className=\"pt-6 border-t border-border-default\">\n <button\n type=\"button\"\n onClick={() => setShowVersionHistory(true)}\n className=\"w-full flex items-center justify-center gap-2 px-4 py-3 text-sm font-medium text-action-primary-text bg-action-primary-bg/10 hover:bg-action-primary-bg/20 rounded-lg transition-all duration-200\"\n >\n <Clock className=\"size-4\" />\n {tWithFallback(\n t,\n \"files.info.viewVersionHistory\",\n \"View Version History\",\n )}\n </button>\n </div>\n )}\n </div>\n\n {/* Version History Modal */}\n {isFile && file && showVersionHistory && (\n <Suspense\n fallback={\n <div className=\"fixed inset-0 z-50 bg-bg-overlay flex items-center justify-center\">\n <div className=\"bg-bg-surface rounded-lg p-8 animate-in fade-in zoom-in duration-200\">\n <div className=\"flex items-center gap-3\">\n <Clock className=\"size-6 text-action-primary-bg animate-spin\" />\n <span className=\"text-text-primary\">\n {tWithFallback(\n t,\n \"files.info.loadingVersionHistory\",\n \"Loading version history...\",\n )}\n </span>\n </div>\n </div>\n </div>\n }\n >\n <FileVersionPanel\n file={file}\n onClose={() => setShowVersionHistory(false)}\n />\n </Suspense>\n )}\n </div>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"FileInfoPanel.js","names":[],"sources":["../../../src/files/components/FileInfoPanel.tsx"],"sourcesContent":["import { useEffect, useEffectEvent, useState, lazy, Suspense } from \"react\";\nimport {\n X,\n FileText,\n Calendar,\n User,\n HardDrive,\n Link as LinkIcon,\n Clock,\n} from \"lucide-react\";\nimport { useI18n } from \"@burdenoff/fe-libs/shared/providers/shell/I18nProvider\";\nimport type { FileItem, FolderItem } from \"../types\";\nimport { tWithFallback } from \"../utils/i18n\";\n\n// Lazy load FileVersionPanel to avoid loading heavy dependencies until needed\nconst FileVersionPanel = lazy(() =>\n import(\"./FileVersionPanel\").then((m) => ({ default: m.FileVersionPanel })),\n);\n\ninterface FileInfoPanelProps {\n item: FileItem | FolderItem;\n type: \"file\" | \"folder\";\n onClose: () => void;\n}\n\nexport function FileInfoPanel({ item, type, onClose }: FileInfoPanelProps) {\n const { t } = useI18n();\n const isFile = type === \"file\";\n const file = isFile ? (item as FileItem) : null;\n const folder = !isFile ? (item as FolderItem) : null;\n const [showVersionHistory, setShowVersionHistory] = useState(false);\n\n const onEscape = useEffectEvent(() => {\n if (showVersionHistory) {\n setShowVersionHistory(false);\n return;\n }\n onClose();\n });\n\n useEffect(() => {\n const handleEscape = (event: KeyboardEvent) => {\n if (event.key === \"Escape\") {\n onEscape();\n }\n };\n\n document.addEventListener(\"keydown\", handleEscape);\n return () => document.removeEventListener(\"keydown\", handleEscape);\n }, []);\n\n const formatDate = (date: string) => {\n return new Date(date).toLocaleString(\"en-US\", {\n year: \"numeric\",\n month: \"long\",\n day: \"numeric\",\n hour: \"2-digit\",\n minute: \"2-digit\",\n });\n };\n\n const formatSize = (bytes: number) => {\n if (bytes < 1024) return `${bytes} B`;\n if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(2)} KB`;\n if (bytes < 1024 * 1024 * 1024)\n return `${(bytes / 1024 / 1024).toFixed(2)} MB`;\n return `${(bytes / 1024 / 1024 / 1024).toFixed(2)} GB`;\n };\n\n return (\n <div\n className=\"fixed inset-y-0 right-0 z-[9999] w-full max-w-full overflow-y-auto border-l border-border-default bg-bg-surface shadow-2xl animate-in slide-in-from-right duration-300 sm:w-96 [&::-webkit-scrollbar]:hidden [-ms-overflow-style:none] [scrollbar-width:none]\"\n role=\"dialog\"\n aria-modal=\"false\"\n aria-label={\n isFile\n ? tWithFallback(t, \"files.info.fileInfo\", \"File information\")\n : tWithFallback(t, \"files.info.folderInfo\", \"Folder information\")\n }\n >\n {/* Header */}\n <div className=\"sticky top-0 bg-bg-surface border-b border-border-default px-6 py-4 flex items-center justify-between\">\n <h2 className=\"text-lg font-semibold text-text-primary\">\n {isFile\n ? tWithFallback(t, \"files.info.fileInfo\", \"File Information\")\n : tWithFallback(t, \"files.info.folderInfo\", \"Folder Information\")}\n </h2>\n <button\n type=\"button\"\n onClick={onClose}\n className=\"p-1.5 rounded-md border border-border-default text-text-secondary bg-bg-elevated hover:bg-action-ghost-bg-hover hover:text-text-primary transition-colors shadow-sm\"\n aria-label={tWithFallback(\n t,\n \"files.info.closePanel\",\n \"Close information panel\",\n )}\n >\n <X className=\"size-5\" />\n </button>\n </div>\n\n {/* Content */}\n <div className=\"p-6 space-y-6\">\n {/* Preview/Icon */}\n <div className=\"flex items-center justify-center py-8 bg-bg-muted rounded-lg\">\n {isFile && file?.mimeType.startsWith(\"image/\") ? (\n <img\n src={file.downloadUrl || file.url}\n alt={item.name}\n className=\"max-w-full max-h-48 object-contain rounded\"\n />\n ) : (\n <FileText className=\"size-20 text-text-muted\" />\n )}\n </div>\n\n {/* Name */}\n <div>\n <h3 className=\"text-xl font-semibold text-text-primary break-words\">\n {item.name}\n </h3>\n {item.description && (\n <p className=\"mt-2 text-sm text-text-secondary\">\n {item.description}\n </p>\n )}\n </div>\n\n {/* Details */}\n <div className=\"space-y-4\">\n <div className=\"flex items-start gap-3\">\n <FileText className=\"size-5 text-text-muted mt-0.5\" />\n <div>\n <p className=\"text-sm font-medium text-text-primary\">\n {tWithFallback(t, \"files.info.type\", \"Type\")}\n </p>\n <p className=\"text-sm text-text-secondary\">\n {isFile\n ? file?.mimeType ||\n tWithFallback(t, \"files.info.unknown\", \"Unknown\")\n : tWithFallback(t, \"files.info.folder\", \"Folder\")}\n </p>\n </div>\n </div>\n\n {isFile && file && (\n <div className=\"flex items-start gap-3\">\n <HardDrive className=\"size-5 text-text-muted mt-0.5\" />\n <div>\n <p className=\"text-sm font-medium text-text-primary\">\n {tWithFallback(t, \"files.info.size\", \"Size\")}\n </p>\n <p className=\"text-sm text-text-secondary\">\n {formatSize(file.size)}\n </p>\n </div>\n </div>\n )}\n\n {!isFile && folder && (\n <>\n <div className=\"flex items-start gap-3\">\n <FileText className=\"size-5 text-text-muted mt-0.5\" />\n <div>\n <p className=\"text-sm font-medium text-text-primary\">\n {tWithFallback(t, \"files.info.contents\", \"Contents\")}\n </p>\n <p className=\"text-sm text-text-secondary\">\n {folder.filesCount}{\" \"}\n {tWithFallback(t, \"files.info.files\", \"files\")},{\" \"}\n {folder.subfoldersCount}{\" \"}\n {tWithFallback(t, \"files.info.folders\", \"folders\")}\n </p>\n </div>\n </div>\n\n {folder.path && (\n <div className=\"flex items-start gap-3\">\n <LinkIcon className=\"size-5 text-text-muted mt-0.5\" />\n <div>\n <p className=\"text-sm font-medium text-text-primary\">\n {tWithFallback(t, \"files.info.path\", \"Path\")}\n </p>\n <p className=\"text-sm text-text-secondary break-all\">\n {folder.path}\n </p>\n </div>\n </div>\n )}\n </>\n )}\n\n <div className=\"flex items-start gap-3\">\n <Calendar className=\"size-5 text-text-muted mt-0.5\" />\n <div>\n <p className=\"text-sm font-medium text-text-primary\">\n {tWithFallback(t, \"files.info.created\", \"Created\")}\n </p>\n <p className=\"text-sm text-text-secondary\">\n {formatDate(item.createdAt)}\n </p>\n </div>\n </div>\n\n {item.updatedAt && (\n <div className=\"flex items-start gap-3\">\n <Calendar className=\"size-5 text-text-muted mt-0.5\" />\n <div>\n <p className=\"text-sm font-medium text-text-primary\">\n {tWithFallback(t, \"files.info.modified\", \"Modified\")}\n </p>\n <p className=\"text-sm text-text-secondary\">\n {formatDate(item.updatedAt)}\n </p>\n </div>\n </div>\n )}\n\n <div className=\"flex items-start gap-3\">\n <User className=\"size-5 text-text-muted mt-0.5\" />\n <div>\n <p className=\"text-sm font-medium text-text-primary\">\n {tWithFallback(t, \"files.info.owner\", \"Owner\")}\n </p>\n <p className=\"text-sm text-text-secondary\">\n {item.createdBy?.name ||\n item.createdById ||\n tWithFallback(t, \"files.info.unknown\", \"Unknown\")}\n </p>\n </div>\n </div>\n </div>\n\n {/* Additional Info */}\n <div className=\"pt-6 border-t border-border-default\">\n <h4 className=\"text-sm font-semibold text-text-primary mb-3\">\n {tWithFallback(t, \"files.info.properties\", \"Properties\")}\n </h4>\n <dl className=\"space-y-2\">\n <div className=\"flex justify-between\">\n <dt className=\"text-sm text-text-secondary\">\n {tWithFallback(t, \"files.info.status\", \"Status\")}\n </dt>\n <dd className=\"text-sm font-medium text-text-primary\">\n {item.status}\n </dd>\n </div>\n <div className=\"flex justify-between\">\n <dt className=\"text-sm text-text-secondary\">\n {tWithFallback(t, \"files.info.visibility\", \"Visibility\")}\n </dt>\n <dd className=\"text-sm font-medium text-text-primary\">\n {item.visibility}\n </dd>\n </div>\n <div className=\"flex justify-between\">\n <dt className=\"text-sm text-text-secondary\">\n {tWithFallback(t, \"files.info.starred\", \"Starred\")}\n </dt>\n <dd className=\"text-sm font-medium text-text-primary\">\n {item.starred\n ? tWithFallback(t, \"files.info.yes\", \"Yes\")\n : tWithFallback(t, \"files.info.no\", \"No\")}\n </dd>\n </div>\n </dl>\n </div>\n\n {/* Version History Button (Files only) */}\n {isFile && file && (\n <div className=\"pt-6 border-t border-border-default\">\n <button\n type=\"button\"\n onClick={() => setShowVersionHistory(true)}\n className=\"w-full flex items-center justify-center gap-2 px-4 py-3 text-sm font-medium text-action-primary-text bg-action-primary-bg/10 hover:bg-action-primary-bg/20 rounded-lg transition-all duration-200\"\n >\n <Clock className=\"size-4\" />\n {tWithFallback(\n t,\n \"files.info.viewVersionHistory\",\n \"View Version History\",\n )}\n </button>\n </div>\n )}\n </div>\n\n {/* Version History Modal */}\n {isFile && file && showVersionHistory && (\n <Suspense\n fallback={\n <div className=\"fixed inset-0 z-50 bg-bg-overlay flex items-center justify-center\">\n <div className=\"bg-bg-surface rounded-lg p-8 animate-in fade-in zoom-in duration-200\">\n <div className=\"flex items-center gap-3\">\n <Clock className=\"size-6 text-action-primary-bg animate-spin\" />\n <span className=\"text-text-primary\">\n {tWithFallback(\n t,\n \"files.info.loadingVersionHistory\",\n \"Loading version history...\",\n )}\n </span>\n </div>\n </div>\n </div>\n }\n >\n <FileVersionPanel\n file={file}\n onClose={() => setShowVersionHistory(false)}\n />\n </Suspense>\n )}\n </div>\n );\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FileListItem.js","names":[],"sources":["../../../src/files/components/FileListItem.tsx"],"sourcesContent":["import { type FC, useMemo, useState } from \"react\";\nimport {\n Download,\n Share2,\n Trash2,\n Star,\n RotateCcw,\n Edit,\n Copy,\n FolderInput,\n Info,\n Activity,\n} from \"lucide-react\";\nimport { useI18n } from \"@burdenoff/fe-libs/shared/providers/shell/I18nProvider\";\nimport type { FileItem } from \"../types\";\nimport { formatFileSize, formatFileDate, getFileIcon } from \"../utils\";\nimport { useFilesStore } from \"../store/filesStore\";\nimport { ActionMenu } from \"./ActionMenu\";\nimport { getDragOperation } from \"../hooks/useDragDrop\";\nimport { tWithFallback } from \"../utils/i18n\";\n\ninterface FileListItemProps {\n file: FileItem;\n isSelected?: boolean;\n isDragging?: boolean;\n onSelect?: (fileId: string) => void;\n onPreview?: (file: FileItem) => void;\n onShare?: (file: FileItem) => void;\n onDelete?: (file: FileItem) => void;\n onRestore?: (file: FileItem) => void;\n onFavorite?: (file: FileItem) => void;\n onRename?: (file: FileItem) => void;\n onDownload?: (file: FileItem) => void;\n onCopy?: (file: FileItem) => void;\n onMove?: (file: FileItem) => void;\n onInfo?: (file: FileItem) => void;\n onActivity?: (file: FileItem) => void;\n onDragStart?: (file: FileItem, operation: \"move\" | \"copy\") => void;\n onDragEnd?: () => void;\n onContextMenu?: (file: FileItem, x: number, y: number) => void;\n}\n\ninterface DraggableFileListItemProps extends Omit<\n FileListItemProps,\n \"onDragStart\" | \"onDragEnd\"\n> {\n onDragStart?: (file: FileItem, operation: \"move\" | \"copy\") => void;\n onDragEnd?: () => void;\n}\n\nexport const FileListItem: FC<DraggableFileListItemProps> = ({\n file,\n isSelected = false,\n isDragging = false,\n onSelect,\n onPreview,\n onShare,\n onDelete,\n onRestore,\n onFavorite,\n onRename,\n onDownload,\n onCopy,\n onMove,\n onInfo,\n onActivity,\n onDragStart,\n onDragEnd,\n onContextMenu,\n}) => {\n const { t } = useI18n();\n const [menuOpen, setMenuOpen] = useState(false);\n const { toggleFileSelection } = useFilesStore();\n\n const handleClick = () => {\n if (onPreview) {\n onPreview(file);\n }\n };\n\n const handleCheckboxChange = (e: React.ChangeEvent<HTMLInputElement>) => {\n e.stopPropagation();\n if (onSelect) {\n onSelect(file.id);\n } else {\n toggleFileSelection(file.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\", file.id);\n e.dataTransfer.setData(\"application/x-file-type\", \"file\");\n const operation = getDragOperation(e);\n e.dataTransfer.setData(\"application/x-drag-operation\", operation);\n onDragStart?.(file, operation);\n };\n\n const handleDragEnd = () => {\n onDragEnd?.();\n };\n\n const handleContextMenu = (e: React.MouseEvent) => {\n e.preventDefault();\n e.stopPropagation();\n onContextMenu?.(file, e.clientX, e.clientY);\n };\n\n const FileIconComponent = getFileIcon(file.mimeType);\n\n // Memoize menu items to prevent re-renders\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(file),\n },\n ]\n : []),\n ...(onDownload\n ? [\n {\n label: tWithFallback(t, \"files.card.download\", \"Download\"),\n icon: <Download className=\"size-4\" />,\n onClick: () => onDownload(file),\n },\n ]\n : []),\n ...(onCopy\n ? [\n {\n label: tWithFallback(t, \"files.card.makeCopy\", \"Make a copy\"),\n icon: <Copy className=\"size-4\" />,\n onClick: () => onCopy(file),\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(file),\n },\n ]\n : []),\n ...(onRename\n ? [\n {\n label: tWithFallback(t, \"files.card.rename\", \"Rename\"),\n icon: <Edit className=\"size-4\" />,\n onClick: () => onRename(file),\n divider: true,\n },\n ]\n : []),\n ...(onFavorite\n ? [\n {\n label: file.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(file),\n },\n ]\n : []),\n ...(onInfo\n ? [\n {\n label: tWithFallback(t, \"files.card.details\", \"Details\"),\n icon: <Info className=\"size-4\" />,\n onClick: () => onInfo(file),\n },\n ]\n : []),\n ...(onActivity\n ? [\n {\n label: tWithFallback(t, \"files.card.activity\", \"Activity\"),\n icon: <Activity className=\"size-4\" />,\n onClick: () => onActivity(file),\n },\n ]\n : []),\n ...(onDelete\n ? [\n {\n label: tWithFallback(t, \"files.card.delete\", \"Delete\"),\n icon: <Trash2 className=\"size-4\" />,\n onClick: () => onDelete(file),\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(file),\n },\n ]\n : []),\n ],\n [\n file,\n onShare,\n onDownload,\n onCopy,\n onMove,\n onRename,\n onFavorite,\n onInfo,\n onActivity,\n onDelete,\n onRestore,\n t,\n ],\n );\n\n return (\n <div\n className={`@container group flex items-center gap-3 border-b border-border-subtle bg-bg-surface p-3 transition-colors hover:bg-bg-sunken focus-within:bg-bg-sunken ${isDragging ? \"opacity-50\" : \"\"}`}\n onClick={handleClick}\n onContextMenu={handleContextMenu}\n onKeyDown={(event) => {\n if (event.key === \"Enter\" || event.key === \" \") {\n event.preventDefault();\n handleClick();\n }\n }}\n draggable={Boolean(onDragStart)}\n onDragStart={handleDragStart}\n onDragEnd={handleDragEnd}\n role=\"button\"\n tabIndex={0}\n aria-label={`Preview ${file.name}`}\n >\n {/* Selection checkbox */}\n <div className=\"flex-shrink-0\">\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 ${file.name}`}\n />\n </div>\n\n {/* File icon */}\n <div className=\"flex-shrink-0\">\n {file.thumbnailUrl ? (\n <img\n src={file.thumbnailUrl}\n alt={file.name}\n className=\"size-8 object-cover rounded\"\n />\n ) : (\n <FileIconComponent className=\"size-6 text-text-muted\" />\n )}\n </div>\n\n {/* File name - takes remaining space */}\n <div className=\"flex-1 min-w-0\">\n <div className=\"flex items-center gap-2\">\n <span className=\"font-text-md font-weight-medium text-text-primary truncate\">\n {file.name}\n </span>\n {file.starred && (\n <Star className=\"size-3 flex-shrink-0 fill-yellow-400 text-yellow-400\" />\n )}\n {file.isShared && (\n <Share2 className=\"size-3 flex-shrink-0 text-text-muted\" />\n )}\n </div>\n\n {/* Tags - visible on medium+ containers */}\n {file.tags && file.tags.length > 0 && (\n <div className=\"hidden @md:flex flex-wrap gap-1 mt-1\">\n {file.tags.slice(0, 3).map((tag) => (\n <span\n key={tag}\n className=\"px-1.5 py-0.5 bg-bg-accent text-text-primary font-text-xs rounded-sm\"\n >\n {tag}\n </span>\n ))}\n {file.tags.length > 3 && (\n <span className=\"text-text-muted font-text-xs\">\n +{file.tags.length - 3}\n </span>\n )}\n </div>\n )}\n </div>\n\n {/* Owner - visible on large+ containers */}\n {file.createdBy && (\n <div className=\"hidden @lg:flex items-center gap-2 flex-shrink-0 w-40\">\n {file.createdBy.avatar && (\n <img\n src={file.createdBy.avatar}\n alt={file.createdBy.name}\n className=\"size-6 rounded-full\"\n />\n )}\n <span className=\"font-text-sm text-text-secondary truncate\">\n {file.createdBy.name}\n </span>\n </div>\n )}\n\n {/* Size - visible on medium+ containers */}\n <div className=\"hidden @md:block flex-shrink-0 w-24 text-right\">\n <span className=\"font-text-sm text-text-secondary\">\n {formatFileSize(file.size)}\n </span>\n </div>\n\n {/* Modified date - visible on large+ containers */}\n <div className=\"hidden @lg:block flex-shrink-0 w-32 text-right\">\n <span className=\"font-text-sm text-text-secondary\">\n {formatFileDate(file.updatedAt)}\n </span>\n </div>\n\n {/* Actions */}\n <div className=\"flex items-center gap-1\">\n <div className=\"flex items-center gap-1 opacity-0 transition-opacity group-hover:opacity-100 group-focus-within:opacity-100\">\n {file.canRead && onDownload && (\n <button\n type=\"button\"\n onClick={(e) => handleActionClick(e, () => onDownload(file))}\n className=\"p-1.5 hover:bg-action-ghost-bg-hover rounded transition-colors\"\n aria-label={tWithFallback(t, \"files.card.download\", \"Download\")}\n title={tWithFallback(t, \"files.card.download\", \"Download\")}\n >\n <Download className=\"size-4 text-text-primary\" />\n </button>\n )}\n\n {onShare && (\n <button\n type=\"button\"\n onClick={(e) => handleActionClick(e, () => onShare(file))}\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-primary\" />\n </button>\n )}\n\n {onFavorite && (\n <button\n type=\"button\"\n onClick={(e) => handleActionClick(e, () => onFavorite(file))}\n className=\"p-1.5 hover:bg-action-ghost-bg-hover rounded transition-colors\"\n aria-label={\n file.starred\n ? tWithFallback(t, \"files.card.unfavorite\", \"Unfavorite\")\n : tWithFallback(t, \"files.card.favorite\", \"Favorite\")\n }\n title={\n file.starred\n ? tWithFallback(t, \"files.card.unfavorite\", \"Unfavorite\")\n : tWithFallback(t, \"files.card.favorite\", \"Favorite\")\n }\n >\n <Star\n className={`size-4 ${\n file.starred\n ? \"fill-status-warning-bg text-status-warning-bg\"\n : \"text-text-primary\"\n }`}\n />\n </button>\n )}\n\n {onRestore && (\n <button\n type=\"button\"\n onClick={(e) => handleActionClick(e, () => onRestore(file))}\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\n {file.canWrite && onRename && (\n <button\n type=\"button\"\n onClick={(e) => handleActionClick(e, () => onRename(file))}\n className=\"hidden @md:block 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-primary\" />\n </button>\n )}\n\n {file.canDelete && onDelete && (\n <button\n type=\"button\"\n onClick={(e) => handleActionClick(e, () => onDelete(file))}\n className=\"p-1.5 hover:bg-action-danger-bg-hover rounded transition-colors\"\n aria-label={tWithFallback(t, \"files.card.delete\", \"Delete\")}\n title={tWithFallback(t, \"files.card.delete\", \"Delete\")}\n >\n <Trash2 className=\"size-4 text-status-error-text\" />\n </button>\n )}\n </div>\n\n {/* More actions dropdown - always visible */}\n <ActionMenu\n items={menuItems}\n align=\"right\"\n isOpen={menuOpen}\n onToggle={setMenuOpen}\n />\n </div>\n </div>\n );\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"FileListItem.js","names":[],"sources":["../../../src/files/components/FileListItem.tsx"],"sourcesContent":["import { type FC, useMemo, useState } from \"react\";\nimport {\n Download,\n Share2,\n Trash2,\n Star,\n RotateCcw,\n Edit,\n Copy,\n FolderInput,\n Info,\n Activity,\n} from \"lucide-react\";\nimport { useI18n } from \"@burdenoff/fe-libs/shared/providers/shell/I18nProvider\";\nimport type { FileItem } from \"../types\";\nimport { formatFileSize, formatFileDate, getFileIcon } from \"../utils\";\nimport { useFilesStore } from \"../store/filesStore\";\nimport { ActionMenu } from \"./ActionMenu\";\nimport { getDragOperation } from \"../hooks/useDragDrop\";\nimport { tWithFallback } from \"../utils/i18n\";\n\ninterface FileListItemProps {\n file: FileItem;\n isSelected?: boolean;\n isDragging?: boolean;\n onSelect?: (fileId: string) => void;\n onPreview?: (file: FileItem) => void;\n onShare?: (file: FileItem) => void;\n onDelete?: (file: FileItem) => void;\n onRestore?: (file: FileItem) => void;\n onFavorite?: (file: FileItem) => void;\n onRename?: (file: FileItem) => void;\n onDownload?: (file: FileItem) => void;\n onCopy?: (file: FileItem) => void;\n onMove?: (file: FileItem) => void;\n onInfo?: (file: FileItem) => void;\n onActivity?: (file: FileItem) => void;\n onDragStart?: (file: FileItem, operation: \"move\" | \"copy\") => void;\n onDragEnd?: () => void;\n onContextMenu?: (file: FileItem, x: number, y: number) => void;\n}\n\ninterface DraggableFileListItemProps extends Omit<\n FileListItemProps,\n \"onDragStart\" | \"onDragEnd\"\n> {\n onDragStart?: (file: FileItem, operation: \"move\" | \"copy\") => void;\n onDragEnd?: () => void;\n}\n\nexport const FileListItem: FC<DraggableFileListItemProps> = ({\n file,\n isSelected = false,\n isDragging = false,\n onSelect,\n onPreview,\n onShare,\n onDelete,\n onRestore,\n onFavorite,\n onRename,\n onDownload,\n onCopy,\n onMove,\n onInfo,\n onActivity,\n onDragStart,\n onDragEnd,\n onContextMenu,\n}) => {\n const { t } = useI18n();\n const [menuOpen, setMenuOpen] = useState(false);\n const { toggleFileSelection } = useFilesStore();\n\n const openPreview = () => {\n if (onPreview) {\n onPreview(file);\n }\n };\n\n const handleCheckboxChange = (e: React.ChangeEvent<HTMLInputElement>) => {\n e.stopPropagation();\n if (onSelect) {\n onSelect(file.id);\n } else {\n toggleFileSelection(file.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\", file.id);\n e.dataTransfer.setData(\"application/x-file-type\", \"file\");\n const operation = getDragOperation(e);\n e.dataTransfer.setData(\"application/x-drag-operation\", operation);\n onDragStart?.(file, operation);\n };\n\n const handleDragEnd = () => {\n onDragEnd?.();\n };\n\n const handleContextMenu = (e: React.MouseEvent) => {\n e.preventDefault();\n e.stopPropagation();\n onContextMenu?.(file, e.clientX, e.clientY);\n };\n\n const FileIconComponent = getFileIcon(file.mimeType);\n\n // Memoize menu items to prevent re-renders\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(file),\n },\n ]\n : []),\n ...(onDownload\n ? [\n {\n label: tWithFallback(t, \"files.card.download\", \"Download\"),\n icon: <Download className=\"size-4\" />,\n onClick: () => onDownload(file),\n },\n ]\n : []),\n ...(onCopy\n ? [\n {\n label: tWithFallback(t, \"files.card.makeCopy\", \"Make a copy\"),\n icon: <Copy className=\"size-4\" />,\n onClick: () => onCopy(file),\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(file),\n },\n ]\n : []),\n ...(onRename\n ? [\n {\n label: tWithFallback(t, \"files.card.rename\", \"Rename\"),\n icon: <Edit className=\"size-4\" />,\n onClick: () => onRename(file),\n divider: true,\n },\n ]\n : []),\n ...(onFavorite\n ? [\n {\n label: file.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(file),\n },\n ]\n : []),\n ...(onInfo\n ? [\n {\n label: tWithFallback(t, \"files.card.details\", \"Details\"),\n icon: <Info className=\"size-4\" />,\n onClick: () => onInfo(file),\n },\n ]\n : []),\n ...(onActivity\n ? [\n {\n label: tWithFallback(t, \"files.card.activity\", \"Activity\"),\n icon: <Activity className=\"size-4\" />,\n onClick: () => onActivity(file),\n },\n ]\n : []),\n ...(onDelete\n ? [\n {\n label: tWithFallback(t, \"files.card.delete\", \"Delete\"),\n icon: <Trash2 className=\"size-4\" />,\n onClick: () => onDelete(file),\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(file),\n },\n ]\n : []),\n ],\n [\n file,\n onShare,\n onDownload,\n onCopy,\n onMove,\n onRename,\n onFavorite,\n onInfo,\n onActivity,\n onDelete,\n onRestore,\n t,\n ],\n );\n\n return (\n <div\n className={`@container group flex items-center gap-3 border-b border-border-subtle bg-bg-surface p-3 transition-colors hover:bg-bg-sunken focus-within:bg-bg-sunken ${isDragging ? \"opacity-50\" : \"\"}`}\n onClick={openPreview}\n onContextMenu={handleContextMenu}\n onKeyDown={(event) => {\n if (event.key === \"Enter\" || event.key === \" \") {\n event.preventDefault();\n openPreview();\n }\n }}\n draggable={Boolean(onDragStart)}\n onDragStart={handleDragStart}\n onDragEnd={handleDragEnd}\n role=\"button\"\n tabIndex={0}\n aria-label={`Preview ${file.name}`}\n >\n {/* Selection checkbox */}\n <div className=\"flex-shrink-0\">\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 ${file.name}`}\n />\n </div>\n\n {/* File icon */}\n <div className=\"flex-shrink-0\">\n {file.thumbnailUrl ? (\n <img\n src={file.thumbnailUrl}\n alt={file.name}\n className=\"size-8 object-cover rounded\"\n />\n ) : (\n <FileIconComponent className=\"size-6 text-text-muted\" />\n )}\n </div>\n\n {/* File name - takes remaining space */}\n <div className=\"flex-1 min-w-0\">\n <div className=\"flex items-center gap-2\">\n <span className=\"font-text-md font-weight-medium text-text-primary truncate\">\n {file.name}\n </span>\n {file.starred && (\n <Star className=\"size-3 flex-shrink-0 fill-yellow-400 text-yellow-400\" />\n )}\n {file.isShared && (\n <Share2 className=\"size-3 flex-shrink-0 text-text-muted\" />\n )}\n </div>\n\n {/* Tags - visible on medium+ containers */}\n {file.tags && file.tags.length > 0 && (\n <div className=\"hidden @md:flex flex-wrap gap-1 mt-1\">\n {file.tags.slice(0, 3).map((tag) => (\n <span\n key={tag}\n className=\"px-1.5 py-0.5 bg-bg-accent text-text-primary font-text-xs rounded-sm\"\n >\n {tag}\n </span>\n ))}\n {file.tags.length > 3 && (\n <span className=\"text-text-muted font-text-xs\">\n +{file.tags.length - 3}\n </span>\n )}\n </div>\n )}\n </div>\n\n {/* Owner - visible on large+ containers */}\n {file.createdBy && (\n <div className=\"hidden @lg:flex items-center gap-2 flex-shrink-0 w-40\">\n {file.createdBy.avatar && (\n <img\n src={file.createdBy.avatar}\n alt={file.createdBy.name}\n className=\"size-6 rounded-full\"\n />\n )}\n <span className=\"font-text-sm text-text-secondary truncate\">\n {file.createdBy.name}\n </span>\n </div>\n )}\n\n {/* Size - visible on medium+ containers */}\n <div className=\"hidden @md:block flex-shrink-0 w-24 text-right\">\n <span className=\"font-text-sm text-text-secondary\">\n {formatFileSize(file.size)}\n </span>\n </div>\n\n {/* Modified date - visible on large+ containers */}\n <div className=\"hidden @lg:block flex-shrink-0 w-32 text-right\">\n <span className=\"font-text-sm text-text-secondary\">\n {formatFileDate(file.updatedAt)}\n </span>\n </div>\n\n {/* Actions */}\n <div className=\"flex items-center gap-1\">\n <div className=\"flex items-center gap-1 opacity-0 transition-opacity group-hover:opacity-100 group-focus-within:opacity-100\">\n {file.canRead && onDownload && (\n <button\n type=\"button\"\n onClick={(e) => handleActionClick(e, () => onDownload(file))}\n className=\"p-1.5 hover:bg-action-ghost-bg-hover rounded transition-colors\"\n aria-label={tWithFallback(t, \"files.card.download\", \"Download\")}\n title={tWithFallback(t, \"files.card.download\", \"Download\")}\n >\n <Download className=\"size-4 text-text-primary\" />\n </button>\n )}\n\n {onShare && (\n <button\n type=\"button\"\n onClick={(e) => handleActionClick(e, () => onShare(file))}\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-primary\" />\n </button>\n )}\n\n {onFavorite && (\n <button\n type=\"button\"\n onClick={(e) => handleActionClick(e, () => onFavorite(file))}\n className=\"p-1.5 hover:bg-action-ghost-bg-hover rounded transition-colors\"\n aria-label={\n file.starred\n ? tWithFallback(t, \"files.card.unfavorite\", \"Unfavorite\")\n : tWithFallback(t, \"files.card.favorite\", \"Favorite\")\n }\n title={\n file.starred\n ? tWithFallback(t, \"files.card.unfavorite\", \"Unfavorite\")\n : tWithFallback(t, \"files.card.favorite\", \"Favorite\")\n }\n >\n <Star\n className={`size-4 ${\n file.starred\n ? \"fill-status-warning-bg text-status-warning-bg\"\n : \"text-text-primary\"\n }`}\n />\n </button>\n )}\n\n {onRestore && (\n <button\n type=\"button\"\n onClick={(e) => handleActionClick(e, () => onRestore(file))}\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\n {file.canWrite && onRename && (\n <button\n type=\"button\"\n onClick={(e) => handleActionClick(e, () => onRename(file))}\n className=\"hidden @md:block 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-primary\" />\n </button>\n )}\n\n {file.canDelete && onDelete && (\n <button\n type=\"button\"\n onClick={(e) => handleActionClick(e, () => onDelete(file))}\n className=\"p-1.5 hover:bg-action-danger-bg-hover rounded transition-colors\"\n aria-label={tWithFallback(t, \"files.card.delete\", \"Delete\")}\n title={tWithFallback(t, \"files.card.delete\", \"Delete\")}\n >\n <Trash2 className=\"size-4 text-status-error-text\" />\n </button>\n )}\n </div>\n\n {/* More actions dropdown - always visible */}\n <ActionMenu\n items={menuItems}\n align=\"right\"\n isOpen={menuOpen}\n onToggle={setMenuOpen}\n />\n </div>\n </div>\n );\n};\n"],"mappings":"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"}
|