react-os-shell 0.1.44 → 0.1.48
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 → Browser-B3XVP6HC.js} +225 -48
- package/dist/Browser-B3XVP6HC.js.map +1 -0
- package/dist/{Calculator-VZM3FSTQ.js → Calculator-HJKPXY2B.js} +5 -5
- package/dist/{Calculator-VZM3FSTQ.js.map → Calculator-HJKPXY2B.js.map} +1 -1
- package/dist/{Calendar-7DNNMOKO.js → Calendar-GCQIWTU3.js} +4 -4
- package/dist/{Calendar-7DNNMOKO.js.map → Calendar-GCQIWTU3.js.map} +1 -1
- package/dist/ConfirmDialog-FKCK45O3.js +3 -0
- package/dist/{ConfirmDialog-ZP4AHVUD.js.map → ConfirmDialog-FKCK45O3.js.map} +1 -1
- package/dist/{CurrencyConverter-XFIGUZ46.js → CurrencyConverter-FYF4JLKZ.js} +5 -5
- package/dist/{CurrencyConverter-XFIGUZ46.js.map → CurrencyConverter-FYF4JLKZ.js.map} +1 -1
- package/dist/{Documents-PK7QFWGR.js → Documents-NTWVLYXJ.js} +4 -4
- package/dist/{Documents-PK7QFWGR.js.map → Documents-NTWVLYXJ.js.map} +1 -1
- package/dist/{Email-66BDCI2Q.js → Email-3B63P7ML.js} +4 -4
- package/dist/{Email-66BDCI2Q.js.map → Email-3B63P7ML.js.map} +1 -1
- package/dist/{Files-PPKWOJWV.js → Files-JYXO4AXI.js} +98 -124
- package/dist/Files-JYXO4AXI.js.map +1 -0
- package/dist/{Minesweeper-7OGCUAKF.js → Minesweeper-MAA4NIV4.js} +4 -4
- package/dist/{Minesweeper-7OGCUAKF.js.map → Minesweeper-MAA4NIV4.js.map} +1 -1
- package/dist/{Notepad-MNDA6AHQ.js → Notepad-2K6HQ2WA.js} +4 -4
- package/dist/{Notepad-MNDA6AHQ.js.map → Notepad-2K6HQ2WA.js.map} +1 -1
- package/dist/{PomodoroTimer-6DHC3H6X.js → PomodoroTimer-IJUONN6I.js} +5 -5
- package/dist/{PomodoroTimer-6DHC3H6X.js.map → PomodoroTimer-IJUONN6I.js.map} +1 -1
- package/dist/Preview-SEQ5NHLQ.js +6 -0
- package/dist/{Preview-LKFMKAIR.js.map → Preview-SEQ5NHLQ.js.map} +1 -1
- package/dist/{Spreadsheet-JT4TIKCY.js → Spreadsheet-W7F6IMTJ.js} +4 -4
- package/dist/{Spreadsheet-JT4TIKCY.js.map → Spreadsheet-W7F6IMTJ.js.map} +1 -1
- package/dist/{Weather-A6MEC4PN.js → Weather-MDTM6OEL.js} +5 -5
- package/dist/{Weather-A6MEC4PN.js.map → Weather-MDTM6OEL.js.map} +1 -1
- package/dist/apps/index.js +16 -16
- package/dist/{chunk-UUJLLTV4.js → chunk-IMHD23FR.js} +3 -3
- package/dist/{chunk-UUJLLTV4.js.map → chunk-IMHD23FR.js.map} +1 -1
- package/dist/{chunk-RFTLYCSF.js → chunk-PLGHQ7QW.js} +79 -4
- package/dist/chunk-PLGHQ7QW.js.map +1 -0
- package/dist/{chunk-44AH2OXU.js → chunk-UD2TKHR2.js} +4 -4
- package/dist/{chunk-44AH2OXU.js.map → chunk-UD2TKHR2.js.map} +1 -1
- package/dist/{chunk-IM3T7WV2.js → chunk-VEEO4U4E.js} +3 -3
- package/dist/{chunk-IM3T7WV2.js.map → chunk-VEEO4U4E.js.map} +1 -1
- package/dist/index.d.ts +11 -1
- package/dist/index.js +5 -5
- package/package.json +1 -1
- package/dist/Browser-KMVL3AJ7.js.map +0 -1
- package/dist/ConfirmDialog-ZP4AHVUD.js +0 -3
- package/dist/Files-PPKWOJWV.js.map +0 -1
- package/dist/Preview-LKFMKAIR.js +0 -6
- package/dist/chunk-RFTLYCSF.js.map +0 -1
|
@@ -1,13 +1,11 @@
|
|
|
1
|
-
import { setPdfPreview } from './chunk-
|
|
1
|
+
import { setPdfPreview } from './chunk-VEEO4U4E.js';
|
|
2
2
|
import { toast_default } from './chunk-WIJ45SYD.js';
|
|
3
|
-
import { useWindowManager, WindowTitle } from './chunk-
|
|
4
|
-
import './chunk-
|
|
3
|
+
import { useWindowManager, WindowTitle } from './chunk-UD2TKHR2.js';
|
|
4
|
+
import { prompt, confirm } from './chunk-PLGHQ7QW.js';
|
|
5
5
|
import { useState, useRef, useCallback, useEffect } from 'react';
|
|
6
|
-
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
6
|
+
import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
|
|
7
7
|
|
|
8
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
9
|
var PREVIEW_EXTS = {
|
|
12
10
|
pdf: "pdf",
|
|
13
11
|
dxf: "dxf",
|
|
@@ -60,71 +58,44 @@ function formatTime(iso) {
|
|
|
60
58
|
}
|
|
61
59
|
}
|
|
62
60
|
function Files() {
|
|
63
|
-
const
|
|
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);
|
|
61
|
+
const server = DEFAULT_SERVER.replace(/\/$/, "");
|
|
72
62
|
const [path, setPath] = useState("/");
|
|
73
63
|
const [entries, setEntries] = useState([]);
|
|
74
64
|
const [selected, setSelected] = useState(null);
|
|
75
|
-
const [loading, setLoading] = useState(
|
|
76
|
-
const [
|
|
65
|
+
const [loading, setLoading] = useState(true);
|
|
66
|
+
const [unreachable, setUnreachable] = useState(false);
|
|
67
|
+
const [quota, setQuota] = useState(null);
|
|
77
68
|
const [isDragging, setIsDragging] = useState(false);
|
|
78
69
|
const dragDepthRef = useRef(0);
|
|
79
70
|
const fileRef = useRef(null);
|
|
80
71
|
const { openPage } = useWindowManager();
|
|
81
72
|
const authedFetch = useCallback(
|
|
82
|
-
(url, init = {}) =>
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
[token]
|
|
73
|
+
(url, init = {}) => (
|
|
74
|
+
// `credentials: 'include'` makes the browser send the identity
|
|
75
|
+
// cookie with every cross-origin request, and accept any
|
|
76
|
+
// Set-Cookie response (e.g. the first-visit assignment).
|
|
77
|
+
fetch(url, { ...init, credentials: "include" })
|
|
78
|
+
),
|
|
79
|
+
[]
|
|
90
80
|
);
|
|
91
|
-
const
|
|
92
|
-
setAuthError(null);
|
|
81
|
+
const refreshQuota = useCallback(async () => {
|
|
93
82
|
try {
|
|
94
|
-
const res = await
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
setAuthError(res.status === 401 ? "Invalid token" : `Server error ${res.status}`);
|
|
99
|
-
return;
|
|
83
|
+
const res = await authedFetch(`${server}/api/quota`);
|
|
84
|
+
if (res.ok) {
|
|
85
|
+
const q = await res.json();
|
|
86
|
+
setQuota({ used: q.used, limit: q.limit });
|
|
100
87
|
}
|
|
101
|
-
|
|
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");
|
|
88
|
+
} catch {
|
|
107
89
|
}
|
|
108
|
-
};
|
|
109
|
-
const signOut = () => {
|
|
110
|
-
setUser(null);
|
|
111
|
-
setEntries([]);
|
|
112
|
-
setPath("/");
|
|
113
|
-
setSelected(null);
|
|
114
|
-
localStorage.removeItem(TOKEN_KEY);
|
|
115
|
-
};
|
|
90
|
+
}, [authedFetch, server]);
|
|
116
91
|
const loadDir = useCallback(async (dir) => {
|
|
117
92
|
setLoading(true);
|
|
118
93
|
setSelected(null);
|
|
119
94
|
try {
|
|
120
95
|
const res = await authedFetch(
|
|
121
|
-
`${server
|
|
96
|
+
`${server}/api/files?path=${encodeURIComponent(dir)}`
|
|
122
97
|
);
|
|
123
98
|
if (!res.ok) {
|
|
124
|
-
if (res.status === 401) {
|
|
125
|
-
setUser(null);
|
|
126
|
-
return;
|
|
127
|
-
}
|
|
128
99
|
const msg = await res.json().catch(() => ({}));
|
|
129
100
|
toast_default.error(msg.error || `Failed to list (${res.status})`);
|
|
130
101
|
return;
|
|
@@ -132,18 +103,17 @@ function Files() {
|
|
|
132
103
|
const data = await res.json();
|
|
133
104
|
setEntries(data.entries || []);
|
|
134
105
|
setPath(data.path || dir);
|
|
106
|
+
setUnreachable(false);
|
|
135
107
|
} catch (e) {
|
|
136
|
-
|
|
108
|
+
setUnreachable(true);
|
|
137
109
|
} finally {
|
|
138
110
|
setLoading(false);
|
|
139
111
|
}
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
if (token && !user && !authError) signIn();
|
|
143
|
-
}, []);
|
|
112
|
+
refreshQuota();
|
|
113
|
+
}, [authedFetch, server, refreshQuota]);
|
|
144
114
|
useEffect(() => {
|
|
145
|
-
|
|
146
|
-
}, [
|
|
115
|
+
loadDir(path);
|
|
116
|
+
}, [path]);
|
|
147
117
|
const openFile = async (entry) => {
|
|
148
118
|
const fullPath = joinPath(path, entry.name);
|
|
149
119
|
const ext = (entry.name.split(".").pop() || "").toLowerCase();
|
|
@@ -154,7 +124,7 @@ function Files() {
|
|
|
154
124
|
}
|
|
155
125
|
try {
|
|
156
126
|
const res = await authedFetch(
|
|
157
|
-
`${server
|
|
127
|
+
`${server}/api/file?path=${encodeURIComponent(fullPath)}`
|
|
158
128
|
);
|
|
159
129
|
if (!res.ok) {
|
|
160
130
|
toast_default.error(`Download failed (${res.status})`);
|
|
@@ -172,7 +142,7 @@ function Files() {
|
|
|
172
142
|
const fullPath = joinPath(path, entry.name);
|
|
173
143
|
try {
|
|
174
144
|
const res = await authedFetch(
|
|
175
|
-
`${server
|
|
145
|
+
`${server}/api/file?path=${encodeURIComponent(fullPath)}`
|
|
176
146
|
);
|
|
177
147
|
if (!res.ok) {
|
|
178
148
|
toast_default.error(`Download failed (${res.status})`);
|
|
@@ -197,12 +167,19 @@ function Files() {
|
|
|
197
167
|
form.append("file", file);
|
|
198
168
|
try {
|
|
199
169
|
const res = await authedFetch(
|
|
200
|
-
`${server
|
|
170
|
+
`${server}/api/upload?path=${encodeURIComponent(path)}`,
|
|
201
171
|
{ method: "POST", body: form }
|
|
202
172
|
);
|
|
203
173
|
if (!res.ok) {
|
|
204
174
|
const msg = await res.json().catch(() => ({}));
|
|
205
|
-
|
|
175
|
+
if (res.status === 413) {
|
|
176
|
+
const remaining = Math.max(0, (msg.limit || 0) - (msg.used || 0));
|
|
177
|
+
toast_default.error(
|
|
178
|
+
`Quota exceeded \u2014 ${formatSize(remaining)} free, ${file.name} is ${formatSize(msg.attempted || file.size)}`
|
|
179
|
+
);
|
|
180
|
+
} else {
|
|
181
|
+
toast_default.error(`Upload ${file.name}: ${msg.error || res.status}`);
|
|
182
|
+
}
|
|
206
183
|
}
|
|
207
184
|
} catch (e) {
|
|
208
185
|
toast_default.error(`Upload ${file.name}: ${e?.message || "failed"}`);
|
|
@@ -211,14 +188,18 @@ function Files() {
|
|
|
211
188
|
loadDir(path);
|
|
212
189
|
};
|
|
213
190
|
const handleNewFolder = async () => {
|
|
214
|
-
const name =
|
|
191
|
+
const name = await prompt({
|
|
192
|
+
title: "New folder",
|
|
193
|
+
placeholder: "Folder name",
|
|
194
|
+
confirmLabel: "Create"
|
|
195
|
+
});
|
|
215
196
|
if (!name) return;
|
|
216
197
|
if (/[\\/]/.test(name)) {
|
|
217
198
|
toast_default.error("Folder names cannot contain slashes");
|
|
218
199
|
return;
|
|
219
200
|
}
|
|
220
201
|
const target = joinPath(path, name);
|
|
221
|
-
const res = await authedFetch(`${server
|
|
202
|
+
const res = await authedFetch(`${server}/api/folder`, {
|
|
222
203
|
method: "POST",
|
|
223
204
|
headers: { "Content-Type": "application/json" },
|
|
224
205
|
body: JSON.stringify({ path: target })
|
|
@@ -231,7 +212,11 @@ function Files() {
|
|
|
231
212
|
loadDir(path);
|
|
232
213
|
};
|
|
233
214
|
const handleRename = async (entry) => {
|
|
234
|
-
const next =
|
|
215
|
+
const next = await prompt({
|
|
216
|
+
title: `Rename ${entry.kind}`,
|
|
217
|
+
defaultValue: entry.name,
|
|
218
|
+
confirmLabel: "Rename"
|
|
219
|
+
});
|
|
235
220
|
if (!next || next === entry.name) return;
|
|
236
221
|
if (/[\\/]/.test(next)) {
|
|
237
222
|
toast_default.error("Names cannot contain slashes");
|
|
@@ -239,7 +224,7 @@ function Files() {
|
|
|
239
224
|
}
|
|
240
225
|
const from = joinPath(path, entry.name);
|
|
241
226
|
const to = joinPath(path, next);
|
|
242
|
-
const res = await authedFetch(`${server
|
|
227
|
+
const res = await authedFetch(`${server}/api/rename`, {
|
|
243
228
|
method: "POST",
|
|
244
229
|
headers: { "Content-Type": "application/json" },
|
|
245
230
|
body: JSON.stringify({ from, to })
|
|
@@ -252,10 +237,16 @@ function Files() {
|
|
|
252
237
|
loadDir(path);
|
|
253
238
|
};
|
|
254
239
|
const handleDelete = async (entry) => {
|
|
255
|
-
|
|
240
|
+
const ok = await confirm({
|
|
241
|
+
title: `Delete ${entry.kind}`,
|
|
242
|
+
message: `"${entry.name}"${entry.kind === "folder" ? " and everything inside" : ""} will be permanently removed.`,
|
|
243
|
+
confirmLabel: "Delete",
|
|
244
|
+
variant: "danger"
|
|
245
|
+
});
|
|
246
|
+
if (!ok) return;
|
|
256
247
|
const target = joinPath(path, entry.name);
|
|
257
248
|
const res = await authedFetch(
|
|
258
|
-
`${server
|
|
249
|
+
`${server}/api/files?path=${encodeURIComponent(target)}`,
|
|
259
250
|
{ method: "DELETE" }
|
|
260
251
|
);
|
|
261
252
|
if (!res.ok) {
|
|
@@ -278,60 +269,29 @@ function Files() {
|
|
|
278
269
|
window.removeEventListener("drop", reset);
|
|
279
270
|
};
|
|
280
271
|
}, []);
|
|
281
|
-
if (
|
|
272
|
+
if (unreachable) {
|
|
282
273
|
return /* @__PURE__ */ jsxs("div", { className: "flex flex-col h-full bg-white", children: [
|
|
283
|
-
/* @__PURE__ */ jsx(WindowTitle, { title: "Files -
|
|
284
|
-
/* @__PURE__ */ jsx("div", { className: "flex
|
|
285
|
-
/* @__PURE__ */
|
|
286
|
-
|
|
287
|
-
"
|
|
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
|
-
)
|
|
274
|
+
/* @__PURE__ */ jsx(WindowTitle, { title: "Files - offline" }),
|
|
275
|
+
/* @__PURE__ */ jsx("div", { className: "flex-1 flex items-center justify-center p-8 text-center", children: /* @__PURE__ */ jsxs("div", { className: "max-w-md", children: [
|
|
276
|
+
/* @__PURE__ */ jsxs("svg", { className: "h-12 w-12 mx-auto text-gray-300 mb-3", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.4, children: [
|
|
277
|
+
/* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M18.364 5.636l-12.728 12.728M5.636 5.636l12.728 12.728" }),
|
|
278
|
+
/* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M12 21a9 9 0 100-18 9 9 0 000 18z" })
|
|
304
279
|
] }),
|
|
305
|
-
/* @__PURE__ */
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
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
|
-
)
|
|
280
|
+
/* @__PURE__ */ jsx("h3", { className: "text-base font-semibold text-gray-800 mb-1", children: "Can't reach the file server" }),
|
|
281
|
+
/* @__PURE__ */ jsxs("p", { className: "text-sm text-gray-500 mb-3", children: [
|
|
282
|
+
"No response from ",
|
|
283
|
+
/* @__PURE__ */ jsx("span", { className: "font-mono", children: server }),
|
|
284
|
+
". Make sure the server is running \u2014 see ",
|
|
285
|
+
/* @__PURE__ */ jsx("span", { className: "font-mono", children: "examples/file-server/README.md" }),
|
|
286
|
+
"."
|
|
320
287
|
] }),
|
|
321
|
-
|
|
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
|
-
)
|
|
288
|
+
/* @__PURE__ */ jsx("button", { onClick: () => loadDir(path), className: "px-3 py-1.5 text-sm bg-blue-500 text-white rounded hover:bg-blue-600", children: "Retry" })
|
|
331
289
|
] }) })
|
|
332
290
|
] });
|
|
333
291
|
}
|
|
334
292
|
const segments = path === "/" ? [] : path.split("/").filter(Boolean);
|
|
293
|
+
const usagePct = quota && quota.limit > 0 ? Math.min(100, Math.round(quota.used / quota.limit * 100)) : 0;
|
|
294
|
+
const usageColor = usagePct > 90 ? "bg-red-500" : usagePct > 75 ? "bg-amber-500" : "bg-blue-500";
|
|
335
295
|
return /* @__PURE__ */ jsxs(
|
|
336
296
|
"div",
|
|
337
297
|
{
|
|
@@ -356,7 +316,7 @@ function Files() {
|
|
|
356
316
|
if (e.dataTransfer.files?.length) uploadFiles(e.dataTransfer.files);
|
|
357
317
|
},
|
|
358
318
|
children: [
|
|
359
|
-
/* @__PURE__ */ jsx(WindowTitle, { title: `Files -
|
|
319
|
+
/* @__PURE__ */ jsx(WindowTitle, { title: `Files${path === "/" ? "" : " - " + path}` }),
|
|
360
320
|
/* @__PURE__ */ jsx(
|
|
361
321
|
"input",
|
|
362
322
|
{
|
|
@@ -382,7 +342,7 @@ function Files() {
|
|
|
382
342
|
}
|
|
383
343
|
),
|
|
384
344
|
/* @__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:
|
|
345
|
+
/* @__PURE__ */ jsx("button", { onClick: () => setPath("/"), className: "px-1.5 py-0.5 rounded hover:bg-gray-200 font-medium", children: "My files" }),
|
|
386
346
|
segments.map((seg, i) => /* @__PURE__ */ jsxs("span", { className: "flex items-center gap-0.5", children: [
|
|
387
347
|
/* @__PURE__ */ jsx("span", { className: "text-gray-400", children: "/" }),
|
|
388
348
|
/* @__PURE__ */ jsx(
|
|
@@ -404,11 +364,25 @@ function Files() {
|
|
|
404
364
|
/* @__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
365
|
"Upload"
|
|
406
366
|
] }),
|
|
407
|
-
/* @__PURE__ */
|
|
408
|
-
|
|
409
|
-
|
|
367
|
+
quota && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
368
|
+
/* @__PURE__ */ jsx("div", { className: "h-4 w-px bg-gray-300 mx-1" }),
|
|
369
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5", title: `${formatSize(quota.used)} of ${formatSize(quota.limit)} used`, children: [
|
|
370
|
+
/* @__PURE__ */ jsx("div", { className: "w-20 h-1.5 rounded-full bg-gray-200 overflow-hidden", children: /* @__PURE__ */ jsx(
|
|
371
|
+
"div",
|
|
372
|
+
{
|
|
373
|
+
className: `h-full ${usageColor} transition-all`,
|
|
374
|
+
style: { width: `${usagePct}%` }
|
|
375
|
+
}
|
|
376
|
+
) }),
|
|
377
|
+
/* @__PURE__ */ jsxs("span", { className: "text-[10px] text-gray-500 tabular-nums whitespace-nowrap", children: [
|
|
378
|
+
formatSize(quota.used),
|
|
379
|
+
" / ",
|
|
380
|
+
formatSize(quota.limit)
|
|
381
|
+
] })
|
|
382
|
+
] })
|
|
383
|
+
] })
|
|
410
384
|
] }),
|
|
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: [
|
|
385
|
+
/* @__PURE__ */ jsx("div", { className: "flex-1 overflow-auto", children: loading && entries.length === 0 ? /* @__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
386
|
"Empty folder. Drop files here or click ",
|
|
413
387
|
/* @__PURE__ */ jsx("span", { className: "font-medium", children: "Upload" }),
|
|
414
388
|
"."
|
|
@@ -482,5 +456,5 @@ function Files() {
|
|
|
482
456
|
}
|
|
483
457
|
|
|
484
458
|
export { Files as default };
|
|
485
|
-
//# sourceMappingURL=Files-
|
|
486
|
-
//# sourceMappingURL=Files-
|
|
459
|
+
//# sourceMappingURL=Files-JYXO4AXI.js.map
|
|
460
|
+
//# sourceMappingURL=Files-JYXO4AXI.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/apps/Files.tsx"],"names":[],"mappings":"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","file":"Files-JYXO4AXI.js","sourcesContent":["/**\n * Files — browser for the per-user file-server (see examples/file-server).\n *\n * Identity is a cookie the server sets on first visit; no login screen.\n * Every fetch carries `credentials: 'include'` so the cookie travels with\n * cross-origin requests. Toolbar shows a live \"X.X / Y MB used\" indicator\n * driven by `/api/quota`. Supported file types open straight into Preview;\n * everything else downloads.\n *\n * Server URL defaults to `http://localhost:4000`. Override at runtime via\n * `window.__REACT_OS_SHELL_FILE_SERVER__ = 'https://files.example.com'`.\n */\nimport { useState, useEffect, useRef, useCallback } from 'react';\nimport { WindowTitle } from '../shell/Modal';\nimport { useWindowManager } from '../shell/WindowManager';\nimport toast from '../shell/toast';\nimport { confirm, prompt } from '../shell/ConfirmDialog';\nimport { setPdfPreview } from './Preview';\n\nconst DEFAULT_SERVER =\n (typeof window !== 'undefined' && (window as any).__REACT_OS_SHELL_FILE_SERVER__) ||\n 'http://localhost:4000';\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 = DEFAULT_SERVER.replace(/\\/$/, '');\n const [path, setPath] = useState('/');\n const [entries, setEntries] = useState<FileEntry[]>([]);\n const [selected, setSelected] = useState<string | null>(null);\n const [loading, setLoading] = useState(true);\n const [unreachable, setUnreachable] = useState(false);\n const [quota, setQuota] = useState<{ used: number; limit: number } | 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 // `credentials: 'include'` makes the browser send the identity\n // cookie with every cross-origin request, and accept any\n // Set-Cookie response (e.g. the first-visit assignment).\n fetch(url, { ...init, credentials: 'include' }),\n [],\n );\n\n const refreshQuota = useCallback(async () => {\n try {\n const res = await authedFetch(`${server}/api/quota`);\n if (res.ok) {\n const q = await res.json();\n setQuota({ used: q.used, limit: q.limit });\n }\n } catch {}\n }, [authedFetch, server]);\n\n const loadDir = useCallback(async (dir: string) => {\n setLoading(true);\n setSelected(null);\n try {\n const res = await authedFetch(\n `${server}/api/files?path=${encodeURIComponent(dir)}`,\n );\n if (!res.ok) {\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 setUnreachable(false);\n } catch (e: any) {\n setUnreachable(true);\n } finally {\n setLoading(false);\n }\n refreshQuota();\n }, [authedFetch, server, refreshQuota]);\n\n useEffect(() => { loadDir(path); /* eslint-disable-next-line */ }, [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 downloadFile(entry);\n return;\n }\n try {\n const res = await authedFetch(\n `${server}/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 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}/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}/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 if (res.status === 413) {\n const remaining = Math.max(0, (msg.limit || 0) - (msg.used || 0));\n toast.error(\n `Quota exceeded — ${formatSize(remaining)} free, ${file.name} is ${formatSize(msg.attempted || file.size)}`,\n );\n } else {\n toast.error(`Upload ${file.name}: ${msg.error || res.status}`);\n }\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 = await prompt({\n title: 'New folder',\n placeholder: 'Folder name',\n confirmLabel: 'Create',\n });\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}/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 = await prompt({\n title: `Rename ${entry.kind}`,\n defaultValue: entry.name,\n confirmLabel: 'Rename',\n });\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}/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 const ok = await confirm({\n title: `Delete ${entry.kind}`,\n message: `\"${entry.name}\"${entry.kind === 'folder' ? ' and everything inside' : ''} will be permanently removed.`,\n confirmLabel: 'Delete',\n variant: 'danger',\n });\n if (!ok) return;\n const target = joinPath(path, entry.name);\n const res = await authedFetch(\n `${server}/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 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 (unreachable) {\n return (\n <div className=\"flex flex-col h-full bg-white\">\n <WindowTitle title=\"Files - offline\" />\n <div className=\"flex-1 flex items-center justify-center p-8 text-center\">\n <div className=\"max-w-md\">\n <svg className=\"h-12 w-12 mx-auto text-gray-300 mb-3\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" strokeWidth={1.4}>\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M18.364 5.636l-12.728 12.728M5.636 5.636l12.728 12.728\" />\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M12 21a9 9 0 100-18 9 9 0 000 18z\" />\n </svg>\n <h3 className=\"text-base font-semibold text-gray-800 mb-1\">Can't reach the file server</h3>\n <p className=\"text-sm text-gray-500 mb-3\">\n No response from <span className=\"font-mono\">{server}</span>. Make sure the\n server is running — see <span className=\"font-mono\">examples/file-server/README.md</span>.\n </p>\n <button onClick={() => loadDir(path)} className=\"px-3 py-1.5 text-sm bg-blue-500 text-white rounded hover:bg-blue-600\">\n Retry\n </button>\n </div>\n </div>\n </div>\n );\n }\n\n const segments = path === '/' ? [] : path.split('/').filter(Boolean);\n const usagePct = quota && quota.limit > 0\n ? Math.min(100, Math.round((quota.used / quota.limit) * 100))\n : 0;\n const usageColor = usagePct > 90 ? 'bg-red-500' : usagePct > 75 ? 'bg-amber-500' : 'bg-blue-500';\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${path === '/' ? '' : ' - ' + 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 <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\">My files</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 {/* Quota indicator */}\n {quota && (\n <>\n <div className=\"h-4 w-px bg-gray-300 mx-1\" />\n <div className=\"flex items-center gap-1.5\" title={`${formatSize(quota.used)} of ${formatSize(quota.limit)} used`}>\n <div className=\"w-20 h-1.5 rounded-full bg-gray-200 overflow-hidden\">\n <div\n className={`h-full ${usageColor} transition-all`}\n style={{ width: `${usagePct}%` }}\n />\n </div>\n <span className=\"text-[10px] text-gray-500 tabular-nums whitespace-nowrap\">\n {formatSize(quota.used)} / {formatSize(quota.limit)}\n </span>\n </div>\n </>\n )}\n </div>\n\n {/* List */}\n <div className=\"flex-1 overflow-auto\">\n {loading && entries.length === 0 ? (\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,7 +1,7 @@
|
|
|
1
1
|
import { formatDate } from './chunk-NSU7OHPC.js';
|
|
2
2
|
import { toast_default } from './chunk-WIJ45SYD.js';
|
|
3
|
-
import { useWindowMenuItem, Modal, client_default } from './chunk-
|
|
4
|
-
import './chunk-
|
|
3
|
+
import { useWindowMenuItem, Modal, client_default } from './chunk-UD2TKHR2.js';
|
|
4
|
+
import './chunk-PLGHQ7QW.js';
|
|
5
5
|
import { useState, useRef, useEffect, useCallback } from 'react';
|
|
6
6
|
import { jsx, jsxs } from 'react/jsx-runtime';
|
|
7
7
|
|
|
@@ -266,5 +266,5 @@ function Minesweeper() {
|
|
|
266
266
|
}
|
|
267
267
|
|
|
268
268
|
export { Minesweeper as default };
|
|
269
|
-
//# sourceMappingURL=Minesweeper-
|
|
270
|
-
//# sourceMappingURL=Minesweeper-
|
|
269
|
+
//# sourceMappingURL=Minesweeper-MAA4NIV4.js.map
|
|
270
|
+
//# sourceMappingURL=Minesweeper-MAA4NIV4.js.map
|