Add spreadsheet export, update author info, rename to PanConverter

- Added Excel (XLS/XLSX) and ODS export functionality
- Updated author to Amit Haridas (amit.wh@gmail.com)
- Renamed app from 'Pan Converter' to 'PanConverter'
- Version bump to 1.1.0
This commit is contained in:
2025-09-01 19:44:48 +05:30
parent f17105aae7
commit 4ea771b757
4 changed files with 121 additions and 13 deletions
+13 -7
View File
@@ -1,6 +1,6 @@
{ {
"name": "pan-converter", "name": "pan-converter",
"version": "1.0.0", "version": "1.1.0",
"description": "Cross-platform Markdown editor and converter using Pandoc", "description": "Cross-platform Markdown editor and converter using Pandoc",
"main": "src/main.js", "main": "src/main.js",
"scripts": { "scripts": {
@@ -14,8 +14,13 @@
"dist:all": "electron-builder -mwl", "dist:all": "electron-builder -mwl",
"generate-icons": "node scripts/generate-icons.js" "generate-icons": "node scripts/generate-icons.js"
}, },
"keywords": ["markdown", "pandoc", "converter", "editor"], "keywords": [
"author": "Your Name", "markdown",
"pandoc",
"converter",
"editor"
],
"author": "Amit Haridas <amit.wh@gmail.com>",
"license": "MIT", "license": "MIT",
"devDependencies": { "devDependencies": {
"electron": "^37.4.0", "electron": "^37.4.0",
@@ -27,11 +32,12 @@
"dompurify": "^3.2.6", "dompurify": "^3.2.6",
"electron-store": "^10.1.0", "electron-store": "^10.1.0",
"highlight.js": "^11.11.1", "highlight.js": "^11.11.1",
"marked": "^16.2.1" "marked": "^16.2.1",
"xlsx": "^0.18.5"
}, },
"build": { "build": {
"appId": "com.panconverter.app", "appId": "com.panconverter.app",
"productName": "Pan Converter", "productName": "PanConverter",
"directories": { "directories": {
"output": "dist" "output": "dist"
}, },
@@ -63,7 +69,7 @@
"pandoc" "pandoc"
], ],
"description": "Markdown editor and converter using Pandoc", "description": "Markdown editor and converter using Pandoc",
"maintainer": "Your Name <your.email@example.com>" "maintainer": "Amit Haridas <amit.wh@gmail.com>"
} }
} }
} }
+1 -1
View File
@@ -3,7 +3,7 @@
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Pan Converter - Markdown Editor</title> <title>PanConverter - Markdown Editor</title>
<link rel="stylesheet" href="styles.css"> <link rel="stylesheet" href="styles.css">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/codemirror/6.65.7/codemirror.min.css"> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/codemirror/6.65.7/codemirror.min.css">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/default.min.css"> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/default.min.css">
+103 -5
View File
@@ -2,6 +2,7 @@ const { app, BrowserWindow, Menu, dialog, ipcMain, shell } = require('electron')
const path = require('path'); const path = require('path');
const fs = require('fs'); const fs = require('fs');
const { exec } = require('child_process'); const { exec } = require('child_process');
const XLSX = require('xlsx');
// Simple storage implementation to replace electron-store // Simple storage implementation to replace electron-store
const settingsPath = path.join(app.getPath('userData'), 'settings.json'); const settingsPath = path.join(app.getPath('userData'), 'settings.json');
@@ -84,7 +85,11 @@ function createMenu() {
{ label: 'LaTeX', click: () => exportFile('latex') }, { label: 'LaTeX', click: () => exportFile('latex') },
{ label: 'RTF', click: () => exportFile('rtf') }, { label: 'RTF', click: () => exportFile('rtf') },
{ label: 'ODT', click: () => exportFile('odt') }, { label: 'ODT', click: () => exportFile('odt') },
{ label: 'EPUB', click: () => exportFile('epub') } { label: 'EPUB', click: () => exportFile('epub') },
{ type: 'separator' },
{ label: 'Excel (XLSX)', click: () => exportSpreadsheet('xlsx') },
{ label: 'Excel Legacy (XLS)', click: () => exportSpreadsheet('xls') },
{ label: 'OpenDocument Spreadsheet (ODS)', click: () => exportSpreadsheet('ods') }
] ]
}, },
{ type: 'separator' }, { type: 'separator' },
@@ -142,16 +147,16 @@ function createMenu() {
click: () => { click: () => {
dialog.showMessageBox(mainWindow, { dialog.showMessageBox(mainWindow, {
type: 'info', type: 'info',
title: 'About Pan Converter', title: 'About PanConverter',
message: 'Pan Converter', message: 'PanConverter',
detail: 'A cross-platform Markdown editor and converter using Pandoc.\n\nVersion: 1.0.0\nLicense: MIT', detail: 'A cross-platform Markdown editor and converter using Pandoc.\n\nVersion: 1.1.0\nAuthor: Amit Haridas\nEmail: amit.wh@gmail.com\nLicense: MIT\n\nFeatures:\n• Markdown editing with live preview\n• Export to multiple formats via Pandoc\n• Export tables to Excel/ODS spreadsheets\n• Multiple themes support',
buttons: ['OK'] buttons: ['OK']
}); });
} }
}, },
{ {
label: 'Documentation', label: 'Documentation',
click: () => shell.openExternal('https://github.com/yourusername/pan-converter') click: () => shell.openExternal('https://github.com/amitwh/pan-converter')
} }
] ]
} }
@@ -223,6 +228,16 @@ function exportFile(format) {
} }
} }
function exportSpreadsheet(format) {
if (!currentFile) {
dialog.showErrorBox('Error', 'Please save the file first');
return;
}
// Request content from renderer
mainWindow.webContents.send('get-content-for-spreadsheet', format);
}
function setTheme(theme) { function setTheme(theme) {
store.set('theme', theme); store.set('theme', theme);
mainWindow.webContents.send('theme-changed', theme); mainWindow.webContents.send('theme-changed', theme);
@@ -247,6 +262,89 @@ ipcMain.on('get-theme', (event) => {
event.reply('theme-changed', theme); event.reply('theme-changed', theme);
}); });
ipcMain.on('export-spreadsheet', (event, { content, format }) => {
const outputFile = dialog.showSaveDialogSync(mainWindow, {
defaultPath: currentFile.replace(/\.[^/.]+$/, `.${format}`),
filters: [
{ name: format.toUpperCase(), extensions: [format] }
]
});
if (outputFile) {
try {
// Parse markdown content to extract tables
const tables = extractTablesFromMarkdown(content);
if (tables.length === 0) {
dialog.showErrorBox('Export Error', 'No tables found in the markdown content');
return;
}
// Create workbook
const wb = XLSX.utils.book_new();
tables.forEach((table, index) => {
const ws = XLSX.utils.aoa_to_sheet(table);
XLSX.utils.book_append_sheet(wb, ws, `Table ${index + 1}`);
});
// Write file
XLSX.writeFile(wb, outputFile);
dialog.showMessageBox(mainWindow, {
type: 'info',
title: 'Export Complete',
message: `Spreadsheet exported successfully to ${outputFile}`,
buttons: ['OK']
});
} catch (error) {
dialog.showErrorBox('Export Error', `Failed to export: ${error.message}`);
}
}
});
// Helper function to extract tables from markdown
function extractTablesFromMarkdown(markdown) {
const tables = [];
const lines = markdown.split('\n');
let currentTable = [];
let inTable = false;
for (const line of lines) {
if (line.includes('|')) {
if (!inTable) {
inTable = true;
currentTable = [];
}
// Skip separator lines (|---|---|)
if (!line.match(/^\s*\|?\s*:?-+:?\s*\|/)) {
const cells = line.split('|')
.map(cell => cell.trim())
.filter(cell => cell !== '');
if (cells.length > 0) {
currentTable.push(cells);
}
}
} else if (inTable && line.trim() === '') {
// End of table
if (currentTable.length > 0) {
tables.push(currentTable);
}
currentTable = [];
inTable = false;
}
}
// Add last table if exists
if (currentTable.length > 0) {
tables.push(currentTable);
}
return tables;
}
app.whenReady().then(createWindow); app.whenReady().then(createWindow);
app.on('window-all-closed', () => { app.on('window-all-closed', () => {
+4
View File
@@ -191,6 +191,10 @@ ipcRenderer.on('theme-changed', (event, theme) => {
updateStatus(`Theme: ${theme}`); updateStatus(`Theme: ${theme}`);
}); });
ipcRenderer.on('get-content-for-spreadsheet', (event, format) => {
ipcRenderer.send('export-spreadsheet', { content: editor.value, format });
});
// Keyboard shortcuts // Keyboard shortcuts
document.addEventListener('keydown', (e) => { document.addEventListener('keydown', (e) => {
// Ctrl/Cmd + Enter to toggle preview // Ctrl/Cmd + Enter to toggle preview