Compare commits

..

3 Commits

Author SHA1 Message Date
f072c5b270 Merge pull request 'fix/initial-fonts-loading' (#35) from fix/initial-fonts-loading into main
All checks were successful
Workflow / build (push) Successful in 46s
Workflow / publish (push) Successful in 45s
Reviewed-on: #35
2026-04-15 08:37:40 +00:00
Ilia Mashkov
bfa99cde20 fix(comparisonStore): add missing batch request and effect for initial font loading
All checks were successful
Workflow / build (pull_request) Successful in 3m8s
Workflow / publish (pull_request) Has been skipped
2026-04-15 11:35:37 +03:00
Ilia Mashkov
75b62265be fix: add missing export 2026-04-15 09:13:22 +03:00
3 changed files with 65 additions and 8 deletions

View File

@@ -1,3 +1,4 @@
export * from './api';
export * from './lib';
export * from './model';
export * from './ui';

View File

@@ -14,15 +14,19 @@
*/
import {
type FontLoadRequestConfig,
type UnifiedFont,
appliedFontsManager,
fetchFontsByIds,
fontStore,
getFontUrl,
} from '$entities/Font';
import {
DEFAULT_TYPOGRAPHY_CONTROLS_DATA,
createTypographyControlManager,
} from '$features/SetupFont';
import { createPersistentStore } from '$shared/lib';
import { untrack } from 'svelte';
/**
* Storage schema for comparison state
@@ -70,8 +74,37 @@ export class ComparisonStore {
constructor() {
this.restoreFromStorage();
// Reactively set defaults if we aren't restoring and have no selection
// Reactively handle font loading and default selection
$effect.root(() => {
// Effect 1: Trigger font loading whenever selection or weight changes
$effect(() => {
const fa = this.#fontA;
const fb = this.#fontB;
const weight = this.#typography.weight;
if (!fa || !fb) return;
const configs: FontLoadRequestConfig[] = [];
[fa, fb].forEach(f => {
const url = getFontUrl(f, weight);
if (url) {
configs.push({
id: f.id,
name: f.name,
weight,
url,
isVariable: f.features?.isVariable,
});
}
});
if (configs.length > 0) {
appliedFontsManager.touch(configs);
this.#checkFontsLoaded();
}
});
// Effect 2: Set defaults if we aren't restoring and have no selection
$effect(() => {
// Wait until we are done checking storage
if (this.#isRestoring) {
@@ -80,24 +113,41 @@ export class ComparisonStore {
// If we already have a selection, do nothing
if (this.#fontA && this.#fontB) {
this.#checkFontsLoaded();
return;
}
// Check if fonts are available to set as defaults
const fonts = fontStore.fonts;
if (fonts.length >= 2) {
// Only set if we really have nothing (fallback)
if (!this.#fontA) this.#fontA = fonts[0];
if (!this.#fontB) this.#fontB = fonts[fonts.length - 1];
// Sync defaults to storage so they persist if the user leaves
this.updateStorage();
// We need full objects with all URLs, so we trigger a batch fetch
// This is the "batch request" seen on initial load when storage is empty
untrack(() => {
this.restoreDefaults([fonts[0].id, fonts[fonts.length - 1].id]);
});
}
});
});
}
/**
* Set default fonts by fetching full objects from the API
*/
private async restoreDefaults(ids: string[]) {
this.#isRestoring = true;
try {
const fullFonts = await fetchFontsByIds(ids);
if (fullFonts.length >= 2) {
this.#fontA = fullFonts[0];
this.#fontB = fullFonts[1];
this.updateStorage();
}
} catch (error) {
console.warn('[ComparisonStore] Failed to set defaults:', error);
} finally {
this.#isRestoring = false;
}
}
/**
* Checks if fonts are actually loaded in the browser at current weight
*

View File

@@ -26,6 +26,12 @@ import {
vi.mock('$entities/Font', () => ({
fetchFontsByIds: vi.fn(),
fontStore: { fonts: [] },
appliedFontsManager: {
touch: vi.fn(),
getFontStatus: vi.fn(),
ready: vi.fn(() => Promise.resolve()),
},
getFontUrl: vi.fn(() => 'http://example.com/font.woff2'),
}));
vi.mock('$features/SetupFont', () => ({