Skip to content

Commit 5fdda4d

Browse files
author
FileShot
committed
feat: UI overhaul - explorer on right side, resizable, no blue, proper close behavior, collapsible tools dropdown
1 parent 6a1ac15 commit 5fdda4d

5 files changed

Lines changed: 128 additions & 58 deletions

File tree

72.1 MB
Binary file not shown.

main.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -374,10 +374,10 @@ function createWindow() {
374374
mainWindow.show();
375375
});
376376

377-
// Handle window close - allow actual close, don't prevent it
377+
// Handle window close - fully quit the app
378378
mainWindow.on('close', (event) => {
379-
// Allow the window to close normally
380-
// Don't minimize to tray on close
379+
// Quit the entire application when window is closed
380+
app.quit();
381381
});
382382

383383
// Handle external links

renderer/local/app.js

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,11 @@ const DOM = {
5555
navItems: () => document.querySelectorAll('.nav-item[data-tool]'),
5656
goOnlineBtn: () => document.getElementById('btnGoOnline'),
5757

58+
// Explorer sidebar (right side)
59+
explorerSidebar: () => document.getElementById('explorerSidebar'),
60+
resizeHandle: () => document.getElementById('resizeHandle'),
61+
btnToggleExplorer: () => document.getElementById('btnToggleExplorer'),
62+
5863
// Tools menu
5964
toolsToggleBtn: () => document.getElementById('btnToolsToggle'),
6065
toolsSubmenu: () => document.getElementById('toolsSubmenu'),
@@ -146,12 +151,61 @@ window.addEventListener('DOMContentLoaded', () => {
146151
initShredTool();
147152
initSettingsTool();
148153
initExplorer();
154+
initExplorerResize();
149155
initVaultSync();
150156
loadSettings();
151157
refreshVault();
152158
switchToTool('vault');
153159
});
154160

161+
// ============================================================================
162+
// EXPLORER RESIZE & TOGGLE
163+
// ============================================================================
164+
165+
function initExplorerResize() {
166+
const handle = DOM.resizeHandle();
167+
const explorer = DOM.explorerSidebar();
168+
const toggleBtn = DOM.btnToggleExplorer();
169+
170+
if (!handle || !explorer) return;
171+
172+
// Toggle explorer visibility
173+
if (toggleBtn) {
174+
toggleBtn.addEventListener('click', () => {
175+
explorer.classList.toggle('hidden');
176+
handle.style.display = explorer.classList.contains('hidden') ? 'none' : '';
177+
});
178+
}
179+
180+
// Resize functionality
181+
let isResizing = false;
182+
183+
handle.addEventListener('mousedown', (e) => {
184+
isResizing = true;
185+
handle.classList.add('dragging');
186+
document.body.style.cursor = 'col-resize';
187+
document.body.style.userSelect = 'none';
188+
e.preventDefault();
189+
});
190+
191+
document.addEventListener('mousemove', (e) => {
192+
if (!isResizing) return;
193+
const containerRect = document.querySelector('.app-container').getBoundingClientRect();
194+
const newWidth = containerRect.right - e.clientX;
195+
const clampedWidth = Math.max(200, Math.min(450, newWidth));
196+
explorer.style.width = clampedWidth + 'px';
197+
});
198+
199+
document.addEventListener('mouseup', () => {
200+
if (isResizing) {
201+
isResizing = false;
202+
handle.classList.remove('dragging');
203+
document.body.style.cursor = '';
204+
document.body.style.userSelect = '';
205+
}
206+
});
207+
}
208+
155209
// ============================================================================
156210
// MAIN-PROCESS VAULT SYNC
157211
// ============================================================================

renderer/local/index.html

Lines changed: 45 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -98,42 +98,10 @@
9898
</button>
9999
</nav>
100100

101-
<!-- Sidebar File Explorer -->
102-
<section class="sidebar-explorer" id="sidebarExplorer" aria-label="File Explorer">
103-
<div class="explorer-header">
104-
<div class="explorer-title">Explorer</div>
105-
<div class="explorer-actions">
106-
<button class="icon-btn" id="btnExplorerView" title="Toggle view">
107-
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
108-
<rect x="3" y="3" width="7" height="7"></rect>
109-
<rect x="14" y="3" width="7" height="7"></rect>
110-
<rect x="3" y="14" width="7" height="7"></rect>
111-
<rect x="14" y="14" width="7" height="7"></rect>
112-
</svg>
113-
</button>
114-
<button class="icon-btn" id="btnExplorerUp" title="Up">
115-
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
116-
<path d="M12 19V5"/>
117-
<polyline points="5 12 12 5 19 12"/>
118-
</svg>
119-
</button>
120-
<button class="icon-btn" id="btnExplorerRefresh" title="Refresh">
121-
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
122-
<polyline points="23 4 23 10 17 10"/>
123-
<polyline points="1 20 1 14 7 14"/>
124-
<path d="M3.51 9a9 9 0 0 1 14.13-3.36L23 10"/>
125-
<path d="M20.49 15a9 9 0 0 1-14.13 3.36L1 14"/>
126-
</svg>
127-
</button>
128-
</div>
129-
</div>
130-
<div class="explorer-path" id="explorerPath">Loading…</div>
131-
<div class="explorer-list" id="explorerList"></div>
132-
<div class="explorer-hint">Drag files/folders into the app to add to Local Vault.</div>
133-
</section>
101+
<!-- Sidebar File Explorer - REMOVED, moved to right panel -->
134102

135103
<div class="sidebar-footer">
136-
<button class="btn btn-secondary btn-full" id="btnGoOnline">
104+
<button class="btn btn-primary btn-full" id="btnGoOnline">
137105
<span>Go Online</span>
138106
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
139107
<path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>
@@ -164,6 +132,11 @@
164132
<h1 id="toolTitle">Local Vault</h1>
165133
</div>
166134
<div class="topbar-right">
135+
<button class="icon-btn" id="btnToggleExplorer" title="Toggle File Explorer">
136+
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
137+
<path d="M22 19a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h5l2 3h9a2 2 0 0 1 2 2z"></path>
138+
</svg>
139+
</button>
167140
<span id="storageStatus" class="status-badge"></span>
168141
</div>
169142
</header>
@@ -419,7 +392,7 @@ <h3>Security Settings</h3>
419392
<div class="settings-card">
420393
<h3>About</h3>
421394
<div class="info-row">
422-
<span>FileShot Desktop v1.2.0</span>
395+
<span>FileShot Desktop v1.4.0</span>
423396
<span class="muted">Offline-first encryption</span>
424397
</div>
425398
<div class="info-row" style="margin-top: 8px;">
@@ -430,6 +403,43 @@ <h3>About</h3>
430403
</section>
431404
</div>
432405
</main>
406+
407+
<!-- Resize Handle -->
408+
<div class="resize-handle" id="resizeHandle"></div>
409+
410+
<!-- Right Sidebar: File Explorer -->
411+
<aside class="explorer-sidebar" id="explorerSidebar">
412+
<div class="explorer-header">
413+
<div class="explorer-title">File Explorer</div>
414+
<div class="explorer-actions">
415+
<button class="icon-btn" id="btnExplorerView" title="Toggle grid/list view">
416+
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
417+
<rect x="3" y="3" width="7" height="7"></rect>
418+
<rect x="14" y="3" width="7" height="7"></rect>
419+
<rect x="3" y="14" width="7" height="7"></rect>
420+
<rect x="14" y="14" width="7" height="7"></rect>
421+
</svg>
422+
</button>
423+
<button class="icon-btn" id="btnExplorerUp" title="Go up">
424+
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
425+
<path d="M12 19V5"/>
426+
<polyline points="5 12 12 5 19 12"/>
427+
</svg>
428+
</button>
429+
<button class="icon-btn" id="btnExplorerRefresh" title="Refresh">
430+
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
431+
<polyline points="23 4 23 10 17 10"/>
432+
<polyline points="1 20 1 14 7 14"/>
433+
<path d="M3.51 9a9 9 0 0 1 14.13-3.36L23 10"/>
434+
<path d="M20.49 15a9 9 0 0 1-14.13 3.36L1 14"/>
435+
</svg>
436+
</button>
437+
</div>
438+
</div>
439+
<div class="explorer-path" id="explorerPath">Loading…</div>
440+
<div class="explorer-list" id="explorerList"></div>
441+
<div class="explorer-hint">Drag files to main area or external apps. Ctrl/Shift for multi-select.</div>
442+
</aside>
433443
</div>
434444

435445
<script src="./app.js"></script>

renderer/local/styles.css

Lines changed: 26 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,10 @@
99
--text-secondary: rgba(232,238,246,0.68);
1010
--accent: #f97316;
1111
--accent-hover: #ea580c;
12-
--accent2: #3b82f6;
1312
--ok: #10b981;
14-
--sidebar-width: 260px;
15-
--sidebar-width-collapsed: 80px;
13+
--sidebar-width: 220px;
14+
--sidebar-width-collapsed: 60px;
15+
--explorer-width: 280px;
1616
}
1717

1818
* { box-sizing: border-box; }
@@ -40,7 +40,8 @@ body {
4040
.nav-item.active { background: rgba(249, 115, 22, 0.16); border-color: rgba(249, 115, 22, 0.45); color: var(--accent); }
4141
.tools-menu { display: flex; flex-direction: column; }
4242
.nav-item.tools-toggle { justify-content: space-between; }
43-
.nav-item .chev { opacity: 0.9; }
43+
.nav-item .chev { opacity: 0.9; transition: transform 0.2s; }
44+
.nav-item.tools-toggle[aria-expanded="true"] .chev { transform: rotate(180deg); }
4445
.tools-submenu { margin: 4px 0 0 10px; border-left: 1px solid rgba(255, 255, 255, 0.1); padding-left: 10px; display: flex; flex-direction: column; gap: 4px; }
4546
.nav-subitem { width: 100%; background: transparent; border: 0; color: var(--text); text-align: left; padding: 8px 10px; border-radius: 8px; cursor: pointer; font-size: 13px; opacity: 0.92; }
4647
.nav-subitem:hover { background: rgba(255, 255, 255, 0.06); opacity: 1; }
@@ -50,7 +51,10 @@ body {
5051
.btn-full { width: 100%; display: flex; align-items: center; justify-content: center; gap: 8px; }
5152
.sidebar.collapsed .btn-full span { display: none; }
5253

53-
.sidebar-explorer { border-top: 1px solid var(--border); padding: 12px; display: flex; flex-direction: column; gap: 8px; }
54+
/* Right-side Explorer Sidebar */
55+
.explorer-sidebar { width: var(--explorer-width); min-width: 200px; max-width: 450px; background: var(--bg-secondary); border-left: 1px solid var(--border); display: flex; flex-direction: column; padding: 12px; gap: 10px; transition: width 0.1s; }
56+
.explorer-sidebar.hidden { display: none; }
57+
5458
.explorer-header { display: flex; align-items: center; justify-content: space-between; gap: 10px; }
5559
.explorer-title { font-size: 12px; font-weight: 800; letter-spacing: 0.4px; text-transform: uppercase; color: rgba(232, 238, 246, 0.75); }
5660
.explorer-actions { display: flex; gap: 6px; }
@@ -59,27 +63,29 @@ body {
5963
.icon-btn:active { transform: scale(0.98); }
6064

6165
.explorer-path { font-size: 12px; color: var(--text-secondary); padding: 6px 8px; border: 1px solid var(--border); border-radius: 10px; background: rgba(0, 0, 0, 0.18); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
62-
.explorer-list { max-height: 260px; overflow-y: auto; border: 1px solid var(--border); border-radius: 12px; background: rgba(0, 0, 0, 0.18); }
66+
.explorer-list { flex: 1; overflow-y: auto; border: 1px solid var(--border); border-radius: 12px; background: rgba(0, 0, 0, 0.18); }
6367
.explorer-list.grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 8px; padding: 8px; }
6468
.explorer-list.grid .explorer-item { border-bottom: none; border: 1px solid rgba(255, 255, 255, 0.06); border-radius: 12px; }
65-
.explorer-item { display: grid; grid-template-columns: 18px 1fr auto; align-items: center; gap: 8px; padding: 8px 10px; border-bottom: 1px solid rgba(255, 255, 255, 0.05); font-size: 12px; color: var(--text); user-select: none; }
69+
.explorer-item { display: grid; grid-template-columns: 18px 1fr auto; align-items: center; gap: 8px; padding: 8px 10px; border-bottom: 1px solid rgba(255, 255, 255, 0.05); font-size: 12px; color: var(--text); user-select: none; cursor: pointer; }
6670
.explorer-item:last-child { border-bottom: none; }
6771
.explorer-item:hover { background: var(--panel-hover); }
6872
.explorer-item .name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
6973
.explorer-list.grid .explorer-item .name { display: -webkit-box; line-clamp: 2; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; white-space: normal; }
70-
.explorer-item.selected { outline: 2px solid rgba(76, 194, 255, 0.45); background: rgba(76, 194, 255, 0.08); }
74+
.explorer-item.selected { outline: 2px solid rgba(249, 115, 22, 0.55); background: rgba(249, 115, 22, 0.12); }
7175
.explorer-item .meta { color: var(--text-secondary); font-size: 11px; }
7276
.explorer-item .add { border: 1px solid var(--border); background: var(--panel); color: var(--accent); border-radius: 10px; padding: 5px 8px; font-size: 11px; font-weight: 800; cursor: pointer; }
7377
.explorer-item .add:hover { background: var(--panel-hover); }
74-
.explorer-hint { font-size: 11px; color: var(--text-secondary); line-height: 1.35; }
78+
.explorer-hint { font-size: 11px; color: var(--text-secondary); line-height: 1.35; padding-top: 6px; }
7579

76-
.sidebar.collapsed .sidebar-explorer { display: none; }
80+
/* Resize handle between main content and explorer */
81+
.resize-handle { width: 5px; background: transparent; cursor: col-resize; transition: background 0.2s; flex-shrink: 0; }
82+
.resize-handle:hover, .resize-handle.dragging { background: var(--accent); }
7783

78-
.main-content { flex: 1; display: flex; flex-direction: column; overflow: hidden; }
79-
.topbar { display: flex; align-items: center; justify-content: space-between; padding: 16px 24px; border-bottom: 1px solid var(--border); background: var(--panel); flex-shrink: 0; }
80-
.topbar-left h1 { margin: 0; font-size: 20px; font-weight: 700; letter-spacing: 0.3px; display: flex; align-items: center; gap: 10px; }
84+
.main-content { flex: 1; display: flex; flex-direction: column; overflow: hidden; min-width: 400px; }
85+
.topbar { display: flex; align-items: center; justify-content: space-between; padding: 12px 20px; border-bottom: 1px solid var(--border); background: var(--panel); flex-shrink: 0; }
86+
.topbar-left h1 { margin: 0; font-size: 18px; font-weight: 700; letter-spacing: 0.3px; display: flex; align-items: center; gap: 10px; }
8187
.topbar-left h1 svg { flex-shrink: 0; }
82-
.topbar-right { display: flex; gap: 12px; align-items: center; }
88+
.topbar-right { display: flex; gap: 10px; align-items: center; }
8389
.status-badge { font-size: 12px; color: var(--text-secondary); background: var(--panel); padding: 6px 12px; border-radius: 8px; border: 1px solid var(--border); }
8490

8591
.drop-zone { position: fixed; inset: 0; background: rgba(0, 0, 0, 0.85); display: none; align-items: center; justify-content: center; z-index: 9999; backdrop-filter: blur(4px); pointer-events: all; }
@@ -93,20 +99,20 @@ body {
9399
.btn:active { transform: scale(0.98); }
94100
.btn-primary { border-color: rgba(249, 115, 22, 0.45); background: rgba(249, 115, 22, 0.16); color: var(--accent); }
95101
.btn-primary:hover { background: rgba(249, 115, 22, 0.22); }
96-
.btn-secondary { border-color: rgba(59, 130, 246, 0.35); background: rgba(59, 130, 246, 0.12); color: var(--accent2); }
97-
.btn-secondary:hover { background: rgba(59, 130, 246, 0.18); }
102+
.btn-secondary { border-color: rgba(249, 115, 22, 0.35); background: rgba(249, 115, 22, 0.10); color: var(--accent); }
103+
.btn-secondary:hover { background: rgba(249, 115, 22, 0.18); }
98104
.btn-danger { border-color: rgba(239, 68, 68, 0.55); background: rgba(239, 68, 68, 0.20); color: #ef4444; }
99105
.btn-danger:hover { background: rgba(239, 68, 68, 0.28); }
100106
.btn:disabled { opacity: 0.5; cursor: not-allowed; }
101107

102-
.tools-container { flex: 1; overflow: auto; padding: 24px; position: relative; }
103-
.tool-panel { display: none; max-width: 1200px; margin: 0 auto; }
108+
.tools-container { flex: 1; overflow: auto; padding: 16px; position: relative; }
109+
.tool-panel { display: none; height: 100%; }
104110
.tool-panel:not([hidden]) { display: block; }
105111
.online-shell { display: flex; flex-direction: column; gap: 10px; height: 100%; min-height: 0; }
106-
.online-bar { display: flex; align-items: center; gap: 10px; }
112+
.online-bar { display: flex; align-items: center; gap: 10px; flex-shrink: 0; }
107113
.online-controls { display: flex; gap: 6px; }
108114
.online-url { flex: 1; min-width: 0; padding: 8px 10px; border-radius: 10px; background: rgba(255, 255, 255, 0.05); border: 1px solid rgba(255, 255, 255, 0.08); color: rgba(255, 255, 255, 0.85); font-size: 12px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
109-
.online-frame { height: calc(100vh - 220px); border-radius: 14px; overflow: hidden; border: 1px solid rgba(255, 255, 255, 0.08); background: rgba(0, 0, 0, 0.2); }
115+
.online-frame { flex: 1; border-radius: 10px; overflow: hidden; border: 1px solid rgba(255, 255, 255, 0.08); background: rgba(0, 0, 0, 0.2); }
110116
#onlineWebview { width: 100%; height: 100%; }
111117
.panel-actions { display: flex; gap: 10px; margin-bottom: 20px; }
112118
.status { font-size: 13px; color: var(--text-secondary); margin-bottom: 16px; padding: 8px 12px; background: var(--panel); border-radius: 8px; border: 1px solid var(--border); }

0 commit comments

Comments
 (0)