diff --git a/src/entities/Font/api/fontshare/fontshare.ts b/src/entities/Font/api/fontshare/fontshare.ts index 0689d93..3630edb 100644 --- a/src/entities/Font/api/fontshare/fontshare.ts +++ b/src/entities/Font/api/fontshare/fontshare.ts @@ -10,7 +10,7 @@ import type { FontshareApiModel, FontshareFont, -} from '$entities/Font'; +} from '$entities/Font/model/types/fontshare'; import { api } from '$shared/api/api'; import { buildQueryString } from '$shared/utils'; import type { QueryParams } from '$shared/utils'; @@ -43,7 +43,7 @@ export interface FontshareParams extends QueryParams { /** * Fontshare API response wrapper - * Re-exported from model/types for backward compatibility + * Re-exported from model/types/fontshare for backward compatibility */ export type FontshareResponse = FontshareApiModel; diff --git a/src/entities/Font/api/google/googleFonts.ts b/src/entities/Font/api/google/googleFonts.ts index 07ba6ad..12749da 100644 --- a/src/entities/Font/api/google/googleFonts.ts +++ b/src/entities/Font/api/google/googleFonts.ts @@ -10,7 +10,7 @@ import type { FontItem, GoogleFontsApiModel, -} from '$entities/Font'; +} from '$entities/Font/model/types/google'; import { api } from '$shared/api/api'; import { buildQueryString } from '$shared/utils'; import type { QueryParams } from '$shared/utils'; @@ -47,13 +47,13 @@ export interface GoogleFontsParams extends QueryParams { /** * Google Fonts API response wrapper - * Re-exported from model/types for backward compatibility + * Re-exported from model/types/google for backward compatibility */ export type GoogleFontsResponse = GoogleFontsApiModel; /** * Simplified font item from Google Fonts API - * Re-exported from model/types for backward compatibility + * Re-exported from model/types/google for backward compatibility */ export type GoogleFontItem = FontItem; diff --git a/src/entities/Font/api/normalize/normalize.test.ts b/src/entities/Font/api/normalize/normalize.test.ts index c1e5dd2..a11dc6a 100644 --- a/src/entities/Font/api/normalize/normalize.test.ts +++ b/src/entities/Font/api/normalize/normalize.test.ts @@ -2,7 +2,7 @@ import type { FontshareFont, GoogleFontItem, UnifiedFont, -} from '$entities/Font'; +} from '$entities/Font/model/types'; import { describe, expect, @@ -136,9 +136,9 @@ describe('Font Normalization', () => { }); it('maps variant weights correctly', () => { - const font = { + const font: GoogleFontItem = { ...mockGoogleFont, - variants: ['regular', '100', '400', '700', '900'], + variants: ['regular', '100', '400', '700', '900'] as any, }; const result = normalizeGoogleFont(font); diff --git a/src/entities/Font/api/normalize/normalize.ts b/src/entities/Font/api/normalize/normalize.ts index 116d64d..7bc78a1 100644 --- a/src/entities/Font/api/normalize/normalize.ts +++ b/src/entities/Font/api/normalize/normalize.ts @@ -12,10 +12,10 @@ import type { FontProvider, FontStyleUrls, FontSubset, - FontshareFont, - GoogleFontItem, - UnifiedFont, -} from '../../model/types'; +} from '$entities/Font/model/types'; +import type { FontshareFont } from '$entities/Font/model/types/fontshare'; +import type { GoogleFontItem } from '$entities/Font/model/types/google'; +import type { UnifiedFont } from '$entities/Font/model/types/normalize'; /** * Map Google Fonts category to unified FontCategory @@ -272,3 +272,6 @@ export function normalizeFontshareFonts( ): UnifiedFont[] { return apiFonts.map(normalizeFontshareFont); } + +// Re-export UnifiedFont for backward compatibility +export type { UnifiedFont } from '$entities/Font/model/types/normalize'; diff --git a/src/entities/Font/index.ts b/src/entities/Font/index.ts index 74250a0..1a26f54 100644 --- a/src/entities/Font/index.ts +++ b/src/entities/Font/index.ts @@ -21,7 +21,7 @@ export { normalizeFontshareFonts, normalizeGoogleFont, normalizeGoogleFonts, -} from './api/normalize'; +} from './api/normalize/normalize'; export type { // Domain types FontCategory, @@ -57,4 +57,4 @@ export type { // Normalization types UnifiedFont, UnifiedFontVariant, -} from './model/types'; +} from './model/types/index'; diff --git a/src/entities/Font/model/stores/fontCollectionStore.ts b/src/entities/Font/model/stores/fontCollectionStore.ts index b4cca62..be6cf4d 100644 --- a/src/entities/Font/model/stores/fontCollectionStore.ts +++ b/src/entities/Font/model/stores/fontCollectionStore.ts @@ -16,7 +16,7 @@ import type { FontProvider, FontSubset, UnifiedFont, -} from '$entities/Font'; +} from '$entities/Font/model/types'; import { createCollectionCache } from '$shared/fetch/collectionCache'; import type { Writable } from 'svelte/store'; import { diff --git a/src/entities/Font/model/types.ts b/src/entities/Font/model/types.ts deleted file mode 100644 index 2aa6c21..0000000 --- a/src/entities/Font/model/types.ts +++ /dev/null @@ -1,814 +0,0 @@ -/** - * ============================================================================ - * DOMAIN TYPES - * ============================================================================ - */ - -/** - * Font category - */ -export type FontCategory = 'sans-serif' | 'serif' | 'display' | 'handwriting' | 'monospace'; - -/** - * Font provider - */ -export type FontProvider = 'google' | 'fontshare'; - -/** - * Font subset - */ -export type FontSubset = 'latin' | 'latin-ext' | 'cyrillic' | 'greek' | 'arabic' | 'devanagari'; - -/** - * ============================================================================ - * GOOGLE FONTS API TYPES - * ============================================================================ */ - -/** - * Model of google fonts api response - */ -export interface GoogleFontsApiModel { - /** - * Array of font items returned by the Google Fonts API - * Contains all font families matching the requested query parameters - */ - items: FontItem[]; -} - -/** - * Individual font from Google Fonts API - */ -export interface FontItem { - /** - * Font family name (e.g., "Roboto", "Open Sans", "Lato") - * This is the name used in CSS font-family declarations - */ - family: string; - - /** - * Font category classification (e.g., "sans-serif", "serif", "display", "handwriting", "monospace") - * Useful for grouping and filtering fonts by style - */ - category: string; - - /** - * Available font variants for this font family - * Array of strings representing available weights and styles - * Examples: ["regular", "italic", "100", "200", "300", "400", "500", "600", "700", "800", "900", "100italic", "900italic"] - * The keys in the `files` object correspond to these variant values - */ - variants: FontVariant[]; - - /** - * Supported character subsets for this font - * Examples: ["latin", "latin-ext", "cyrillic", "greek", "arabic", "devanagari", "vietnamese", "hebrew", "thai", etc.] - * Determines which character sets are included in the font files - */ - subsets: string[]; - - /** - * Font version identifier - * Format: "v" followed by version number (e.g., "v31", "v20", "v1") - * Used to track font updates and cache busting - */ - version: string; - - /** - * Last modification date of the font - * Format: ISO 8601 date string (e.g., "2024-01-15", "2023-12-01") - * Indicates when the font was last updated by the font foundry - */ - lastModified: string; - - /** - * Mapping of font variants to their downloadable URLs - * Keys correspond to values in the `variants` array - * Examples: - * - "regular" → "https://fonts.gstatic.com/s/roboto/v30/KFOmCnqEu92Fr1Me4W..." - * - "700" → "https://fonts.gstatic.com/s/roboto/v30/KFOlCnqEu92Fr1MmWUlf..." - * - "700italic" → "https://fonts.gstatic.com/s/roboto/v30/KFOjCnqEu92Fr1Mu51TzA..." - */ - files: FontFiles; - - /** - * URL to the font menu preview image - * Typically a PNG showing the font family name in the font - * Example: "https://fonts.gstatic.com/l/font?kit=KFOmCnqEu92Fr1Me4W...&s=i2" - */ - menu: string; -} - -/** - * Type alias for backward compatibility - * Google Fonts API font item - */ -export type GoogleFontItem = FontItem; - -/** - * Individual font from Google Fonts API - */ -export interface FontItem { - /** - * Font family name (e.g., "Roboto", "Open Sans", "Lato") - * This is the name used in CSS font-family declarations - */ - family: string; - - /** - * Font category classification (e.g., "sans-serif", "serif", "display", "handwriting", "monospace") - * Useful for grouping and filtering fonts by style - */ - category: string; - - /** - * Available font variants for this font family - * Array of strings representing available weights and styles - * Examples: ["regular", "italic", "100", "200", "300", "400", "500", "600", "700", "800", "900", "100italic", "900italic"] - * The keys in the `files` object correspond to these variant values - */ - variants: FontVariant[]; - - /** - * Supported character subsets for this font - * Examples: ["latin", "latin-ext", "cyrillic", "greek", "arabic", "devanagari", "vietnamese", "hebrew", "thai", etc.] - * Determines which character sets are included in the font files - */ - subsets: string[]; - - /** - * Font version identifier - * Format: "v" followed by version number (e.g., "v31", "v20", "v1") - * Used to track font updates and cache busting - */ - version: string; - - /** - * Last modification date of the font - * Format: ISO 8601 date string (e.g., "2024-01-15", "2023-12-01") - * Indicates when the font was last updated by the font foundry - */ - lastModified: string; - - /** - * Mapping of font variants to their downloadable URLs - * Keys correspond to values in the `variants` array - * Examples: - * - "regular" → "https://fonts.gstatic.com/s/roboto/v30/KFOmCnqEu92Fr1Me4W..." - * - "700" → "https://fonts.gstatic.com/s/roboto/v30/KFOlCnqEu92Fr1MmWUlf..." - * - "700italic" → "https://fonts.gstatic.com/s/roboto/v30/KFOjCnqEu92Fr1Mu51TzA..." - */ - files: FontFiles; - - /** - * URL to the font menu preview image - * Typically a PNG showing the font family name in the font - * Example: "https://fonts.gstatic.com/l/font?kit=KFOmCnqEu92Fr1Me4W...&s=i2" - */ - menu: string; -} - -/** - * Standard font weights that can appear in Google Fonts API - */ -export type FontWeight = '100' | '200' | '300' | '400' | '500' | '600' | '700' | '800' | '900'; - -/** - * Italic variant format: e.g., "100italic", "400italic", "700italic" - */ -export type FontWeightItalic = `${FontWeight}italic`; - -/** - * All possible font variants in Google Fonts API - * - Numeric weights: "400", "700", etc. - * - Italic variants: "400italic", "700italic", etc. - * - Legacy names: "regular", "italic", "bold", "bolditalic" - */ -export type FontVariant = - | FontWeight - | FontWeightItalic - | 'regular' - | 'italic' - | 'bold' - | 'bolditalic'; - -/** - * Google Fonts API file mapping - * Dynamic keys that match the variants array - * - * Examples: - * - { "regular": "...", "italic": "...", "700": "...", "700italic": "..." } - * - { "400": "...", "400italic": "...", "900": "..." } - */ -export type FontFiles = Partial>; - -/** - * ============================================================================ - * FONTHARE API TYPES - * ============================================================================ - */ - -import type { CollectionApiModel } from '$shared/types/collection'; - -export const FONTSHARE_API_URL = 'https://api.fontshare.com/v2' as const; - -/** - * Model of Fontshare API response - * @see https://fontshare.com - */ -export type FontshareApiModel = CollectionApiModel; - -/** - * Individual font metadata from Fontshare API - */ -export interface FontshareFont { - /** - * Unique identifier for the font - * UUID v4 format (e.g., "20e9fcdc-1e41-4559-a43d-1ede0adc8896") - */ - id: string; - - /** - * Display name of the font family - * Examples: "Satoshi", "General Sans", "Clash Display" - */ - name: string; - - /** - * Native/localized name of the font (if available) - * Often null for Latin-script fonts - */ - native_name: string | null; - - /** - * URL-friendly identifier for the font - * Used in URLs: e.g., "satoshi", "general-sans", "clash-display" - */ - slug: string; - - /** - * Font category classification - * Examples: "Sans", "Serif", "Display", "Script" - */ - category: string; - - /** - * Script/writing system supported by the font - * Examples: "latin", "arabic", "devanagari" - */ - script: string; - - /** - * Font publisher/foundry information - */ - publisher: FontsharePublisher; - - /** - * Array of designers who created this font - * Multiple designers may have collaborated on a single font - */ - designers: FontshareDesigner[]; - - /** - * Related font families (if any) - * Often null, as fonts are typically independent - */ - related_families: string | null; - - /** - * Whether to display publisher as the designer instead of individual designers - */ - display_publisher_as_designer: boolean; - - /** - * Whether trial downloads are enabled for this font - */ - trials_enabled: boolean; - - /** - * Whether to show Latin-specific metrics - */ - show_latin_metrics: boolean; - - /** - * Type of license for this font - * Examples: "itf_ffl" (ITF Free Font License) - */ - license_type: string; - - /** - * Comma-separated list of languages supported by this font - * Example: "Afar, Afrikaans, Albanian, Aranese, Aromanian, Aymara, ..." - */ - languages: string; - - /** - * ISO 8601 timestamp when the font was added to Fontshare - * Format: "2021-03-12T20:49:05Z" - */ - inserted_at: string; - - /** - * HTML-formatted story/description about the font - * Contains marketing text, design philosophy, and usage recommendations - */ - story: string; - - /** - * Version of the font family - * Format: "1.0", "1.2", etc. - */ - version: string; - - /** - * Total number of times this font has been viewed - */ - views: number; - - /** - * Number of views in the recent time period - */ - views_recent: number; - - /** - * Whether this font is marked as "hot"/trending - */ - is_hot: boolean; - - /** - * Whether this font is marked as new - */ - is_new: boolean; - - /** - * Whether this font is in the shortlisted collection - */ - is_shortlisted: boolean | null; - - /** - * Whether this font is marked as top/popular - */ - is_top: boolean; - - /** - * Variable font axes (for variable fonts) - * Empty array [] for static fonts - */ - axes: FontshareAxis[]; - - /** - * Tags/categories for this font - * Examples: ["Magazines", "Branding", "Logos", "Posters"] - */ - font_tags: FontshareTag[]; - - /** - * OpenType features available in this font - */ - features: FontshareFeature[]; - - /** - * Array of available font styles/variants - * Each style represents a different font file (weight, italic, variable) - */ - styles: FontshareStyle[]; -} - -/** - * Publisher/foundry information - */ -export interface FontsharePublisher { - /** - * Description/bio of the publisher - * Example: "Indian Type Foundry (ITF) creates retail and custom multilingual fonts..." - */ - bio: string; - - /** - * Publisher email (if available) - */ - email: string | null; - - /** - * Unique publisher identifier - * UUID format - */ - id: string; - - /** - * Publisher links (social media, website, etc.) - */ - links: FontshareLink[]; - - /** - * Publisher name - * Example: "Indian Type Foundry" - */ - name: string; -} - -/** - * Designer information - */ -export interface FontshareDesigner { - /** - * Designer bio/description - */ - bio: string; - - /** - * Designer links (Twitter, website, etc.) - */ - links: FontshareLink[]; - - /** - * Designer name - */ - name: string; -} - -/** - * Link information - */ -export interface FontshareLink { - /** - * Name of the link platform/site - * Examples: "Twitter", "GitHub", "Website" - */ - name: string; - - /** - * URL of the link (may be null) - */ - url: string | null; -} - -/** - * Font tag/category - */ -export interface FontshareTag { - /** - * Tag name - * Examples: "Magazines", "Branding", "Logos", "Posters" - */ - name: string; -} - -/** - * OpenType feature - */ -export interface FontshareFeature { - /** - * Feature name (descriptive name or null) - * Examples: "Alternate t", "All Alternates", or null - */ - name: string | null; - - /** - * Whether this feature is on by default - */ - on_by_default: boolean; - - /** - * OpenType feature tag (4-character code) - * Examples: "ss01", "frac", "liga", "aalt", "case" - */ - tag: string; -} - -/** - * Variable font axis (for variable fonts) - * Defines the range and properties of a variable font axis (e.g., weight) - */ -export interface FontshareAxis { - /** - * Name of the axis - * Example: "wght" (weight axis) - */ - name: string; - - /** - * CSS property name for the axis - * Example: "wght" - */ - property: string; - - /** - * Default value for the axis - * Example: 420.0, 650.0, 700.0 - */ - range_default: number; - - /** - * Minimum value for the axis - * Example: 300.0, 100.0, 200.0 - */ - range_left: number; - - /** - * Maximum value for the axis - * Example: 900.0, 700.0, 800.0 - */ - range_right: number; -} - -/** - * Individual font style/variant - * Each style represents a single downloadable font file - */ -export interface FontshareStyle { - /** - * Unique identifier for this style - * UUID format - */ - id: string; - - /** - * Whether this is the default style for the font family - * Typically, one style per font is marked as default - */ - default: boolean; - - /** - * CDN URL to the font file - * Protocol-relative URL: "//cdn.fontshare.com/wf/..." - * Note: URL starts with "//" (protocol-relative), may need protocol prepended - */ - file: string; - - /** - * Whether this style is italic - * false for upright, true for italic styles - */ - is_italic: boolean; - - /** - * Whether this is a variable font - * Variable fonts have adjustable axes (weight, slant, etc.) - */ - is_variable: boolean; - - /** - * Typography properties for this style - * Contains measurements like cap height, x-height, ascenders/descenders - * May be empty object {} for some styles - */ - properties: FontshareStyleProperties | Record; - - /** - * Weight information for this style - */ - weight: FontshareWeight; -} - -/** - * Typography/measurement properties for a font style - */ -export interface FontshareStyleProperties { - /** - * Distance from baseline to the top of ascenders - * Example: 1010, 990, 1000 - */ - ascending_leading: number | null; - - /** - * Height of uppercase letters (cap height) - * Example: 710, 680, 750 - */ - cap_height: number | null; - - /** - * Distance from baseline to the bottom of descenders (negative value) - * Example: -203, -186, -220 - */ - descending_leading: number | null; - - /** - * Body height of the font - * Often null in Fontshare data - */ - body_height: number | null; - - /** - * Maximum character width in the font - * Example: 1739, 1739, 1739 - */ - max_char_width: number | null; - - /** - * Height of lowercase x-height - * Example: 480, 494, 523 - */ - x_height: number | null; - - /** - * Maximum Y coordinate (top of ascenders) - * Example: 1010, 990, 1026 - */ - y_max: number | null; - - /** - * Minimum Y coordinate (bottom of descenders) - * Example: -240, -250, -280 - */ - y_min: number | null; -} - -/** - * Weight information for a font style - */ -export interface FontshareWeight { - /** - * Display label for the weight - * Examples: "Light", "Regular", "Bold", "Variable", "Variable Italic" - */ - label: string; - - /** - * Internal name for the weight - * Examples: "Light", "Regular", "Bold", "Variable", "VariableItalic" - */ - name: string; - - /** - * Native/localized name for the weight (if available) - * Often null for Latin-script fonts - */ - native_name: string | null; - - /** - * Numeric weight value - * Examples: 300, 400, 700, 0 (for variable fonts), 1, 2 - * Note: This matches the `weight` property - */ - number: number; - - /** - * Numeric weight value (duplicate of `number`) - * Appears to be redundant with `number` field - */ - weight: number; -} - -/** - * ============================================================================ - * NORMALIZATION TYPES - * ============================================================================ - */ - -/** - * Font variant types (standardized) - */ -export type UnifiedFontVariant = string; - -/** - * Font style URLs - */ -export interface FontStyleUrls { - /** Regular weight URL */ - regular?: string; - /** Italic URL */ - italic?: string; - /** Bold weight URL */ - bold?: string; - /** Bold italic URL */ - boldItalic?: string; -} - -/** - * Font metadata - */ -export interface FontMetadata { - /** Timestamp when font was cached */ - cachedAt: number; - /** Font version from provider */ - version?: string; - /** Last modified date from provider */ - lastModified?: string; - /** Popularity rank (if available from provider) */ - popularity?: number; -} - -/** - * Font features (variable fonts, axes, tags) - */ -export interface FontFeatures { - /** Whether this is a variable font */ - isVariable?: boolean; - /** Variable font axes (for Fontshare) */ - axes?: Array<{ - name: string; - property: string; - default: number; - min: number; - max: number; - }>; - /** Usage tags (for Fontshare) */ - tags?: string[]; -} - -/** - * Unified font model - * - * Combines Google Fonts and Fontshare data into a common interface - * for consistent font handling across the application. - */ -export interface UnifiedFont { - /** Unique identifier (Google: family name, Fontshare: slug) */ - id: string; - /** Font display name */ - name: string; - /** Font provider (google | fontshare) */ - provider: FontProvider; - /** Font category classification */ - category: FontCategory; - /** Supported character subsets */ - subsets: FontSubset[]; - /** Available font variants (weights, styles) */ - variants: UnifiedFontVariant[]; - /** URL mapping for font file downloads */ - styles: FontStyleUrls; - /** Additional metadata */ - metadata: FontMetadata; - /** Advanced font features */ - features: FontFeatures; -} - -/** - * ============================================================================ - * STORE TYPES - * ============================================================================ - */ - -/** - * Font collection state - */ -export interface FontCollectionState { - /** All cached fonts */ - fonts: Record; - /** Active filters */ - filters: FontCollectionFilters; - /** Sort configuration */ - sort: FontCollectionSort; -} - -/** - * Font collection filters - */ -export interface FontCollectionFilters { - /** Search query */ - searchQuery?: string; - /** Filter by provider */ - provider?: FontProvider; - /** Filter by category */ - category?: FontCategory; - /** Filter by subsets */ - subsets?: string[]; -} - -/** - * Font collection sort configuration - */ -export interface FontCollectionSort { - /** Sort field */ - field: 'name' | 'popularity' | 'category'; - /** Sort direction */ - direction: 'asc' | 'desc'; -} - -/** - * Font collection store interface - */ -export interface FontCollectionStore { - /** Main state store */ - state: import('svelte/store').Writable; - /** All fonts as array */ - fonts: import('svelte/store').Readable; - /** Filtered fonts as array */ - filteredFonts: import('svelte/store').Readable; - /** Number of fonts in collection */ - count: import('svelte/store').Readable; - /** Loading state */ - isLoading: import('svelte/store').Readable; - /** Error state */ - error: import('svelte/store').Readable; - /** Add fonts to collection */ - addFonts: (fonts: UnifiedFont[]) => void; - /** Add single font to collection */ - addFont: (font: UnifiedFont) => void; - /** Remove font from collection */ - removeFont: (fontId: string) => void; - /** Clear all fonts */ - clear: () => void; - /** Update filters */ - setFilters: (filters: Partial) => void; - /** Clear filters */ - clearFilters: () => void; - /** Update sort configuration */ - setSort: (sort: FontCollectionSort) => void; - /** Get font by ID */ - getFont: (fontId: string) => UnifiedFont | undefined; - /** Get fonts by provider */ - getFontsByProvider: (provider: FontProvider) => UnifiedFont[]; - /** Get fonts by category */ - getFontsByCategory: (category: FontCategory) => UnifiedFont[]; -} diff --git a/src/entities/Font/model/types/common.ts b/src/entities/Font/model/types/common.ts new file mode 100644 index 0000000..de8fea9 --- /dev/null +++ b/src/entities/Font/model/types/common.ts @@ -0,0 +1,20 @@ +/** + * ============================================================================ + * DOMAIN TYPES + * ============================================================================ + */ + +/** + * Font category + */ +export type FontCategory = 'sans-serif' | 'serif' | 'display' | 'handwriting' | 'monospace'; + +/** + * Font provider + */ +export type FontProvider = 'google' | 'fontshare'; + +/** + * Font subset + */ +export type FontSubset = 'latin' | 'latin-ext' | 'cyrillic' | 'greek' | 'arabic' | 'devanagari'; diff --git a/src/entities/Font/model/types/fontshare.ts b/src/entities/Font/model/types/fontshare.ts new file mode 100644 index 0000000..49ff8dc --- /dev/null +++ b/src/entities/Font/model/types/fontshare.ts @@ -0,0 +1,447 @@ +/** + * ============================================================================ + * FONTHARE API TYPES + * ============================================================================ + */ + +import type { CollectionApiModel } from '$shared/types/collection'; + +export const FONTSHARE_API_URL = 'https://api.fontshare.com/v2' as const; + +/** + * Model of Fontshare API response + * @see https://fontshare.com + */ +export type FontshareApiModel = CollectionApiModel; + +/** + * Individual font metadata from Fontshare API + */ +export interface FontshareFont { + /** + * Unique identifier for the font + * UUID v4 format (e.g., "20e9fcdc-1e41-4559-a43d-1ede0adc8896") + */ + id: string; + + /** + * Display name of the font family + * Examples: "Satoshi", "General Sans", "Clash Display" + */ + name: string; + + /** + * Native/localized name of the font (if available) + * Often null for Latin-script fonts + */ + native_name: string | null; + + /** + * URL-friendly identifier for the font + * Used in URLs: e.g., "satoshi", "general-sans", "clash-display" + */ + slug: string; + + /** + * Font category classification + * Examples: "Sans", "Serif", "Display", "Script" + */ + category: string; + + /** + * Script/writing system supported by the font + * Examples: "latin", "arabic", "devanagari" + */ + script: string; + + /** + * Font publisher/foundry information + */ + publisher: FontsharePublisher; + + /** + * Array of designers who created this font + * Multiple designers may have collaborated on a single font + */ + designers: FontshareDesigner[]; + + /** + * Related font families (if any) + * Often null, as fonts are typically independent + */ + related_families: string | null; + + /** + * Whether to display publisher as the designer instead of individual designers + */ + display_publisher_as_designer: boolean; + + /** + * Whether trial downloads are enabled for this font + */ + trials_enabled: boolean; + + /** + * Whether to show Latin-specific metrics + */ + show_latin_metrics: boolean; + + /** + * Type of license for this font + * Examples: "itf_ffl" (ITF Free Font License) + */ + license_type: string; + + /** + * Comma-separated list of languages supported by this font + * Example: "Afar, Afrikaans, Albanian, Aranese, Aromanian, Aymara, ..." + */ + languages: string; + + /** + * ISO 8601 timestamp when the font was added to Fontshare + * Format: "2021-03-12T20:49:05Z" + */ + inserted_at: string; + + /** + * HTML-formatted story/description about the font + * Contains marketing text, design philosophy, and usage recommendations + */ + story: string; + + /** + * Version of the font family + * Format: "1.0", "1.2", etc. + */ + version: string; + + /** + * Total number of times this font has been viewed + */ + views: number; + + /** + * Number of views in the recent time period + */ + views_recent: number; + + /** + * Whether this font is marked as "hot"/trending + */ + is_hot: boolean; + + /** + * Whether this font is marked as new + */ + is_new: boolean; + + /** + * Whether this font is in the shortlisted collection + */ + is_shortlisted: boolean | null; + + /** + * Whether this font is marked as top/popular + */ + is_top: boolean; + + /** + * Variable font axes (for variable fonts) + * Empty array [] for static fonts + */ + axes: FontshareAxis[]; + + /** + * Tags/categories for this font + * Examples: ["Magazines", "Branding", "Logos", "Posters"] + */ + font_tags: FontshareTag[]; + + /** + * OpenType features available in this font + */ + features: FontshareFeature[]; + + /** + * Array of available font styles/variants + * Each style represents a different font file (weight, italic, variable) + */ + styles: FontshareStyle[]; +} + +/** + * Publisher/foundry information + */ +export interface FontsharePublisher { + /** + * Description/bio of the publisher + * Example: "Indian Type Foundry (ITF) creates retail and custom multilingual fonts..." + */ + bio: string; + + /** + * Publisher email (if available) + */ + email: string | null; + + /** + * Unique publisher identifier + * UUID format + */ + id: string; + + /** + * Publisher links (social media, website, etc.) + */ + links: FontshareLink[]; + + /** + * Publisher name + * Example: "Indian Type Foundry" + */ + name: string; +} + +/** + * Designer information + */ +export interface FontshareDesigner { + /** + * Designer bio/description + */ + bio: string; + + /** + * Designer links (Twitter, website, etc.) + */ + links: FontshareLink[]; + + /** + * Designer name + */ + name: string; +} + +/** + * Link information + */ +export interface FontshareLink { + /** + * Name of the link platform/site + * Examples: "Twitter", "GitHub", "Website" + */ + name: string; + + /** + * URL of the link (may be null) + */ + url: string | null; +} + +/** + * Font tag/category + */ +export interface FontshareTag { + /** + * Tag name + * Examples: "Magazines", "Branding", "Logos", "Posters" + */ + name: string; +} + +/** + * OpenType feature + */ +export interface FontshareFeature { + /** + * Feature name (descriptive name or null) + * Examples: "Alternate t", "All Alternates", or null + */ + name: string | null; + + /** + * Whether this feature is on by default + */ + on_by_default: boolean; + + /** + * OpenType feature tag (4-character code) + * Examples: "ss01", "frac", "liga", "aalt", "case" + */ + tag: string; +} + +/** + * Variable font axis (for variable fonts) + * Defines the range and properties of a variable font axis (e.g., weight) + */ +export interface FontshareAxis { + /** + * Name of the axis + * Example: "wght" (weight axis) + */ + name: string; + + /** + * CSS property name for the axis + * Example: "wght" + */ + property: string; + + /** + * Default value for the axis + * Example: 420.0, 650.0, 700.0 + */ + range_default: number; + + /** + * Minimum value for the axis + * Example: 300.0, 100.0, 200.0 + */ + range_left: number; + + /** + * Maximum value for the axis + * Example: 900.0, 700.0, 800.0 + */ + range_right: number; +} + +/** + * Individual font style/variant + * Each style represents a single downloadable font file + */ +export interface FontshareStyle { + /** + * Unique identifier for this style + * UUID format + */ + id: string; + + /** + * Whether this is the default style for the font family + * Typically, one style per font is marked as default + */ + default: boolean; + + /** + * CDN URL to the font file + * Protocol-relative URL: "//cdn.fontshare.com/wf/..." + * Note: URL starts with "//" (protocol-relative), may need protocol prepended + */ + file: string; + + /** + * Whether this style is italic + * false for upright, true for italic styles + */ + is_italic: boolean; + + /** + * Whether this is a variable font + * Variable fonts have adjustable axes (weight, slant, etc.) + */ + is_variable: boolean; + + /** + * Typography properties for this style + * Contains measurements like cap height, x-height, ascenders/descenders + * May be empty object {} for some styles + */ + properties: FontshareStyleProperties | Record; + + /** + * Weight information for this style + */ + weight: FontshareWeight; +} + +/** + * Typography/measurement properties for a font style + */ +export interface FontshareStyleProperties { + /** + * Distance from baseline to the top of ascenders + * Example: 1010, 990, 1000 + */ + ascending_leading: number | null; + + /** + * Height of uppercase letters (cap height) + * Example: 710, 680, 750 + */ + cap_height: number | null; + + /** + * Distance from baseline to the bottom of descenders (negative value) + * Example: -203, -186, -220 + */ + descending_leading: number | null; + + /** + * Body height of the font + * Often null in Fontshare data + */ + body_height: number | null; + + /** + * Maximum character width in the font + * Example: 1739, 1739, 1739 + */ + max_char_width: number | null; + + /** + * Height of lowercase x-height + * Example: 480, 494, 523 + */ + x_height: number | null; + + /** + * Maximum Y coordinate (top of ascenders) + * Example: 1010, 990, 1026 + */ + y_max: number | null; + + /** + * Minimum Y coordinate (bottom of descenders) + * Example: -240, -250, -280 + */ + y_min: number | null; +} + +/** + * Weight information for a font style + */ +export interface FontshareWeight { + /** + * Display label for the weight + * Examples: "Light", "Regular", "Bold", "Variable", "Variable Italic" + */ + label: string; + + /** + * Internal name for the weight + * Examples: "Light", "Regular", "Bold", "Variable", "VariableItalic" + */ + name: string; + + /** + * Native/localized name for the weight (if available) + * Often null for Latin-script fonts + */ + native_name: string | null; + + /** + * Numeric weight value + * Examples: 300, 400, 700, 0 (for variable fonts), 1, 2 + * Note: This matches the `weight` property + */ + number: number; + + /** + * Numeric weight value (duplicate of `number`) + * Appears to be redundant with `number` field + */ + weight: number; +} diff --git a/src/entities/Font/model/types/google.ts b/src/entities/Font/model/types/google.ts new file mode 100644 index 0000000..26a1f56 --- /dev/null +++ b/src/entities/Font/model/types/google.ts @@ -0,0 +1,119 @@ +/** + * ============================================================================ + * GOOGLE FONTS API TYPES + * ============================================================================ + */ + +/** + * Model of google fonts api response + */ +export interface GoogleFontsApiModel { + /** + * Array of font items returned by the Google Fonts API + * Contains all font families matching the requested query parameters + */ + items: FontItem[]; +} + +/** + * Individual font from Google Fonts API + */ +export interface FontItem { + /** + * Font family name (e.g., "Roboto", "Open Sans", "Lato") + * This is the name used in CSS font-family declarations + */ + family: string; + + /** + * Font category classification (e.g., "sans-serif", "serif", "display", "handwriting", "monospace") + * Useful for grouping and filtering fonts by style + */ + category: string; + + /** + * Available font variants for this font family + * Array of strings representing available weights and styles + * Examples: ["regular", "italic", "100", "200", "300", "400", "500", "600", "700", "800", "900", "100italic", "900italic"] + * The keys in the `files` object correspond to these variant values + */ + variants: FontVariant[]; + + /** + * Supported character subsets for this font + * Examples: ["latin", "latin-ext", "cyrillic", "greek", "arabic", "devanagari", "vietnamese", "hebrew", "thai", etc.] + * Determines which character sets are included in the font files + */ + subsets: string[]; + + /** + * Font version identifier + * Format: "v" followed by version number (e.g., "v31", "v20", "v1") + * Used to track font updates and cache busting + */ + version: string; + + /** + * Last modification date of the font + * Format: ISO 8601 date string (e.g., "2024-01-15", "2023-12-01") + * Indicates when the font was last updated by the font foundry + */ + lastModified: string; + + /** + * Mapping of font variants to their downloadable URLs + * Keys correspond to values in the `variants` array + * Examples: + * - "regular" → "https://fonts.gstatic.com/s/roboto/v30/KFOmCnqEu92Fr1Me4W..." + * - "700" → "https://fonts.gstatic.com/s/roboto/v30/KFOlCnqEu92Fr1MmWUlf..." + * - "700italic" → "https://fonts.gstatic.com/s/roboto/v30/KFOjCnqEu92Fr1Mu51TzA..." + */ + files: FontFiles; + + /** + * URL to the font menu preview image + * Typically a PNG showing the font family name in the font + * Example: "https://fonts.gstatic.com/l/font?kit=KFOmCnqEu92Fr1Me4W...&s=i2" + */ + menu: string; +} + +/** + * Type alias for backward compatibility + * Google Fonts API font item + */ +export type GoogleFontItem = FontItem; + +/** + * Standard font weights that can appear in Google Fonts API + */ +export type FontWeight = '100' | '200' | '300' | '400' | '500' | '600' | '700' | '800' | '900'; + +/** + * Italic variant format: e.g., "100italic", "400italic", "700italic" + */ +export type FontWeightItalic = `${FontWeight}italic`; + +/** + * All possible font variants in Google Fonts API + * - Numeric weights: "400", "700", etc. + * - Italic variants: "400italic", "700italic", etc. + * - Legacy names: "regular", "italic", "bold", "bolditalic" + */ +export type FontVariant = + | FontWeight + | FontWeightItalic + | 'regular' + | 'italic' + | 'bold' + | 'bolditalic'; + +/** + * Google Fonts API file mapping + * Dynamic keys that match the variants array + * + * Examples: + * - { "regular": "...", "italic": "...", "700": "...", "700italic": "..." } + * - { "400": "...", "400italic": "...", "900": "..." } + */ +export type FontFiles = Partial>; diff --git a/src/entities/Font/model/types/index.ts b/src/entities/Font/model/types/index.ts new file mode 100644 index 0000000..368f3d7 --- /dev/null +++ b/src/entities/Font/model/types/index.ts @@ -0,0 +1,59 @@ +/** + * ============================================================================ + * SINGLE EXPORT POINT + * ============================================================================ + * + * This is the single export point for all Font types. + * All imports should use: `import { X } from '$entities/Font/model/types'` + */ + +// Domain types +export type { + FontCategory, + FontProvider, + FontSubset, +} from './common'; + +// Google Fonts API types +export type { + FontFiles, + FontItem, + FontVariant, + FontWeight, + FontWeightItalic, + GoogleFontItem, + GoogleFontsApiModel, +} from './google'; + +// Fontshare API types +export type { + FontshareApiModel, + FontshareAxis, + FontshareDesigner, + FontshareFeature, + FontshareFont, + FontshareLink, + FontsharePublisher, + FontshareStyle, + FontshareStyleProperties, + FontshareTag, + FontshareWeight, +} from './fontshare'; +export { FONTSHARE_API_URL } from './fontshare'; + +// Normalization types +export type { + FontFeatures, + FontMetadata, + FontStyleUrls, + UnifiedFont, + UnifiedFontVariant, +} from './normalize'; + +// Store types +export type { + FontCollectionFilters, + FontCollectionSort, + FontCollectionState, + FontCollectionStore, +} from './store'; diff --git a/src/entities/Font/model/types/normalize.ts b/src/entities/Font/model/types/normalize.ts new file mode 100644 index 0000000..91f58eb --- /dev/null +++ b/src/entities/Font/model/types/normalize.ts @@ -0,0 +1,89 @@ +/** + * ============================================================================ + * NORMALIZATION TYPES + * ============================================================================ + */ + +import type { + FontCategory, + FontProvider, + FontSubset, +} from './common'; + +/** + * Font variant types (standardized) + */ +export type UnifiedFontVariant = string; + +/** + * Font style URLs + */ +export interface FontStyleUrls { + /** Regular weight URL */ + regular?: string; + /** Italic URL */ + italic?: string; + /** Bold weight URL */ + bold?: string; + /** Bold italic URL */ + boldItalic?: string; +} + +/** + * Font metadata + */ +export interface FontMetadata { + /** Timestamp when font was cached */ + cachedAt: number; + /** Font version from provider */ + version?: string; + /** Last modified date from provider */ + lastModified?: string; + /** Popularity rank (if available from provider) */ + popularity?: number; +} + +/** + * Font features (variable fonts, axes, tags) + */ +export interface FontFeatures { + /** Whether this is a variable font */ + isVariable?: boolean; + /** Variable font axes (for Fontshare) */ + axes?: Array<{ + name: string; + property: string; + default: number; + min: number; + max: number; + }>; + /** Usage tags (for Fontshare) */ + tags?: string[]; +} + +/** + * Unified font model + * + * Combines Google Fonts and Fontshare data into a common interface + * for consistent font handling across the application. + */ +export interface UnifiedFont { + /** Unique identifier (Google: family name, Fontshare: slug) */ + id: string; + /** Font display name */ + name: string; + /** Font provider (google | fontshare) */ + provider: FontProvider; + /** Font category classification */ + category: FontCategory; + /** Supported character subsets */ + subsets: FontSubset[]; + /** Available font variants (weights, styles) */ + variants: UnifiedFontVariant[]; + /** URL mapping for font file downloads */ + styles: FontStyleUrls; + /** Additional metadata */ + metadata: FontMetadata; + /** Advanced font features */ + features: FontFeatures; +} diff --git a/src/entities/Font/model/types/store.ts b/src/entities/Font/model/types/store.ts new file mode 100644 index 0000000..5cc2383 --- /dev/null +++ b/src/entities/Font/model/types/store.ts @@ -0,0 +1,86 @@ +/** + * ============================================================================ + * STORE TYPES + * ============================================================================ + */ + +import type { + FontCategory, + FontProvider, + FontSubset, +} from './common'; +import type { UnifiedFont } from './normalize'; + +/** + * Font collection state + */ +export interface FontCollectionState { + /** All cached fonts */ + fonts: Record; + /** Active filters */ + filters: FontCollectionFilters; + /** Sort configuration */ + sort: FontCollectionSort; +} + +/** + * Font collection filters + */ +export interface FontCollectionFilters { + /** Search query */ + searchQuery?: string; + /** Filter by provider */ + provider?: FontProvider; + /** Filter by category */ + category?: FontCategory; + /** Filter by subsets */ + subsets?: string[]; +} + +/** + * Font collection sort configuration + */ +export interface FontCollectionSort { + /** Sort field */ + field: 'name' | 'popularity' | 'category'; + /** Sort direction */ + direction: 'asc' | 'desc'; +} + +/** + * Font collection store interface + */ +export interface FontCollectionStore { + /** Main state store */ + state: import('svelte/store').Writable; + /** All fonts as array */ + fonts: import('svelte/store').Readable; + /** Filtered fonts as array */ + filteredFonts: import('svelte/store').Readable; + /** Number of fonts in collection */ + count: import('svelte/store').Readable; + /** Loading state */ + isLoading: import('svelte/store').Readable; + /** Error state */ + error: import('svelte/store').Readable; + /** Add fonts to collection */ + addFonts: (fonts: UnifiedFont[]) => void; + /** Add single font to collection */ + addFont: (font: UnifiedFont) => void; + /** Remove font from collection */ + removeFont: (fontId: string) => void; + /** Clear all fonts */ + clear: () => void; + /** Update filters */ + setFilters: (filters: Partial) => void; + /** Clear filters */ + clearFilters: () => void; + /** Update sort configuration */ + setSort: (sort: FontCollectionSort) => void; + /** Get font by ID */ + getFont: (fontId: string) => UnifiedFont | undefined; + /** Get fonts by provider */ + getFontsByProvider: (provider: FontProvider) => UnifiedFont[]; + /** Get fonts by category */ + getFontsByCategory: (category: FontCategory) => UnifiedFont[]; +} diff --git a/src/features/FetchFonts/model/services/fetchFontshareFonts.ts b/src/features/FetchFonts/model/services/fetchFontshareFonts.ts index 000946e..d9310b3 100644 --- a/src/features/FetchFonts/model/services/fetchFontshareFonts.ts +++ b/src/features/FetchFonts/model/services/fetchFontshareFonts.ts @@ -5,9 +5,9 @@ * and automatic refetching. */ -import { fetchFontshareFonts } from '$entities/Font/api/fontshare'; -import { normalizeFontshareFonts } from '$entities/Font/api/normalize'; -import type { UnifiedFont } from '$entities/Font/api/normalize'; +import { fetchFontshareFonts } from '$entities/Font/api/fontshare/fontshare'; +import { normalizeFontshareFonts } from '$entities/Font/api/normalize/normalize'; +import type { UnifiedFont } from '$entities/Font/model/types/normalize'; import type { QueryFunction } from '@tanstack/svelte-query'; import { createQuery, diff --git a/src/features/FetchFonts/model/services/fetchGoogleFonts.ts b/src/features/FetchFonts/model/services/fetchGoogleFonts.ts index 43c4c3b..2259980 100644 --- a/src/features/FetchFonts/model/services/fetchGoogleFonts.ts +++ b/src/features/FetchFonts/model/services/fetchGoogleFonts.ts @@ -7,13 +7,13 @@ * Uses reactive query args pattern for Svelte 5 compatibility. */ +import { fetchGoogleFonts } from '$entities/Font/api/google/googleFonts'; +import { normalizeGoogleFonts } from '$entities/Font/api/normalize/normalize'; import type { FontCategory, FontSubset, -} from '$entities/Font'; -import { fetchGoogleFonts } from '$entities/Font/api/googleFonts'; -import { normalizeGoogleFonts } from '$entities/Font/api/normalize'; -import type { UnifiedFont } from '$entities/Font/api/normalize'; +} from '$entities/Font/model/types'; +import type { UnifiedFont } from '$entities/Font/model/types/normalize'; import type { QueryFunction } from '@tanstack/svelte-query'; import { createQuery, diff --git a/src/features/FetchFonts/model/types.ts b/src/features/FetchFonts/model/types.ts index c21eb17..a4f4ea0 100644 --- a/src/features/FetchFonts/model/types.ts +++ b/src/features/FetchFonts/model/types.ts @@ -8,8 +8,8 @@ import type { FontCategory, FontProvider, FontSubset, -} from '$entities/Font'; -import type { UnifiedFont } from '$entities/Font/api/normalize'; +} from '$entities/Font/model/types'; +import type { UnifiedFont } from '$entities/Font/model/types/normalize'; /** * Combined query parameters for fetching from any provider