diff --git a/src/main.js b/src/main.js index f9305c0..8a15265 100644 --- a/src/main.js +++ b/src/main.js @@ -7,6 +7,7 @@ const PDFOperations = require('./main/PDFOperations'); const GitOperations = require('./main/GitOperations'); const { getAllowedDirectories, validatePath, resolveWritablePath, isPathAccessible } = require('./main/utils/paths'); const fileOps = require('./main/files'); +const menu = require('./main/menu'); // Add MiKTeX to PATH for LaTeX support if (process.platform === 'win32') { @@ -406,7 +407,7 @@ function createWindow() { mainWindow.show(); }); - createMenu(); + menu.register(mainWindow); mainWindow.on('closed', () => { mainWindow = null; @@ -452,493 +453,6 @@ function createWindow() { }); } -function buildRecentFilesMenu() { - const recentFiles = getRecentFiles(); - - if (recentFiles.length === 0) { - return [ - { - label: 'No recent files', - enabled: false - } - ]; - } - - const recentFileItems = recentFiles.map(filePath => ({ - label: filePath.split(/[\\/]/).pop(), // Get filename only - click: () => { - if (fs.existsSync(filePath)) { - const stats = fs.statSync(filePath); - if (stats.size > MAX_FILE_SIZE) { - dialog.showErrorBox('File Too Large', `File exceeds the ${MAX_FILE_SIZE_MB}MB size limit.`); - return; - } - currentFile = filePath; - const content = fs.readFileSync(filePath, 'utf-8'); - mainWindow.webContents.send('file-opened', { path: filePath, content }); - } else { - dialog.showErrorBox('File Not Found', sanitizeErrorMessage(`The file "${filePath}" could not be found.`)); - } - }, - toolTip: filePath // Show full path in tooltip - })); - - return [ - ...recentFileItems, - { type: 'separator' }, - { - label: 'Clear Recent Files', - click: () => { - mainWindow.webContents.send('clear-recent-files'); - } - } - ]; -} - -function getRecentFiles() { - try { - const recentFiles = JSON.parse(fs.readFileSync(path.join(app.getPath('userData'), 'recent-files.json'), 'utf-8')); - return recentFiles.filter(file => fs.existsSync(file)); - } catch (e) { - return []; - } -} - -function createMenu() { - const template = [ - { - label: 'File', - submenu: [ - { - label: 'New', - accelerator: 'CmdOrCtrl+N', - click: () => mainWindow.webContents.send('file-new') - }, - { - label: 'Open', - accelerator: 'CmdOrCtrl+O', - click: openFile - }, - { - label: 'Open PDF', - accelerator: 'CmdOrCtrl+Shift+O', - click: openPdfFile - }, - { - label: 'Save', - accelerator: 'CmdOrCtrl+S', - click: () => mainWindow.webContents.send('file-save') - }, - { - label: 'Save As', - accelerator: 'CmdOrCtrl+Shift+S', - click: saveAsFile - }, - { type: 'separator' }, - { - label: 'Print', - submenu: [ - { - label: 'Print Preview', - accelerator: 'CmdOrCtrl+P', - click: () => mainWindow.webContents.send('print-preview') - }, - { - label: 'Print Preview (With Styles)', - click: () => mainWindow.webContents.send('print-preview-styled') - } - ] - }, - { type: 'separator' }, - { - label: 'Recent Files', - submenu: buildRecentFilesMenu() - }, - { type: 'separator' }, - { - label: 'New from Template', - submenu: [ - { label: 'Blog Post', click: () => mainWindow.webContents.send('load-template-menu', 'blog-post.md') }, - { label: 'Meeting Notes', click: () => mainWindow.webContents.send('load-template-menu', 'meeting-notes.md') }, - { label: 'Technical Spec', click: () => mainWindow.webContents.send('load-template-menu', 'technical-spec.md') }, - { label: 'Changelog', click: () => mainWindow.webContents.send('load-template-menu', 'changelog.md') }, - { label: 'README', click: () => mainWindow.webContents.send('load-template-menu', 'readme.md') }, - { label: 'Project Plan', click: () => mainWindow.webContents.send('load-template-menu', 'project-plan.md') }, - { label: 'API Documentation', click: () => mainWindow.webContents.send('load-template-menu', 'api-docs.md') }, - { label: 'Tutorial', click: () => mainWindow.webContents.send('load-template-menu', 'tutorial.md') }, - { label: 'Release Notes', click: () => mainWindow.webContents.send('load-template-menu', 'release-notes.md') }, - { label: 'Comparison', click: () => mainWindow.webContents.send('load-template-menu', 'comparison.md') } - ] - }, - { type: 'separator' }, - { - label: 'Import Document...', - accelerator: 'CmdOrCtrl+I', - click: importDocument - }, - { - label: 'Export', - submenu: [ - { label: 'HTML', click: () => exportFile('html') }, - { label: 'PDF', click: () => exportFile('pdf') }, - { label: 'PDF (Enhanced)', click: () => exportPDFViaWordTemplate(), accelerator: 'Ctrl+Shift+P' }, - { label: 'DOCX', click: () => exportFile('docx') }, - { label: 'DOCX (Enhanced)', click: () => exportWordWithTemplate(), accelerator: 'Ctrl+Shift+W' }, - { label: 'LaTeX', click: () => exportFile('latex') }, - { label: 'RTF', click: () => exportFile('rtf') }, - { label: 'ODT', click: () => exportFile('odt') }, - { label: 'EPUB', click: () => exportFile('epub') }, - { type: 'separator' }, - { label: 'PowerPoint (PPTX)', click: () => exportFile('pptx') }, - { label: 'OpenDocument Presentation (ODP)', click: () => exportFile('odp') }, - { type: 'separator' }, - { label: 'CSV (Tables)', click: () => exportSpreadsheet('csv') }, - { type: 'separator' }, - { label: 'JSON (.json)', click: () => exportFile('json') }, - { label: 'YAML (.yaml)', click: () => exportFile('yaml') }, - { label: 'XML (.xml)', click: () => exportFile('xml') }, - { label: 'TOML (.toml)', click: () => exportFile('toml') }, - { type: 'separator' }, - { label: 'Reveal.js Slides (.html)', click: () => exportFile('revealjs') }, - { label: 'Beamer Slides (.pdf)', click: () => exportFile('beamer') }, - { type: 'separator' }, - { label: 'Confluence Wiki (.txt)', click: () => exportFile('confluence') }, - { label: 'MOBI E-book (.mobi)', click: () => exportFile('mobi') }, - ] - }, - { type: 'separator' }, - { - label: 'Select Word Template...', - click: selectWordTemplate - }, - { - label: 'Template Settings...', - click: showTemplateSettings - }, - { - label: 'Header & Footer Settings...', - click: () => { - if (mainWindow) { - mainWindow.webContents.send('open-header-footer-dialog'); - } - } - }, - { type: 'separator' }, - { - label: 'Quit', - accelerator: process.platform === 'darwin' ? 'Cmd+Q' : 'Ctrl+Q', - click: () => app.quit() - } - ] - }, - { - label: 'Edit', - submenu: [ - { - label: 'Undo', - accelerator: 'CmdOrCtrl+Z', - click: () => mainWindow.webContents.send('undo') - }, - { - label: 'Redo', - accelerator: 'CmdOrCtrl+Shift+Z', - click: () => mainWindow.webContents.send('redo') - }, - { type: 'separator' }, - { label: 'Cut', accelerator: 'CmdOrCtrl+X', role: 'cut' }, - { label: 'Copy', accelerator: 'CmdOrCtrl+C', role: 'copy' }, - { label: 'Paste', accelerator: 'CmdOrCtrl+V', role: 'paste' }, - { label: 'Select All', accelerator: 'CmdOrCtrl+A', role: 'selectAll' }, - { type: 'separator' }, - { - label: 'Find & Replace', - accelerator: 'CmdOrCtrl+F', - click: () => mainWindow.webContents.send('toggle-find') - } - ] - }, - { - label: 'View', - submenu: [ - { - label: 'Toggle Preview', - accelerator: 'CmdOrCtrl+Shift+V', - click: () => mainWindow.webContents.send('toggle-preview') - }, - { - label: 'Command Palette', - accelerator: 'CmdOrCtrl+Shift+P', - click: () => mainWindow.webContents.send('toggle-command-palette') - }, - { type: 'separator' }, - { - label: 'Sidebar', - submenu: [ - { label: 'File Explorer', click: () => mainWindow.webContents.send('toggle-sidebar-panel', 'explorer') }, - { label: 'Git', click: () => mainWindow.webContents.send('toggle-sidebar-panel', 'git') }, - { label: 'Snippets', click: () => mainWindow.webContents.send('toggle-sidebar-panel', 'snippets') }, - { label: 'Templates', click: () => mainWindow.webContents.send('toggle-sidebar-panel', 'templates') } - ] - }, - { - label: 'Bottom Panel (REPL)', - click: () => mainWindow.webContents.send('toggle-bottom-panel') - }, - { type: 'separator' }, - { - label: 'Theme', - submenu: [ - // Light Themes (grouped first) - { label: 'Atom One Light (Default)', click: () => setTheme('atomonelight') }, - { label: 'GitHub Light', click: () => setTheme('github') }, - { label: 'Light', click: () => setTheme('light') }, - { label: 'Solarized Light', click: () => setTheme('solarized') }, - { label: 'Gruvbox Light', click: () => setTheme('gruvbox-light') }, - { label: 'Ayu Light', click: () => setTheme('ayu-light') }, - { label: 'Sepia', click: () => setTheme('sepia') }, - { label: 'Paper', click: () => setTheme('paper') }, - { label: 'Rose Pine Dawn', click: () => setTheme('rosepine-dawn') }, - { label: 'Concrete Light', click: () => setTheme('concrete-light') }, - { type: 'separator' }, - // Dark Themes - { label: 'Dark', click: () => setTheme('dark') }, - { label: 'One Dark', click: () => setTheme('onedark') }, - { label: 'Dracula', click: () => setTheme('dracula') }, - { label: 'Nord', click: () => setTheme('nord') }, - { label: 'Monokai', click: () => setTheme('monokai') }, - { label: 'Material', click: () => setTheme('material') }, - { label: 'Gruvbox Dark', click: () => setTheme('gruvbox-dark') }, - { label: 'Tokyo Night', click: () => setTheme('tokyonight') }, - { label: 'Palenight', click: () => setTheme('palenight') }, - { label: 'Ayu Dark', click: () => setTheme('ayu-dark') }, - { label: 'Ayu Mirage', click: () => setTheme('ayu-mirage') }, - { label: 'Oceanic Next', click: () => setTheme('oceanic-next') }, - { label: 'Cobalt2', click: () => setTheme('cobalt2') }, - { label: 'Concrete Dark', click: () => setTheme('concrete-dark') }, - { label: 'Concrete Warm', click: () => setTheme('concrete-warm') } - ] - }, - { type: 'separator' }, - { - label: 'Font Size', - submenu: [ - { - label: 'Increase Font Size', - accelerator: 'CmdOrCtrl+Shift+Plus', - click: () => mainWindow.webContents.send('adjust-font-size', 'increase') - }, - { - label: 'Decrease Font Size', - accelerator: 'CmdOrCtrl+Shift+-', - click: () => mainWindow.webContents.send('adjust-font-size', 'decrease') - }, - { - label: 'Reset Font Size', - accelerator: 'CmdOrCtrl+Shift+0', - click: () => mainWindow.webContents.send('adjust-font-size', 'reset') - } - ] - }, - { type: 'separator' }, - { - label: 'Spell Check', - type: 'checkbox', - checked: true, - click: (menuItem) => { - mainWindow.webContents.session.setSpellCheckerEnabled(menuItem.checked); - } - }, - { type: 'separator' }, - { - label: 'Custom Preview CSS', - submenu: [ - { - label: 'Load Custom Preview CSS...', - click: () => mainWindow.webContents.send('load-custom-css') - }, - { - label: 'Clear Custom Preview CSS', - click: () => mainWindow.webContents.send('clear-custom-css') - } - ] - }, - { type: 'separator' }, - { label: 'Reload', accelerator: 'CmdOrCtrl+R', role: 'reload' }, - { label: 'Toggle DevTools', accelerator: 'F12', role: 'toggleDevTools' }, - { type: 'separator' }, - { label: 'Zoom In', accelerator: 'CmdOrCtrl+Plus', role: 'zoomIn' }, - { label: 'Zoom Out', accelerator: 'CmdOrCtrl+-', role: 'zoomOut' }, - { label: 'Reset Zoom', accelerator: 'CmdOrCtrl+0', role: 'resetZoom' } - ] - }, - { - label: 'Batch', - submenu: [ - { - label: 'Convert Markdown Folder...', - click: () => showBatchConversionDialog() - }, - { type: 'separator' }, - { - label: 'Batch Image Conversion...', - click: () => mainWindow.webContents.send('show-batch-converter', 'image') - }, - { - label: 'Batch Audio Conversion...', - click: () => mainWindow.webContents.send('show-batch-converter', 'audio') - }, - { - label: 'Batch Video Conversion...', - click: () => mainWindow.webContents.send('show-batch-converter', 'video') - }, - { - label: 'Batch PDF Conversion...', - click: () => mainWindow.webContents.send('show-batch-converter', 'pdf') - } - ] - }, - { - label: 'Convert', - submenu: [ - { - label: 'Universal File Converter...', - accelerator: 'CmdOrCtrl+Shift+C', - click: () => showUniversalConverterDialog() - } - ] - }, - { - label: 'PDF Editor', - submenu: [ - { - label: 'Open PDF File...', - accelerator: 'CmdOrCtrl+Shift+O', - click: () => openPDFFile() - }, - { type: 'separator' }, - { - label: 'Merge PDFs...', - click: () => showPDFEditorDialog('merge') - }, - { - label: 'Split PDF...', - click: () => showPDFEditorDialog('split') - }, - { - label: 'Compress PDF...', - click: () => showPDFEditorDialog('compress') - }, - { - type: 'separator' - }, - { - label: 'Rotate Pages...', - click: () => showPDFEditorDialog('rotate') - }, - { - label: 'Delete Pages...', - click: () => showPDFEditorDialog('delete') - }, - { - label: 'Reorder Pages...', - click: () => showPDFEditorDialog('reorder') - }, - { - type: 'separator' - }, - { - label: 'Add Watermark...', - click: () => showPDFEditorDialog('watermark') - }, - { - type: 'separator' - }, - { - label: 'Security', - submenu: [ - { - label: 'Add Password Protection...', - click: () => showPDFEditorDialog('encrypt') - }, - { - label: 'Remove Password...', - click: () => showPDFEditorDialog('decrypt') - }, - { - label: 'Set Permissions...', - click: () => showPDFEditorDialog('permissions') - } - ] - }, - { - type: 'separator' - }, - { - label: 'About PDF Editor', - click: () => { - dialog.showMessageBox(mainWindow, { - type: 'info', - title: 'About PDF Editor', - message: 'PDF Editor', - detail: 'Comprehensive PDF editing capabilities powered by pdf-lib.\n\nFeatures:\n• Merge multiple PDF files\n• Split PDF into separate files\n• Compress PDF to reduce file size\n• Rotate pages (90°, 180°, 270°)\n• Delete unwanted pages\n• Reorder pages\n• Add text watermarks\n\nSecurity Features:\n• Password protection (encryption)\n• Remove passwords (decryption)\n• Set document permissions\n\n100% offline and open-source.', - buttons: ['OK'] - }); - } - } - ] - }, - { - label: 'Tools', - submenu: [ - { - label: 'Table Generator', - accelerator: 'CmdOrCtrl+Shift+T', - click: () => openTableGenerator() - }, - { - label: 'ASCII Art Generator', - accelerator: 'CmdOrCtrl+Shift+A', - click: () => openAsciiGenerator() - }, - { type: 'separator' }, - { - label: 'Document Compare', - click: () => mainWindow.webContents.send('show-document-compare') - } - ] - }, - { - label: 'Help', - submenu: [ - { - label: 'About MarkdownConverter', - click: () => showAboutDialog() - }, - { type: 'separator' }, - { - label: 'Dependencies & Requirements', - click: () => showDependenciesDialog() - }, - { type: 'separator' }, - { - label: 'Documentation', - click: () => shell.openExternal('https://github.com/amitwh/markdown-converter') - }, - { - label: 'Report Issue', - click: () => shell.openExternal('https://github.com/amitwh/markdown-converter/issues') - }, - { - label: 'Check for Updates', - click: () => shell.openExternal('https://github.com/amitwh/markdown-converter/releases') - } - ] - } - ]; - - const menu = Menu.buildFromTemplate(template); - Menu.setApplicationMenu(menu); -} // Show About Dialog with logo function showAboutDialog() { @@ -3685,7 +3199,7 @@ ipcMain.on('clear-recent-files', (event) => { const recentFilesPath = path.join(userDataPath, 'recent-files.json'); fs.writeFileSync(recentFilesPath, JSON.stringify([], null, 2)); // Rebuild menu to reflect changes - createMenu(); + menu.register(mainWindow); event.reply('recent-files-cleared'); } catch (error) { console.error('Error clearing recent files:', error); @@ -3772,80 +3286,6 @@ ipcMain.on('select-pdf-folder', (event, inputId) => { } }); -// ============================================ -// ASCII Art Generator Window -// ============================================ -let asciiGeneratorWindow = null; - -function openAsciiGenerator() { - if (asciiGeneratorWindow) { - asciiGeneratorWindow.focus(); - return; - } - - asciiGeneratorWindow = new BrowserWindow({ - width: 800, - height: 700, - parent: mainWindow, - modal: false, - title: 'ASCII Art Generator', - icon: path.join(__dirname, '../assets/icon.png'), - webPreferences: { - nodeIntegration: false, - contextIsolation: true, - preload: path.join(__dirname, 'preload.js') - } - }); - - asciiGeneratorWindow.loadFile(path.join(__dirname, 'ascii-generator.html')); - asciiGeneratorWindow.setMenuBarVisibility(false); - - asciiGeneratorWindow.on('closed', () => { - asciiGeneratorWindow = null; - }); -} - -ipcMain.on('open-ascii-generator', () => { - openAsciiGenerator(); -}); - -// ============================================ -// Table Generator Window -// ============================================ -let tableGeneratorWindow = null; - -function openTableGenerator() { - if (tableGeneratorWindow) { - tableGeneratorWindow.focus(); - return; - } - - tableGeneratorWindow = new BrowserWindow({ - width: 900, - height: 700, - parent: mainWindow, - modal: false, - title: 'Table Generator', - icon: path.join(__dirname, '../assets/icon.png'), - webPreferences: { - nodeIntegration: false, - contextIsolation: true, - preload: path.join(__dirname, 'preload.js') - } - }); - - tableGeneratorWindow.loadFile(path.join(__dirname, 'table-generator.html')); - tableGeneratorWindow.setMenuBarVisibility(false); - - tableGeneratorWindow.on('closed', () => { - tableGeneratorWindow = null; - }); -} - -ipcMain.on('open-table-generator', () => { - openTableGenerator(); -}); - // IPC Handler for loading document templates ipcMain.handle('load-template', async (event, filename) => { try { @@ -4021,3 +3461,24 @@ ipcMain.handle('execute-code', async (event, { code, language }) => { }); }); }); + +// Exports for src/main/menu/ items.js (lazy require inside click handlers) +module.exports = { + openFile, + openPdfFile, + openFileFromPath, + saveAsFile, + exportFile, + exportPDFViaWordTemplate, + exportWordWithTemplate, + exportSpreadsheet, + importDocument, + selectWordTemplate, + showTemplateSettings, + setTheme, + showBatchConversionDialog, + showUniversalConverterDialog, + showPDFEditorDialog, + showAboutDialog, + showDependenciesDialog, +}; diff --git a/src/main/menu/index.js b/src/main/menu/index.js new file mode 100644 index 0000000..4aa762b --- /dev/null +++ b/src/main/menu/index.js @@ -0,0 +1,34 @@ +// src/main/menu/index.js +// buildMenu() composes the app menu from items; register() sets it on the app + +const { Menu } = require('electron'); +const { + fileItems, + editItems, + viewItems, + batchItems, + convertItems, + pdfEditorItems, + toolsItems, + helpItems +} = require('./items'); + +function buildMenu(mainWindow) { + const template = [ + { label: '&File', submenu: fileItems(mainWindow) }, + { label: '&Edit', submenu: editItems(mainWindow) }, + { label: '&View', submenu: viewItems(mainWindow) }, + { label: '&Batch', submenu: batchItems(mainWindow) }, + { label: '&Convert', submenu: convertItems(mainWindow) }, + { label: 'PDF Editor', submenu: pdfEditorItems(mainWindow) }, + { label: '&Tools', submenu: toolsItems(mainWindow) }, + { label: '&Help', submenu: helpItems(mainWindow) } + ]; + return Menu.buildFromTemplate(template); +} + +function register(mainWindow) { + Menu.setApplicationMenu(buildMenu(mainWindow)); +} + +module.exports = { register, buildMenu }; \ No newline at end of file diff --git a/src/main/menu/items.js b/src/main/menu/items.js new file mode 100644 index 0000000..3ecf9a8 --- /dev/null +++ b/src/main/menu/items.js @@ -0,0 +1,522 @@ +// src/main/menu/items.js +// Individual menu items — pure functions that take (mainWindow) and return menu item arrays + +const { app, dialog, shell } = require('electron'); +const path = require('path'); +const fs = require('fs'); + +// Helper: build recent files submenu +function buildRecentFilesMenu(mainWindow) { + try { + const recentFilesPath = path.join(app.getPath('userData'), 'recent-files.json'); + if (!fs.existsSync(recentFilesPath)) return [{ label: 'No Recent Files', enabled: false }]; + const recentFiles = JSON.parse(fs.readFileSync(recentFilesPath, 'utf-8')); + const existing = recentFiles.filter(file => fs.existsSync(file)); + if (existing.length === 0) return [{ label: 'No Recent Files', enabled: false }]; + const items = existing.map(file => ({ + label: path.basename(file), + click: () => { + const { openFileFromPath } = require('../main'); + openFileFromPath(file); + } + })); + items.push( + { type: 'separator' }, + { + label: 'Clear Recent Files', + click: () => { + if (mainWindow) { + mainWindow.webContents.send('clear-recent-files'); + } + } + } + ); + return items; + } catch (e) { + return [{ label: 'No Recent Files', enabled: false }]; + } +} + +function fileItems(mainWindow) { + return [ + { + label: 'New', + accelerator: 'CmdOrCtrl+N', + click: () => mainWindow.webContents.send('file-new') + }, + { + label: 'Open', + accelerator: 'CmdOrCtrl+O', + click: () => { + const { openFile } = require('../main'); + openFile(); + } + }, + { + label: 'Open PDF', + accelerator: 'CmdOrCtrl+Shift+O', + click: () => { + const { openPdfFile } = require('../main'); + openPdfFile(); + } + }, + { + label: 'Save', + accelerator: 'CmdOrCtrl+S', + click: () => mainWindow.webContents.send('file-save') + }, + { + label: 'Save As', + accelerator: 'CmdOrCtrl+Shift+S', + click: () => { + const { saveAsFile } = require('../main'); + saveAsFile(); + } + }, + { type: 'separator' }, + // NOTE: Print Preview submenu removed — handled by React overlay + { type: 'separator' }, + { + label: 'Recent Files', + submenu: buildRecentFilesMenu(mainWindow) + }, + { type: 'separator' }, + { + label: 'New from Template', + submenu: [ + { label: 'Blog Post', click: () => mainWindow.webContents.send('load-template-menu', 'blog-post.md') }, + { label: 'Meeting Notes', click: () => mainWindow.webContents.send('load-template-menu', 'meeting-notes.md') }, + { label: 'Technical Spec', click: () => mainWindow.webContents.send('load-template-menu', 'technical-spec.md') }, + { label: 'Changelog', click: () => mainWindow.webContents.send('load-template-menu', 'changelog.md') }, + { label: 'README', click: () => mainWindow.webContents.send('load-template-menu', 'readme.md') }, + { label: 'Project Plan', click: () => mainWindow.webContents.send('load-template-menu', 'project-plan.md') }, + { label: 'API Documentation', click: () => mainWindow.webContents.send('load-template-menu', 'api-docs.md') }, + { label: 'Tutorial', click: () => mainWindow.webContents.send('load-template-menu', 'tutorial.md') }, + { label: 'Release Notes', click: () => mainWindow.webContents.send('load-template-menu', 'release-notes.md') }, + { label: 'Comparison', click: () => mainWindow.webContents.send('load-template-menu', 'comparison.md') } + ] + }, + { type: 'separator' }, + { + label: 'Import Document...', + accelerator: 'CmdOrCtrl+I', + click: () => { + const { importDocument } = require('../main'); + importDocument(); + } + }, + { + label: 'Export', + submenu: [ + { + label: 'HTML', click: () => { + const { exportFile } = require('../main'); + exportFile('html'); + } + }, + { + label: 'PDF', click: () => { + const { exportFile } = require('../main'); + exportFile('pdf'); + } + }, + { + label: 'PDF (Enhanced)', click: () => { + const { exportPDFViaWordTemplate } = require('../main'); + exportPDFViaWordTemplate(); + }, accelerator: 'Ctrl+Shift+P' + }, + { + label: 'DOCX', click: () => { + const { exportFile } = require('../main'); + exportFile('docx'); + } + }, + { + label: 'DOCX (Enhanced)', click: () => { + const { exportWordWithTemplate } = require('../main'); + exportWordWithTemplate(); + }, accelerator: 'Ctrl+Shift+W' + }, + { label: 'LaTeX', click: () => { const { exportFile } = require('../main'); exportFile('latex'); } }, + { label: 'RTF', click: () => { const { exportFile } = require('../main'); exportFile('rtf'); } }, + { label: 'ODT', click: () => { const { exportFile } = require('../main'); exportFile('odt'); } }, + { label: 'EPUB', click: () => { const { exportFile } = require('../main'); exportFile('epub'); } }, + { type: 'separator' }, + { label: 'PowerPoint (PPTX)', click: () => { const { exportFile } = require('../main'); exportFile('pptx'); } }, + { label: 'OpenDocument Presentation (ODP)', click: () => { const { exportFile } = require('../main'); exportFile('odp'); } }, + { type: 'separator' }, + { label: 'CSV (Tables)', click: () => { const { exportSpreadsheet } = require('../main'); exportSpreadsheet('csv'); } }, + { type: 'separator' }, + { label: 'JSON (.json)', click: () => { const { exportFile } = require('../main'); exportFile('json'); } }, + { label: 'YAML (.yaml)', click: () => { const { exportFile } = require('../main'); exportFile('yaml'); } }, + { label: 'XML (.xml)', click: () => { const { exportFile } = require('../main'); exportFile('xml'); } }, + { type: 'separator' }, + { label: 'Confluence Wiki (.txt)', click: () => { const { exportFile } = require('../main'); exportFile('confluence'); } }, + { label: 'MOBI E-book (.mobi)', click: () => { const { exportFile } = require('../main'); exportFile('mobi'); } } + ] + }, + { type: 'separator' }, + { + label: 'Select Word Template...', + click: () => { + const { selectWordTemplate } = require('../main'); + selectWordTemplate(); + } + }, + { + label: 'Template Settings...', + click: () => { + const { showTemplateSettings } = require('../main'); + showTemplateSettings(); + } + }, + { + label: 'Header & Footer Settings...', + click: () => { + if (mainWindow) { + mainWindow.webContents.send('open-header-footer-dialog'); + } + } + }, + { type: 'separator' }, + { + label: 'Quit', + accelerator: process.platform === 'darwin' ? 'Cmd+Q' : 'Ctrl+Q', + click: () => app.quit() + } + ]; +} + +function editItems(mainWindow) { + return [ + { + label: 'Undo', + accelerator: 'CmdOrCtrl+Z', + click: () => mainWindow.webContents.send('undo') + }, + { + label: 'Redo', + accelerator: 'CmdOrCtrl+Shift+Z', + click: () => mainWindow.webContents.send('redo') + }, + { type: 'separator' }, + { label: 'Cut', accelerator: 'CmdOrCtrl+X', role: 'cut' }, + { label: 'Copy', accelerator: 'CmdOrCtrl+C', role: 'copy' }, + { label: 'Paste', accelerator: 'CmdOrCtrl+V', role: 'paste' }, + { label: 'Select All', accelerator: 'CmdOrCtrl+A', role: 'selectAll' }, + { type: 'separator' }, + { + label: 'Find & Replace', + accelerator: 'CmdOrCtrl+F', + click: () => mainWindow.webContents.send('toggle-find') + } + ]; +} + +function viewItems(mainWindow) { + return [ + { + label: 'Toggle Preview', + accelerator: 'CmdOrCtrl+Shift+V', + click: () => mainWindow.webContents.send('toggle-preview') + }, + // NOTE: Command Palette removed — handled by useCommandStore + { type: 'separator' }, + { + label: 'Sidebar', + submenu: [ + { label: 'File Explorer', click: () => mainWindow.webContents.send('toggle-sidebar-panel', 'explorer') }, + { label: 'Git', click: () => mainWindow.webContents.send('toggle-sidebar-panel', 'git') }, + { label: 'Snippets', click: () => mainWindow.webContents.send('toggle-sidebar-panel', 'snippets') }, + { label: 'Templates', click: () => mainWindow.webContents.send('toggle-sidebar-panel', 'templates') } + ] + }, + { + label: 'Bottom Panel (REPL)', + click: () => mainWindow.webContents.send('toggle-bottom-panel') + }, + { type: 'separator' }, + { + label: 'Theme', + submenu: [ + { label: 'Atom One Light (Default)', click: () => { const { setTheme } = require('../main'); setTheme('atomonelight'); } }, + { label: 'GitHub Light', click: () => { const { setTheme } = require('../main'); setTheme('github'); } }, + { label: 'Light', click: () => { const { setTheme } = require('../main'); setTheme('light'); } }, + { label: 'Solarized Light', click: () => { const { setTheme } = require('../main'); setTheme('solarized'); } }, + { label: 'Gruvbox Light', click: () => { const { setTheme } = require('../main'); setTheme('gruvbox-light'); } }, + { label: 'Ayu Light', click: () => { const { setTheme } = require('../main'); setTheme('ayu-light'); } }, + { label: 'Sepia', click: () => { const { setTheme } = require('../main'); setTheme('sepia'); } }, + { label: 'Paper', click: () => { const { setTheme } = require('../main'); setTheme('paper'); } }, + { label: 'Rose Pine Dawn', click: () => { const { setTheme } = require('../main'); setTheme('rosepine-dawn'); } }, + { label: 'Concrete Light', click: () => { const { setTheme } = require('../main'); setTheme('concrete-light'); } }, + { type: 'separator' }, + { label: 'Dark', click: () => { const { setTheme } = require('../main'); setTheme('dark'); } }, + { label: 'One Dark', click: () => { const { setTheme } = require('../main'); setTheme('onedark'); } }, + { label: 'Dracula', click: () => { const { setTheme } = require('../main'); setTheme('dracula'); } }, + { label: 'Nord', click: () => { const { setTheme } = require('../main'); setTheme('nord'); } }, + { label: 'Monokai', click: () => { const { setTheme } = require('../main'); setTheme('monokai'); } }, + { label: 'Material', click: () => { const { setTheme } = require('../main'); setTheme('material'); } }, + { label: 'Gruvbox Dark', click: () => { const { setTheme } = require('../main'); setTheme('gruvbox-dark'); } }, + { label: 'Tokyo Night', click: () => { const { setTheme } = require('../main'); setTheme('tokyonight'); } }, + { label: 'Palenight', click: () => { const { setTheme } = require('../main'); setTheme('palenight'); } }, + { label: 'Ayu Dark', click: () => { const { setTheme } = require('../main'); setTheme('ayu-dark'); } }, + { label: 'Ayu Mirage', click: () => { const { setTheme } = require('../main'); setTheme('ayu-mirage'); } }, + { label: 'Oceanic Next', click: () => { const { setTheme } = require('../main'); setTheme('oceanic-next'); } }, + { label: 'Cobalt2', click: () => { const { setTheme } = require('../main'); setTheme('cobalt2'); } }, + { label: 'Concrete Dark', click: () => { const { setTheme } = require('../main'); setTheme('concrete-dark'); } }, + { label: 'Concrete Warm', click: () => { const { setTheme } = require('../main'); setTheme('concrete-warm'); } } + ] + }, + { type: 'separator' }, + { + label: 'Font Size', + submenu: [ + { + label: 'Increase Font Size', + accelerator: 'CmdOrCtrl+Shift+Plus', + click: () => mainWindow.webContents.send('adjust-font-size', 'increase') + }, + { + label: 'Decrease Font Size', + accelerator: 'CmdOrCtrl+Shift+-', + click: () => mainWindow.webContents.send('adjust-font-size', 'decrease') + }, + { + label: 'Reset Font Size', + accelerator: 'CmdOrCtrl+Shift+0', + click: () => mainWindow.webContents.send('adjust-font-size', 'reset') + } + ] + }, + { type: 'separator' }, + { + label: 'Spell Check', + type: 'checkbox', + checked: true, + click: (menuItem) => { + mainWindow.webContents.session.setSpellCheckerEnabled(menuItem.checked); + } + }, + { type: 'separator' }, + { + label: 'Custom Preview CSS', + submenu: [ + { + label: 'Load Custom Preview CSS...', + click: () => mainWindow.webContents.send('load-custom-css') + }, + { + label: 'Clear Custom Preview CSS', + click: () => mainWindow.webContents.send('clear-custom-css') + } + ] + }, + { type: 'separator' }, + { label: 'Reload', accelerator: 'CmdOrCtrl+R', role: 'reload' }, + { label: 'Toggle DevTools', accelerator: 'F12', role: 'toggleDevTools' }, + { type: 'separator' }, + { label: 'Zoom In', accelerator: 'CmdOrCtrl+Plus', role: 'zoomIn' }, + { label: 'Zoom Out', accelerator: 'CmdOrCtrl+-', role: 'zoomOut' }, + { label: 'Reset Zoom', accelerator: 'CmdOrCtrl+0', role: 'resetZoom' } + ]; +} + +function batchItems(mainWindow) { + return [ + { + label: 'Convert Markdown Folder...', + click: () => { + const { showBatchConversionDialog } = require('../main'); + showBatchConversionDialog(); + } + }, + { type: 'separator' }, + { + label: 'Batch Image Conversion...', + click: () => mainWindow.webContents.send('show-batch-converter', 'image') + }, + { + label: 'Batch Audio Conversion...', + click: () => mainWindow.webContents.send('show-batch-converter', 'audio') + }, + { + label: 'Batch Video Conversion...', + click: () => mainWindow.webContents.send('show-batch-converter', 'video') + }, + { + label: 'Batch PDF Conversion...', + click: () => mainWindow.webContents.send('show-batch-converter', 'pdf') + } + ]; +} + +function convertItems(mainWindow) { + return [ + { + label: 'Universal File Converter...', + accelerator: 'CmdOrCtrl+Shift+C', + click: () => { + const { showUniversalConverterDialog } = require('../main'); + showUniversalConverterDialog(); + } + } + ]; +} + +function pdfEditorItems(mainWindow) { + return [ + { + label: 'Open PDF File...', + accelerator: 'CmdOrCtrl+Shift+O', + click: () => { + const { openPdfFile } = require('../main'); + openPdfFile(); + } + }, + { type: 'separator' }, + { + label: 'Merge PDFs...', + click: () => { + const { showPDFEditorDialog } = require('../main'); + showPDFEditorDialog('merge'); + } + }, + { + label: 'Split PDF...', + click: () => { + const { showPDFEditorDialog } = require('../main'); + showPDFEditorDialog('split'); + } + }, + { + label: 'Compress PDF...', + click: () => { + const { showPDFEditorDialog } = require('../main'); + showPDFEditorDialog('compress'); + } + }, + { type: 'separator' }, + { + label: 'Rotate Pages...', + click: () => { + const { showPDFEditorDialog } = require('../main'); + showPDFEditorDialog('rotate'); + } + }, + { + label: 'Delete Pages...', + click: () => { + const { showPDFEditorDialog } = require('../main'); + showPDFEditorDialog('delete'); + } + }, + { + label: 'Reorder Pages...', + click: () => { + const { showPDFEditorDialog } = require('../main'); + showPDFEditorDialog('reorder'); + } + }, + { type: 'separator' }, + { + label: 'Add Watermark...', + click: () => { + const { showPDFEditorDialog } = require('../main'); + showPDFEditorDialog('watermark'); + } + }, + { type: 'separator' }, + { + label: 'Security', + submenu: [ + { + label: 'Add Password Protection...', + click: () => { + const { showPDFEditorDialog } = require('../main'); + showPDFEditorDialog('encrypt'); + } + }, + { + label: 'Remove Password...', + click: () => { + const { showPDFEditorDialog } = require('../main'); + showPDFEditorDialog('decrypt'); + } + }, + { + label: 'Set Permissions...', + click: () => { + const { showPDFEditorDialog } = require('../main'); + showPDFEditorDialog('permissions'); + } + } + ] + }, + { type: 'separator' }, + { + label: 'About PDF Editor', + click: () => { + const { showAboutDialog } = require('../main'); + showAboutDialog(); + } + } + ]; +} + +function toolsItems(mainWindow) { + // NOTE: Table Generator and ASCII Art Generator removed — handled by React dialogs + return [ + // Removed: Table Generator (Cmd+Ctrl+Shift+T) — now React + // Removed: ASCII Art Generator (Cmd+Ctrl+Shift+A) — now React + { type: 'separator' }, + { + label: 'Document Compare', + click: () => mainWindow.webContents.send('show-document-compare') + } + ]; +} + +function helpItems(mainWindow) { + return [ + { + label: 'About MarkdownConverter', + click: () => { + const { showAboutDialog } = require('../main'); + showAboutDialog(); + } + }, + { type: 'separator' }, + { + label: 'Dependencies & Requirements', + click: () => { + const { showDependenciesDialog } = require('../main'); + showDependenciesDialog(); + } + }, + { type: 'separator' }, + { + label: 'Documentation', + click: () => shell.openExternal('https://github.com/amitwh/markdown-converter') + }, + { + label: 'Report Issue', + click: () => shell.openExternal('https://github.com/amitwh/markdown-converter/issues') + }, + { + label: 'Check for Updates', + click: () => shell.openExternal('https://github.com/amitwh/markdown-converter/releases') + } + ]; +} + +module.exports = { + fileItems, + editItems, + viewItems, + batchItems, + convertItems, + pdfEditorItems, + toolsItems, + helpItems +}; \ No newline at end of file