@haowjy/remote-workspace 0.1.1 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/launcher.js +0 -0
- package/package.json +1 -1
- package/static/app.js +66 -7
- package/static/index.html +41 -15
package/dist/launcher.js
CHANGED
|
File without changes
|
package/package.json
CHANGED
package/static/app.js
CHANGED
|
@@ -1,8 +1,22 @@
|
|
|
1
1
|
// ---------------------------------------------------------------------------
|
|
2
|
-
// Theme —
|
|
2
|
+
// Theme — sync with early head initialization
|
|
3
3
|
// ---------------------------------------------------------------------------
|
|
4
|
-
|
|
4
|
+
function resolveSavedTheme() {
|
|
5
|
+
if (window.__workspaceTheme === "dark" || window.__workspaceTheme === "light") {
|
|
6
|
+
return window.__workspaceTheme;
|
|
7
|
+
}
|
|
8
|
+
try {
|
|
9
|
+
const savedTheme = localStorage.getItem("workspace-theme");
|
|
10
|
+
if (savedTheme === "dark" || savedTheme === "light") return savedTheme;
|
|
11
|
+
} catch {
|
|
12
|
+
// Ignore storage access errors.
|
|
13
|
+
}
|
|
14
|
+
return "light";
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const savedTheme = resolveSavedTheme();
|
|
5
18
|
document.documentElement.dataset.theme = savedTheme;
|
|
19
|
+
window.__workspaceTheme = savedTheme;
|
|
6
20
|
|
|
7
21
|
// ---------------------------------------------------------------------------
|
|
8
22
|
// Constants
|
|
@@ -46,7 +60,7 @@ const CACHE_KEYS = {
|
|
|
46
60
|
// State
|
|
47
61
|
// ---------------------------------------------------------------------------
|
|
48
62
|
const state = {
|
|
49
|
-
activeTab: "
|
|
63
|
+
activeTab: "files",
|
|
50
64
|
// Tree: top-level entries loaded eagerly, children loaded on expand
|
|
51
65
|
topLevelEntries: [],
|
|
52
66
|
dirChildren: new Map(),
|
|
@@ -64,6 +78,7 @@ const state = {
|
|
|
64
78
|
clipboardApiMode: "modern",
|
|
65
79
|
pendingUploadFile: null,
|
|
66
80
|
searchDebounceTimer: null,
|
|
81
|
+
filesMobileMode: "explorer",
|
|
67
82
|
// Screenshots
|
|
68
83
|
screenshotEntries: [],
|
|
69
84
|
screenshotsRequestId: 0,
|
|
@@ -88,6 +103,9 @@ const uploadNameInput = $("upload-name-input");
|
|
|
88
103
|
const uploadBtn = $("upload-btn");
|
|
89
104
|
const clipboardRefreshBtn = $("clipboard-refresh-btn");
|
|
90
105
|
const treeRefreshBtn = $("tree-refresh-btn");
|
|
106
|
+
const fileTreeContainer = $("file-tree-container");
|
|
107
|
+
const fileViewerContainer = $("file-viewer-container");
|
|
108
|
+
const mobileExplorerBackBtn = $("mobile-explorer-back-btn");
|
|
91
109
|
const screenshotsGrid = $("screenshots-grid");
|
|
92
110
|
const screenshotsStatusEl = $("screenshots-status");
|
|
93
111
|
const screenshotsRefreshBtn = $("screenshots-refresh-btn");
|
|
@@ -125,7 +143,7 @@ const md = window.markdownit({
|
|
|
125
143
|
window.mermaid.initialize({
|
|
126
144
|
startOnLoad: false,
|
|
127
145
|
securityLevel: "strict",
|
|
128
|
-
theme:
|
|
146
|
+
theme: savedTheme === "dark" ? "dark" : "default",
|
|
129
147
|
});
|
|
130
148
|
|
|
131
149
|
// ---------------------------------------------------------------------------
|
|
@@ -198,7 +216,9 @@ function updateThemeIcon(theme) {
|
|
|
198
216
|
// Set initial icon to match saved theme
|
|
199
217
|
updateThemeIcon(savedTheme);
|
|
200
218
|
// Set initial hljs theme to match
|
|
201
|
-
if (savedTheme === "
|
|
219
|
+
if (savedTheme === "dark") {
|
|
220
|
+
hljsThemeLink.href = "https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/github-dark.min.css";
|
|
221
|
+
} else {
|
|
202
222
|
hljsThemeLink.href = "https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/github.min.css";
|
|
203
223
|
}
|
|
204
224
|
|
|
@@ -207,6 +227,7 @@ function toggleTheme() {
|
|
|
207
227
|
const next = current === "dark" ? "light" : "dark";
|
|
208
228
|
document.documentElement.dataset.theme = next;
|
|
209
229
|
localStorage.setItem("workspace-theme", next);
|
|
230
|
+
window.__workspaceTheme = next;
|
|
210
231
|
|
|
211
232
|
updateThemeIcon(next);
|
|
212
233
|
|
|
@@ -301,6 +322,27 @@ function appendVersionQuery(url, entry) {
|
|
|
301
322
|
return `${url}${separator}v=${version}`;
|
|
302
323
|
}
|
|
303
324
|
|
|
325
|
+
function isDesktopLayout() {
|
|
326
|
+
return window.matchMedia("(min-width: 1024px)").matches;
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
function syncFilesLayout() {
|
|
330
|
+
if (!fileTreeContainer || !fileViewerContainer) return;
|
|
331
|
+
const desktop = isDesktopLayout();
|
|
332
|
+
if (desktop) {
|
|
333
|
+
fileTreeContainer.classList.remove("hidden");
|
|
334
|
+
fileViewerContainer.classList.remove("hidden");
|
|
335
|
+
if (mobileExplorerBackBtn) mobileExplorerBackBtn.classList.add("hidden");
|
|
336
|
+
return;
|
|
337
|
+
}
|
|
338
|
+
const viewerMode = state.filesMobileMode === "viewer";
|
|
339
|
+
fileTreeContainer.classList.toggle("hidden", viewerMode);
|
|
340
|
+
fileViewerContainer.classList.toggle("hidden", !viewerMode);
|
|
341
|
+
if (mobileExplorerBackBtn) {
|
|
342
|
+
mobileExplorerBackBtn.classList.toggle("hidden", !viewerMode);
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
|
|
304
346
|
// ---------------------------------------------------------------------------
|
|
305
347
|
// Tab navigation
|
|
306
348
|
// ---------------------------------------------------------------------------
|
|
@@ -312,6 +354,7 @@ function switchTab(tabName) {
|
|
|
312
354
|
localStorage.setItem("workspace-tab", tabName);
|
|
313
355
|
tabPanels.forEach((p) => p.classList.toggle("hidden", p.id !== `panel-${tabName}`));
|
|
314
356
|
tabButtons.forEach((b) => b.classList.toggle("active", b.dataset.tab === tabName));
|
|
357
|
+
syncFilesLayout();
|
|
315
358
|
refreshIcons();
|
|
316
359
|
}
|
|
317
360
|
|
|
@@ -319,8 +362,8 @@ tabButtons.forEach((btn) => {
|
|
|
319
362
|
btn.addEventListener("click", () => switchTab(btn.dataset.tab));
|
|
320
363
|
});
|
|
321
364
|
|
|
322
|
-
// Initialize tab — restore last active or default to
|
|
323
|
-
switchTab(localStorage.getItem("workspace-tab") || "
|
|
365
|
+
// Initialize tab — restore last active or default to files
|
|
366
|
+
switchTab(localStorage.getItem("workspace-tab") || "files");
|
|
324
367
|
|
|
325
368
|
// ---------------------------------------------------------------------------
|
|
326
369
|
// Lightbox
|
|
@@ -638,6 +681,10 @@ function handleSearch(query) {
|
|
|
638
681
|
searchResultsEl.innerHTML = "";
|
|
639
682
|
expandParentsOf(result.path);
|
|
640
683
|
if (result.type === "directory") {
|
|
684
|
+
if (!isDesktopLayout()) {
|
|
685
|
+
state.filesMobileMode = "explorer";
|
|
686
|
+
syncFilesLayout();
|
|
687
|
+
}
|
|
641
688
|
toggleDirectory(result.path);
|
|
642
689
|
} else {
|
|
643
690
|
openFile(result.path).catch(handleActionError);
|
|
@@ -678,6 +725,10 @@ async function openFile(filePath) {
|
|
|
678
725
|
viewerRefreshBtn.classList.remove("hidden");
|
|
679
726
|
expandParentsOf(filePath);
|
|
680
727
|
renderTree();
|
|
728
|
+
if (!isDesktopLayout()) {
|
|
729
|
+
state.filesMobileMode = "viewer";
|
|
730
|
+
syncFilesLayout();
|
|
731
|
+
}
|
|
681
732
|
|
|
682
733
|
viewerTitle.textContent = filePath;
|
|
683
734
|
setStatus(`Opening ${filePath}...`);
|
|
@@ -1227,6 +1278,14 @@ screenshotsRefreshBtn.onclick = () => {
|
|
|
1227
1278
|
viewerRefreshBtn.onclick = () => {
|
|
1228
1279
|
if (state.selectedPath) openFile(state.selectedPath).catch(handleActionError);
|
|
1229
1280
|
};
|
|
1281
|
+
if (mobileExplorerBackBtn) {
|
|
1282
|
+
mobileExplorerBackBtn.onclick = () => {
|
|
1283
|
+
state.filesMobileMode = "explorer";
|
|
1284
|
+
syncFilesLayout();
|
|
1285
|
+
};
|
|
1286
|
+
}
|
|
1287
|
+
window.addEventListener("resize", syncFilesLayout);
|
|
1288
|
+
syncFilesLayout();
|
|
1230
1289
|
|
|
1231
1290
|
// ---------------------------------------------------------------------------
|
|
1232
1291
|
// Init
|
package/static/index.html
CHANGED
|
@@ -4,6 +4,19 @@
|
|
|
4
4
|
<meta charset="UTF-8" />
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover" />
|
|
6
6
|
<title>Workspace</title>
|
|
7
|
+
<script>
|
|
8
|
+
(() => {
|
|
9
|
+
let theme = "light";
|
|
10
|
+
try {
|
|
11
|
+
const savedTheme = localStorage.getItem("workspace-theme");
|
|
12
|
+
if (savedTheme === "dark" || savedTheme === "light") theme = savedTheme;
|
|
13
|
+
} catch {
|
|
14
|
+
// Ignore storage errors and keep light default.
|
|
15
|
+
}
|
|
16
|
+
document.documentElement.dataset.theme = theme;
|
|
17
|
+
window.__workspaceTheme = theme;
|
|
18
|
+
})();
|
|
19
|
+
</script>
|
|
7
20
|
<script src="https://cdn.tailwindcss.com"></script>
|
|
8
21
|
<script>
|
|
9
22
|
tailwind.config = {
|
|
@@ -29,7 +42,15 @@
|
|
|
29
42
|
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
|
30
43
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
|
31
44
|
<link href="https://fonts.googleapis.com/css2?family=DM+Sans:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500;600&display=swap" rel="stylesheet" />
|
|
32
|
-
<link id="hljs-theme" rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/github
|
|
45
|
+
<link id="hljs-theme" rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/github.min.css" />
|
|
46
|
+
<script>
|
|
47
|
+
if (window.__workspaceTheme === "dark") {
|
|
48
|
+
const hljsTheme = document.getElementById("hljs-theme");
|
|
49
|
+
if (hljsTheme) {
|
|
50
|
+
hljsTheme.href = "https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/github-dark.min.css";
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
</script>
|
|
33
54
|
<link rel="stylesheet" href="/styles.css" />
|
|
34
55
|
</head>
|
|
35
56
|
<body class="bg-ink-950 text-ink-100 font-sans h-[100dvh] flex flex-col overflow-hidden">
|
|
@@ -48,7 +69,7 @@
|
|
|
48
69
|
<div class="flex-1 min-h-0 relative">
|
|
49
70
|
|
|
50
71
|
<!-- Tab: Clipboard -->
|
|
51
|
-
<section id="panel-clipboard" class="tab-panel absolute inset-0 flex flex-col">
|
|
72
|
+
<section id="panel-clipboard" class="tab-panel absolute inset-0 flex flex-col hidden">
|
|
52
73
|
<div class="shrink-0 bg-ink-900/60 border-b border-ink-800 px-4 py-3 flex flex-wrap items-center gap-2">
|
|
53
74
|
<label class="inline-flex items-center gap-1.5 px-3 py-1.5 text-sm font-medium text-brand bg-brand-light/10 border border-brand/20 rounded-lg cursor-pointer hover:bg-brand-light/20 transition-colors">
|
|
54
75
|
<i data-lucide="image-plus" class="w-3.5 h-3.5"></i>
|
|
@@ -78,7 +99,7 @@
|
|
|
78
99
|
</section>
|
|
79
100
|
|
|
80
101
|
<!-- Tab: Files -->
|
|
81
|
-
<section id="panel-files" class="tab-panel absolute inset-0 flex flex-col
|
|
102
|
+
<section id="panel-files" class="tab-panel absolute inset-0 flex flex-col">
|
|
82
103
|
<!-- Search bar -->
|
|
83
104
|
<div class="shrink-0 bg-ink-900/60 border-b border-ink-800 px-4 py-2.5 flex items-center gap-2">
|
|
84
105
|
<div class="relative flex-1">
|
|
@@ -91,20 +112,25 @@
|
|
|
91
112
|
/>
|
|
92
113
|
<div id="search-results" class="hidden absolute top-full left-0 right-0 mt-1 bg-ink-800 border border-ink-700 rounded-lg shadow-xl max-h-72 overflow-y-auto z-40"></div>
|
|
93
114
|
</div>
|
|
94
|
-
<button id="tree-refresh-btn" type="button" class="p-1.5 text-ink-500 hover:text-ink-300 rounded-lg hover:bg-ink-800 transition-colors" title="Refresh">
|
|
115
|
+
<button id="tree-refresh-btn" type="button" class="hidden lg:inline-flex p-1.5 text-ink-500 hover:text-ink-300 rounded-lg hover:bg-ink-800 transition-colors" title="Refresh">
|
|
95
116
|
<i data-lucide="refresh-cw" class="w-4 h-4"></i>
|
|
96
117
|
</button>
|
|
97
118
|
</div>
|
|
98
|
-
<!-- Split: tree + preview -->
|
|
119
|
+
<!-- Split: tree + preview (desktop) / single panel (mobile) -->
|
|
99
120
|
<div class="flex-1 min-h-0 flex flex-col lg:flex-row">
|
|
100
|
-
<div id="file-tree" class="
|
|
101
|
-
|
|
121
|
+
<div id="file-tree-container" class="flex-1 min-h-0 lg:flex-none lg:w-72 lg:min-w-[220px] lg:max-w-[360px] border-b lg:border-b-0 lg:border-r border-ink-800">
|
|
122
|
+
<div id="file-tree" class="h-full overflow-y-auto overscroll-contain px-1 py-1"></div>
|
|
123
|
+
</div>
|
|
124
|
+
<div id="file-viewer-container" class="hidden flex flex-1 min-h-0 flex-col lg:flex">
|
|
102
125
|
<div class="shrink-0 flex items-center gap-2 px-4 py-2 border-b border-ink-800/60">
|
|
103
|
-
<
|
|
104
|
-
|
|
105
|
-
|
|
126
|
+
<button id="mobile-explorer-back-btn" type="button" class="hidden lg:hidden p-1 text-ink-500 hover:text-ink-300 rounded-lg hover:bg-ink-800 transition-colors" title="Back to files">
|
|
127
|
+
<i data-lucide="arrow-left" class="w-3.5 h-3.5"></i>
|
|
128
|
+
</button>
|
|
129
|
+
<i data-lucide="eye" class="hidden lg:block w-3.5 h-3.5 text-ink-500"></i>
|
|
130
|
+
<button id="viewer-refresh-btn" type="button" class="order-2 lg:order-none lg:ml-auto p-1 text-ink-500 hover:text-ink-300 rounded-lg hover:bg-ink-800 transition-colors hidden" title="Refresh file">
|
|
106
131
|
<i data-lucide="refresh-cw" class="w-3.5 h-3.5"></i>
|
|
107
132
|
</button>
|
|
133
|
+
<span id="viewer-title" class="order-3 lg:order-none min-w-0 flex-1 text-xs font-mono text-ink-400 truncate">Select a file</span>
|
|
108
134
|
</div>
|
|
109
135
|
<div id="viewer" class="flex-1 overflow-y-auto overscroll-contain p-4">
|
|
110
136
|
<div class="flex flex-col items-center justify-center h-full text-ink-600">
|
|
@@ -150,16 +176,16 @@
|
|
|
150
176
|
|
|
151
177
|
<!-- Bottom tab bar -->
|
|
152
178
|
<nav class="shrink-0 bg-ink-900 border-t border-ink-800 flex z-30 safe-bottom">
|
|
153
|
-
<button type="button" class="tab-btn flex-1 flex flex-col items-center gap-0.5 py-2.5 text-ink-500 transition-colors" data-tab="clipboard">
|
|
154
|
-
<i data-lucide="clipboard" class="w-5 h-5"></i>
|
|
155
|
-
<span class="text-[10px] font-semibold uppercase tracking-wide">Clipboard</span>
|
|
156
|
-
<span id="tab-badge-clipboard" class="text-[9px] font-mono text-ink-600"></span>
|
|
157
|
-
</button>
|
|
158
179
|
<button type="button" class="tab-btn flex-1 flex flex-col items-center gap-0.5 py-2.5 text-ink-500 transition-colors" data-tab="files">
|
|
159
180
|
<i data-lucide="folder-tree" class="w-5 h-5"></i>
|
|
160
181
|
<span class="text-[10px] font-semibold uppercase tracking-wide">Files</span>
|
|
161
182
|
<span id="tab-badge-files" class="text-[9px] font-mono text-ink-600"></span>
|
|
162
183
|
</button>
|
|
184
|
+
<button type="button" class="tab-btn flex-1 flex flex-col items-center gap-0.5 py-2.5 text-ink-500 transition-colors" data-tab="clipboard">
|
|
185
|
+
<i data-lucide="clipboard" class="w-5 h-5"></i>
|
|
186
|
+
<span class="text-[10px] font-semibold uppercase tracking-wide">Clipboard</span>
|
|
187
|
+
<span id="tab-badge-clipboard" class="text-[9px] font-mono text-ink-600"></span>
|
|
188
|
+
</button>
|
|
163
189
|
<button type="button" class="tab-btn flex-1 flex flex-col items-center gap-0.5 py-2.5 text-ink-500 transition-colors" data-tab="screenshots">
|
|
164
190
|
<i data-lucide="camera" class="w-5 h-5"></i>
|
|
165
191
|
<span class="text-[10px] font-semibold uppercase tracking-wide">Screenshots</span>
|