refactor: extract magic constants — wave 1 (UX, API, storage)

- Use existing MULTIPLIER_S/M/L from \$entities/Font in SliderArea instead
  of inlining the 0.5/0.75/1 literals (constants already existed but were
  duplicated at the call site).
- Centralize API base URL in \$shared/api/endpoints.ts (was duplicated
  between proxyFonts and FilterAndSortFonts filters api).
- Promote every 'glyphdiff:...' localStorage key to a named module-level
  STORAGE_KEY constant. Test files now import the source constant rather
  than redeclaring it (eliminates silent-typo divergence risk).
This commit is contained in:
Ilia Mashkov
2026-05-24 20:30:26 +03:00
parent f92577608a
commit e3b489f173
10 changed files with 55 additions and 16 deletions
+4 -2
View File
@@ -29,10 +29,12 @@ export function seedFontCache(fonts: UnifiedFont[]): void {
}); });
} }
import { API_ENDPOINTS } from '$shared/api/endpoints';
/** /**
* Proxy API base URL * Proxy API endpoint for font resources.
*/ */
const PROXY_API_URL = 'https://api.glyphdiff.com/api/v1/fonts' as const; const PROXY_API_URL = API_ENDPOINTS.fonts;
/** /**
* Proxy API parameters * Proxy API parameters
@@ -297,6 +297,16 @@ export class TypographySettingsStore {
} }
} }
/**
* Default factory storage key — used when a caller doesn't pass one.
*/
const DEFAULT_STORAGE_KEY = 'glyphdiff:typography';
/**
* Storage key used by the app-wide singleton (scoped to comparison view).
*/
const COMPARISON_STORAGE_KEY = 'glyphdiff:comparison:typography';
/** /**
* Creates a typography control manager * Creates a typography control manager
* *
@@ -306,7 +316,7 @@ export class TypographySettingsStore {
*/ */
export function createTypographySettingsStore( export function createTypographySettingsStore(
configs: ControlModel<ControlId>[], configs: ControlModel<ControlId>[],
storageId: string = 'glyphdiff:typography', storageId: string = DEFAULT_STORAGE_KEY,
) { ) {
const storage = createPersistentStore<TypographySettings>(storageId, { const storage = createPersistentStore<TypographySettings>(storageId, {
fontSize: DEFAULT_FONT_SIZE, fontSize: DEFAULT_FONT_SIZE,
@@ -322,5 +332,5 @@ export function createTypographySettingsStore(
*/ */
export const typographySettingsStore = createTypographySettingsStore( export const typographySettingsStore = createTypographySettingsStore(
DEFAULT_TYPOGRAPHY_CONTROLS_DATA, DEFAULT_TYPOGRAPHY_CONTROLS_DATA,
'glyphdiff:comparison:typography', COMPARISON_STORAGE_KEY,
); );
@@ -30,6 +30,8 @@
import { createPersistentStore } from '$shared/lib'; import { createPersistentStore } from '$shared/lib';
export const STORAGE_KEY = 'glyphdiff:theme';
type Theme = 'light' | 'dark'; type Theme = 'light' | 'dark';
type ThemeSource = 'system' | 'user'; type ThemeSource = 'system' | 'user';
@@ -56,7 +58,7 @@ class ThemeManager {
/** /**
* Persistent storage for user's theme preference * Persistent storage for user's theme preference
*/ */
#store = createPersistentStore<Theme | null>('glyphdiff:theme', null); #store = createPersistentStore<Theme | null>(STORAGE_KEY, null);
/** /**
* Bound handler for system theme change events * Bound handler for system theme change events
*/ */
@@ -40,8 +40,7 @@ import { ThemeManager } from './ThemeManager.svelte';
* - MediaQueryList listener management * - MediaQueryList listener management
*/ */
// Storage key used by ThemeManager import { STORAGE_KEY } from './ThemeManager.svelte';
const STORAGE_KEY = 'glyphdiff:theme';
// Helper type for MediaQueryList event handler // Helper type for MediaQueryList event handler
type MediaQueryListCallback = (this: MediaQueryList, ev: MediaQueryListEvent) => void; type MediaQueryListCallback = (this: MediaQueryList, ev: MediaQueryListEvent) => void;
@@ -8,8 +8,9 @@
*/ */
import { api } from '$shared/api/api'; import { api } from '$shared/api/api';
import { API_ENDPOINTS } from '$shared/api/endpoints';
const PROXY_API_URL = 'https://api.glyphdiff.com/api/v1/filters' as const; const PROXY_API_URL = API_ENDPOINTS.filters;
/** /**
* Filter metadata type from backend * Filter metadata type from backend
+19
View File
@@ -0,0 +1,19 @@
/**
* Centralized backend endpoint definitions.
*
* One source of truth for the proxy API base URL — individual resource
* modules (proxyFonts, filters) append their own paths.
*/
export const API_BASE_URL = 'https://api.glyphdiff.com/api/v1' as const;
export const API_ENDPOINTS = {
/**
* Font catalog + per-id detail + batch lookup
*/
fonts: `${API_BASE_URL}/fonts`,
/**
* Filter metadata (providers, categories, subsets)
*/
filters: `${API_BASE_URL}/filters`,
} as const;
@@ -42,8 +42,10 @@ interface ComparisonState {
export type Side = 'A' | 'B'; export type Side = 'A' | 'B';
const STORAGE_KEY = 'glyphdiff:comparison';
// Persistent storage for selected comparison fonts // Persistent storage for selected comparison fonts
const storage = createPersistentStore<ComparisonState>('glyphdiff:comparison', { const storage = createPersistentStore<ComparisonState>(STORAGE_KEY, {
fontAId: null, fontAId: null,
fontBId: null, fontBId: null,
}); });
@@ -8,6 +8,11 @@
- Performance optimized using offscreen canvas for measurements and transform-based animations. - Performance optimized using offscreen canvas for measurements and transform-based animations.
--> -->
<script lang="ts"> <script lang="ts">
import {
MULTIPLIER_L,
MULTIPLIER_M,
MULTIPLIER_S,
} from '$entities/Font';
import { TypographyMenu } from '$features/AdjustTypography'; import { TypographyMenu } from '$features/AdjustTypography';
import { typographySettingsStore } from '$features/AdjustTypography/model'; import { typographySettingsStore } from '$features/AdjustTypography/model';
import { import {
@@ -122,16 +127,16 @@ $effect(() => {
} }
switch (true) { switch (true) {
case responsive.isMobile: case responsive.isMobile:
typography.multiplier = 0.5; typography.multiplier = MULTIPLIER_S;
break; break;
case responsive.isTablet: case responsive.isTablet:
typography.multiplier = 0.75; typography.multiplier = MULTIPLIER_M;
break; break;
case responsive.isDesktop: case responsive.isDesktop:
typography.multiplier = 1; typography.multiplier = MULTIPLIER_L;
break; break;
default: default:
typography.multiplier = 1; typography.multiplier = MULTIPLIER_L;
} }
}); });
@@ -28,7 +28,7 @@ interface LayoutConfig {
mode: LayoutMode; mode: LayoutMode;
} }
const STORAGE_KEY = 'glyphdiff:sample-list-layout'; export const STORAGE_KEY = 'glyphdiff:sample-list-layout';
const SM_GAP_PX = 16; const SM_GAP_PX = 16;
const MD_GAP_PX = 24; const MD_GAP_PX = 24;
@@ -16,8 +16,7 @@ async function flushEffects() {
await Promise.resolve(); await Promise.resolve();
} }
// Storage key used by LayoutManager import { STORAGE_KEY } from './layoutStore.svelte';
const STORAGE_KEY = 'glyphdiff:sample-list-layout';
describe('layoutStore', () => { describe('layoutStore', () => {
// Default viewport for most tests (desktop large - >= 1536px) // Default viewport for most tests (desktop large - >= 1536px)