feat(appliedFontsStore): incorporate implemented font weight logic
This commit is contained in:
@@ -20,6 +20,10 @@ interface Props {
|
|||||||
* Font id to load
|
* Font id to load
|
||||||
*/
|
*/
|
||||||
id: string;
|
id: string;
|
||||||
|
/**
|
||||||
|
* Font weight
|
||||||
|
*/
|
||||||
|
weight?: number;
|
||||||
/**
|
/**
|
||||||
* Additional classes
|
* Additional classes
|
||||||
*/
|
*/
|
||||||
@@ -30,7 +34,7 @@ interface Props {
|
|||||||
children?: Snippet;
|
children?: Snippet;
|
||||||
}
|
}
|
||||||
|
|
||||||
let { name, id, className, children }: Props = $props();
|
let { name, id, weight = 400, className, children }: Props = $props();
|
||||||
let element: Element;
|
let element: Element;
|
||||||
|
|
||||||
// Track if the user has actually scrolled this into view
|
// Track if the user has actually scrolled this into view
|
||||||
@@ -40,7 +44,7 @@ $effect(() => {
|
|||||||
const observer = new IntersectionObserver(entries => {
|
const observer = new IntersectionObserver(entries => {
|
||||||
if (entries[0].isIntersecting) {
|
if (entries[0].isIntersecting) {
|
||||||
hasEnteredViewport = true;
|
hasEnteredViewport = true;
|
||||||
appliedFontsManager.touch([id]);
|
appliedFontsManager.touch([{ slug: id, weight }]);
|
||||||
|
|
||||||
// Once it has entered, we can stop observing to save CPU
|
// Once it has entered, we can stop observing to save CPU
|
||||||
observer.unobserve(element);
|
observer.unobserve(element);
|
||||||
@@ -50,7 +54,7 @@ $effect(() => {
|
|||||||
return () => observer.disconnect();
|
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)
|
// The "Show" condition: Element is in view AND (Font is ready OR it errored out)
|
||||||
const shouldReveal = $derived(hasEnteredViewport && (status === 'loaded' || status === 'error'));
|
const shouldReveal = $derived(hasEnteredViewport && (status === 'loaded' || status === 'error'));
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { appliedFontsManager } from '$entities/Font';
|
import { appliedFontsManager } from '$entities/Font';
|
||||||
|
import { controlManager } from '$features/SetupFont';
|
||||||
import { Input } from '$shared/shadcn/ui/input';
|
import { Input } from '$shared/shadcn/ui/input';
|
||||||
import { ComparisonSlider } from '$shared/ui';
|
import { ComparisonSlider } from '$shared/ui';
|
||||||
import { displayedFontsStore } from '../../model';
|
import { displayedFontsStore } from '../../model';
|
||||||
@@ -10,7 +11,7 @@ const [fontA, fontB] = $derived(displayedFontsStore.selectedPair);
|
|||||||
const hasAnyPairs = $derived(displayedFontsStore.fonts.length > 0);
|
const hasAnyPairs = $derived(displayedFontsStore.fonts.length > 0);
|
||||||
|
|
||||||
$effect(() => {
|
$effect(() => {
|
||||||
appliedFontsManager.touch(displayedFontsStore.fonts.map(font => font.id));
|
appliedFontsManager.touch(displayedFontsStore.fonts.map(font => ({ slug: font.id, weight })));
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@@ -22,7 +23,13 @@ $effect(() => {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{#if fontA && fontB}
|
{#if fontA && fontB}
|
||||||
<ComparisonSlider fontA={fontA} fontB={fontB} text={displayedText} />
|
<ComparisonSlider
|
||||||
|
fontA={fontA}
|
||||||
|
fontB={fontB}
|
||||||
|
text={displayedText}
|
||||||
|
weight={weight}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import {
|
|||||||
FontApplicator,
|
FontApplicator,
|
||||||
type UnifiedFont,
|
type UnifiedFont,
|
||||||
} from '$entities/Font';
|
} from '$entities/Font';
|
||||||
|
import { controlManager } from '$features/SetupFont';
|
||||||
import { ContentEditable } from '$shared/ui';
|
import { ContentEditable } from '$shared/ui';
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
@@ -31,6 +32,8 @@ let {
|
|||||||
text = $bindable(),
|
text = $bindable(),
|
||||||
...restProps
|
...restProps
|
||||||
}: Props = $props();
|
}: Props = $props();
|
||||||
|
|
||||||
|
const weight = $derived(controlManager.weight ?? 400);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
@@ -39,6 +42,7 @@ let {
|
|||||||
bg-white p-6 border border-slate-200
|
bg-white p-6 border border-slate-200
|
||||||
shadow-sm dark:border-slate-800 dark:bg-slate-950
|
shadow-sm dark:border-slate-800 dark:bg-slate-950
|
||||||
"
|
"
|
||||||
|
style:font-weight={weight}
|
||||||
>
|
>
|
||||||
<FontApplicator id={font.id} name={font.name}>
|
<FontApplicator id={font.id} name={font.name}>
|
||||||
<ContentEditable bind:text={text} {...restProps} />
|
<ContentEditable bind:text={text} {...restProps} />
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ export function createCharacterComparison(
|
|||||||
text: () => string,
|
text: () => string,
|
||||||
fontA: () => { name: string; id: string },
|
fontA: () => { name: string; id: string },
|
||||||
fontB: () => { name: string; id: string },
|
fontB: () => { name: string; id: string },
|
||||||
|
weight: () => number,
|
||||||
) {
|
) {
|
||||||
let lines = $state<LineData[]>([]);
|
let lines = $state<LineData[]>([]);
|
||||||
let containerWidth = $state(0);
|
let containerWidth = $state(0);
|
||||||
@@ -29,14 +30,16 @@ export function createCharacterComparison(
|
|||||||
* @param text - Text string to measure
|
* @param text - Text string to measure
|
||||||
* @param fontFamily - Font family name
|
* @param fontFamily - Font family name
|
||||||
* @param fontSize - Font size in pixels
|
* @param fontSize - Font size in pixels
|
||||||
|
* @param fontWeight - Font weight
|
||||||
*/
|
*/
|
||||||
function measureText(
|
function measureText(
|
||||||
ctx: CanvasRenderingContext2D,
|
ctx: CanvasRenderingContext2D,
|
||||||
text: string,
|
text: string,
|
||||||
fontFamily: string,
|
fontFamily: string,
|
||||||
fontSize: number,
|
fontSize: number,
|
||||||
|
fontWeight: number,
|
||||||
): number {
|
): number {
|
||||||
ctx.font = `bold ${fontSize}px ${fontFamily}`;
|
ctx.font = `${fontWeight} ${fontSize}px ${fontFamily}`;
|
||||||
return ctx.measureText(text).width;
|
return ctx.measureText(text).width;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -62,6 +65,7 @@ export function createCharacterComparison(
|
|||||||
* @param container - The container element to measure width from
|
* @param container - The container element to measure width from
|
||||||
* @param measureCanvas - The canvas element used for text measurement
|
* @param measureCanvas - The canvas element used for text measurement
|
||||||
*/
|
*/
|
||||||
|
|
||||||
function breakIntoLines(
|
function breakIntoLines(
|
||||||
container: HTMLElement | undefined,
|
container: HTMLElement | undefined,
|
||||||
measureCanvas: HTMLCanvasElement | undefined,
|
measureCanvas: HTMLCanvasElement | undefined,
|
||||||
@@ -70,15 +74,14 @@ export function createCharacterComparison(
|
|||||||
|
|
||||||
const rect = container.getBoundingClientRect();
|
const rect = container.getBoundingClientRect();
|
||||||
containerWidth = rect.width;
|
containerWidth = rect.width;
|
||||||
|
|
||||||
// Padding considerations - matches the container padding
|
// Padding considerations - matches the container padding
|
||||||
const padding = window.innerWidth < 640 ? 48 : 96;
|
const padding = window.innerWidth < 640 ? 48 : 96;
|
||||||
const availableWidth = rect.width - padding;
|
const availableWidth = rect.width - padding;
|
||||||
|
|
||||||
const ctx = measureCanvas.getContext('2d');
|
const ctx = measureCanvas.getContext('2d');
|
||||||
if (!ctx) return;
|
if (!ctx) return;
|
||||||
|
|
||||||
const fontSize = getFontSize();
|
const fontSize = getFontSize();
|
||||||
|
const currentWeight = weight(); // Get current weight
|
||||||
const words = text().split(' ');
|
const words = text().split(' ');
|
||||||
const newLines: LineData[] = [];
|
const newLines: LineData[] = [];
|
||||||
let currentLineWords: string[] = [];
|
let currentLineWords: string[] = [];
|
||||||
@@ -86,9 +89,9 @@ export function createCharacterComparison(
|
|||||||
function pushLine(words: string[]) {
|
function pushLine(words: string[]) {
|
||||||
if (words.length === 0) return;
|
if (words.length === 0) return;
|
||||||
const lineText = words.join(' ');
|
const lineText = words.join(' ');
|
||||||
// Measure width to ensure we know exactly how wide this line renders
|
// Measure both fonts at the CURRENT weight
|
||||||
const widthA = measureText(ctx!, lineText, fontA().name, fontSize);
|
const widthA = measureText(ctx!, lineText, fontA().name, fontSize, currentWeight);
|
||||||
const widthB = measureText(ctx!, lineText, fontB().name, fontSize);
|
const widthB = measureText(ctx!, lineText, fontB().name, fontSize, currentWeight);
|
||||||
const maxWidth = Math.max(widthA, widthB);
|
const maxWidth = Math.max(widthA, widthB);
|
||||||
newLines.push({ text: lineText, width: maxWidth });
|
newLines.push({ text: lineText, width: maxWidth });
|
||||||
}
|
}
|
||||||
@@ -97,10 +100,9 @@ export function createCharacterComparison(
|
|||||||
const testLine = currentLineWords.length > 0
|
const testLine = currentLineWords.length > 0
|
||||||
? currentLineWords.join(' ') + ' ' + word
|
? currentLineWords.join(' ') + ' ' + word
|
||||||
: word;
|
: word;
|
||||||
|
|
||||||
// Measure with both fonts and use the wider one to prevent layout shifts
|
// Measure with both fonts and use the wider one to prevent layout shifts
|
||||||
const widthA = measureText(ctx, testLine, fontA().name, fontSize);
|
const widthA = measureText(ctx, testLine, fontA().name, fontSize, currentWeight);
|
||||||
const widthB = measureText(ctx, testLine, fontB().name, fontSize);
|
const widthB = measureText(ctx, testLine, fontB().name, fontSize, currentWeight);
|
||||||
const maxWidth = Math.max(widthA, widthB);
|
const maxWidth = Math.max(widthA, widthB);
|
||||||
|
|
||||||
if (maxWidth > availableWidth && currentLineWords.length > 0) {
|
if (maxWidth > availableWidth && currentLineWords.length > 0) {
|
||||||
@@ -111,10 +113,7 @@ export function createCharacterComparison(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (currentLineWords.length > 0) {
|
if (currentLineWords.length > 0) pushLine(currentLineWords);
|
||||||
pushLine(currentLineWords);
|
|
||||||
}
|
|
||||||
|
|
||||||
lines = newLines;
|
lines = newLines;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user