From 8edc2673b39f43ca6146fd39b5f65afdb5475de8 Mon Sep 17 00:00:00 2001 From: Davide Grilli Date: Thu, 5 Mar 2026 16:30:03 +0100 Subject: [PATCH] feat: aggiunge drag & drop di cartelle e file zip per lo smistamento --- main.js | 24 ++++++++++++++++++ preload.js | 1 + renderer/index.html | 27 +++++++++++++++++++++ renderer/renderer.js | 58 ++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 110 insertions(+) diff --git a/main.js b/main.js index 1125305..8155348 100644 --- a/main.js +++ b/main.js @@ -101,6 +101,30 @@ ipcMain.handle('select-zip', async () => { return { canceled: false, ...routingResult }; }); +ipcMain.handle('process-dropped-path', async (_event, payload) => { + const droppedPath = String(payload?.path || '').trim(); + if (!droppedPath) { + throw new Error('Percorso non valido'); + } + + const stats = await fs.stat(droppedPath).catch(() => null); + if (!stats) { + throw new Error('Percorso non trovato'); + } + + if (stats.isDirectory()) { + const routingResult = await processFolder(droppedPath, config); + return { canceled: false, sourceType: 'folder', ...routingResult }; + } + + if (stats.isFile() && path.extname(droppedPath).toLowerCase() === '.zip') { + const routingResult = await processZip(droppedPath, config); + return { canceled: false, sourceType: 'zip', ...routingResult }; + } + + throw new Error('Trascina una cartella o un file .zip'); +}); + ipcMain.handle('get-destination', async () => ({ destination: config.destination || DEFAULT_DESTINATION, })); diff --git a/preload.js b/preload.js index 1d93772..00be9ac 100644 --- a/preload.js +++ b/preload.js @@ -3,6 +3,7 @@ const { contextBridge, ipcRenderer } = require('electron'); contextBridge.exposeInMainWorld('api', { selectFolder: () => ipcRenderer.invoke('select-folder'), selectZip: () => ipcRenderer.invoke('select-zip'), + processDroppedPath: (path) => ipcRenderer.invoke('process-dropped-path', { path }), getDestination: () => ipcRenderer.invoke('get-destination'), selectDestinationFolder: () => ipcRenderer.invoke('select-destination-folder'), updateDestination: (destination) => ipcRenderer.invoke('update-destination', { destination }), diff --git a/renderer/index.html b/renderer/index.html index 1911c17..d4ce8c1 100644 --- a/renderer/index.html +++ b/renderer/index.html @@ -92,6 +92,29 @@ background: #f8fafc; } + .drop-zone { + margin-top: 18px; + border: 2px dashed #9db4d8; + border-radius: 12px; + background: #f2f7ff; + color: #1e3a5f; + padding: 20px; + text-align: center; + font-size: 14px; + transition: border-color 120ms ease, background-color 120ms ease, color 120ms ease; + } + + .drop-zone.active { + border-color: var(--accent); + background: #e8f0ff; + } + + .drop-zone.error { + border-color: #dc2626; + background: #fff1f2; + color: #991b1b; + } + .rules h2 { margin: 0 0 10px; font-size: 17px; @@ -166,6 +189,10 @@ +
+ Trascina qui una cartella o un file .zip +
+

Destinazione file CAD

diff --git a/renderer/renderer.js b/renderer/renderer.js index c02d41b..0076468 100644 --- a/renderer/renderer.js +++ b/renderer/renderer.js @@ -1,10 +1,13 @@ const folderBtn = document.getElementById('folderBtn'); const zipBtn = document.getElementById('zipBtn'); +const dropZone = document.getElementById('dropZone'); const output = document.getElementById('output'); const destinationInput = document.getElementById('destinationInput'); const browseDestinationBtn = document.getElementById('browseDestinationBtn'); const saveDestinationBtn = document.getElementById('saveDestinationBtn'); const destinationStatus = document.getElementById('destinationStatus'); +const defaultDropZoneText = 'Trascina qui una cartella o un file .zip'; +let isProcessing = false; function setLoading(isLoading) { folderBtn.disabled = isLoading; @@ -37,6 +40,11 @@ function renderResult(title, result) { } async function handleAction(actionName, actionFn) { + if (isProcessing) { + return; + } + + isProcessing = true; setLoading(true); output.textContent = `${actionName} in corso...`; @@ -53,12 +61,62 @@ async function handleAction(actionName, actionFn) { output.textContent = `${actionName} fallito:\n${error.message}`; } finally { setLoading(false); + isProcessing = false; } } folderBtn.addEventListener('click', () => handleAction('Process Folder', window.api.selectFolder)); zipBtn.addEventListener('click', () => handleAction('Process ZIP', window.api.selectZip)); +function resetDropZoneText() { + dropZone.textContent = defaultDropZoneText; +} + +function setDropZoneError(message) { + dropZone.textContent = message; + dropZone.classList.add('error'); + setTimeout(() => { + dropZone.classList.remove('error'); + resetDropZoneText(); + }, 1800); +} + +dropZone.addEventListener('dragover', (event) => { + event.preventDefault(); + dropZone.classList.add('active'); +}); + +dropZone.addEventListener('dragleave', () => { + dropZone.classList.remove('active'); +}); + +window.addEventListener('dragover', (event) => { + event.preventDefault(); +}); + +window.addEventListener('drop', (event) => { + if (event.target instanceof Node && dropZone.contains(event.target)) { + return; + } + + event.preventDefault(); +}); + +dropZone.addEventListener('drop', async (event) => { + event.preventDefault(); + dropZone.classList.remove('active'); + + const droppedFile = event.dataTransfer?.files?.[0]; + const droppedPath = droppedFile?.path; + + if (!droppedPath) { + setDropZoneError('Elemento non valido. Trascina una cartella o un file .zip'); + return; + } + + await handleAction('Process Drag & Drop', () => window.api.processDroppedPath(droppedPath)); +}); + browseDestinationBtn.addEventListener('click', async () => { try { setDestinationLoading(true);