Skip to content

Commit 16549da

Browse files
author
FileShot
committed
feat: embed online in shell, add tools dropdown, enable drag from explorer
- Keep sidebar always visible when going online (embed via webview) - Add Tools dropdown with real FileShot tool URLs - Enable native drag-out from Explorer (multi-select + folder support) - Add grid view toggle for Explorer - Remove unused archiver dependency
1 parent 4170a31 commit 16549da

5 files changed

Lines changed: 529 additions & 81 deletions

File tree

main.js

Lines changed: 82 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -349,7 +349,8 @@ function createWindow() {
349349
preload: path.join(__dirname, 'preload.js'),
350350
nodeIntegration: false,
351351
contextIsolation: true,
352-
webSecurity: true
352+
webSecurity: true,
353+
webviewTag: true
353354
},
354355
show: false, // Don't show until ready
355356
backgroundColor: '#1a1a1a',
@@ -405,6 +406,60 @@ function createWindow() {
405406
});
406407
}
407408

409+
// ============================================================================
410+
// DRAG-OUT FROM LOCAL EXPLORER (OS DRAG)
411+
// ============================================================================
412+
413+
ipcMain.on('start-drag', async (event, paths) => {
414+
const list = Array.isArray(paths) ? paths.map(String).filter(Boolean) : [];
415+
if (!list.length) return;
416+
417+
const wc = event.sender;
418+
if (!wc || typeof wc.startDrag !== 'function') return;
419+
420+
// If folders are included, expand them into file paths so web uploads can accept the drop.
421+
// NOTE: Many sites don't accept directory drops, but do accept multiple files.
422+
let dragFiles = [];
423+
for (const p of list) {
424+
const st = safeStat(p);
425+
if (!st) continue;
426+
if (st.isFile()) {
427+
dragFiles.push(p);
428+
} else if (st.isDirectory()) {
429+
try {
430+
const files = getAllFilesInFolder(p);
431+
dragFiles.push(...files);
432+
} catch (_) {}
433+
}
434+
}
435+
436+
// Prevent pathological huge drags from freezing the app.
437+
if (dragFiles.length > 2000) {
438+
dragFiles = dragFiles.slice(0, 2000);
439+
}
440+
441+
if (!dragFiles.length) {
442+
// Fall back to dragging the first original path if expansion produced nothing.
443+
dragFiles = [list[0]];
444+
}
445+
446+
const iconPath = path.join(__dirname, 'assets', 'icon.png');
447+
const icon = nativeImage.createFromPath(iconPath);
448+
449+
try {
450+
// Electron supports `files` in newer versions; fall back to single file.
451+
try {
452+
if (dragFiles.length > 1) {
453+
wc.startDrag({ files: dragFiles, icon });
454+
} else {
455+
wc.startDrag({ file: dragFiles[0], icon });
456+
}
457+
} catch (_) {
458+
wc.startDrag({ file: dragFiles[0], icon });
459+
}
460+
}
461+
});
462+
408463
/**
409464
* Create system tray icon
410465
*/
@@ -907,12 +962,37 @@ ipcMain.handle('shred-start', async (event, payload) => {
907962

908963
ipcMain.handle('go-online', async () => {
909964
if (!mainWindow) return { success: false };
910-
await loadFrontendFallback({ preferredPath: '/', reason: 'renderer:go-online' });
965+
966+
// Always keep the local UI shell so the sidebar remains available.
967+
// The renderer will embed the live site in a <webview> panel.
968+
const url = String(mainWindow.webContents.getURL() || '');
969+
const inLocalShell = url.startsWith('file:') && url.includes('renderer/local/index.html');
970+
if (!inLocalShell) {
971+
try {
972+
await mainWindow.loadFile(LOCAL_UI_INDEX);
973+
} catch (_) {}
974+
}
975+
976+
try {
977+
mainWindow.webContents.send('navigate-to', { tool: 'online', url: FRONTEND_URL });
978+
} catch (_) {}
979+
911980
mainWindow.show();
912981
mainWindow.focus();
913982
return { success: true };
914983
});
915984

985+
ipcMain.handle('open-external', async (_event, url) => {
986+
const u = String(url || '').trim();
987+
if (!u) return { success: false };
988+
try {
989+
await shell.openExternal(u);
990+
return { success: true };
991+
} catch (e) {
992+
return { success: false, error: e && e.message ? e.message : String(e) };
993+
}
994+
});
995+
916996
ipcMain.handle('vault-list', async () => {
917997
const items = getVaultItems();
918998
return { items, totalBytes: vaultTotalBytes(items) };

preload.js

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,11 @@ contextBridge.exposeInMainWorld('electronAPI', {
5656
// App controls
5757
goOnline: () => ipcRenderer.invoke('go-online'),
5858
copyToClipboard: (text) => ipcRenderer.invoke('copy-to-clipboard', String(text || '')),
59+
openExternal: (url) => ipcRenderer.invoke('open-external', String(url || '')),
60+
61+
// Initiate an OS drag operation for one or more file paths.
62+
// Useful for dragging from the sidebar Explorer into the embedded webview or other apps.
63+
startDrag: (paths) => ipcRenderer.send('start-drag', Array.isArray(paths) ? paths : [paths]),
5964

6065
// Secure shred (local destructive operation)
6166
shredStart: (payload, progressCb) => {
@@ -73,7 +78,9 @@ contextBridge.exposeInMainWorld('electronAPI', {
7378

7479
// Navigation
7580
onNavigateTo: (callback) => {
76-
ipcRenderer.on('navigate-to', (event, route) => callback(route));
81+
ipcRenderer.on('navigate-to', (_event, route) => {
82+
try { callback(route); } catch (_) {}
83+
});
7784
},
7885

7986
// Upload events

0 commit comments

Comments
 (0)