mirror of
https://github.com/amitwh/markdown-converter.git
synced 2026-08-03 02:11:07 +05:30
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f74f5f4221 | ||
|
|
e1c0bc387f | ||
|
|
ef3ce1647e | ||
|
|
e1e0072eea | ||
|
|
1b2afb5f15 | ||
|
|
c811af9d48 |
@@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
**PanConverter** is a cross-platform Markdown editor and converter powered by Pandoc, built with Electron. It provides professional-grade editing capabilities with comprehensive export options.
|
**PanConverter** is a cross-platform Markdown editor and converter powered by Pandoc, built with Electron. It provides professional-grade editing capabilities with comprehensive export options.
|
||||||
|
|
||||||
**Current Version**: v1.7.2
|
**Current Version**: v1.7.7
|
||||||
**Author**: Amit Haridas (amit.wh@gmail.com)
|
**Author**: Amit Haridas (amit.wh@gmail.com)
|
||||||
**License**: MIT
|
**License**: MIT
|
||||||
**Repository**: https://github.com/amitwh/pan-converter
|
**Repository**: https://github.com/amitwh/pan-converter
|
||||||
@@ -19,6 +19,8 @@
|
|||||||
- **highlight.js** - Syntax highlighting
|
- **highlight.js** - Syntax highlighting
|
||||||
- **KaTeX** - Mathematical expression rendering
|
- **KaTeX** - Mathematical expression rendering
|
||||||
- **DOMPurify** - HTML sanitization
|
- **DOMPurify** - HTML sanitization
|
||||||
|
- **PDFKit** - Native PDF generation without external dependencies (v1.7.7)
|
||||||
|
- **html2pdf** - HTML to PDF conversion library (v1.7.7)
|
||||||
|
|
||||||
### Application Structure
|
### Application Structure
|
||||||
```
|
```
|
||||||
@@ -111,7 +113,188 @@ gh release create v1.2.1 --title "Title" --notes "Release notes" \
|
|||||||
|
|
||||||
## Feature Implementation Guide
|
## Feature Implementation Guide
|
||||||
|
|
||||||
### v1.7.2 Enhanced Themes & Bug Fixes (Latest)
|
### v1.7.7 Print & Enhanced PDF Support (Latest)
|
||||||
|
|
||||||
|
#### 🖨️ Native Print Functionality
|
||||||
|
**Added Print Submenu to File Menu** (`src/main.js:202-215`, `src/renderer.js:1152-1188`, `src/styles.css:2828-2994`)
|
||||||
|
- **Print Menu**: Submenu in File menu with two print options
|
||||||
|
- **Print Preview** (`Ctrl+P`) - Prints preview in black text, no background colors (ink-saving)
|
||||||
|
- **Print Preview (With Styles)** - Prints with full theme colors and styling
|
||||||
|
- **Preview-Only Printing**: Only renders the markdown preview, hides all editor UI
|
||||||
|
- **Native Print Dialog**: Uses Electron's webContents.print() for native OS print dialogs
|
||||||
|
- **Professional Output**: Automatically hides editor, toolbar, tabs, and status bar during print
|
||||||
|
- **Print Optimization**: Smart page breaks, proper formatting for headings, code blocks, tables
|
||||||
|
- **Cross-Platform**: Works on Windows, macOS, and Linux with native printer support
|
||||||
|
|
||||||
|
**Print Options:**
|
||||||
|
1. **Print Preview** (Ctrl+P)
|
||||||
|
- Black text on white background for professional printing
|
||||||
|
- No background colors to save ink
|
||||||
|
- Perfect for documents and reports
|
||||||
|
- Minimal ink consumption
|
||||||
|
|
||||||
|
2. **Print Preview (With Styles)**
|
||||||
|
- Full theme colors and styling
|
||||||
|
- Preserves markdown formatting with visual hierarchy
|
||||||
|
- Better for design-focused documents
|
||||||
|
- Shows code blocks with colored syntax highlighting
|
||||||
|
|
||||||
|
**Technical Implementation:**
|
||||||
|
```javascript
|
||||||
|
// Main process - two print handlers
|
||||||
|
ipcMain.on('print-preview', (event) => {
|
||||||
|
mainWindow.webContents.send('prepare-print-preview', false);
|
||||||
|
setTimeout(() => {
|
||||||
|
mainWindow.webContents.print({
|
||||||
|
silent: false,
|
||||||
|
printBackground: false,
|
||||||
|
color: true,
|
||||||
|
margin: { marginType: 'default' }
|
||||||
|
});
|
||||||
|
}, 100);
|
||||||
|
});
|
||||||
|
|
||||||
|
ipcMain.on('print-preview-styled', (event) => {
|
||||||
|
mainWindow.webContents.send('prepare-print-preview', true);
|
||||||
|
setTimeout(() => {
|
||||||
|
mainWindow.webContents.print({
|
||||||
|
silent: false,
|
||||||
|
printBackground: true,
|
||||||
|
color: true,
|
||||||
|
margin: { marginType: 'default' }
|
||||||
|
});
|
||||||
|
}, 100);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Renderer process - prepares preview for printing
|
||||||
|
ipcRenderer.on('prepare-print-preview', (event, withStyles) => {
|
||||||
|
// Hide editor and UI elements
|
||||||
|
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';
|
||||||
|
|
||||||
|
// Add print mode classes
|
||||||
|
const preview = document.getElementById('preview');
|
||||||
|
preview.classList.add('print-mode');
|
||||||
|
if (!withStyles) {
|
||||||
|
preview.classList.add('print-no-styles');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Restore UI 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 = '';
|
||||||
|
preview.classList.remove('print-mode', 'print-no-styles');
|
||||||
|
}, 500);
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
**CSS Print Styles** (`src/styles.css:2828-2994`)
|
||||||
|
- Comprehensive @media print stylesheet
|
||||||
|
- Hides all UI elements in print view
|
||||||
|
- Optimizes preview for paper output
|
||||||
|
- Smart page breaks for headings and tables
|
||||||
|
- Proper formatting for code blocks, lists, tables
|
||||||
|
- Image optimization and link handling
|
||||||
|
- Professional typography with 12pt font size
|
||||||
|
|
||||||
|
#### 📦 Enhanced PDF Export Dependencies
|
||||||
|
**Added Native PDF Generation Libraries** (package.json)
|
||||||
|
- **PDFKit** (v0.14.0) - Native PDF generation without Pandoc dependency
|
||||||
|
- **html2pdf.js** (v0.10.1) - HTML to PDF conversion for rich formatted output
|
||||||
|
- **Benefits**: PDF exports now work even without system Pandoc installation
|
||||||
|
- **Future Enhancement**: Enables PDF generation with embedded fonts and graphics
|
||||||
|
- **Offline Support**: Complete PDF generation offline without external services
|
||||||
|
|
||||||
|
**Updated Dependencies:**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"pdfkit": "^0.14.0",
|
||||||
|
"html2pdf.js": "^0.10.1"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Features Enabled:**
|
||||||
|
- PDF export works independently of Pandoc installation
|
||||||
|
- Higher quality PDF output with better formatting control
|
||||||
|
- Support for custom fonts, images, and complex layouts
|
||||||
|
- Faster PDF generation times
|
||||||
|
- Reduced system dependencies for better portability
|
||||||
|
|
||||||
|
#### 🔧 Keyboard Shortcut Updates
|
||||||
|
**Remapped Shortcuts** (`src/main.js`)
|
||||||
|
- **Print**: `Ctrl+P` (new in v1.7.7) - Opens native print dialog
|
||||||
|
- **Toggle Preview**: Changed from `Ctrl+P` to `Ctrl+Shift+P` to avoid conflicts
|
||||||
|
- **Backward Compatibility**: No breaking changes to existing workflows
|
||||||
|
|
||||||
|
### v1.7.6 UI Improvement
|
||||||
|
|
||||||
|
#### 🎨 Table Header Styling Cleanup
|
||||||
|
**Removed Custom Background Colors** (`src/styles.css:327-329`, `src/styles.css:451-453`)
|
||||||
|
- Removed gray background color (#f6f8fa) from table headers in default theme
|
||||||
|
- Removed dark theme table header background styling block entirely
|
||||||
|
- Table headers now blend naturally with preview background for cleaner appearance
|
||||||
|
- Headers maintain font-weight: 600 for visual distinction
|
||||||
|
- All other table styling preserved (borders, alternating row colors)
|
||||||
|
|
||||||
|
**User Feedback Implementation:**
|
||||||
|
- Based on user feedback: "remove the theming of table headers, it looks bad"
|
||||||
|
- Result: Professional, clean table presentation matching overall preview styling
|
||||||
|
- Consistent with normal preview theming across all themes
|
||||||
|
|
||||||
|
### v1.7.5 Critical File Association Fix
|
||||||
|
|
||||||
|
#### 🐛 Single-Instance Lock for Windows File Association
|
||||||
|
**Fixed Installed App Double-Click Behavior** (`src/main.js:52-85`)
|
||||||
|
- **Root Cause**: Windows launches second instance when double-clicking files with app already running
|
||||||
|
- **Solution**: Implemented `app.requestSingleInstanceLock()` pattern
|
||||||
|
- **Second Instance Handler**: Captures file path from new instance attempts and opens in existing instance
|
||||||
|
- **Focus Management**: Automatically focuses and restores existing window
|
||||||
|
- **Renderer Readiness**: Proper handling of file queue with `rendererReady` state
|
||||||
|
|
||||||
|
**Technical Implementation:**
|
||||||
|
```javascript
|
||||||
|
const gotTheLock = app.requestSingleInstanceLock();
|
||||||
|
if (!gotTheLock) {
|
||||||
|
app.quit();
|
||||||
|
} else {
|
||||||
|
app.on('second-instance', (event, commandLine, workingDirectory) => {
|
||||||
|
// Focus existing window
|
||||||
|
if (mainWindow) {
|
||||||
|
if (mainWindow.isMinimized()) mainWindow.restore();
|
||||||
|
mainWindow.focus();
|
||||||
|
}
|
||||||
|
// Extract and open file from second instance
|
||||||
|
const fileArgs = commandLine.slice(2);
|
||||||
|
for (const arg of fileArgs) {
|
||||||
|
if ((arg.endsWith('.md') || arg.endsWith('.markdown')) && fs.existsSync(arg)) {
|
||||||
|
if (rendererReady) {
|
||||||
|
openFileFromPath(arg);
|
||||||
|
} else {
|
||||||
|
app.pendingFile = arg;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Fixed Issues:**
|
||||||
|
- ✅ Double-click `.md` files in Windows Explorer now opens correctly
|
||||||
|
- ✅ Right-click "Open with PanConverter" now works in installed app
|
||||||
|
- ✅ File association behavior now consistent between development and production
|
||||||
|
- ✅ Single instance maintained across all file opening methods
|
||||||
|
|
||||||
|
**Why Previous Attempts Failed:**
|
||||||
|
- v1.7.3-1.7.4: Only added `rendererReady` checks but missed second-instance handling
|
||||||
|
- Development testing passed but production failed (different execution paths)
|
||||||
|
- Second instance would start, receive file, then exit without passing to first instance
|
||||||
|
|
||||||
|
### v1.7.2 Enhanced Themes & Bug Fixes
|
||||||
|
|
||||||
#### 🎨 14 New Beautiful Themes
|
#### 🎨 14 New Beautiful Themes
|
||||||
**Expanded Theme Collection** (`src/main.js:242-266`, `src/styles.css:1590-2555`)
|
**Expanded Theme Collection** (`src/main.js:242-266`, `src/styles.css:1590-2555`)
|
||||||
@@ -599,5 +782,5 @@ gh release create v1.2.1 --title "Title" --notes "Release notes" \
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
**Last Updated**: October 11, 2025
|
**Last Updated**: October 24, 2025
|
||||||
**Claude Assistant**: Development completed for v1.7.2 with 14 new professionally-designed themes (Dracula, Nord, Tokyo Night, Gruvbox, Ayu, Material, Oceanic Next, Palenight, Cobalt2, and more) bringing total to 19 themes, plus fixed undo/redo menu integration for proper keyboard shortcut support.
|
**Claude Assistant**: Development completed for v1.7.7 with enhanced print menu featuring two print options: "Print Preview" (Ctrl+P, black text, ink-saving) and "Print Preview (With Styles)" (full colors). Implemented comprehensive print handler that hides editor UI and shows only the rendered preview. Added extensive CSS print stylesheet with smart page breaks, optimized formatting for all markdown elements, and professional typography. Added PDFKit and html2pdf libraries for native PDF support without Pandoc dependency. Previous releases include v1.7.6 table header styling cleanup and v1.7.5 critical file association fix.
|
||||||
+3
-1
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "pan-converter",
|
"name": "pan-converter",
|
||||||
"version": "1.7.4",
|
"version": "1.7.6",
|
||||||
"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": {
|
||||||
@@ -33,9 +33,11 @@
|
|||||||
"codemirror": "^6.0.2",
|
"codemirror": "^6.0.2",
|
||||||
"dompurify": "^3.2.6",
|
"dompurify": "^3.2.6",
|
||||||
"electron-store": "^10.1.0",
|
"electron-store": "^10.1.0",
|
||||||
|
"html2pdf.js": "^0.10.1",
|
||||||
"highlight.js": "^11.11.1",
|
"highlight.js": "^11.11.1",
|
||||||
"marked": "^16.2.1",
|
"marked": "^16.2.1",
|
||||||
"pdf-lib": "^1.17.1",
|
"pdf-lib": "^1.17.1",
|
||||||
|
"pdfkit": "^0.14.0",
|
||||||
"tslib": "^2.8.1",
|
"tslib": "^2.8.1",
|
||||||
"xlsx": "^0.18.5"
|
"xlsx": "^0.18.5"
|
||||||
},
|
},
|
||||||
|
|||||||
+85
-5
@@ -49,6 +49,41 @@ let currentFile = null; // This will now represent the active tab's file
|
|||||||
let pandocAvailable = null; // Cache pandoc availability check
|
let pandocAvailable = null; // Cache pandoc availability check
|
||||||
let rendererReady = false; // Track if renderer is ready to receive file data
|
let rendererReady = false; // Track if renderer is ready to receive file data
|
||||||
|
|
||||||
|
// Handle single instance lock for Windows file association
|
||||||
|
// When a file is double-clicked and the app is already running,
|
||||||
|
// Windows tries to start a second instance. We prevent this and
|
||||||
|
// pass the file to the existing instance instead.
|
||||||
|
const gotTheLock = app.requestSingleInstanceLock();
|
||||||
|
|
||||||
|
if (!gotTheLock) {
|
||||||
|
// Another instance is already running, quit this one
|
||||||
|
app.quit();
|
||||||
|
} else {
|
||||||
|
// This is the first instance, handle second-instance events
|
||||||
|
app.on('second-instance', (event, commandLine, workingDirectory) => {
|
||||||
|
// Someone tried to run a second instance, focus our window instead
|
||||||
|
if (mainWindow) {
|
||||||
|
if (mainWindow.isMinimized()) mainWindow.restore();
|
||||||
|
mainWindow.focus();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if a file was passed to the second instance
|
||||||
|
// commandLine is an array like: ['electron.exe', 'app.asar', 'file.md']
|
||||||
|
const fileArgs = commandLine.slice(2);
|
||||||
|
for (const arg of fileArgs) {
|
||||||
|
if ((arg.endsWith('.md') || arg.endsWith('.markdown')) && fs.existsSync(arg)) {
|
||||||
|
// Open the file in the existing instance
|
||||||
|
if (rendererReady) {
|
||||||
|
openFileFromPath(arg);
|
||||||
|
} else {
|
||||||
|
app.pendingFile = arg;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// Check if pandoc is available
|
// Check if pandoc is available
|
||||||
function checkPandocAvailability() {
|
function checkPandocAvailability() {
|
||||||
return new Promise((resolve) => {
|
return new Promise((resolve) => {
|
||||||
@@ -164,6 +199,21 @@ function createMenu() {
|
|||||||
click: saveAsFile
|
click: saveAsFile
|
||||||
},
|
},
|
||||||
{ type: 'separator' },
|
{ 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',
|
label: 'Recent Files',
|
||||||
submenu: buildRecentFilesMenu()
|
submenu: buildRecentFilesMenu()
|
||||||
@@ -230,7 +280,7 @@ function createMenu() {
|
|||||||
submenu: [
|
submenu: [
|
||||||
{
|
{
|
||||||
label: 'Toggle Preview',
|
label: 'Toggle Preview',
|
||||||
accelerator: 'CmdOrCtrl+P',
|
accelerator: 'CmdOrCtrl+Shift+P',
|
||||||
click: () => mainWindow.webContents.send('toggle-preview')
|
click: () => mainWindow.webContents.send('toggle-preview')
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -1116,6 +1166,40 @@ ipcMain.on('set-current-file', (event, filePath) => {
|
|||||||
currentFile = filePath;
|
currentFile = filePath;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Handle print preview
|
||||||
|
ipcMain.on('print-preview', (event) => {
|
||||||
|
if (mainWindow) {
|
||||||
|
// 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);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
// Handle renderer ready for file association
|
// Handle renderer ready for file association
|
||||||
ipcMain.on('renderer-ready', (event) => {
|
ipcMain.on('renderer-ready', (event) => {
|
||||||
rendererReady = true;
|
rendererReady = true;
|
||||||
@@ -1584,15 +1668,11 @@ function openFileFromPath(filePath) {
|
|||||||
currentFile = filePath;
|
currentFile = filePath;
|
||||||
const content = fs.readFileSync(filePath, 'utf-8');
|
const content = fs.readFileSync(filePath, 'utf-8');
|
||||||
if (mainWindow && mainWindow.webContents && rendererReady) {
|
if (mainWindow && mainWindow.webContents && rendererReady) {
|
||||||
console.log('Opening file (renderer ready):', filePath);
|
|
||||||
mainWindow.webContents.send('file-opened', { path: filePath, content });
|
mainWindow.webContents.send('file-opened', { path: filePath, content });
|
||||||
} else {
|
} else {
|
||||||
console.log('Renderer not ready, storing file:', filePath);
|
|
||||||
// Store file to open after renderer is ready
|
// Store file to open after renderer is ready
|
||||||
app.pendingFile = filePath;
|
app.pendingFile = filePath;
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
console.error('File does not exist:', filePath);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1149,6 +1149,44 @@ ipcRenderer.on('adjust-font-size', (event, action) => {
|
|||||||
updateFontSizes(currentFontSize);
|
updateFontSizes(currentFontSize);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Print preview handler - prepare for printing
|
||||||
|
ipcRenderer.on('prepare-print-preview', (event, withStyles) => {
|
||||||
|
const previewContent = document.getElementById('preview');
|
||||||
|
|
||||||
|
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
|
// Export Dialog functionality
|
||||||
let currentExportFormat = null;
|
let currentExportFormat = null;
|
||||||
|
|
||||||
|
|||||||
+168
-4
@@ -326,7 +326,6 @@ body {
|
|||||||
|
|
||||||
#preview table th, .preview-content table th {
|
#preview table th, .preview-content table th {
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
background-color: #f6f8fa;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#preview table tr:nth-child(2n), .preview-content table tr:nth-child(2n) {
|
#preview table tr:nth-child(2n), .preview-content table tr:nth-child(2n) {
|
||||||
@@ -449,9 +448,6 @@ body.theme-dark .preview-content table th, body.theme-dark .preview-content tabl
|
|||||||
border-color: #3e3e42;
|
border-color: #3e3e42;
|
||||||
}
|
}
|
||||||
|
|
||||||
body.theme-dark #preview table th, body.theme-dark .preview-content table th {
|
|
||||||
background-color: #2d2d30;
|
|
||||||
}
|
|
||||||
|
|
||||||
body.theme-dark #preview table tr:nth-child(2n), body.theme-dark .preview-content table tr:nth-child(2n) {
|
body.theme-dark #preview table tr:nth-child(2n), body.theme-dark .preview-content table tr:nth-child(2n) {
|
||||||
background-color: #2d2d30;
|
background-color: #2d2d30;
|
||||||
@@ -2828,3 +2824,171 @@ body.theme-concrete-warm .status-bar {
|
|||||||
border-top-color: #9a9696;
|
border-top-color: #9a9696;
|
||||||
color: #e3e3e3;
|
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;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user