mirror of
https://github.com/amitwh/markdown-converter.git
synced 2026-08-02 18:10:18 +05:30
feat(renderer): body-class monospace toggle + CSS tokens
- useMonospaceClasses hook calls electronAPI.monospace.getSettings()
and toggles body.mono-{jetbrains-mono,fira-code} and
body.mono-ligatures-{on,off} classes
- Add --font-mono-active and --font-mono-feature tokens in globals.css
- Apply to code/pre/kbd/samp so all code rendering picks up the active
monospace font + ligature settings
This commit is contained in:
@@ -9,6 +9,7 @@ import { UpdateBanner } from './components/UpdateBanner';
|
|||||||
import { FirstRunWizard } from './components/FirstRunWizard';
|
import { FirstRunWizard } from './components/FirstRunWizard';
|
||||||
import { useWelcomeTrigger } from './hooks/use-welcome-trigger';
|
import { useWelcomeTrigger } from './hooks/use-welcome-trigger';
|
||||||
import { useAutoUpdateCheck } from './hooks/useAutoUpdateCheck';
|
import { useAutoUpdateCheck } from './hooks/useAutoUpdateCheck';
|
||||||
|
import { useMonospaceClasses } from './hooks/use-monospace-classes';
|
||||||
|
|
||||||
import { useSettingsStore } from './stores/settings-store';
|
import { useSettingsStore } from './stores/settings-store';
|
||||||
import { ipc } from './lib/ipc';
|
import { ipc } from './lib/ipc';
|
||||||
@@ -35,6 +36,7 @@ function scopeCSS(cssText: string, scopeSelector: string) {
|
|||||||
function App() {
|
function App() {
|
||||||
useWelcomeTrigger();
|
useWelcomeTrigger();
|
||||||
useAutoUpdateCheck();
|
useAutoUpdateCheck();
|
||||||
|
useMonospaceClasses();
|
||||||
const [printOpen, setPrintOpen] = useState(false);
|
const [printOpen, setPrintOpen] = useState(false);
|
||||||
const customCssPath = useSettingsStore((s) => s.customCssPath);
|
const customCssPath = useSettingsStore((s) => s.customCssPath);
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,41 @@
|
|||||||
|
export interface MonospaceSettings {
|
||||||
|
monospaceFont: 'jetbrains-mono' | 'fira-code';
|
||||||
|
monospaceLigatures: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
const DEFAULTS: MonospaceSettings = {
|
||||||
|
monospaceFont: 'jetbrains-mono',
|
||||||
|
monospaceLigatures: false,
|
||||||
|
};
|
||||||
|
|
||||||
|
const FAMILY_CLASSES = ['mono-jetbrains-mono', 'mono-fira-code'];
|
||||||
|
const LIG_CLASSES = ['mono-ligatures-on', 'mono-ligatures-off'];
|
||||||
|
|
||||||
|
function stripMonospaceClasses(): void {
|
||||||
|
for (const c of [...FAMILY_CLASSES, ...LIG_CLASSES]) {
|
||||||
|
document.body.classList.remove(c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function applyMonospaceClasses(input: Partial<MonospaceSettings> | null | undefined): MonospaceSettings {
|
||||||
|
const safe: MonospaceSettings = {
|
||||||
|
monospaceFont:
|
||||||
|
input && input.monospaceFont === 'fira-code' ? 'fira-code' : DEFAULTS.monospaceFont,
|
||||||
|
monospaceLigatures: !!(input && input.monospaceLigatures === true),
|
||||||
|
};
|
||||||
|
stripMonospaceClasses();
|
||||||
|
document.body.classList.add(`mono-${safe.monospaceFont}`);
|
||||||
|
document.body.classList.add(`mono-ligatures-${safe.monospaceLigatures ? 'on' : 'off'}`);
|
||||||
|
return safe;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function useMonospaceClasses(): void {
|
||||||
|
if (typeof window === 'undefined') return;
|
||||||
|
const api = (window as unknown as { electronAPI?: { monospace?: { getSettings?: () => Promise<MonospaceSettings> } } })
|
||||||
|
.electronAPI;
|
||||||
|
if (!api || !api.monospace || typeof api.monospace.getSettings !== 'function') return;
|
||||||
|
api.monospace
|
||||||
|
.getSettings()
|
||||||
|
.then(applyMonospaceClasses)
|
||||||
|
.catch(() => applyMonospaceClasses(null));
|
||||||
|
}
|
||||||
@@ -96,3 +96,22 @@
|
|||||||
.cm-editor .cm-scroller {
|
.cm-editor .cm-scroller {
|
||||||
@apply font-mono text-sm;
|
@apply font-mono text-sm;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Monospace font + ligature tokens — driven by body.mono-* classes */
|
||||||
|
:root {
|
||||||
|
--font-mono-active: 'JetBrains Mono', 'SF Mono', Monaco, 'Courier New', monospace;
|
||||||
|
--font-mono-feature: 'liga' 0, 'calt' 0;
|
||||||
|
}
|
||||||
|
body.mono-fira-code {
|
||||||
|
--font-mono-active: 'Fira Code', 'JetBrains Mono', 'SF Mono', monospace;
|
||||||
|
}
|
||||||
|
body.mono-ligatures-on {
|
||||||
|
--font-mono-feature: 'liga' 1, 'calt' 1;
|
||||||
|
}
|
||||||
|
code,
|
||||||
|
pre,
|
||||||
|
kbd,
|
||||||
|
samp {
|
||||||
|
font-family: var(--font-mono-active);
|
||||||
|
font-feature-settings: var(--font-mono-feature);
|
||||||
|
}
|
||||||
|
|||||||
@@ -0,0 +1,37 @@
|
|||||||
|
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
|
||||||
|
import { applyMonospaceClasses } from "../../../src/renderer/hooks/use-monospace-classes";
|
||||||
|
|
||||||
|
describe('applyMonospaceClasses', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
document.body.className = '';
|
||||||
|
});
|
||||||
|
afterEach(() => {
|
||||||
|
document.body.className = '';
|
||||||
|
});
|
||||||
|
|
||||||
|
it('applies jetbrains-mono + ligatures-off for default settings', () => {
|
||||||
|
applyMonospaceClasses({ monospaceFont: 'jetbrains-mono', monospaceLigatures: false });
|
||||||
|
expect(document.body.classList.contains('mono-jetbrains-mono')).toBe(true);
|
||||||
|
expect(document.body.classList.contains('mono-ligatures-off')).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('applies fira-code + ligatures-on when enabled', () => {
|
||||||
|
applyMonospaceClasses({ monospaceFont: 'fira-code', monospaceLigatures: true });
|
||||||
|
expect(document.body.classList.contains('mono-fira-code')).toBe(true);
|
||||||
|
expect(document.body.classList.contains('mono-ligatures-on')).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('strips prior mono-* classes before applying new ones', () => {
|
||||||
|
document.body.classList.add('mono-jetbrains-mono', 'mono-ligatures-off');
|
||||||
|
applyMonospaceClasses({ monospaceFont: 'fira-code', monospaceLigatures: true });
|
||||||
|
expect(document.body.classList.contains('mono-jetbrains-mono')).toBe(false);
|
||||||
|
expect(document.body.classList.contains('mono-ligatures-off')).toBe(false);
|
||||||
|
expect(document.body.classList.contains('mono-fira-code')).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('falls back to defaults when given null', () => {
|
||||||
|
applyMonospaceClasses(null);
|
||||||
|
expect(document.body.classList.contains('mono-jetbrains-mono')).toBe(true);
|
||||||
|
expect(document.body.classList.contains('mono-ligatures-off')).toBe(true);
|
||||||
|
});
|
||||||
|
});
|
||||||
Reference in New Issue
Block a user