mirror of
https://github.com/amitwh/markdown-converter.git
synced 2026-08-23 23:10:17 +05:30
feat(monospace): print-preview iframe uses bundled monospace font
Inlines @font-face as base64 data URI so the iframe srcdoc can render JetBrains Mono / Fira Code without depending on the parent window's loaded @font-face sets. Reads family + ligature state from the renderer-wide cache populated by applyMonospaceClasses(). Amit Haridas
This commit is contained in:
File diff suppressed because it is too large
Load Diff
+63
-2
@@ -1,11 +1,55 @@
|
|||||||
|
const fs = require('fs');
|
||||||
|
const path = require('path');
|
||||||
|
|
||||||
|
function getBundledFontWoff2Path(familyKey, weight) {
|
||||||
|
// Renderer can read directly from disk because nodeIntegration is on.
|
||||||
|
// Try repo-relative first, then packaged app.asar mirror.
|
||||||
|
const familyDir = familyKey === 'fira-code' ? 'FiraCode' : 'JetBrainsMono';
|
||||||
|
const weightName = weight >= 700 ? 'Bold' : 'Regular';
|
||||||
|
const filename = `${familyDir}-${weightName}.woff2`;
|
||||||
|
const repoPath = path.resolve(__dirname, '..', 'assets', 'fonts', filename);
|
||||||
|
if (fs.existsSync(repoPath)) return repoPath;
|
||||||
|
// Packaged: under <resourcesPath>/assets/fonts/
|
||||||
|
if (process.resourcesPath) {
|
||||||
|
const packaged = path.join(process.resourcesPath, 'assets', 'fonts', filename);
|
||||||
|
if (fs.existsSync(packaged)) return packaged;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildFontFaceBlock(familyKey) {
|
||||||
|
const family = familyKey === 'fira-code' ? 'Fira Code' : 'JetBrains Mono';
|
||||||
|
const fontPath = getBundledFontWoff2Path(familyKey, 400);
|
||||||
|
if (!fontPath) return '';
|
||||||
|
try {
|
||||||
|
const data = fs.readFileSync(fontPath);
|
||||||
|
const dataUri = `data:font/woff2;base64,${data.toString('base64')}`;
|
||||||
|
return `@font-face { font-family: '${family}'; font-weight: 400; font-style: normal; src: url('${dataUri}') format('woff2'); }`;
|
||||||
|
} catch (_) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class PrintPreview {
|
class PrintPreview {
|
||||||
constructor() {
|
constructor(monospaceSettings = {}) {
|
||||||
this.overlay = document.getElementById('print-preview-overlay');
|
this.overlay = document.getElementById('print-preview-overlay');
|
||||||
this.modal = window.modals?.printPreviewModal;
|
this.modal = window.modals?.printPreviewModal;
|
||||||
this._lastContent = '';
|
this._lastContent = '';
|
||||||
|
this._monospaceSettings = {
|
||||||
|
monospaceFont: monospaceSettings.monospaceFont || 'jetbrains-mono',
|
||||||
|
monospaceLigatures: monospaceSettings.monospaceLigatures === true,
|
||||||
|
};
|
||||||
this.setupEventListeners();
|
this.setupEventListeners();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setMonospaceSettings(settings) {
|
||||||
|
this._monospaceSettings = {
|
||||||
|
monospaceFont: (settings && settings.monospaceFont) || 'jetbrains-mono',
|
||||||
|
monospaceLigatures: !!(settings && settings.monospaceLigatures === true),
|
||||||
|
};
|
||||||
|
this.refreshPreview();
|
||||||
|
}
|
||||||
|
|
||||||
open(htmlContent) {
|
open(htmlContent) {
|
||||||
this._lastContent = htmlContent;
|
this._lastContent = htmlContent;
|
||||||
if (this.modal) {
|
if (this.modal) {
|
||||||
@@ -79,11 +123,17 @@ class PrintPreview {
|
|||||||
const width = orientation === 'landscape' ? size.height : size.width;
|
const width = orientation === 'landscape' ? size.height : size.width;
|
||||||
const height = orientation === 'landscape' ? size.width : size.height;
|
const height = orientation === 'landscape' ? size.width : size.height;
|
||||||
|
|
||||||
|
const family = this._monospaceSettings.monospaceFont === 'fira-code' ? 'Fira Code' : 'JetBrains Mono';
|
||||||
|
const ligaturesOn = this._monospaceSettings.monospaceLigatures === true;
|
||||||
|
const featureSettings = ligaturesOn ? 'normal' : "'liga' 0, 'calt' 0, 'dlig' 0";
|
||||||
|
const fontFaceBlock = buildFontFaceBlock(this._monospaceSettings.monospaceFont);
|
||||||
|
|
||||||
const previewHtml = `
|
const previewHtml = `
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<style>
|
<style>
|
||||||
|
${fontFaceBlock}
|
||||||
body {
|
body {
|
||||||
margin: 20px;
|
margin: 20px;
|
||||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
|
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
|
||||||
@@ -91,7 +141,18 @@ class PrintPreview {
|
|||||||
line-height: 1.6;
|
line-height: 1.6;
|
||||||
}
|
}
|
||||||
@page { size: ${width} ${height}; }
|
@page { size: ${width} ${height}; }
|
||||||
pre { background: #f5f5f5; padding: 12px; border-radius: 6px; overflow-x: auto; }
|
pre, code, kbd, samp {
|
||||||
|
font-family: '${family}', monospace;
|
||||||
|
font-feature-settings: ${featureSettings};
|
||||||
|
}
|
||||||
|
pre {
|
||||||
|
background: #f5f5f5;
|
||||||
|
padding: 12px;
|
||||||
|
border-radius: 6px;
|
||||||
|
overflow-x: auto;
|
||||||
|
white-space: pre;
|
||||||
|
tab-size: 4;
|
||||||
|
}
|
||||||
code { background: #f0f0f0; padding: 2px 6px; border-radius: 3px; font-size: 13px; }
|
code { background: #f0f0f0; padding: 2px 6px; border-radius: 3px; font-size: 13px; }
|
||||||
pre code { background: none; padding: 0; }
|
pre code { background: none; padding: 0; }
|
||||||
table { border-collapse: collapse; width: 100%; }
|
table { border-collapse: collapse; width: 100%; }
|
||||||
|
|||||||
+18
-2
@@ -15,10 +15,21 @@ const { undo, redo } = require('@codemirror/commands');
|
|||||||
/**
|
/**
|
||||||
* Toggle body classes that drive the monospace font + ligatures CSS tokens.
|
* Toggle body classes that drive the monospace font + ligatures CSS tokens.
|
||||||
* Single source of truth for the live preview/editor font behaviour.
|
* Single source of truth for the live preview/editor font behaviour.
|
||||||
|
* Also pushes the settings into the renderer-wide cache so PrintPreview can read them.
|
||||||
* @param {{monospaceFont?: string, monospaceLigatures?: boolean} | null | undefined} settings
|
* @param {{monospaceFont?: string, monospaceLigatures?: boolean} | null | undefined} settings
|
||||||
*/
|
*/
|
||||||
function applyMonospaceClasses(settings) {
|
function applyMonospaceClasses(settings) {
|
||||||
const s = settings || {};
|
const s = settings || {};
|
||||||
|
// Cache for downstream consumers (PrintPreview, future settings UI, etc.)
|
||||||
|
if (typeof window !== 'undefined') {
|
||||||
|
window.__monospaceSettings = {
|
||||||
|
monospaceFont: s.monospaceFont || 'jetbrains-mono',
|
||||||
|
monospaceLigatures: s.monospaceLigatures === true,
|
||||||
|
};
|
||||||
|
if (window.__printPreview && typeof window.__printPreview.setMonospaceSettings === 'function') {
|
||||||
|
window.__printPreview.setMonospaceSettings(window.__monospaceSettings);
|
||||||
|
}
|
||||||
|
}
|
||||||
const body = document.body;
|
const body = document.body;
|
||||||
if (!body) return;
|
if (!body) return;
|
||||||
const isFira = s.monospaceFont === 'fira-code';
|
const isFira = s.monospaceFont === 'fira-code';
|
||||||
@@ -1951,7 +1962,10 @@ document.addEventListener('DOMContentLoaded', async () => {
|
|||||||
|
|
||||||
// Initialize print preview
|
// Initialize print preview
|
||||||
const PrintPreview = getPrintPreview();
|
const PrintPreview = getPrintPreview();
|
||||||
const printPreview = new PrintPreview();
|
const printPreview = new PrintPreview(
|
||||||
|
window.__monospaceSettings || { monospaceFont: 'jetbrains-mono', monospaceLigatures: false }
|
||||||
|
);
|
||||||
|
window.__printPreview = printPreview;
|
||||||
|
|
||||||
// Register commands
|
// Register commands
|
||||||
commandPalette.register('New File', 'Ctrl+N', () => tabManager.createNewTab());
|
commandPalette.register('New File', 'Ctrl+N', () => tabManager.createNewTab());
|
||||||
@@ -2270,7 +2284,9 @@ function openPrintPreviewDialog() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const PrintPreviewClass = getPrintPreview();
|
const PrintPreviewClass = getPrintPreview();
|
||||||
const printPreviewInstance = new PrintPreviewClass();
|
const printPreviewInstance = new PrintPreviewClass(
|
||||||
|
window.__monospaceSettings || { monospaceFont: 'jetbrains-mono', monospaceLigatures: false }
|
||||||
|
);
|
||||||
printPreviewInstance.open(previewContent.innerHTML);
|
printPreviewInstance.open(previewContent.innerHTML);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user