feat: [Electron Demo] - implement OS level file associations via dist build.

This commit is contained in:
syntaxbullet 2025-04-30 20:15:48 +02:00
parent 93de5bce80
commit d1efa326f6
4 changed files with 95 additions and 5 deletions

@ -1,5 +1,6 @@
const XLSX = require("xlsx");
const electron = require("@electron/remote");
const { ipcRenderer } = require('electron');
// --- Supported Extensions ---
const EXTENSIONS =
@ -202,3 +203,16 @@ async function readFile(files) {
// --- Initial Setup ---
attachDropListeners();
// handle file opening events from the main process
ipcRenderer.on('file-opened', async (_evt, filePath) => {
console.log('Received file-opened event:', filePath);
showSpinner();
// yield to event loop to render spinner
await new Promise(r => setTimeout(r, 50));
renderWorkbookToTables(XLSX.readFile(filePath)); // already in your helper list
showLoadedFileUI(filePath.split(/[/\\]/).pop());
hideSpinner();
hideDropUI();
showExportBtn();
});

@ -6,6 +6,57 @@ require('@electron/remote/main').initialize(); // required for Electron 14+
var win = null;
const EXT_REGEX = /\.(xls|xlsx|xlsm|xlsb|xml|csv|txt|dif|sylk|slk|prn|ods|fods|htm|html|numbers)$/i;
const pendingPaths = []; // any paths that arrive before the window exists
// send file opening events to renderer
function sendToRenderer(filePath) {
if (win && win.webContents) {
win.webContents.send('file-opened', filePath);
} else {
pendingPaths.push(filePath);
}
}
function firstSpreadsheetFromArgv() {
const args = process.defaultApp // dev: electron .
? process.argv.slice(2) // skip electron executable & dir
: process.argv.slice(1); // skip packaged exe
return args.find(a => EXT_REGEX.test(a)); // undefined if none
}
/* ---- 1⃣ single-instance guard (needed for Windows / Linux) ---- */
// on windows and linux, opening a file opens a new instance of the app, this prevents that.
const gotLock = app.requestSingleInstanceLock();
if (!gotLock) app.quit();
else {
app.on('second-instance', (_e, argv) => { // emitted in *primary* instance
const fp = argv.find(a => EXT_REGEX.test(a));
if (fp) sendToRenderer(fp);
if (win) { win.show(); win.focus(); }
});
}
/* ---- 2⃣ platform-specific “open file” hooks ---- */
app.on('open-file', (event, fp) => { // macOS Dock / Finder
event.preventDefault();
sendToRenderer(fp);
});
app.on('open-url', (event, url) => { // you can add a custom protocol if you want to handle URLs
event.preventDefault();
sendToRenderer(url.replace('file://', '')); // crude, adjust if you keep deep-links
});
/* ---- 3⃣ normal start-up, harvest argv ---- */
app.whenReady().then(() => {
const fp = firstSpreadsheetFromArgv(); // Windows & Linux first launch
if (fp) pendingPaths.push(fp);
createWindow();
});
/* ---- 4⃣ create the window ---- */
function createWindow() {
if (win) return;
win = new electron.BrowserWindow({
@ -18,12 +69,15 @@ function createWindow() {
}
});
win.loadURL("file://" + __dirname + "/index.html");
require('@electron/remote/main').enable(win.webContents); // required for Electron 14+
win.webContents.openDevTools();
require('@electron/remote/main').enable(win.webContents); // required for Electron 14
if (process.env.NODE_ENV === 'development') win.webContents.openDevTools(); // only open devtools in development
win.on('closed', function () { win = null; });
win.webContents.once('did-finish-load', () => {
pendingPaths.splice(0).forEach(sendToRenderer);
});
}
if (app.setAboutPanelOptions) app.setAboutPanelOptions({ applicationName: 'sheetjs-electron', applicationVersion: "XLSX " + XLSX.version, copyright: "(C) 2017-present SheetJS LLC" });
app.on('open-file', function () { console.log(arguments); });
app.on('ready', createWindow);
app.on('activate', createWindow);
app.on('window-all-closed', function () { if (process.platform !== 'darwin') app.quit(); });

@ -12,7 +12,8 @@
"scripts": {
"start": "electron-forge start",
"package": "electron-forge package",
"make": "electron-forge make"
"make": "electron-forge make",
"dist": "electron-builder"
},
"devDependencies": {
"@electron-forge/cli": "7.8.0",
@ -20,8 +21,28 @@
"@electron-forge/maker-rpm": "7.8.0",
"@electron-forge/maker-squirrel": "7.8.0",
"@electron-forge/maker-zip": "7.8.0",
"electron": "35.1.2"
"electron": "35.1.2",
"electron-builder": "^26.0.12"
},
"build": {
"appId": "com.sheetjs.electron",
"fileAssociations": [
{
"ext": [
"xls","xlsx","xlsm","xlsb","xml","csv","txt","dif",
"sylk","slk","prn","ods","fods","htm","html","numbers"
],
"name": "Spreadsheet / Delimited File",
"description": "Spreadsheets and delimited text files opened by SheetJS-Electron",
"role": "Editor"
}
],
"mac": { "target": "dmg" },
"win": { "target": "nsis" },
"linux": { "target": "deb" }
},
"config": {
"forge": {
"packagerConfig": {},

@ -288,6 +288,7 @@ summary:focus-within {
.sheetjs-tab-content {
cursor: pointer;
padding: 1rem;
overflow-x: auto;
}
/* =====================