Enhance print menu with preview-only printing options (v1.7.7)

- Added Print submenu to File menu with two print options:
  * Print Preview (Ctrl+P): Black text, no colors, ink-saving
  * Print Preview (With Styles): Full colors and styling
- Implemented print handler that hides all editor UI and shows only preview
- Editor, toolbar, tabs, and status bar hidden during printing
- Added comprehensive CSS print stylesheet with:
  * Smart page breaks for headings, tables, and paragraphs
  * Optimized formatting for code blocks, lists, and tables
  * Professional typography (12pt font size, 1.6 line height)
  * Image optimization and proper link handling
  * Support for blockquotes, horizontal rules, and other elements
- Print-specific CSS classes for styling control
- Preview automatically restored after printing
Features:
- Prints only the rendered markdown preview (not source)
- Two print modes: simple (black) and styled (colored)
- Native OS print dialogs for all platforms
- Professional output formatting with page breaks
- Cross-platform support (Windows, macOS, Linux)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
This commit is contained in:
2025-10-24 22:14:53 +05:30
parent 55da44e0a8
commit 1a6ca50e03
4 changed files with 311 additions and 34 deletions
+41 -11
View File
@@ -201,8 +201,17 @@ function createMenu() {
{ type: 'separator' },
{
label: 'Print',
accelerator: 'CmdOrCtrl+P',
click: () => mainWindow.webContents.send('print-document')
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' },
{
@@ -1157,16 +1166,37 @@ ipcMain.on('set-current-file', (event, filePath) => {
currentFile = filePath;
});
// Handle print document
ipcMain.on('print-document', (event) => {
// Handle print preview
ipcMain.on('print-preview', (event) => {
if (mainWindow) {
// Open native print dialog
mainWindow.webContents.print({
silent: false,
printBackground: true,
color: true,
margin: { marginType: 'default' }
});
// Prepare for printing preview only (black text, no colors)
mainWindow.webContents.send('prepare-print-preview', false);
// Give renderer time to prepare, then print
setTimeout(() => {
mainWindow.webContents.print({
silent: false,
printBackground: false,
color: true,
margin: { marginType: 'default' }
});
}, 100);
}
});
// Handle print preview with styles
ipcMain.on('print-preview-styled', (event) => {
if (mainWindow) {
// Prepare for printing preview with colors
mainWindow.webContents.send('prepare-print-preview', true);
// Give renderer time to prepare, then print
setTimeout(() => {
mainWindow.webContents.print({
silent: false,
printBackground: true,
color: true,
margin: { marginType: 'default' }
});
}, 100);
}
});
+33 -7
View File
@@ -1149,16 +1149,42 @@ ipcRenderer.on('adjust-font-size', (event, action) => {
updateFontSizes(currentFontSize);
});
// Print document handler
ipcRenderer.on('print-document', () => {
// Use the preview pane for printing
// Print preview handler - prepare for printing
ipcRenderer.on('prepare-print-preview', (event, withStyles) => {
const previewContent = document.getElementById('preview');
if (previewContent && previewContent.innerHTML.trim()) {
// Create a print window with the preview content
window.print();
} else {
if (!previewContent || !previewContent.innerHTML.trim()) {
alert('Nothing to print. Please create or open a document and ensure the preview is visible.');
return;
}
// Hide editor and other UI elements for print
document.getElementById('editor-container').style.display = 'none';
document.getElementById('toolbar').style.display = 'none';
document.getElementById('tab-bar').style.display = 'none';
document.getElementById('status-bar').style.display = 'none';
// Show preview in full width
const preview = document.getElementById('preview');
if (preview) {
preview.classList.add('print-mode');
if (!withStyles) {
preview.classList.add('print-no-styles');
}
}
// Re-show everything after print
setTimeout(() => {
document.getElementById('editor-container').style.display = '';
document.getElementById('toolbar').style.display = '';
document.getElementById('tab-bar').style.display = '';
document.getElementById('status-bar').style.display = '';
const preview = document.getElementById('preview');
if (preview) {
preview.classList.remove('print-mode', 'print-no-styles');
}
}, 500);
});
// Export Dialog functionality
+168
View File
@@ -2823,4 +2823,172 @@ body.theme-concrete-warm .status-bar {
background: #3a3836;
border-top-color: #9a9696;
color: #e3e3e3;
}
/* Print Styles */
@media print {
/* Hide UI elements for clean print output */
#toolbar,
#tab-bar,
#editor-container,
.editor-container,
#status-bar,
.status-bar {
display: none !important;
}
/* Show preview in full width */
#preview,
.preview,
.preview-content {
display: block !important;
width: 100% !important;
max-width: 100% !important;
height: auto !important;
margin: 0 !important;
padding: 20px !important;
overflow: visible !important;
}
/* Optimize preview content for printing */
.preview-content {
line-height: 1.6;
font-size: 12pt;
color: #000 !important;
background: white !important;
}
/* Text formatting */
.preview-content h1,
.preview-content h2,
.preview-content h3,
.preview-content h4,
.preview-content h5,
.preview-content h6 {
page-break-after: avoid;
margin-top: 1em;
margin-bottom: 0.5em;
}
.preview-content p {
margin-bottom: 0.5em;
page-break-inside: avoid;
}
/* Code blocks */
.preview-content pre {
background: #f5f5f5 !important;
border: 1px solid #ddd !important;
page-break-inside: avoid;
padding: 10px;
font-size: 10pt;
}
.preview-content code {
background: #f5f5f5 !important;
color: #000 !important;
font-size: 10pt;
}
/* Lists */
.preview-content ul,
.preview-content ol {
margin-left: 20px;
page-break-inside: avoid;
}
.preview-content li {
page-break-inside: avoid;
margin-bottom: 0.3em;
}
/* Tables */
.preview-content table {
width: 100%;
border-collapse: collapse;
page-break-inside: avoid;
margin-bottom: 1em;
}
.preview-content th,
.preview-content td {
border: 1px solid #999 !important;
padding: 8px !important;
text-align: left;
}
.preview-content th {
background: #f0f0f0 !important;
font-weight: bold;
}
/* Links - remove underline for print */
.preview-content a {
color: #000 !important;
text-decoration: none;
}
/* Blockquotes */
.preview-content blockquote {
border-left: 3px solid #ccc;
padding-left: 15px;
margin-left: 0;
color: #333 !important;
}
/* Images */
.preview-content img {
max-width: 100%;
height: auto;
page-break-inside: avoid;
}
/* Horizontal rules */
.preview-content hr {
border: none;
border-top: 1px solid #999;
margin: 1em 0;
}
}
/* Print mode classes */
.print-mode {
display: block !important;
width: 100% !important;
max-width: 100% !important;
}
.print-no-styles .preview-content {
color: #000 !important;
background: white !important;
}
.print-no-styles .preview-content h1,
.print-no-styles .preview-content h2,
.print-no-styles .preview-content h3,
.print-no-styles .preview-content h4,
.print-no-styles .preview-content h5,
.print-no-styles .preview-content h6 {
color: #000 !important;
border-color: #999 !important;
}
.print-no-styles .preview-content code {
background: #f5f5f5 !important;
color: #000 !important;
}
.print-no-styles .preview-content pre {
background: #f5f5f5 !important;
color: #000 !important;
border-color: #999 !important;
}
.print-no-styles .preview-content a {
color: #000 !important;
}
.print-no-styles .preview-content blockquote {
color: #333 !important;
border-color: #999 !important;
}