feat(rsvp): apply reader font face/family settings to the RSVP word (#4519) (#4537)

RSVP displayed the focal word in a hardcoded monospace font, ignoring the
reader's configured font. Resolve the reader's body font-family (serif or
sans-serif chain, per the "Default Font" setting, including the chosen
typeface, CJK font, and any user-imported custom font) and apply it to the
RSVP word display.

Custom and additional fonts are already mounted in the top document where
the overlay renders, so the resolved family resolves the same typeface. The
monospace fallback is kept only when no font setting is available.

Extracts the font-family list building from getFontStyles into a shared
buildFontFamilyLists helper and exposes getBaseFontFamily for top-level UI.

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Huang Xin
2026-06-12 01:24:46 +08:00
committed by GitHub
parent 6dc42222e0
commit cf41e7d50d
6 changed files with 149 additions and 13 deletions
+48 -9
View File
@@ -18,16 +18,18 @@ import { createFontCSS, CustomFont } from '@/styles/fonts';
import { getOSPlatform } from './misc';
import { SCROLL_WRAPPER_CLASS, SCROLL_WRAPPER_FIT_CLASS } from './scrollable';
const getFontStyles = (
/**
* Build the resolved CSS font-family lists (serif / sans-serif / monospace)
* from the user's font settings. Each value is a ready-to-use `font-family`
* string ending in the matching generic family. Shared by getFontStyles (which
* exposes them as CSS variables inside the reader iframe) and getBaseFontFamily
* (which applies the body font directly to top-level UI such as the RSVP overlay).
*/
const buildFontFamilyLists = (
serif: string,
sansSerif: string,
monospace: string,
defaultFont: string,
defaultCJKFont: string,
fontSize: number,
minFontSize: number,
fontWeight: number,
overrideFont: boolean,
) => {
const lastSerifFonts = ['Georgia', 'Times New Roman'];
const serifFonts = [
@@ -50,12 +52,49 @@ const getFontStyles = (
...FALLBACK_FONTS,
];
const monospaceFonts = [monospace, ...MONOSPACE_FONTS.filter((font) => font !== monospace)];
const quote = (fonts: string[]) => fonts.map((font) => `"${font}"`).join(', ');
return {
serif: `${quote(serifFonts)}, serif`,
sansSerif: `${quote(sansSerifFonts)}, sans-serif`,
monospace: `${quote(monospaceFonts)}, monospace`,
};
};
/**
* Resolve the body font-family string (serif or sans-serif chain, per the
* user's "Default Font" setting) for use outside the reader iframe — e.g. the
* RSVP overlay, which renders in the top document and can't read the iframe's
* --serif/--sans-serif CSS variables. Custom fonts are already mounted in the
* top document, so the returned chain resolves them by family name.
*/
export const getBaseFontFamily = (viewSettings: ViewSettings): string => {
const families = buildFontFamilyLists(
viewSettings.serifFont!,
viewSettings.sansSerifFont!,
viewSettings.monospaceFont!,
viewSettings.defaultCJKFont!,
);
return viewSettings.defaultFont!.toLowerCase() === 'serif' ? families.serif : families.sansSerif;
};
const getFontStyles = (
serif: string,
sansSerif: string,
monospace: string,
defaultFont: string,
defaultCJKFont: string,
fontSize: number,
minFontSize: number,
fontWeight: number,
overrideFont: boolean,
) => {
const families = buildFontFamilyLists(serif, sansSerif, monospace, defaultCJKFont);
const defaultFontFamily = defaultFont.toLowerCase() === 'serif' ? '--serif' : '--sans-serif';
const fontStyles = `
html {
--serif: ${serifFonts.map((font) => `"${font}"`).join(', ')}, serif;
--sans-serif: ${sansSerifFonts.map((font) => `"${font}"`).join(', ')}, sans-serif;
--monospace: ${monospaceFonts.map((font) => `"${font}"`).join(', ')}, monospace;
--serif: ${families.serif};
--sans-serif: ${families.sansSerif};
--monospace: ${families.monospace};
--font-size: ${fontSize}px;
--min-font-size: ${minFontSize}px;
--font-weight: ${fontWeight};