diff --git a/src/main.js b/src/main.js index 4a7757a..8582c8f 100644 --- a/src/main.js +++ b/src/main.js @@ -3880,6 +3880,35 @@ ipcMain.on('open-table-generator', () => { openTableGenerator(); }); +// IPC Handler for saving pasted/dropped images +ipcMain.handle('save-pasted-image', async (event, { base64, ext }) => { + try { + let saveDir; + + if (currentFile) { + // Save relative to current file + saveDir = path.join(path.dirname(currentFile), 'assets'); + } else { + // Use temp directory + saveDir = path.join(app.getPath('temp'), 'markdown-converter-images'); + } + + if (!fs.existsSync(saveDir)) { + fs.mkdirSync(saveDir, { recursive: true }); + } + + const filename = `image-${Date.now()}.${ext}`; + const filePath = path.join(saveDir, filename); + const buffer = Buffer.from(base64, 'base64'); + fs.writeFileSync(filePath, buffer); + + return { relativePath: `assets/${filename}`, absolutePath: filePath }; + } catch (error) { + console.error('Failed to save pasted image:', error); + return null; + } +}); + // IPC Handler to receive generated content from generator windows ipcMain.on('insert-generated-content', (event, content) => { if (mainWindow && !mainWindow.isDestroyed()) { diff --git a/src/preload.js b/src/preload.js index 1813ada..41800f5 100644 --- a/src/preload.js +++ b/src/preload.js @@ -91,7 +91,10 @@ const ALLOWED_SEND_CHANNELS = [ 'open-table-generator', // Insert generated content - 'insert-generated-content' + 'insert-generated-content', + + // Image paste/drop + 'save-pasted-image' ]; const ALLOWED_RECEIVE_CHANNELS = [ diff --git a/src/renderer.js b/src/renderer.js index 50985f7..967d273 100644 --- a/src/renderer.js +++ b/src/renderer.js @@ -1112,6 +1112,53 @@ document.addEventListener('DOMContentLoaded', () => { render: (container) => { container.innerHTML = '

Templates coming soon...

'; } }); + // Image paste handler + document.addEventListener('paste', async (e) => { + const items = e.clipboardData?.items; + if (!items) return; + + for (const item of items) { + if (item.type.startsWith('image/')) { + e.preventDefault(); + const blob = item.getAsFile(); + const reader = new FileReader(); + reader.onload = async () => { + const base64 = reader.result.split(',')[1]; + const ext = item.type.split('/')[1] === 'png' ? 'png' : 'jpg'; + const result = await ipcRenderer.invoke('save-pasted-image', { base64, ext }); + if (result?.relativePath) { + tabManager.insertAtCursor(`![image](${result.relativePath})\n`); + } + }; + reader.readAsDataURL(blob); + break; + } + } + }); + + // Drag and drop images + const editorContainer = document.querySelector('.editor-container'); + editorContainer?.addEventListener('dragover', (e) => { + e.preventDefault(); + e.dataTransfer.dropEffect = 'copy'; + }); + editorContainer?.addEventListener('drop', async (e) => { + e.preventDefault(); + const files = Array.from(e.dataTransfer.files).filter(f => f.type.startsWith('image/')); + for (const file of files) { + const reader = new FileReader(); + reader.onload = async () => { + const base64 = reader.result.split(',')[1]; + const ext = file.name.split('.').pop() || 'png'; + const result = await ipcRenderer.invoke('save-pasted-image', { base64, ext }); + if (result?.relativePath) { + tabManager.insertAtCursor(`![${file.name}](${result.relativePath})\n`); + } + }; + reader.readAsDataURL(file); + } + }); + // Initialize command palette const commandPalette = new CommandPalette();