From b01293aa2057c8ce571dbbd8dcdd0f4fc9ed1482 Mon Sep 17 00:00:00 2001 From: Gigi Date: Mon, 6 Oct 2025 20:04:11 +0100 Subject: [PATCH] fix: ensure fonts are fully loaded before applying styles - Convert loadFont to async function that returns a Promise - Use Font Loading API to wait for fonts to be actually ready - Add comprehensive logging for font loading stages - Wait for font loading in useSettings before applying CSS variables - Update Settings component to handle async font loading - Prevents FOUT (Flash of Unstyled Text) by ensuring fonts are ready - Fixes timing issue where custom fonts weren't being applied consistently This ensures custom fonts are fully loaded and ready before being applied, eliminating the race condition where content would render with system fonts before custom fonts were available. --- src/components/Settings.tsx | 6 ++- src/hooks/useSettings.ts | 34 +++++++++++----- src/utils/fontLoader.ts | 78 ++++++++++++++++++++++++++++++++----- 3 files changed, 97 insertions(+), 21 deletions(-) diff --git a/src/components/Settings.tsx b/src/components/Settings.tsx index 308860a9..448340da 100644 --- a/src/components/Settings.tsx +++ b/src/components/Settings.tsx @@ -39,13 +39,15 @@ const Settings: React.FC = ({ settings, onSave, onClose }) => { useEffect(() => { // Preload all fonts for the dropdown const fonts = ['inter', 'lora', 'merriweather', 'open-sans', 'roboto', 'source-serif-4', 'crimson-text', 'libre-baskerville', 'pt-serif'] - fonts.forEach(font => loadFont(font)) + fonts.forEach(font => { + loadFont(font).catch(err => console.warn('Failed to preload font:', font, err)) + }) }, []) useEffect(() => { // Load font for preview when it changes const fontToLoad = localSettings.readingFont || 'source-serif-4' - loadFont(fontToLoad) + loadFont(fontToLoad).catch(err => console.warn('Failed to load preview font:', fontToLoad, err)) }, [localSettings.readingFont]) // Auto-save settings whenever they change (except on initial mount) diff --git a/src/hooks/useSettings.ts b/src/hooks/useSettings.ts index 06143808..4527c60e 100644 --- a/src/hooks/useSettings.ts +++ b/src/hooks/useSettings.ts @@ -43,16 +43,32 @@ export function useSettings({ relayPool, eventStore, pubkey, accountManager }: U // Apply settings to document useEffect(() => { - const root = document.documentElement.style - const fontKey = settings.readingFont || 'system' - if (fontKey !== 'system') loadFont(fontKey) - root.setProperty('--reading-font', getFontFamily(fontKey)) - root.setProperty('--reading-font-size', `${settings.fontSize || 18}px`) + const applyStyles = async () => { + const root = document.documentElement.style + const fontKey = settings.readingFont || 'system' + + console.log('🎨 Applying settings styles:', { fontKey, fontSize: settings.fontSize }) + + // Load font first and wait for it to be ready + if (fontKey !== 'system') { + console.log('⏳ Waiting for font to load...') + await loadFont(fontKey) + console.log('✅ Font loaded, applying styles') + } + + // Apply font settings after font is loaded + root.setProperty('--reading-font', getFontFamily(fontKey)) + root.setProperty('--reading-font-size', `${settings.fontSize || 18}px`) + + // Set highlight colors for three levels + root.setProperty('--highlight-color-mine', settings.highlightColorMine || '#ffff00') + root.setProperty('--highlight-color-friends', settings.highlightColorFriends || '#f97316') + root.setProperty('--highlight-color-nostrverse', settings.highlightColorNostrverse || '#9333ea') + + console.log('✅ All styles applied') + } - // Set highlight colors for three levels - root.setProperty('--highlight-color-mine', settings.highlightColorMine || '#ffff00') - root.setProperty('--highlight-color-friends', settings.highlightColorFriends || '#f97316') - root.setProperty('--highlight-color-nostrverse', settings.highlightColorNostrverse || '#9333ea') + applyStyles() }, [settings]) const saveSettingsWithToast = useCallback(async (newSettings: UserSettings) => { diff --git a/src/utils/fontLoader.ts b/src/utils/fontLoader.ts index d2bdb541..b78af185 100644 --- a/src/utils/fontLoader.ts +++ b/src/utils/fontLoader.ts @@ -12,25 +12,83 @@ const FONT_FAMILIES: Record = { } const loadedFonts = new Set() +const loadingFonts = new Map>() -export function loadFont(fontKey: string) { - if (fontKey === 'system' || loadedFonts.has(fontKey)) { - return +export async function loadFont(fontKey: string): Promise { + if (fontKey === 'system') { + console.log('📝 Using system font') + return Promise.resolve() + } + + if (loadedFonts.has(fontKey)) { + console.log('✅ Font already loaded:', fontKey) + return Promise.resolve() + } + + // If font is currently loading, return the existing promise + if (loadingFonts.has(fontKey)) { + console.log('⏳ Font already loading:', fontKey) + return loadingFonts.get(fontKey)! } const fontFamily = FONT_FAMILIES[fontKey] if (!fontFamily) { console.warn(`Unknown font: ${fontKey}`) - return + return Promise.resolve() } - // Create a link element to load the font from Bunny Fonts - const link = document.createElement('link') - link.rel = 'stylesheet' - link.href = `https://fonts.bunny.net/css?family=${encodeURIComponent(fontFamily.toLowerCase().replace(/ /g, '-'))}:400,400i,700,700i` - document.head.appendChild(link) + console.log('🔤 Loading font:', fontFamily) - loadedFonts.add(fontKey) + // Create a promise for this font loading + const loadPromise = new Promise((resolve) => { + // Create a link element to load the font from Bunny Fonts + const link = document.createElement('link') + link.rel = 'stylesheet' + link.href = `https://fonts.bunny.net/css?family=${encodeURIComponent(fontFamily.toLowerCase().replace(/ /g, '-'))}:400,400i,700,700i` + + // Wait for the stylesheet to load + link.onload = () => { + console.log('📄 Stylesheet loaded for:', fontFamily) + + // Use Font Loading API to wait for the actual font to be ready + if ('fonts' in document) { + Promise.all([ + document.fonts.load(`400 16px "${fontFamily}"`), + document.fonts.load(`700 16px "${fontFamily}"`) + ]).then(() => { + console.log('✅ Font ready:', fontFamily) + loadedFonts.add(fontKey) + loadingFonts.delete(fontKey) + resolve() + }).catch((err) => { + console.warn('⚠️ Font loading failed:', fontFamily, err) + loadedFonts.add(fontKey) // Mark as loaded anyway to prevent retries + loadingFonts.delete(fontKey) + resolve() + }) + } else { + // Fallback: just wait a bit for older browsers + setTimeout(() => { + console.log('✅ Font assumed ready (no Font Loading API):', fontFamily) + loadedFonts.add(fontKey) + loadingFonts.delete(fontKey) + resolve() + }, 100) + } + } + + link.onerror = () => { + console.error('❌ Failed to load font stylesheet:', fontFamily) + loadedFonts.add(fontKey) // Mark as loaded to prevent retries + loadingFonts.delete(fontKey) + resolve() // Resolve anyway so we don't block + } + + document.head.appendChild(link) + }) + + loadingFonts.set(fontKey, loadPromise) + return loadPromise } export function getFontFamily(fontKey: string | undefined): string {