diff --git a/src/entities/Font/ui/FontApplicator/FontApplicator.svelte b/src/entities/Font/ui/FontApplicator/FontApplicator.svelte index 15dd0d9..f724e94 100644 --- a/src/entities/Font/ui/FontApplicator/FontApplicator.svelte +++ b/src/entities/Font/ui/FontApplicator/FontApplicator.svelte @@ -20,6 +20,10 @@ interface Props { * Font id to load */ id: string; + /** + * Font weight + */ + weight?: number; /** * Additional classes */ @@ -30,7 +34,7 @@ interface Props { children?: Snippet; } -let { name, id, className, children }: Props = $props(); +let { name, id, weight = 400, className, children }: Props = $props(); let element: Element; // Track if the user has actually scrolled this into view @@ -40,7 +44,7 @@ $effect(() => { const observer = new IntersectionObserver(entries => { if (entries[0].isIntersecting) { hasEnteredViewport = true; - appliedFontsManager.touch([id]); + appliedFontsManager.touch([{ slug: id, weight }]); // Once it has entered, we can stop observing to save CPU observer.unobserve(element); @@ -50,7 +54,7 @@ $effect(() => { return () => observer.disconnect(); }); -const status = $derived(appliedFontsManager.getFontStatus(id)); +const status = $derived(appliedFontsManager.getFontStatus(id, weight, false)); // The "Show" condition: Element is in view AND (Font is ready OR it errored out) const shouldReveal = $derived(hasEnteredViewport && (status === 'loaded' || status === 'error')); diff --git a/src/features/DisplayFont/ui/FontComparer/FontComparer.svelte b/src/features/DisplayFont/ui/FontComparer/FontComparer.svelte index 7a3238b..287f206 100644 --- a/src/features/DisplayFont/ui/FontComparer/FontComparer.svelte +++ b/src/features/DisplayFont/ui/FontComparer/FontComparer.svelte @@ -1,5 +1,6 @@ @@ -22,7 +23,13 @@ $effect(() => { {#if fontA && fontB} - + + {/if} {/if} diff --git a/src/features/DisplayFont/ui/FontSampler/FontSampler.svelte b/src/features/DisplayFont/ui/FontSampler/FontSampler.svelte index 872e11c..fa506f2 100644 --- a/src/features/DisplayFont/ui/FontSampler/FontSampler.svelte +++ b/src/features/DisplayFont/ui/FontSampler/FontSampler.svelte @@ -7,6 +7,7 @@ import { FontApplicator, type UnifiedFont, } from '$entities/Font'; +import { controlManager } from '$features/SetupFont'; import { ContentEditable } from '$shared/ui'; interface Props { @@ -31,6 +32,8 @@ let { text = $bindable(), ...restProps }: Props = $props(); + +const weight = $derived(controlManager.weight ?? 400);
diff --git a/src/shared/lib/helpers/createCharacterComparison/createCharacterComparison.svelte.ts b/src/shared/lib/helpers/createCharacterComparison/createCharacterComparison.svelte.ts index 6c2f458..6eca284 100644 --- a/src/shared/lib/helpers/createCharacterComparison/createCharacterComparison.svelte.ts +++ b/src/shared/lib/helpers/createCharacterComparison/createCharacterComparison.svelte.ts @@ -19,6 +19,7 @@ export function createCharacterComparison( text: () => string, fontA: () => { name: string; id: string }, fontB: () => { name: string; id: string }, + weight: () => number, ) { let lines = $state([]); let containerWidth = $state(0); @@ -29,14 +30,16 @@ export function createCharacterComparison( * @param text - Text string to measure * @param fontFamily - Font family name * @param fontSize - Font size in pixels + * @param fontWeight - Font weight */ function measureText( ctx: CanvasRenderingContext2D, text: string, fontFamily: string, fontSize: number, + fontWeight: number, ): number { - ctx.font = `bold ${fontSize}px ${fontFamily}`; + ctx.font = `${fontWeight} ${fontSize}px ${fontFamily}`; return ctx.measureText(text).width; } @@ -62,6 +65,7 @@ export function createCharacterComparison( * @param container - The container element to measure width from * @param measureCanvas - The canvas element used for text measurement */ + function breakIntoLines( container: HTMLElement | undefined, measureCanvas: HTMLCanvasElement | undefined, @@ -70,15 +74,14 @@ export function createCharacterComparison( const rect = container.getBoundingClientRect(); containerWidth = rect.width; - // Padding considerations - matches the container padding const padding = window.innerWidth < 640 ? 48 : 96; const availableWidth = rect.width - padding; - const ctx = measureCanvas.getContext('2d'); if (!ctx) return; const fontSize = getFontSize(); + const currentWeight = weight(); // Get current weight const words = text().split(' '); const newLines: LineData[] = []; let currentLineWords: string[] = []; @@ -86,9 +89,9 @@ export function createCharacterComparison( function pushLine(words: string[]) { if (words.length === 0) return; const lineText = words.join(' '); - // Measure width to ensure we know exactly how wide this line renders - const widthA = measureText(ctx!, lineText, fontA().name, fontSize); - const widthB = measureText(ctx!, lineText, fontB().name, fontSize); + // Measure both fonts at the CURRENT weight + const widthA = measureText(ctx!, lineText, fontA().name, fontSize, currentWeight); + const widthB = measureText(ctx!, lineText, fontB().name, fontSize, currentWeight); const maxWidth = Math.max(widthA, widthB); newLines.push({ text: lineText, width: maxWidth }); } @@ -97,10 +100,9 @@ export function createCharacterComparison( const testLine = currentLineWords.length > 0 ? currentLineWords.join(' ') + ' ' + word : word; - // Measure with both fonts and use the wider one to prevent layout shifts - const widthA = measureText(ctx, testLine, fontA().name, fontSize); - const widthB = measureText(ctx, testLine, fontB().name, fontSize); + const widthA = measureText(ctx, testLine, fontA().name, fontSize, currentWeight); + const widthB = measureText(ctx, testLine, fontB().name, fontSize, currentWeight); const maxWidth = Math.max(widthA, widthB); if (maxWidth > availableWidth && currentLineWords.length > 0) { @@ -111,10 +113,7 @@ export function createCharacterComparison( } } - if (currentLineWords.length > 0) { - pushLine(currentLineWords); - } - + if (currentLineWords.length > 0) pushLine(currentLineWords); lines = newLines; }