mirror of
https://github.com/amitwh/markdown-converter.git
synced 2026-08-02 18:10:18 +05:30
Fix v1.9.0 logo upload and add MiKTeX PATH support
This commit fixes the logo upload issue and adds MiKTeX to the app's PATH for LaTeX/PDF support. **Logo Upload Fix:** - Replaced file input with Browse button that uses dialog.showOpenDialog - Added browse-header-footer-logo IPC handler in main process - Now gets reliable file paths without depending on file.path property - Added browse-btn CSS styling **MiKTeX PATH Addition:** - Automatically adds MiKTeX bin directory to process.env.PATH on Windows - Enables XeLaTeX/PDFLaTeX for PDF exports with headers/footers - Logs PATH addition for debugging **Files Changed:** - src/main.js: Added MiKTeX PATH setup, browse logo IPC handler - src/renderer.js: Changed to browseForLogo() function, updated event listeners - src/index.html: Replaced file inputs with browse buttons - src/styles.css: Added .browse-btn styling **Testing Notes:** - Logo upload now works without "path undefined" errors - DOCX exports with headers/footers confirmed working - PDF exports should now use Pandoc+XeLaTeX with MiKTeX in PATH - Requires MiKTeX installation and PC restart for full functionality 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
+2
-2
@@ -964,7 +964,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="hf-logo-row">
|
<div class="hf-logo-row">
|
||||||
<label>Header Logo/Image:</label>
|
<label>Header Logo/Image:</label>
|
||||||
<input type="file" id="header-logo" accept="image/*">
|
<button id="header-logo-browse" class="browse-btn">Browse...</button>
|
||||||
<button id="header-logo-clear" class="clear-btn">Clear</button>
|
<button id="header-logo-clear" class="clear-btn">Clear</button>
|
||||||
<span id="header-logo-preview" class="logo-preview"></span>
|
<span id="header-logo-preview" class="logo-preview"></span>
|
||||||
</div>
|
</div>
|
||||||
@@ -992,7 +992,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="hf-logo-row">
|
<div class="hf-logo-row">
|
||||||
<label>Footer Logo/Image:</label>
|
<label>Footer Logo/Image:</label>
|
||||||
<input type="file" id="footer-logo" accept="image/*">
|
<button id="footer-logo-browse" class="browse-btn">Browse...</button>
|
||||||
<button id="footer-logo-clear" class="clear-btn">Clear</button>
|
<button id="footer-logo-clear" class="clear-btn">Clear</button>
|
||||||
<span id="footer-logo-preview" class="logo-preview"></span>
|
<span id="footer-logo-preview" class="logo-preview"></span>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
+55
@@ -5,6 +5,15 @@ const { exec } = require('child_process');
|
|||||||
const { PDFDocument, rgb, degrees, StandardFonts } = require('pdf-lib');
|
const { PDFDocument, rgb, degrees, StandardFonts } = require('pdf-lib');
|
||||||
const WordTemplateExporter = require('./wordTemplateExporter');
|
const WordTemplateExporter = require('./wordTemplateExporter');
|
||||||
|
|
||||||
|
// Add MiKTeX to PATH for LaTeX support
|
||||||
|
if (process.platform === 'win32') {
|
||||||
|
const miktexPath = 'C:\\Program Files\\MiKTeX\\miktex\\bin\\x64';
|
||||||
|
if (fs.existsSync(miktexPath)) {
|
||||||
|
process.env.PATH = `${miktexPath};${process.env.PATH}`;
|
||||||
|
console.log('[MAIN] Added MiKTeX to PATH:', miktexPath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Get the system Pandoc path
|
// Get the system Pandoc path
|
||||||
function getPandocPath() {
|
function getPandocPath() {
|
||||||
// Pandoc is expected to be in the system's PATH.
|
// Pandoc is expected to be in the system's PATH.
|
||||||
@@ -664,6 +673,52 @@ ipcMain.on('save-header-footer-settings', (event, settings) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Save header/footer logo image
|
// Save header/footer logo image
|
||||||
|
// Browse for header/footer logo
|
||||||
|
ipcMain.on('browse-header-footer-logo', async (event, position) => {
|
||||||
|
try {
|
||||||
|
const result = await dialog.showOpenDialog(mainWindow, {
|
||||||
|
title: `Select ${position.charAt(0).toUpperCase() + position.slice(1)} Logo/Image`,
|
||||||
|
filters: [
|
||||||
|
{ name: 'Images', extensions: ['png', 'jpg', 'jpeg', 'gif', 'bmp', 'svg', 'webp'] }
|
||||||
|
],
|
||||||
|
properties: ['openFile']
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!result.canceled && result.filePaths.length > 0) {
|
||||||
|
const filePath = result.filePaths[0];
|
||||||
|
|
||||||
|
// Copy image to userData directory for persistent storage
|
||||||
|
const userDataPath = app.getPath('userData');
|
||||||
|
const logoDir = path.join(userDataPath, 'logos');
|
||||||
|
|
||||||
|
// Create logos directory if it doesn't exist
|
||||||
|
if (!fs.existsSync(logoDir)) {
|
||||||
|
fs.mkdirSync(logoDir, { recursive: true });
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generate unique filename
|
||||||
|
const ext = path.extname(filePath);
|
||||||
|
const filename = `${position}_${Date.now()}${ext}`;
|
||||||
|
const destPath = path.join(logoDir, filename);
|
||||||
|
|
||||||
|
// Copy file
|
||||||
|
fs.copyFileSync(filePath, destPath);
|
||||||
|
|
||||||
|
// Update settings
|
||||||
|
if (position === 'header') {
|
||||||
|
headerFooterSettings.header.logo = destPath;
|
||||||
|
} else if (position === 'footer') {
|
||||||
|
headerFooterSettings.footer.logo = destPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
event.reply('header-footer-logo-saved', { position, path: destPath });
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Logo browse error:', error);
|
||||||
|
dialog.showErrorBox('Logo Error', `Failed to select logo: ${error.message}`);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
ipcMain.on('save-header-footer-logo', async (event, { position, filePath }) => {
|
ipcMain.on('save-header-footer-logo', async (event, { position, filePath }) => {
|
||||||
try {
|
try {
|
||||||
if (!filePath) {
|
if (!filePath) {
|
||||||
|
|||||||
+6
-21
@@ -2658,23 +2658,9 @@ function saveHeaderFooterSettings() {
|
|||||||
closeHeaderFooterDialog();
|
closeHeaderFooterDialog();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle logo file selection
|
// Handle logo browsing - ask main process to show open dialog
|
||||||
function handleLogoSelection(position) {
|
function browseForLogo(position) {
|
||||||
const input = document.getElementById(`${position}-logo`);
|
ipcRenderer.send('browse-header-footer-logo', position);
|
||||||
|
|
||||||
if (input.files && input.files[0]) {
|
|
||||||
const file = input.files[0];
|
|
||||||
// Use webUtils to get the real file path in Electron
|
|
||||||
const filePath = file.path || (window.electron && window.electron.webUtils ? window.electron.webUtils.getPathForFile(file) : null);
|
|
||||||
|
|
||||||
if (!filePath) {
|
|
||||||
alert('Error: Could not get file path. Please try again.');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Send to main process to save
|
|
||||||
ipcRenderer.send('save-header-footer-logo', { position, filePath });
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle logo saved confirmation
|
// Handle logo saved confirmation
|
||||||
@@ -2685,7 +2671,6 @@ ipcRenderer.on('header-footer-logo-saved', (event, { position, path }) => {
|
|||||||
// Clear logo
|
// Clear logo
|
||||||
function clearLogo(position) {
|
function clearLogo(position) {
|
||||||
ipcRenderer.send('clear-header-footer-logo', position);
|
ipcRenderer.send('clear-header-footer-logo', position);
|
||||||
document.getElementById(`${position}-logo`).value = '';
|
|
||||||
document.getElementById(`${position}-logo-preview`).textContent = '';
|
document.getElementById(`${position}-logo-preview`).textContent = '';
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2728,9 +2713,9 @@ document.querySelectorAll('.field-insert-btn').forEach(btn => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// Logo file inputs
|
// Logo browse buttons
|
||||||
document.getElementById('header-logo').addEventListener('change', () => handleLogoSelection('header'));
|
document.getElementById('header-logo-browse').addEventListener('click', () => browseForLogo('header'));
|
||||||
document.getElementById('footer-logo').addEventListener('change', () => handleLogoSelection('footer'));
|
document.getElementById('footer-logo-browse').addEventListener('click', () => browseForLogo('footer'));
|
||||||
|
|
||||||
// Logo clear buttons
|
// Logo clear buttons
|
||||||
document.getElementById('header-logo-clear').addEventListener('click', () => clearLogo('header'));
|
document.getElementById('header-logo-clear').addEventListener('click', () => clearLogo('header'));
|
||||||
|
|||||||
@@ -3312,6 +3312,22 @@ body.printing-no-styles .preview-content pre,
|
|||||||
background: var(--button-hover, #5a6268);
|
background: var(--button-hover, #5a6268);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.browse-btn {
|
||||||
|
padding: 6px 12px;
|
||||||
|
background: var(--accent-color, #007bff);
|
||||||
|
color: white;
|
||||||
|
border: none;
|
||||||
|
border-radius: 4px;
|
||||||
|
cursor: pointer;
|
||||||
|
font-size: 13px;
|
||||||
|
transition: background 0.2s ease;
|
||||||
|
margin-right: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.browse-btn:hover {
|
||||||
|
background: var(--accent-hover, #0056b3);
|
||||||
|
}
|
||||||
|
|
||||||
.clear-btn {
|
.clear-btn {
|
||||||
padding: 6px 12px;
|
padding: 6px 12px;
|
||||||
background: var(--danger-color, #dc3545);
|
background: var(--danger-color, #dc3545);
|
||||||
|
|||||||
Reference in New Issue
Block a user