fixes/mobile-comparator #25

Merged
ilia merged 10 commits from fixes/mobile-comparator into main 2026-02-10 16:21:45 +00:00
Showing only changes of commit b43aa99f3e - Show all commits

View File

@@ -34,6 +34,7 @@ class ComparisonStore {
#fontB = $state<UnifiedFont | undefined>();
#sampleText = $state('The quick brown fox jumps over the lazy dog');
#isRestoring = $state(true);
#fontsReady = $state(false);
#typography = createTypographyControlManager(DEFAULT_TYPOGRAPHY_CONTROLS_DATA, 'glyphdiff:comparison:typography');
constructor() {
@@ -49,6 +50,7 @@ class ComparisonStore {
// If we already have a selection, do nothing
if (this.#fontA && this.#fontB) {
this.#checkFontsLoaded();
return;
}
@@ -66,6 +68,48 @@ class ComparisonStore {
});
}
/**
* Checks if fonts are actually loaded in the browser at current weight.
* Uses CSS Font Loading API to prevent FOUT.
*/
async #checkFontsLoaded() {
if (!('fonts' in document)) {
this.#fontsReady = true;
return;
}
this.#fontsReady = false;
const weight = this.#typography.weight;
const size = this.#typography.renderedSize;
const fontAName = this.#fontA?.name;
const fontBName = this.#fontB?.name;
if (!fontAName || !fontBName) return;
try {
// Step 1: Load fonts into memory
await Promise.all([
document.fonts.load(`${weight} ${size}px "${fontAName}"`),
document.fonts.load(`${weight} ${size}px "${fontBName}"`),
]);
// Step 2: Wait for browser to be ready to render
await document.fonts.ready;
// Step 3: Force a layout/paint cycle (critical!)
await new Promise(resolve => {
requestAnimationFrame(() => {
requestAnimationFrame(resolve); // Double rAF ensures paint completes
});
});
this.#fontsReady = true;
} catch (error) {
console.warn('[ComparisonStore] Font loading failed:', error);
setTimeout(() => this.#fontsReady = true, 1000);
}
}
/**
* Restore state from persistent storage
*/
@@ -141,13 +185,12 @@ class ComparisonStore {
* Check if both fonts are selected
*/
get isReady() {
return !!this.#fontA && !!this.#fontB;
return !!this.#fontA && !!this.#fontB && this.#fontsReady;
}
get isLoading() {
return this.#isRestoring;
return this.#isRestoring || !this.#fontsReady;
}
/**
* Public initializer (optional, as constructor starts it)
* Kept for compatibility if manual re-init is needed