feat(settings): manage shared interface and editor fonts

This commit is contained in:
eezd committed 2026-10-24 20:14:48 +08:00
1 parent 1d5637a5eb
commit 1882312435
19 files changed
+849 -16

No files matched your search

+11 -6
View File
@@ -12,26 +12,31 @@ export const CODE_FONTS = {
system: { label: '系统等宽字体', css: 'ui-monospace, monospace' },
}
export const UI_FONT_SIZE = { min: 14, max: 20, default: 14 }
export const DISPLAY_DEFAULTS = { uiFontSize: UI_FONT_SIZE.default, fontSize: 16, contentWidth: 760, textFont: 'maple' as keyof typeof TEXT_FONTS, codeFont: 'maple' as keyof typeof CODE_FONTS, lineHeight: 1.75, paragraphSpacing: 16, glassOpacity: .75 }
export const FONT_PRESETS: Record<string, { label: string; css: string }> = { ...TEXT_FONTS, jetbrains: CODE_FONTS.jetbrains }
export const DISPLAY_DEFAULTS = { uiFont: 'maple', uiFontSize: UI_FONT_SIZE.default, fontSize: 16, contentWidth: 760, textFont: 'maple', codeFont: 'maple', lineHeight: 1.75, paragraphSpacing: 16, glassOpacity: .75 }
export type DisplaySettings = typeof DISPLAY_DEFAULTS
export function sanitizeDisplaySettings(raw: Record<string, unknown>): DisplaySettings {
export function sanitizeDisplaySettings(raw: Record<string, unknown>, customIDs: string[] = [], hiddenFonts: string[] = []): DisplaySettings {
const ranged = (key: 'lineHeight' | 'paragraphSpacing' | 'glassOpacity', min: number, max: number) => typeof raw[key] === 'number' && Number.isFinite(raw[key]) && raw[key] >= min && raw[key] <= max ? raw[key] : DISPLAY_DEFAULTS[key]
const font = (value: unknown) => typeof value === 'string' && !hiddenFonts.includes(value) && (Object.hasOwn(FONT_PRESETS, value) || customIDs.includes(value)) ? value : 'maple'
return {
uiFont: font(raw.uiFont),
uiFontSize: typeof raw.uiFontSize === 'number' && Number.isInteger(raw.uiFontSize) && raw.uiFontSize >= UI_FONT_SIZE.min && raw.uiFontSize <= UI_FONT_SIZE.max ? raw.uiFontSize : UI_FONT_SIZE.default,
fontSize: typeof raw.fontSize === 'number' && Number.isFinite(raw.fontSize) && raw.fontSize > 0 ? raw.fontSize : 16,
contentWidth: typeof raw.contentWidth === 'number' && [0, 680, 760, 960].includes(raw.contentWidth) ? raw.contentWidth : 760,
textFont: raw.textFont === 'sans' || raw.textFont === 'serif' || raw.textFont === 'system' ? raw.textFont : 'maple',
codeFont: raw.codeFont === 'jetbrains' || raw.codeFont === 'system' ? raw.codeFont : 'maple',
textFont: font(raw.textFont),
codeFont: font(raw.codeFont),
lineHeight: ranged('lineHeight', 1.2, 2.5), paragraphSpacing: ranged('paragraphSpacing', 0, 40), glassOpacity: ranged('glassOpacity', .4, 1),
}
}
export function applyDisplaySettings(settings: DisplaySettings) {
const root = document.documentElement.style
const css = (id: string, code = false) => id === 'system' && code ? CODE_FONTS.system.css : FONT_PRESETS[id]?.css ?? `'${id}', ${maple.css}`
root.setProperty('--rm-font-text', css(settings.uiFont))
root.setProperty('--rm-ui-font-size', settings.uiFontSize + 'px')
root.setProperty('--rm-font-size', settings.fontSize + 'px')
root.setProperty('--rm-content-width', settings.contentWidth ? settings.contentWidth + 'px' : 'none')
root.setProperty('--rm-font-editor', TEXT_FONTS[settings.textFont].css)
root.setProperty('--rm-font-mono', CODE_FONTS[settings.codeFont].css)
root.setProperty('--rm-font-editor', css(settings.textFont))
root.setProperty('--rm-font-mono', css(settings.codeFont, true))
root.setProperty('--rm-line-height', String(settings.lineHeight))
root.setProperty('--rm-paragraph-spacing', settings.paragraphSpacing + 'px')
root.setProperty('--rm-glass-opacity', String(settings.glassOpacity))