react-os-shell 0.1.41 → 0.1.44
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/Browser-KMVL3AJ7.js +245 -0
- package/dist/Browser-KMVL3AJ7.js.map +1 -0
- package/dist/Files-PPKWOJWV.js +486 -0
- package/dist/Files-PPKWOJWV.js.map +1 -0
- package/dist/Preview-LKFMKAIR.js +6 -0
- package/dist/{Preview-BZCBM5PX.js.map → Preview-LKFMKAIR.js.map} +1 -1
- package/dist/apps/index.d.ts +8 -1
- package/dist/apps/index.js +12 -5
- package/dist/apps/index.js.map +1 -1
- package/dist/{chunk-S7DYUZNB.js → chunk-IM3T7WV2.js} +6 -22
- package/dist/chunk-IM3T7WV2.js.map +1 -0
- package/dist/index.js +2 -2
- package/package.json +1 -1
- package/dist/Preview-BZCBM5PX.js +0 -6
- package/dist/chunk-S7DYUZNB.js.map +0 -1
|
@@ -0,0 +1,486 @@
|
|
|
1
|
+
import { setPdfPreview } from './chunk-IM3T7WV2.js';
|
|
2
|
+
import { toast_default } from './chunk-WIJ45SYD.js';
|
|
3
|
+
import { useWindowManager, WindowTitle } from './chunk-44AH2OXU.js';
|
|
4
|
+
import './chunk-RFTLYCSF.js';
|
|
5
|
+
import { useState, useRef, useCallback, useEffect } from 'react';
|
|
6
|
+
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
7
|
+
|
|
8
|
+
var DEFAULT_SERVER = typeof window !== "undefined" && window.__REACT_OS_SHELL_FILE_SERVER__ || "http://localhost:4000";
|
|
9
|
+
var URL_KEY = "react-os-shell:file-server-url";
|
|
10
|
+
var TOKEN_KEY = "react-os-shell:file-server-token";
|
|
11
|
+
var PREVIEW_EXTS = {
|
|
12
|
+
pdf: "pdf",
|
|
13
|
+
dxf: "dxf",
|
|
14
|
+
jpg: "image",
|
|
15
|
+
jpeg: "image",
|
|
16
|
+
png: "image",
|
|
17
|
+
gif: "image",
|
|
18
|
+
webp: "image",
|
|
19
|
+
svg: "image",
|
|
20
|
+
avif: "image",
|
|
21
|
+
bmp: "image",
|
|
22
|
+
stp: "3d",
|
|
23
|
+
step: "3d",
|
|
24
|
+
stl: "3d",
|
|
25
|
+
obj: "3d",
|
|
26
|
+
gltf: "3d",
|
|
27
|
+
glb: "3d",
|
|
28
|
+
"3mf": "3d",
|
|
29
|
+
iges: "3d",
|
|
30
|
+
igs: "3d",
|
|
31
|
+
ply: "3d",
|
|
32
|
+
fbx: "3d"
|
|
33
|
+
};
|
|
34
|
+
function joinPath(parent, name) {
|
|
35
|
+
if (parent === "/" || parent === "") return "/" + name;
|
|
36
|
+
return parent.replace(/\/$/, "") + "/" + name;
|
|
37
|
+
}
|
|
38
|
+
function parentOf(p) {
|
|
39
|
+
if (p === "/" || p === "") return "/";
|
|
40
|
+
const trimmed = p.replace(/\/$/, "");
|
|
41
|
+
const idx = trimmed.lastIndexOf("/");
|
|
42
|
+
return idx <= 0 ? "/" : trimmed.slice(0, idx);
|
|
43
|
+
}
|
|
44
|
+
function formatSize(bytes) {
|
|
45
|
+
if (!bytes) return "\u2014";
|
|
46
|
+
const units = ["B", "KB", "MB", "GB"];
|
|
47
|
+
let v = bytes, i = 0;
|
|
48
|
+
while (v >= 1024 && i < units.length - 1) {
|
|
49
|
+
v /= 1024;
|
|
50
|
+
i++;
|
|
51
|
+
}
|
|
52
|
+
return `${v < 10 ? v.toFixed(1) : Math.round(v)} ${units[i]}`;
|
|
53
|
+
}
|
|
54
|
+
function formatTime(iso) {
|
|
55
|
+
try {
|
|
56
|
+
const d = new Date(iso);
|
|
57
|
+
return d.toLocaleString(void 0, { dateStyle: "short", timeStyle: "short" });
|
|
58
|
+
} catch {
|
|
59
|
+
return iso;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
function Files() {
|
|
63
|
+
const [server, setServer] = useState(() => {
|
|
64
|
+
if (typeof window === "undefined") return DEFAULT_SERVER;
|
|
65
|
+
return localStorage.getItem(URL_KEY) || DEFAULT_SERVER;
|
|
66
|
+
});
|
|
67
|
+
const [token, setToken] = useState(() => {
|
|
68
|
+
if (typeof window === "undefined") return "";
|
|
69
|
+
return localStorage.getItem(TOKEN_KEY) || "";
|
|
70
|
+
});
|
|
71
|
+
const [user, setUser] = useState(null);
|
|
72
|
+
const [path, setPath] = useState("/");
|
|
73
|
+
const [entries, setEntries] = useState([]);
|
|
74
|
+
const [selected, setSelected] = useState(null);
|
|
75
|
+
const [loading, setLoading] = useState(false);
|
|
76
|
+
const [authError, setAuthError] = useState(null);
|
|
77
|
+
const [isDragging, setIsDragging] = useState(false);
|
|
78
|
+
const dragDepthRef = useRef(0);
|
|
79
|
+
const fileRef = useRef(null);
|
|
80
|
+
const { openPage } = useWindowManager();
|
|
81
|
+
const authedFetch = useCallback(
|
|
82
|
+
(url, init = {}) => {
|
|
83
|
+
const headers = {
|
|
84
|
+
Authorization: `Bearer ${token}`,
|
|
85
|
+
...init.headers || {}
|
|
86
|
+
};
|
|
87
|
+
return fetch(url, { ...init, headers });
|
|
88
|
+
},
|
|
89
|
+
[token]
|
|
90
|
+
);
|
|
91
|
+
const signIn = async () => {
|
|
92
|
+
setAuthError(null);
|
|
93
|
+
try {
|
|
94
|
+
const res = await fetch(`${server.replace(/\/$/, "")}/api/me`, {
|
|
95
|
+
headers: { Authorization: `Bearer ${token}` }
|
|
96
|
+
});
|
|
97
|
+
if (!res.ok) {
|
|
98
|
+
setAuthError(res.status === 401 ? "Invalid token" : `Server error ${res.status}`);
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
const data = await res.json();
|
|
102
|
+
setUser(data.user);
|
|
103
|
+
localStorage.setItem(URL_KEY, server);
|
|
104
|
+
localStorage.setItem(TOKEN_KEY, token);
|
|
105
|
+
} catch (e) {
|
|
106
|
+
setAuthError(e?.message || "Could not reach server");
|
|
107
|
+
}
|
|
108
|
+
};
|
|
109
|
+
const signOut = () => {
|
|
110
|
+
setUser(null);
|
|
111
|
+
setEntries([]);
|
|
112
|
+
setPath("/");
|
|
113
|
+
setSelected(null);
|
|
114
|
+
localStorage.removeItem(TOKEN_KEY);
|
|
115
|
+
};
|
|
116
|
+
const loadDir = useCallback(async (dir) => {
|
|
117
|
+
setLoading(true);
|
|
118
|
+
setSelected(null);
|
|
119
|
+
try {
|
|
120
|
+
const res = await authedFetch(
|
|
121
|
+
`${server.replace(/\/$/, "")}/api/files?path=${encodeURIComponent(dir)}`
|
|
122
|
+
);
|
|
123
|
+
if (!res.ok) {
|
|
124
|
+
if (res.status === 401) {
|
|
125
|
+
setUser(null);
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
128
|
+
const msg = await res.json().catch(() => ({}));
|
|
129
|
+
toast_default.error(msg.error || `Failed to list (${res.status})`);
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
const data = await res.json();
|
|
133
|
+
setEntries(data.entries || []);
|
|
134
|
+
setPath(data.path || dir);
|
|
135
|
+
} catch (e) {
|
|
136
|
+
toast_default.error(e?.message || "Could not reach server");
|
|
137
|
+
} finally {
|
|
138
|
+
setLoading(false);
|
|
139
|
+
}
|
|
140
|
+
}, [authedFetch, server]);
|
|
141
|
+
useEffect(() => {
|
|
142
|
+
if (token && !user && !authError) signIn();
|
|
143
|
+
}, []);
|
|
144
|
+
useEffect(() => {
|
|
145
|
+
if (user) loadDir(path);
|
|
146
|
+
}, [user, path]);
|
|
147
|
+
const openFile = async (entry) => {
|
|
148
|
+
const fullPath = joinPath(path, entry.name);
|
|
149
|
+
const ext = (entry.name.split(".").pop() || "").toLowerCase();
|
|
150
|
+
const kind = PREVIEW_EXTS[ext];
|
|
151
|
+
if (!kind) {
|
|
152
|
+
downloadFile(entry);
|
|
153
|
+
return;
|
|
154
|
+
}
|
|
155
|
+
try {
|
|
156
|
+
const res = await authedFetch(
|
|
157
|
+
`${server.replace(/\/$/, "")}/api/file?path=${encodeURIComponent(fullPath)}`
|
|
158
|
+
);
|
|
159
|
+
if (!res.ok) {
|
|
160
|
+
toast_default.error(`Download failed (${res.status})`);
|
|
161
|
+
return;
|
|
162
|
+
}
|
|
163
|
+
const blob = await res.blob();
|
|
164
|
+
const url = URL.createObjectURL(blob);
|
|
165
|
+
setPdfPreview({ url, filename: entry.name, kind });
|
|
166
|
+
openPage("/preview");
|
|
167
|
+
} catch (e) {
|
|
168
|
+
toast_default.error(e?.message || "Open failed");
|
|
169
|
+
}
|
|
170
|
+
};
|
|
171
|
+
const downloadFile = async (entry) => {
|
|
172
|
+
const fullPath = joinPath(path, entry.name);
|
|
173
|
+
try {
|
|
174
|
+
const res = await authedFetch(
|
|
175
|
+
`${server.replace(/\/$/, "")}/api/file?path=${encodeURIComponent(fullPath)}`
|
|
176
|
+
);
|
|
177
|
+
if (!res.ok) {
|
|
178
|
+
toast_default.error(`Download failed (${res.status})`);
|
|
179
|
+
return;
|
|
180
|
+
}
|
|
181
|
+
const blob = await res.blob();
|
|
182
|
+
const url = URL.createObjectURL(blob);
|
|
183
|
+
const a = document.createElement("a");
|
|
184
|
+
a.href = url;
|
|
185
|
+
a.download = entry.name;
|
|
186
|
+
a.click();
|
|
187
|
+
setTimeout(() => URL.revokeObjectURL(url), 1e3);
|
|
188
|
+
} catch (e) {
|
|
189
|
+
toast_default.error(e?.message || "Download failed");
|
|
190
|
+
}
|
|
191
|
+
};
|
|
192
|
+
const handlePick = () => fileRef.current?.click();
|
|
193
|
+
const uploadFiles = async (files) => {
|
|
194
|
+
const arr = Array.from(files);
|
|
195
|
+
for (const file of arr) {
|
|
196
|
+
const form = new FormData();
|
|
197
|
+
form.append("file", file);
|
|
198
|
+
try {
|
|
199
|
+
const res = await authedFetch(
|
|
200
|
+
`${server.replace(/\/$/, "")}/api/upload?path=${encodeURIComponent(path)}`,
|
|
201
|
+
{ method: "POST", body: form }
|
|
202
|
+
);
|
|
203
|
+
if (!res.ok) {
|
|
204
|
+
const msg = await res.json().catch(() => ({}));
|
|
205
|
+
toast_default.error(`Upload ${file.name}: ${msg.error || res.status}`);
|
|
206
|
+
}
|
|
207
|
+
} catch (e) {
|
|
208
|
+
toast_default.error(`Upload ${file.name}: ${e?.message || "failed"}`);
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
loadDir(path);
|
|
212
|
+
};
|
|
213
|
+
const handleNewFolder = async () => {
|
|
214
|
+
const name = window.prompt("Folder name");
|
|
215
|
+
if (!name) return;
|
|
216
|
+
if (/[\\/]/.test(name)) {
|
|
217
|
+
toast_default.error("Folder names cannot contain slashes");
|
|
218
|
+
return;
|
|
219
|
+
}
|
|
220
|
+
const target = joinPath(path, name);
|
|
221
|
+
const res = await authedFetch(`${server.replace(/\/$/, "")}/api/folder`, {
|
|
222
|
+
method: "POST",
|
|
223
|
+
headers: { "Content-Type": "application/json" },
|
|
224
|
+
body: JSON.stringify({ path: target })
|
|
225
|
+
});
|
|
226
|
+
if (!res.ok) {
|
|
227
|
+
const msg = await res.json().catch(() => ({}));
|
|
228
|
+
toast_default.error(msg.error || `Create folder failed (${res.status})`);
|
|
229
|
+
return;
|
|
230
|
+
}
|
|
231
|
+
loadDir(path);
|
|
232
|
+
};
|
|
233
|
+
const handleRename = async (entry) => {
|
|
234
|
+
const next = window.prompt("New name", entry.name);
|
|
235
|
+
if (!next || next === entry.name) return;
|
|
236
|
+
if (/[\\/]/.test(next)) {
|
|
237
|
+
toast_default.error("Names cannot contain slashes");
|
|
238
|
+
return;
|
|
239
|
+
}
|
|
240
|
+
const from = joinPath(path, entry.name);
|
|
241
|
+
const to = joinPath(path, next);
|
|
242
|
+
const res = await authedFetch(`${server.replace(/\/$/, "")}/api/rename`, {
|
|
243
|
+
method: "POST",
|
|
244
|
+
headers: { "Content-Type": "application/json" },
|
|
245
|
+
body: JSON.stringify({ from, to })
|
|
246
|
+
});
|
|
247
|
+
if (!res.ok) {
|
|
248
|
+
const msg = await res.json().catch(() => ({}));
|
|
249
|
+
toast_default.error(msg.error || `Rename failed (${res.status})`);
|
|
250
|
+
return;
|
|
251
|
+
}
|
|
252
|
+
loadDir(path);
|
|
253
|
+
};
|
|
254
|
+
const handleDelete = async (entry) => {
|
|
255
|
+
if (!window.confirm(`Delete "${entry.name}"${entry.kind === "folder" ? " and everything inside" : ""}?`)) return;
|
|
256
|
+
const target = joinPath(path, entry.name);
|
|
257
|
+
const res = await authedFetch(
|
|
258
|
+
`${server.replace(/\/$/, "")}/api/files?path=${encodeURIComponent(target)}`,
|
|
259
|
+
{ method: "DELETE" }
|
|
260
|
+
);
|
|
261
|
+
if (!res.ok) {
|
|
262
|
+
const msg = await res.json().catch(() => ({}));
|
|
263
|
+
toast_default.error(msg.error || `Delete failed (${res.status})`);
|
|
264
|
+
return;
|
|
265
|
+
}
|
|
266
|
+
loadDir(path);
|
|
267
|
+
};
|
|
268
|
+
const resetDrag = () => {
|
|
269
|
+
dragDepthRef.current = 0;
|
|
270
|
+
setIsDragging(false);
|
|
271
|
+
};
|
|
272
|
+
useEffect(() => {
|
|
273
|
+
const reset = () => resetDrag();
|
|
274
|
+
window.addEventListener("dragend", reset);
|
|
275
|
+
window.addEventListener("drop", reset);
|
|
276
|
+
return () => {
|
|
277
|
+
window.removeEventListener("dragend", reset);
|
|
278
|
+
window.removeEventListener("drop", reset);
|
|
279
|
+
};
|
|
280
|
+
}, []);
|
|
281
|
+
if (!user) {
|
|
282
|
+
return /* @__PURE__ */ jsxs("div", { className: "flex flex-col h-full bg-white", children: [
|
|
283
|
+
/* @__PURE__ */ jsx(WindowTitle, { title: "Files - Sign in" }),
|
|
284
|
+
/* @__PURE__ */ jsx("div", { className: "flex flex-1 items-center justify-center p-6", children: /* @__PURE__ */ jsxs("div", { className: "w-full max-w-sm space-y-3", children: [
|
|
285
|
+
/* @__PURE__ */ jsx("h2", { className: "text-base font-semibold text-gray-800", children: "Connect to file server" }),
|
|
286
|
+
/* @__PURE__ */ jsxs("p", { className: "text-xs text-gray-500", children: [
|
|
287
|
+
"Paste your bearer token from ",
|
|
288
|
+
/* @__PURE__ */ jsx("span", { className: "font-mono", children: "users.json" }),
|
|
289
|
+
". See ",
|
|
290
|
+
/* @__PURE__ */ jsx("span", { className: "font-mono", children: "examples/file-server" }),
|
|
291
|
+
" for setup."
|
|
292
|
+
] }),
|
|
293
|
+
/* @__PURE__ */ jsxs("label", { className: "block", children: [
|
|
294
|
+
/* @__PURE__ */ jsx("span", { className: "block text-[11px] uppercase tracking-wide text-gray-500 mb-1", children: "Server URL" }),
|
|
295
|
+
/* @__PURE__ */ jsx(
|
|
296
|
+
"input",
|
|
297
|
+
{
|
|
298
|
+
type: "text",
|
|
299
|
+
value: server,
|
|
300
|
+
onChange: (e) => setServer(e.target.value),
|
|
301
|
+
className: "w-full text-sm px-2 py-1.5 border border-gray-300 rounded font-mono"
|
|
302
|
+
}
|
|
303
|
+
)
|
|
304
|
+
] }),
|
|
305
|
+
/* @__PURE__ */ jsxs("label", { className: "block", children: [
|
|
306
|
+
/* @__PURE__ */ jsx("span", { className: "block text-[11px] uppercase tracking-wide text-gray-500 mb-1", children: "Bearer token" }),
|
|
307
|
+
/* @__PURE__ */ jsx(
|
|
308
|
+
"input",
|
|
309
|
+
{
|
|
310
|
+
type: "password",
|
|
311
|
+
value: token,
|
|
312
|
+
onChange: (e) => setToken(e.target.value),
|
|
313
|
+
onKeyDown: (e) => {
|
|
314
|
+
if (e.key === "Enter") signIn();
|
|
315
|
+
},
|
|
316
|
+
className: "w-full text-sm px-2 py-1.5 border border-gray-300 rounded font-mono",
|
|
317
|
+
placeholder: "paste token\u2026"
|
|
318
|
+
}
|
|
319
|
+
)
|
|
320
|
+
] }),
|
|
321
|
+
authError && /* @__PURE__ */ jsx("div", { className: "text-xs text-red-600", children: authError }),
|
|
322
|
+
/* @__PURE__ */ jsx(
|
|
323
|
+
"button",
|
|
324
|
+
{
|
|
325
|
+
onClick: signIn,
|
|
326
|
+
disabled: !token,
|
|
327
|
+
className: "w-full px-3 py-1.5 text-sm bg-blue-500 text-white rounded hover:bg-blue-600 disabled:opacity-40",
|
|
328
|
+
children: "Connect"
|
|
329
|
+
}
|
|
330
|
+
)
|
|
331
|
+
] }) })
|
|
332
|
+
] });
|
|
333
|
+
}
|
|
334
|
+
const segments = path === "/" ? [] : path.split("/").filter(Boolean);
|
|
335
|
+
return /* @__PURE__ */ jsxs(
|
|
336
|
+
"div",
|
|
337
|
+
{
|
|
338
|
+
className: "relative flex flex-col h-full bg-white",
|
|
339
|
+
onDragEnter: (e) => {
|
|
340
|
+
if (!e.dataTransfer?.types?.includes?.("Files")) return;
|
|
341
|
+
e.preventDefault();
|
|
342
|
+
dragDepthRef.current++;
|
|
343
|
+
if (!isDragging) setIsDragging(true);
|
|
344
|
+
},
|
|
345
|
+
onDragOver: (e) => {
|
|
346
|
+
if (!e.dataTransfer?.types?.includes?.("Files")) return;
|
|
347
|
+
e.preventDefault();
|
|
348
|
+
},
|
|
349
|
+
onDragLeave: () => {
|
|
350
|
+
if (dragDepthRef.current > 0) dragDepthRef.current--;
|
|
351
|
+
if (dragDepthRef.current === 0) setIsDragging(false);
|
|
352
|
+
},
|
|
353
|
+
onDrop: (e) => {
|
|
354
|
+
e.preventDefault();
|
|
355
|
+
resetDrag();
|
|
356
|
+
if (e.dataTransfer.files?.length) uploadFiles(e.dataTransfer.files);
|
|
357
|
+
},
|
|
358
|
+
children: [
|
|
359
|
+
/* @__PURE__ */ jsx(WindowTitle, { title: `Files - ${user}${path}` }),
|
|
360
|
+
/* @__PURE__ */ jsx(
|
|
361
|
+
"input",
|
|
362
|
+
{
|
|
363
|
+
ref: fileRef,
|
|
364
|
+
type: "file",
|
|
365
|
+
multiple: true,
|
|
366
|
+
className: "hidden",
|
|
367
|
+
onChange: (e) => {
|
|
368
|
+
if (e.target.files?.length) uploadFiles(e.target.files);
|
|
369
|
+
if (fileRef.current) fileRef.current.value = "";
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
),
|
|
373
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1 px-2 py-1.5 border-b border-gray-200 bg-gray-50 shrink-0 text-xs", children: [
|
|
374
|
+
/* @__PURE__ */ jsx(
|
|
375
|
+
"button",
|
|
376
|
+
{
|
|
377
|
+
onClick: () => setPath(parentOf(path)),
|
|
378
|
+
disabled: path === "/",
|
|
379
|
+
className: "px-2 py-1 rounded hover:bg-gray-200 disabled:opacity-30 text-gray-600",
|
|
380
|
+
title: "Parent folder",
|
|
381
|
+
children: /* @__PURE__ */ jsx("svg", { className: "h-3.5 w-3.5", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 2, children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M10.5 19.5L3 12m0 0l7.5-7.5M3 12h18" }) })
|
|
382
|
+
}
|
|
383
|
+
),
|
|
384
|
+
/* @__PURE__ */ jsxs("div", { className: "flex-1 flex items-center gap-0.5 text-gray-700 truncate min-w-0", children: [
|
|
385
|
+
/* @__PURE__ */ jsx("button", { onClick: () => setPath("/"), className: "px-1.5 py-0.5 rounded hover:bg-gray-200 font-medium", children: user }),
|
|
386
|
+
segments.map((seg, i) => /* @__PURE__ */ jsxs("span", { className: "flex items-center gap-0.5", children: [
|
|
387
|
+
/* @__PURE__ */ jsx("span", { className: "text-gray-400", children: "/" }),
|
|
388
|
+
/* @__PURE__ */ jsx(
|
|
389
|
+
"button",
|
|
390
|
+
{
|
|
391
|
+
onClick: () => setPath("/" + segments.slice(0, i + 1).join("/")),
|
|
392
|
+
className: "px-1.5 py-0.5 rounded hover:bg-gray-200",
|
|
393
|
+
children: seg
|
|
394
|
+
}
|
|
395
|
+
)
|
|
396
|
+
] }, i))
|
|
397
|
+
] }),
|
|
398
|
+
/* @__PURE__ */ jsx("button", { onClick: () => loadDir(path), className: "px-2 py-1 rounded hover:bg-gray-200 text-gray-600", title: "Refresh", children: /* @__PURE__ */ jsx("svg", { className: "h-3.5 w-3.5", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M16.023 9.348h4.992V4.356M2.985 19.644v-4.992h4.992M3.05 9.348a9 9 0 0114.85-3.36L21.015 9.348m0 5.304a9 9 0 01-14.85 3.36l-3.115-3.36" }) }) }),
|
|
399
|
+
/* @__PURE__ */ jsxs("button", { onClick: handleNewFolder, className: "px-2 py-1 rounded hover:bg-gray-200 text-gray-600 flex items-center gap-1", children: [
|
|
400
|
+
/* @__PURE__ */ jsx("svg", { className: "h-3.5 w-3.5", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.5, children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M12 10.5v6m3-3H9m4.06-7.19l-2.12-2.12a1.5 1.5 0 00-1.061-.44H4.5A2.25 2.25 0 002.25 6v12a2.25 2.25 0 002.25 2.25h15A2.25 2.25 0 0021.75 18V9a2.25 2.25 0 00-2.25-2.25h-5.379a1.5 1.5 0 01-1.06-.44z" }) }),
|
|
401
|
+
"New Folder"
|
|
402
|
+
] }),
|
|
403
|
+
/* @__PURE__ */ jsxs("button", { onClick: handlePick, className: "px-2 py-1 rounded bg-blue-500 text-white hover:bg-blue-600 flex items-center gap-1", children: [
|
|
404
|
+
/* @__PURE__ */ jsx("svg", { className: "h-3.5 w-3.5", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.8, children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M3 16.5v2.25A2.25 2.25 0 005.25 21h13.5A2.25 2.25 0 0021 18.75V16.5M7.5 7.5L12 3m0 0l4.5 4.5M12 3v13.5" }) }),
|
|
405
|
+
"Upload"
|
|
406
|
+
] }),
|
|
407
|
+
/* @__PURE__ */ jsx("div", { className: "h-4 w-px bg-gray-300 mx-1" }),
|
|
408
|
+
/* @__PURE__ */ jsx("span", { className: "text-[10px] text-gray-400", children: user }),
|
|
409
|
+
/* @__PURE__ */ jsx("button", { onClick: signOut, className: "px-1.5 py-0.5 rounded hover:bg-gray-200 text-gray-500 text-[10px]", children: "sign out" })
|
|
410
|
+
] }),
|
|
411
|
+
/* @__PURE__ */ jsx("div", { className: "flex-1 overflow-auto", children: loading ? /* @__PURE__ */ jsx("div", { className: "p-6 text-center text-sm text-gray-400", children: "Loading\u2026" }) : entries.length === 0 ? /* @__PURE__ */ jsxs("div", { className: "p-10 text-center text-sm text-gray-400", children: [
|
|
412
|
+
"Empty folder. Drop files here or click ",
|
|
413
|
+
/* @__PURE__ */ jsx("span", { className: "font-medium", children: "Upload" }),
|
|
414
|
+
"."
|
|
415
|
+
] }) : /* @__PURE__ */ jsxs("table", { className: "w-full text-sm", children: [
|
|
416
|
+
/* @__PURE__ */ jsx("thead", { className: "bg-gray-50 text-[11px] uppercase tracking-wide text-gray-500", children: /* @__PURE__ */ jsxs("tr", { children: [
|
|
417
|
+
/* @__PURE__ */ jsx("th", { className: "text-left font-medium px-3 py-1.5", children: "Name" }),
|
|
418
|
+
/* @__PURE__ */ jsx("th", { className: "text-right font-medium px-3 py-1.5 w-24", children: "Size" }),
|
|
419
|
+
/* @__PURE__ */ jsx("th", { className: "text-right font-medium px-3 py-1.5 w-40", children: "Modified" }),
|
|
420
|
+
/* @__PURE__ */ jsx("th", { className: "w-32" })
|
|
421
|
+
] }) }),
|
|
422
|
+
/* @__PURE__ */ jsx("tbody", { children: entries.map((e) => /* @__PURE__ */ jsxs(
|
|
423
|
+
"tr",
|
|
424
|
+
{
|
|
425
|
+
onClick: () => setSelected(e.name),
|
|
426
|
+
onDoubleClick: () => {
|
|
427
|
+
if (e.kind === "folder") setPath(joinPath(path, e.name));
|
|
428
|
+
else openFile(e);
|
|
429
|
+
},
|
|
430
|
+
className: `cursor-default border-b border-gray-100 ${selected === e.name ? "bg-blue-50" : "hover:bg-gray-50"}`,
|
|
431
|
+
children: [
|
|
432
|
+
/* @__PURE__ */ jsxs("td", { className: "px-3 py-1.5 flex items-center gap-2", children: [
|
|
433
|
+
e.kind === "folder" ? /* @__PURE__ */ jsx("svg", { className: "h-4 w-4 text-amber-500 shrink-0", fill: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx("path", { d: "M2.25 7.125A2.25 2.25 0 014.5 4.875h4.504c.61 0 1.193.243 1.624.673l1.494 1.494a.75.75 0 00.53.22h7.098A2.25 2.25 0 0122 9.51v8.366A2.25 2.25 0 0119.75 20.125H4.25A2.25 2.25 0 012 17.875V7.125z" }) }) : /* @__PURE__ */ jsx("svg", { className: "h-4 w-4 text-gray-400 shrink-0", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.5, children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M19.5 14.25v-2.625a3.375 3.375 0 00-3.375-3.375h-1.5A1.125 1.125 0 0113.5 7.125v-1.5a3.375 3.375 0 00-3.375-3.375H8.25m2.25 0H5.625c-.621 0-1.125.504-1.125 1.125v17.25c0 .621.504 1.125 1.125 1.125h12.75c.621 0 1.125-.504 1.125-1.125V11.25a9 9 0 00-9-9z" }) }),
|
|
434
|
+
/* @__PURE__ */ jsx("span", { className: "truncate", title: e.name, children: e.name })
|
|
435
|
+
] }),
|
|
436
|
+
/* @__PURE__ */ jsx("td", { className: "px-3 py-1.5 text-right tabular-nums text-gray-500", children: e.kind === "folder" ? "\u2014" : formatSize(e.size) }),
|
|
437
|
+
/* @__PURE__ */ jsx("td", { className: "px-3 py-1.5 text-right text-gray-500 tabular-nums", children: formatTime(e.modifiedAt) }),
|
|
438
|
+
/* @__PURE__ */ jsxs("td", { className: "px-3 py-1.5 text-right whitespace-nowrap", children: [
|
|
439
|
+
e.kind === "file" && /* @__PURE__ */ jsx(
|
|
440
|
+
"button",
|
|
441
|
+
{
|
|
442
|
+
onClick: (ev) => {
|
|
443
|
+
ev.stopPropagation();
|
|
444
|
+
downloadFile(e);
|
|
445
|
+
},
|
|
446
|
+
className: "px-1.5 py-0.5 rounded hover:bg-gray-200 text-gray-500 text-[11px]",
|
|
447
|
+
children: "Download"
|
|
448
|
+
}
|
|
449
|
+
),
|
|
450
|
+
/* @__PURE__ */ jsx(
|
|
451
|
+
"button",
|
|
452
|
+
{
|
|
453
|
+
onClick: (ev) => {
|
|
454
|
+
ev.stopPropagation();
|
|
455
|
+
handleRename(e);
|
|
456
|
+
},
|
|
457
|
+
className: "px-1.5 py-0.5 rounded hover:bg-gray-200 text-gray-500 text-[11px] ml-1",
|
|
458
|
+
children: "Rename"
|
|
459
|
+
}
|
|
460
|
+
),
|
|
461
|
+
/* @__PURE__ */ jsx(
|
|
462
|
+
"button",
|
|
463
|
+
{
|
|
464
|
+
onClick: (ev) => {
|
|
465
|
+
ev.stopPropagation();
|
|
466
|
+
handleDelete(e);
|
|
467
|
+
},
|
|
468
|
+
className: "px-1.5 py-0.5 rounded hover:bg-red-100 text-red-600 text-[11px] ml-1",
|
|
469
|
+
children: "Delete"
|
|
470
|
+
}
|
|
471
|
+
)
|
|
472
|
+
] })
|
|
473
|
+
]
|
|
474
|
+
},
|
|
475
|
+
e.name
|
|
476
|
+
)) })
|
|
477
|
+
] }) }),
|
|
478
|
+
isDragging && /* @__PURE__ */ jsx("div", { className: "absolute inset-0 bg-blue-500/15 border-4 border-dashed border-blue-500 pointer-events-none flex items-center justify-center z-20", children: /* @__PURE__ */ jsx("div", { className: "px-4 py-2 rounded-md bg-blue-600 text-white text-sm font-medium shadow-lg", children: "Drop to upload" }) })
|
|
479
|
+
]
|
|
480
|
+
}
|
|
481
|
+
);
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
export { Files as default };
|
|
485
|
+
//# sourceMappingURL=Files-PPKWOJWV.js.map
|
|
486
|
+
//# sourceMappingURL=Files-PPKWOJWV.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/apps/Files.tsx"],"names":[],"mappings":"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","file":"Files-PPKWOJWV.js","sourcesContent":["/**\n * Files — browser for the per-user file-server\n * (see examples/file-server). Lists the user's folder, navigates,\n * uploads (button + drag-from-OS), creates folders, renames, deletes,\n * and opens supported files via the Preview window.\n *\n * Server URL is configurable per-instance through an in-app field, then\n * persisted to localStorage. Bearer token same — paste it once, stays.\n */\nimport { useState, useEffect, useRef, useCallback } from 'react';\nimport { WindowTitle } from '../shell/Modal';\nimport { useWindowManager } from '../shell/WindowManager';\nimport toast from '../shell/toast';\nimport { setPdfPreview } from './Preview';\n\nconst DEFAULT_SERVER =\n (typeof window !== 'undefined' && (window as any).__REACT_OS_SHELL_FILE_SERVER__) ||\n 'http://localhost:4000';\nconst URL_KEY = 'react-os-shell:file-server-url';\nconst TOKEN_KEY = 'react-os-shell:file-server-token';\n\nconst PREVIEW_EXTS: Record<string, 'pdf' | 'image' | 'dxf' | '3d'> = {\n pdf: 'pdf',\n dxf: 'dxf',\n jpg: 'image', jpeg: 'image', png: 'image', gif: 'image',\n webp: 'image', svg: 'image', avif: 'image', bmp: 'image',\n stp: '3d', step: '3d', stl: '3d', obj: '3d',\n gltf: '3d', glb: '3d', '3mf': '3d', iges: '3d', igs: '3d', ply: '3d', fbx: '3d',\n};\n\ninterface FileEntry {\n name: string;\n kind: 'file' | 'folder';\n size: number;\n modifiedAt: string;\n}\n\nfunction joinPath(parent: string, name: string) {\n if (parent === '/' || parent === '') return '/' + name;\n return parent.replace(/\\/$/, '') + '/' + name;\n}\n\nfunction parentOf(p: string) {\n if (p === '/' || p === '') return '/';\n const trimmed = p.replace(/\\/$/, '');\n const idx = trimmed.lastIndexOf('/');\n return idx <= 0 ? '/' : trimmed.slice(0, idx);\n}\n\nfunction formatSize(bytes: number) {\n if (!bytes) return '—';\n const units = ['B', 'KB', 'MB', 'GB'];\n let v = bytes, i = 0;\n while (v >= 1024 && i < units.length - 1) { v /= 1024; i++; }\n return `${v < 10 ? v.toFixed(1) : Math.round(v)} ${units[i]}`;\n}\n\nfunction formatTime(iso: string) {\n try {\n const d = new Date(iso);\n return d.toLocaleString(undefined, { dateStyle: 'short', timeStyle: 'short' });\n } catch { return iso; }\n}\n\nexport default function Files() {\n const [server, setServer] = useState<string>(() => {\n if (typeof window === 'undefined') return DEFAULT_SERVER;\n return localStorage.getItem(URL_KEY) || DEFAULT_SERVER;\n });\n const [token, setToken] = useState<string>(() => {\n if (typeof window === 'undefined') return '';\n return localStorage.getItem(TOKEN_KEY) || '';\n });\n const [user, setUser] = useState<string | null>(null);\n const [path, setPath] = useState('/');\n const [entries, setEntries] = useState<FileEntry[]>([]);\n const [selected, setSelected] = useState<string | null>(null);\n const [loading, setLoading] = useState(false);\n const [authError, setAuthError] = useState<string | null>(null);\n const [isDragging, setIsDragging] = useState(false);\n const dragDepthRef = useRef(0);\n const fileRef = useRef<HTMLInputElement>(null);\n\n const { openPage } = useWindowManager();\n\n const authedFetch = useCallback(\n (url: string, init: RequestInit = {}) => {\n const headers: Record<string, string> = {\n Authorization: `Bearer ${token}`,\n ...((init.headers as Record<string, string>) || {}),\n };\n return fetch(url, { ...init, headers });\n },\n [token],\n );\n\n const signIn = async () => {\n setAuthError(null);\n try {\n const res = await fetch(`${server.replace(/\\/$/, '')}/api/me`, {\n headers: { Authorization: `Bearer ${token}` },\n });\n if (!res.ok) {\n setAuthError(res.status === 401 ? 'Invalid token' : `Server error ${res.status}`);\n return;\n }\n const data = await res.json();\n setUser(data.user);\n localStorage.setItem(URL_KEY, server);\n localStorage.setItem(TOKEN_KEY, token);\n } catch (e: any) {\n setAuthError(e?.message || 'Could not reach server');\n }\n };\n\n const signOut = () => {\n setUser(null);\n setEntries([]);\n setPath('/');\n setSelected(null);\n localStorage.removeItem(TOKEN_KEY);\n };\n\n const loadDir = useCallback(async (dir: string) => {\n setLoading(true);\n setSelected(null);\n try {\n const res = await authedFetch(\n `${server.replace(/\\/$/, '')}/api/files?path=${encodeURIComponent(dir)}`,\n );\n if (!res.ok) {\n if (res.status === 401) { setUser(null); return; }\n const msg = await res.json().catch(() => ({} as any));\n toast.error(msg.error || `Failed to list (${res.status})`);\n return;\n }\n const data = await res.json();\n setEntries(data.entries || []);\n setPath(data.path || dir);\n } catch (e: any) {\n toast.error(e?.message || 'Could not reach server');\n } finally {\n setLoading(false);\n }\n }, [authedFetch, server]);\n\n // Auto-sign-in if token already in localStorage (validate by hitting /api/me).\n useEffect(() => {\n if (token && !user && !authError) signIn();\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n // (Re)load on path change once authenticated.\n useEffect(() => {\n if (user) loadDir(path);\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [user, path]);\n\n // Open a file: fetch as Blob, route to Preview if extension is supported.\n const openFile = async (entry: FileEntry) => {\n const fullPath = joinPath(path, entry.name);\n const ext = (entry.name.split('.').pop() || '').toLowerCase();\n const kind = PREVIEW_EXTS[ext];\n if (!kind) {\n // Just download.\n downloadFile(entry);\n return;\n }\n try {\n const res = await authedFetch(\n `${server.replace(/\\/$/, '')}/api/file?path=${encodeURIComponent(fullPath)}`,\n );\n if (!res.ok) {\n toast.error(`Download failed (${res.status})`);\n return;\n }\n const blob = await res.blob();\n const url = URL.createObjectURL(blob);\n setPdfPreview({ url, filename: entry.name, kind });\n openPage('/preview');\n } catch (e: any) {\n toast.error(e?.message || 'Open failed');\n }\n };\n\n const downloadFile = async (entry: FileEntry) => {\n const fullPath = joinPath(path, entry.name);\n try {\n const res = await authedFetch(\n `${server.replace(/\\/$/, '')}/api/file?path=${encodeURIComponent(fullPath)}`,\n );\n if (!res.ok) { toast.error(`Download failed (${res.status})`); return; }\n const blob = await res.blob();\n const url = URL.createObjectURL(blob);\n const a = document.createElement('a');\n a.href = url;\n a.download = entry.name;\n a.click();\n setTimeout(() => URL.revokeObjectURL(url), 1000);\n } catch (e: any) {\n toast.error(e?.message || 'Download failed');\n }\n };\n\n const handlePick = () => fileRef.current?.click();\n\n const uploadFiles = async (files: FileList | File[]) => {\n const arr = Array.from(files);\n for (const file of arr) {\n const form = new FormData();\n form.append('file', file);\n try {\n const res = await authedFetch(\n `${server.replace(/\\/$/, '')}/api/upload?path=${encodeURIComponent(path)}`,\n { method: 'POST', body: form },\n );\n if (!res.ok) {\n const msg = await res.json().catch(() => ({} as any));\n toast.error(`Upload ${file.name}: ${msg.error || res.status}`);\n }\n } catch (e: any) {\n toast.error(`Upload ${file.name}: ${e?.message || 'failed'}`);\n }\n }\n loadDir(path);\n };\n\n const handleNewFolder = async () => {\n const name = window.prompt('Folder name');\n if (!name) return;\n if (/[\\\\/]/.test(name)) { toast.error('Folder names cannot contain slashes'); return; }\n const target = joinPath(path, name);\n const res = await authedFetch(`${server.replace(/\\/$/, '')}/api/folder`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ path: target }),\n });\n if (!res.ok) {\n const msg = await res.json().catch(() => ({} as any));\n toast.error(msg.error || `Create folder failed (${res.status})`);\n return;\n }\n loadDir(path);\n };\n\n const handleRename = async (entry: FileEntry) => {\n const next = window.prompt('New name', entry.name);\n if (!next || next === entry.name) return;\n if (/[\\\\/]/.test(next)) { toast.error('Names cannot contain slashes'); return; }\n const from = joinPath(path, entry.name);\n const to = joinPath(path, next);\n const res = await authedFetch(`${server.replace(/\\/$/, '')}/api/rename`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ from, to }),\n });\n if (!res.ok) {\n const msg = await res.json().catch(() => ({} as any));\n toast.error(msg.error || `Rename failed (${res.status})`);\n return;\n }\n loadDir(path);\n };\n\n const handleDelete = async (entry: FileEntry) => {\n if (!window.confirm(`Delete \"${entry.name}\"${entry.kind === 'folder' ? ' and everything inside' : ''}?`)) return;\n const target = joinPath(path, entry.name);\n const res = await authedFetch(\n `${server.replace(/\\/$/, '')}/api/files?path=${encodeURIComponent(target)}`,\n { method: 'DELETE' },\n );\n if (!res.ok) {\n const msg = await res.json().catch(() => ({} as any));\n toast.error(msg.error || `Delete failed (${res.status})`);\n return;\n }\n loadDir(path);\n };\n\n // Drag overlay reset helpers (mirror Preview).\n const resetDrag = () => { dragDepthRef.current = 0; setIsDragging(false); };\n useEffect(() => {\n const reset = () => resetDrag();\n window.addEventListener('dragend', reset);\n window.addEventListener('drop', reset);\n return () => {\n window.removeEventListener('dragend', reset);\n window.removeEventListener('drop', reset);\n };\n }, []);\n\n // ── render ─────────────────────────────────────────────────────────────\n if (!user) {\n return (\n <div className=\"flex flex-col h-full bg-white\">\n <WindowTitle title=\"Files - Sign in\" />\n <div className=\"flex flex-1 items-center justify-center p-6\">\n <div className=\"w-full max-w-sm space-y-3\">\n <h2 className=\"text-base font-semibold text-gray-800\">Connect to file server</h2>\n <p className=\"text-xs text-gray-500\">\n Paste your bearer token from <span className=\"font-mono\">users.json</span>.\n See <span className=\"font-mono\">examples/file-server</span> for setup.\n </p>\n <label className=\"block\">\n <span className=\"block text-[11px] uppercase tracking-wide text-gray-500 mb-1\">Server URL</span>\n <input\n type=\"text\"\n value={server}\n onChange={(e) => setServer(e.target.value)}\n className=\"w-full text-sm px-2 py-1.5 border border-gray-300 rounded font-mono\"\n />\n </label>\n <label className=\"block\">\n <span className=\"block text-[11px] uppercase tracking-wide text-gray-500 mb-1\">Bearer token</span>\n <input\n type=\"password\"\n value={token}\n onChange={(e) => setToken(e.target.value)}\n onKeyDown={(e) => { if (e.key === 'Enter') signIn(); }}\n className=\"w-full text-sm px-2 py-1.5 border border-gray-300 rounded font-mono\"\n placeholder=\"paste token…\"\n />\n </label>\n {authError && <div className=\"text-xs text-red-600\">{authError}</div>}\n <button\n onClick={signIn}\n disabled={!token}\n className=\"w-full px-3 py-1.5 text-sm bg-blue-500 text-white rounded hover:bg-blue-600 disabled:opacity-40\"\n >\n Connect\n </button>\n </div>\n </div>\n </div>\n );\n }\n\n // Breadcrumb segments\n const segments = path === '/' ? [] : path.split('/').filter(Boolean);\n\n return (\n <div\n className=\"relative flex flex-col h-full bg-white\"\n onDragEnter={(e) => {\n if (!e.dataTransfer?.types?.includes?.('Files')) return;\n e.preventDefault();\n dragDepthRef.current++;\n if (!isDragging) setIsDragging(true);\n }}\n onDragOver={(e) => {\n if (!e.dataTransfer?.types?.includes?.('Files')) return;\n e.preventDefault();\n }}\n onDragLeave={() => {\n if (dragDepthRef.current > 0) dragDepthRef.current--;\n if (dragDepthRef.current === 0) setIsDragging(false);\n }}\n onDrop={(e) => {\n e.preventDefault();\n resetDrag();\n if (e.dataTransfer.files?.length) uploadFiles(e.dataTransfer.files);\n }}\n >\n <WindowTitle title={`Files - ${user}${path}`} />\n <input\n ref={fileRef}\n type=\"file\"\n multiple\n className=\"hidden\"\n onChange={(e) => {\n if (e.target.files?.length) uploadFiles(e.target.files);\n if (fileRef.current) fileRef.current.value = '';\n }}\n />\n\n {/* Toolbar */}\n <div className=\"flex items-center gap-1 px-2 py-1.5 border-b border-gray-200 bg-gray-50 shrink-0 text-xs\">\n <button\n onClick={() => setPath(parentOf(path))}\n disabled={path === '/'}\n className=\"px-2 py-1 rounded hover:bg-gray-200 disabled:opacity-30 text-gray-600\"\n title=\"Parent folder\"\n >\n <svg className=\"h-3.5 w-3.5\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" strokeWidth={2}>\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M10.5 19.5L3 12m0 0l7.5-7.5M3 12h18\" />\n </svg>\n </button>\n\n {/* Breadcrumbs */}\n <div className=\"flex-1 flex items-center gap-0.5 text-gray-700 truncate min-w-0\">\n <button onClick={() => setPath('/')} className=\"px-1.5 py-0.5 rounded hover:bg-gray-200 font-medium\">{user}</button>\n {segments.map((seg, i) => (\n <span key={i} className=\"flex items-center gap-0.5\">\n <span className=\"text-gray-400\">/</span>\n <button\n onClick={() => setPath('/' + segments.slice(0, i + 1).join('/'))}\n className=\"px-1.5 py-0.5 rounded hover:bg-gray-200\"\n >\n {seg}\n </button>\n </span>\n ))}\n </div>\n\n <button onClick={() => loadDir(path)} className=\"px-2 py-1 rounded hover:bg-gray-200 text-gray-600\" title=\"Refresh\">\n <svg className=\"h-3.5 w-3.5\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" strokeWidth={1.8}>\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M16.023 9.348h4.992V4.356M2.985 19.644v-4.992h4.992M3.05 9.348a9 9 0 0114.85-3.36L21.015 9.348m0 5.304a9 9 0 01-14.85 3.36l-3.115-3.36\" />\n </svg>\n </button>\n <button onClick={handleNewFolder} className=\"px-2 py-1 rounded hover:bg-gray-200 text-gray-600 flex items-center gap-1\">\n <svg className=\"h-3.5 w-3.5\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" strokeWidth={1.5}>\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M12 10.5v6m3-3H9m4.06-7.19l-2.12-2.12a1.5 1.5 0 00-1.061-.44H4.5A2.25 2.25 0 002.25 6v12a2.25 2.25 0 002.25 2.25h15A2.25 2.25 0 0021.75 18V9a2.25 2.25 0 00-2.25-2.25h-5.379a1.5 1.5 0 01-1.06-.44z\" />\n </svg>\n New Folder\n </button>\n <button onClick={handlePick} className=\"px-2 py-1 rounded bg-blue-500 text-white hover:bg-blue-600 flex items-center gap-1\">\n <svg className=\"h-3.5 w-3.5\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" strokeWidth={1.8}>\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M3 16.5v2.25A2.25 2.25 0 005.25 21h13.5A2.25 2.25 0 0021 18.75V16.5M7.5 7.5L12 3m0 0l4.5 4.5M12 3v13.5\" />\n </svg>\n Upload\n </button>\n\n <div className=\"h-4 w-px bg-gray-300 mx-1\" />\n <span className=\"text-[10px] text-gray-400\">{user}</span>\n <button onClick={signOut} className=\"px-1.5 py-0.5 rounded hover:bg-gray-200 text-gray-500 text-[10px]\">sign out</button>\n </div>\n\n {/* List */}\n <div className=\"flex-1 overflow-auto\">\n {loading ? (\n <div className=\"p-6 text-center text-sm text-gray-400\">Loading…</div>\n ) : entries.length === 0 ? (\n <div className=\"p-10 text-center text-sm text-gray-400\">\n Empty folder. Drop files here or click <span className=\"font-medium\">Upload</span>.\n </div>\n ) : (\n <table className=\"w-full text-sm\">\n <thead className=\"bg-gray-50 text-[11px] uppercase tracking-wide text-gray-500\">\n <tr>\n <th className=\"text-left font-medium px-3 py-1.5\">Name</th>\n <th className=\"text-right font-medium px-3 py-1.5 w-24\">Size</th>\n <th className=\"text-right font-medium px-3 py-1.5 w-40\">Modified</th>\n <th className=\"w-32\" />\n </tr>\n </thead>\n <tbody>\n {entries.map((e) => (\n <tr\n key={e.name}\n onClick={() => setSelected(e.name)}\n onDoubleClick={() => {\n if (e.kind === 'folder') setPath(joinPath(path, e.name));\n else openFile(e);\n }}\n className={`cursor-default border-b border-gray-100 ${selected === e.name ? 'bg-blue-50' : 'hover:bg-gray-50'}`}\n >\n <td className=\"px-3 py-1.5 flex items-center gap-2\">\n {e.kind === 'folder' ? (\n <svg className=\"h-4 w-4 text-amber-500 shrink-0\" fill=\"currentColor\" viewBox=\"0 0 24 24\"><path d=\"M2.25 7.125A2.25 2.25 0 014.5 4.875h4.504c.61 0 1.193.243 1.624.673l1.494 1.494a.75.75 0 00.53.22h7.098A2.25 2.25 0 0122 9.51v8.366A2.25 2.25 0 0119.75 20.125H4.25A2.25 2.25 0 012 17.875V7.125z\" /></svg>\n ) : (\n <svg className=\"h-4 w-4 text-gray-400 shrink-0\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" strokeWidth={1.5}><path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M19.5 14.25v-2.625a3.375 3.375 0 00-3.375-3.375h-1.5A1.125 1.125 0 0113.5 7.125v-1.5a3.375 3.375 0 00-3.375-3.375H8.25m2.25 0H5.625c-.621 0-1.125.504-1.125 1.125v17.25c0 .621.504 1.125 1.125 1.125h12.75c.621 0 1.125-.504 1.125-1.125V11.25a9 9 0 00-9-9z\" /></svg>\n )}\n <span className=\"truncate\" title={e.name}>{e.name}</span>\n </td>\n <td className=\"px-3 py-1.5 text-right tabular-nums text-gray-500\">\n {e.kind === 'folder' ? '—' : formatSize(e.size)}\n </td>\n <td className=\"px-3 py-1.5 text-right text-gray-500 tabular-nums\">\n {formatTime(e.modifiedAt)}\n </td>\n <td className=\"px-3 py-1.5 text-right whitespace-nowrap\">\n {e.kind === 'file' && (\n <button\n onClick={(ev) => { ev.stopPropagation(); downloadFile(e); }}\n className=\"px-1.5 py-0.5 rounded hover:bg-gray-200 text-gray-500 text-[11px]\"\n >Download</button>\n )}\n <button\n onClick={(ev) => { ev.stopPropagation(); handleRename(e); }}\n className=\"px-1.5 py-0.5 rounded hover:bg-gray-200 text-gray-500 text-[11px] ml-1\"\n >Rename</button>\n <button\n onClick={(ev) => { ev.stopPropagation(); handleDelete(e); }}\n className=\"px-1.5 py-0.5 rounded hover:bg-red-100 text-red-600 text-[11px] ml-1\"\n >Delete</button>\n </td>\n </tr>\n ))}\n </tbody>\n </table>\n )}\n </div>\n\n {isDragging && (\n <div className=\"absolute inset-0 bg-blue-500/15 border-4 border-dashed border-blue-500 pointer-events-none flex items-center justify-center z-20\">\n <div className=\"px-4 py-2 rounded-md bg-blue-600 text-white text-sm font-medium shadow-lg\">\n Drop to upload\n </div>\n </div>\n )}\n </div>\n );\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":[],"names":[],"mappings":"","file":"Preview-
|
|
1
|
+
{"version":3,"sources":[],"names":[],"mappings":"","file":"Preview-LKFMKAIR.js"}
|
package/dist/apps/index.d.ts
CHANGED
|
@@ -2,6 +2,10 @@ import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
|
2
2
|
import * as react from 'react';
|
|
3
3
|
import { W as WindowRegistry } from '../types-BKoa7nhP.js';
|
|
4
4
|
|
|
5
|
+
declare function Browser$1(): react_jsx_runtime.JSX.Element;
|
|
6
|
+
|
|
7
|
+
declare function Files$1(): react_jsx_runtime.JSX.Element;
|
|
8
|
+
|
|
5
9
|
declare function Documents$1(): react_jsx_runtime.JSX.Element;
|
|
6
10
|
|
|
7
11
|
interface PdfPreviewData {
|
|
@@ -77,10 +81,13 @@ declare const GeminiChat: react.LazyExoticComponent<typeof GeminiChat$1>;
|
|
|
77
81
|
declare const Calendar: react.LazyExoticComponent<typeof Calendar$1>;
|
|
78
82
|
declare const Preview: react.LazyExoticComponent<typeof Preview$1>;
|
|
79
83
|
declare const Documents: react.LazyExoticComponent<typeof Documents$1>;
|
|
84
|
+
declare const Files: react.LazyExoticComponent<typeof Files$1>;
|
|
85
|
+
declare const Browser: react.LazyExoticComponent<typeof Browser$1>;
|
|
80
86
|
declare const utilityApps: WindowRegistry;
|
|
81
87
|
declare const gameApps: WindowRegistry;
|
|
82
88
|
declare const googleApps: WindowRegistry;
|
|
83
89
|
declare const documentApps: WindowRegistry;
|
|
90
|
+
declare const webApps: WindowRegistry;
|
|
84
91
|
declare const bundledApps: WindowRegistry;
|
|
85
92
|
|
|
86
|
-
export { Calculator, Calendar, Checkers, Chess, CurrencyConverter, Documents, Email, Game2048, GeminiChat, Minesweeper, Notepad, type PdfPreviewData, PomodoroTimer, Preview, Spreadsheet, Sudoku, Tetris, Weather, bundledApps, documentApps, gameApps, googleApps, setPdfPreview, utilityApps };
|
|
93
|
+
export { Browser, Calculator, Calendar, Checkers, Chess, CurrencyConverter, Documents, Email, Files, Game2048, GeminiChat, Minesweeper, Notepad, type PdfPreviewData, PomodoroTimer, Preview, Spreadsheet, Sudoku, Tetris, Weather, bundledApps, documentApps, gameApps, googleApps, setPdfPreview, utilityApps, webApps };
|