/** * ============================================================================ * MOCK FONT DATA * ============================================================================ * * Factory functions and preset mock data for fonts. * Used in Storybook stories, tests, and development. * * ## Usage * * ```ts * import { * mockGoogleFont, * mockFontshareFont, * mockUnifiedFont, * GOOGLE_FONTS, * FONTHARE_FONTS, * UNIFIED_FONTS, * } from '$entities/Font/lib/mocks'; * * // Create a mock Google Font * const roboto = mockGoogleFont({ family: 'Roboto', category: 'sans-serif' }); * * // Create a mock Fontshare font * const satoshi = mockFontshareFont({ name: 'Satoshi', slug: 'satoshi' }); * * // Create a mock UnifiedFont * const font = mockUnifiedFont({ id: 'roboto', name: 'Roboto' }); * * // Use preset fonts * import { UNIFIED_FONTS } from '$entities/Font/lib/mocks'; * ``` */ import type { FontCategory, FontProvider, FontSubset, FontVariant, } from '$entities/Font/model/types'; import type { FontItem, FontshareFont, GoogleFontItem, } from '$entities/Font/model/types'; import type { FontFeatures, FontMetadata, FontStyleUrls, UnifiedFont, } from '$entities/Font/model/types'; // GOOGLE FONTS MOCKS /** * Options for creating a mock Google Font */ export interface MockGoogleFontOptions { /** Font family name (default: 'Mock Font') */ family?: string; /** Font category (default: 'sans-serif') */ category?: 'sans-serif' | 'serif' | 'display' | 'handwriting' | 'monospace'; /** Font variants (default: ['regular', '700', 'italic', '700italic']) */ variants?: FontVariant[]; /** Font subsets (default: ['latin']) */ subsets?: string[]; /** Font version (default: 'v30') */ version?: string; /** Last modified date (default: current ISO date) */ lastModified?: string; /** Custom file URLs (if not provided, mock URLs are generated) */ files?: Partial>; /** Popularity rank (1 = most popular) */ popularity?: number; } /** * Default mock Google Font */ export function mockGoogleFont(options: MockGoogleFontOptions = {}): GoogleFontItem { const { family = 'Mock Font', category = 'sans-serif', variants = ['regular', '700', 'italic', '700italic'], subsets = ['latin'], version = 'v30', lastModified = new Date().toISOString().split('T')[0], files, popularity = 1, } = options; const baseUrl = `https://fonts.gstatic.com/s/${family.toLowerCase().replace(/\s+/g, '')}/${version}`; return { family, category, variants: variants as FontVariant[], subsets, version, lastModified, files: files ?? { regular: `${baseUrl}/KFOmCnqEu92Fr1Me4W.woff2`, '700': `${baseUrl}/KFOlCnqEu92Fr1MmWUlfBBc9.woff2`, italic: `${baseUrl}/KFOkCnqEu92Fr1Mu51xIIzI.woff2`, '700italic': `${baseUrl}/KFOjCnqEu92Fr1Mu51TzBic6CsQ.woff2`, }, menu: `https://fonts.googleapis.com/css2?family=${encodeURIComponent(family)}`, }; } /** * Preset Google Font mocks */ export const GOOGLE_FONTS: Record = { roboto: mockGoogleFont({ family: 'Roboto', category: 'sans-serif', variants: ['100', '300', '400', '500', '700', '900', 'italic', '700italic'], subsets: ['latin', 'latin-ext', 'cyrillic', 'greek'], popularity: 1, }), openSans: mockGoogleFont({ family: 'Open Sans', category: 'sans-serif', variants: ['300', '400', '500', '600', '700', '800', 'italic', '700italic'], subsets: ['latin', 'latin-ext', 'cyrillic', 'greek'], popularity: 2, }), lato: mockGoogleFont({ family: 'Lato', category: 'sans-serif', variants: ['100', '300', '400', '700', '900', 'italic', '700italic'], subsets: ['latin', 'latin-ext'], popularity: 3, }), playfairDisplay: mockGoogleFont({ family: 'Playfair Display', category: 'serif', variants: ['400', '500', '600', '700', '800', '900', 'italic', '700italic'], subsets: ['latin', 'latin-ext', 'cyrillic'], popularity: 10, }), montserrat: mockGoogleFont({ family: 'Montserrat', category: 'sans-serif', variants: ['100', '200', '300', '400', '500', '600', '700', '800', '900', 'italic', '700italic'], subsets: ['latin', 'latin-ext', 'cyrillic', 'vietnamese'], popularity: 4, }), sourceSansPro: mockGoogleFont({ family: 'Source Sans Pro', category: 'sans-serif', variants: ['200', '300', '400', '600', '700', '900', 'italic', '700italic'], subsets: ['latin', 'latin-ext', 'cyrillic', 'greek', 'vietnamese'], popularity: 5, }), merriweather: mockGoogleFont({ family: 'Merriweather', category: 'serif', variants: ['300', '400', '700', '900', 'italic', '700italic'], subsets: ['latin', 'latin-ext', 'cyrillic', 'vietnamese'], popularity: 15, }), robotoSlab: mockGoogleFont({ family: 'Roboto Slab', category: 'serif', variants: ['100', '300', '400', '500', '700', '900'], subsets: ['latin', 'latin-ext', 'cyrillic', 'greek', 'vietnamese'], popularity: 8, }), oswald: mockGoogleFont({ family: 'Oswald', category: 'sans-serif', variants: ['200', '300', '400', '500', '600', '700'], subsets: ['latin', 'latin-ext', 'vietnamese'], popularity: 6, }), raleway: mockGoogleFont({ family: 'Raleway', category: 'sans-serif', variants: ['100', '200', '300', '400', '500', '600', '700', '800', '900', 'italic'], subsets: ['latin', 'latin-ext', 'cyrillic', 'vietnamese'], popularity: 7, }), }; // FONTHARE MOCKS /** * Options for creating a mock Fontshare font */ export interface MockFontshareFontOptions { /** Font name (default: 'Mock Font') */ name?: string; /** URL-friendly slug (default: derived from name) */ slug?: string; /** Font category (default: 'sans') */ category?: 'sans' | 'serif' | 'slab' | 'display' | 'handwritten' | 'script' | 'mono'; /** Script (default: 'latin') */ script?: string; /** Whether this is a variable font (default: false) */ isVariable?: boolean; /** Font version (default: '1.0') */ version?: string; /** Popularity/views count (default: 1000) */ views?: number; /** Usage tags */ tags?: string[]; /** Font weights available */ weights?: number[]; /** Publisher name */ publisher?: string; /** Designer name */ designer?: string; } /** * Create a mock Fontshare style */ function mockFontshareStyle( weight: number, isItalic: boolean, isVariable: boolean, slug: string, ): FontshareFont['styles'][number] { const weightLabel = weight === 400 ? 'Regular' : weight === 700 ? 'Bold' : weight.toString(); const suffix = isItalic ? 'italic' : ''; const variablePrefix = isVariable ? 'variable-' : ''; return { id: `style-${weight}${isItalic ? '-italic' : ''}`, default: weight === 400 && !isItalic, file: `//cdn.fontshare.com/wf/${slug}-${variablePrefix}${weight}${suffix}.woff2`, is_italic: isItalic, is_variable: isVariable, properties: {}, weight: { label: isVariable ? 'Variable' + (isItalic ? ' Italic' : '') : weightLabel, name: isVariable ? 'Variable' + (isItalic ? 'Italic' : '') : weightLabel, native_name: null, number: isVariable ? 0 : weight, weight: isVariable ? 0 : weight, }, }; } /** * Default mock Fontshare font */ export function mockFontshareFont(options: MockFontshareFontOptions = {}): FontshareFont { const { name = 'Mock Font', slug = name.toLowerCase().replace(/\s+/g, '-'), category = 'sans', script = 'latin', isVariable = false, version = '1.0', views = 1000, tags = [], weights = [400, 700], publisher = 'Mock Foundry', designer = 'Mock Designer', } = options; // Generate styles based on weights and variable setting const styles: FontshareFont['styles'] = isVariable ? [ mockFontshareStyle(0, false, true, slug), mockFontshareStyle(0, true, true, slug), ] : weights.flatMap(weight => [ mockFontshareStyle(weight, false, false, slug), mockFontshareStyle(weight, true, false, slug), ]); return { id: `mock-${slug}`, name, native_name: null, slug, category, script, publisher: { bio: `Mock publisher bio for ${publisher}`, email: null, id: `pub-${slug}`, links: [], name: publisher, }, designers: [ { bio: `Mock designer bio for ${designer}`, links: [], name: designer, }, ], related_families: null, display_publisher_as_designer: false, trials_enabled: true, show_latin_metrics: false, license_type: 'ofl', languages: 'English, Spanish, French, German', inserted_at: '2021-03-12T20:49:05Z', story: `

A mock font story for ${name}.

`, version, views, views_recent: Math.floor(views * 0.1), is_hot: views > 5000, is_new: views < 500, is_shortlisted: null, is_top: views > 10000, axes: isVariable ? [ { name: 'Weight', property: 'wght', range_default: 400, range_left: 300, range_right: 700, }, ] : [], font_tags: tags.map(name => ({ name })), features: [], styles, }; } /** * Preset Fontshare font mocks */ export const FONTHARE_FONTS: Record = { satoshi: mockFontshareFont({ name: 'Satoshi', slug: 'satoshi', category: 'sans', isVariable: true, views: 15000, tags: ['Branding', 'Logos', 'Editorial'], publisher: 'Indian Type Foundry', designer: 'Denis Shelabovets', }), generalSans: mockFontshareFont({ name: 'General Sans', slug: 'general-sans', category: 'sans', isVariable: true, views: 12000, tags: ['UI', 'Branding', 'Display'], publisher: 'Indestructible Type', designer: 'Eugene Tantsur', }), clashDisplay: mockFontshareFont({ name: 'Clash Display', slug: 'clash-display', category: 'display', isVariable: false, views: 8000, tags: ['Headlines', 'Posters', 'Branding'], weights: [400, 500, 600, 700], publisher: 'Letterogika', designer: 'Matěj Trnka', }), fonta: mockFontshareFont({ name: 'Fonta', slug: 'fonta', category: 'serif', isVariable: false, views: 5000, tags: ['Editorial', 'Books', 'Magazines'], weights: [300, 400, 500, 600, 700], publisher: 'Fonta', designer: 'Alexei Vanyashin', }), aileron: mockFontshareFont({ name: 'Aileron', slug: 'aileron', category: 'sans', isVariable: false, views: 3000, tags: ['Display', 'Headlines'], weights: [100, 200, 300, 400, 500, 600, 700, 800, 900], publisher: 'Sorkin Type', designer: 'Sorkin Type', }), beVietnamPro: mockFontshareFont({ name: 'Be Vietnam Pro', slug: 'be-vietnam-pro', category: 'sans', isVariable: true, views: 20000, tags: ['UI', 'App', 'Web'], publisher: 'ildefox', designer: 'Manh Nguyen', }), }; // UNIFIED FONT MOCKS /** * Options for creating a mock UnifiedFont */ export interface MockUnifiedFontOptions { /** Unique identifier (default: derived from name) */ id?: string; /** Font display name (default: 'Mock Font') */ name?: string; /** Font provider (default: 'google') */ provider?: FontProvider; /** Font category (default: 'sans-serif') */ category?: FontCategory; /** Font subsets (default: ['latin']) */ subsets?: FontSubset[]; /** Font variants (default: ['regular', '700', 'italic', '700italic']) */ variants?: FontVariant[]; /** Style URLs (if not provided, mock URLs are generated) */ styles?: FontStyleUrls; /** Metadata overrides */ metadata?: Partial; /** Features overrides */ features?: Partial; } /** * Default mock UnifiedFont */ export function mockUnifiedFont(options: MockUnifiedFontOptions = {}): UnifiedFont { const { id, name = 'Mock Font', provider = 'google', category = 'sans-serif', subsets = ['latin'], variants = ['regular', '700', 'italic', '700italic'], styles, metadata, features, } = options; const fontId = id ?? name.toLowerCase().replace(/\s+/g, ''); const baseUrl = provider === 'google' ? `https://fonts.gstatic.com/s/${fontId}/v30` : `//cdn.fontshare.com/wf/${fontId}`; return { id: fontId, name, provider, category, subsets, variants: variants as FontVariant[], styles: styles ?? { regular: `${baseUrl}/regular.woff2`, bold: `${baseUrl}/bold.woff2`, italic: `${baseUrl}/italic.woff2`, boldItalic: `${baseUrl}/bolditalic.woff2`, }, metadata: { cachedAt: Date.now(), version: '1.0', lastModified: new Date().toISOString().split('T')[0], popularity: 1, ...metadata, }, features: { isVariable: false, ...features, }, }; } /** * Preset UnifiedFont mocks */ export const UNIFIED_FONTS: Record = { roboto: mockUnifiedFont({ id: 'roboto', name: 'Roboto', provider: 'google', category: 'sans-serif', subsets: ['latin', 'latin-ext'], variants: ['100', '300', '400', '500', '700', '900'], metadata: { popularity: 1 }, }), openSans: mockUnifiedFont({ id: 'open-sans', name: 'Open Sans', provider: 'google', category: 'sans-serif', subsets: ['latin', 'latin-ext'], variants: ['300', '400', '500', '600', '700', '800'], metadata: { popularity: 2 }, }), lato: mockUnifiedFont({ id: 'lato', name: 'Lato', provider: 'google', category: 'sans-serif', subsets: ['latin', 'latin-ext'], variants: ['100', '300', '400', '700', '900'], metadata: { popularity: 3 }, }), playfairDisplay: mockUnifiedFont({ id: 'playfair-display', name: 'Playfair Display', provider: 'google', category: 'serif', subsets: ['latin'], variants: ['400', '700', '900'], metadata: { popularity: 10 }, }), montserrat: mockUnifiedFont({ id: 'montserrat', name: 'Montserrat', provider: 'google', category: 'sans-serif', subsets: ['latin', 'latin-ext'], variants: ['100', '200', '300', '400', '500', '600', '700', '800', '900'], metadata: { popularity: 4 }, }), satoshi: mockUnifiedFont({ id: 'satoshi', name: 'Satoshi', provider: 'fontshare', category: 'sans-serif', subsets: ['latin'], variants: ['regular', 'bold', 'italic', 'bolditalic'] as FontVariant[], features: { isVariable: true, axes: [{ name: 'wght', property: 'wght', default: 400, min: 300, max: 700 }] }, metadata: { popularity: 15000 }, }), generalSans: mockUnifiedFont({ id: 'general-sans', name: 'General Sans', provider: 'fontshare', category: 'sans-serif', subsets: ['latin'], variants: ['regular', 'bold', 'italic', 'bolditalic'] as FontVariant[], features: { isVariable: true }, metadata: { popularity: 12000 }, }), clashDisplay: mockUnifiedFont({ id: 'clash-display', name: 'Clash Display', provider: 'fontshare', category: 'display', subsets: ['latin'], variants: ['regular', '500', '600', 'bold'] as FontVariant[], features: { tags: ['Headlines', 'Posters', 'Branding'] }, metadata: { popularity: 8000 }, }), oswald: mockUnifiedFont({ id: 'oswald', name: 'Oswald', provider: 'google', category: 'sans-serif', subsets: ['latin'], variants: ['200', '300', '400', '500', '600', '700'], metadata: { popularity: 6 }, }), raleway: mockUnifiedFont({ id: 'raleway', name: 'Raleway', provider: 'google', category: 'sans-serif', subsets: ['latin'], variants: ['100', '200', '300', '400', '500', '600', '700', '800', '900'], metadata: { popularity: 7 }, }), }; /** * Get an array of all preset UnifiedFonts */ export function getAllMockFonts(): UnifiedFont[] { return Object.values(UNIFIED_FONTS); } /** * Get fonts by provider */ export function getFontsByProvider(provider: FontProvider): UnifiedFont[] { return getAllMockFonts().filter(font => font.provider === provider); } /** * Get fonts by category */ export function getFontsByCategory(category: FontCategory): UnifiedFont[] { return getAllMockFonts().filter(font => font.category === category); } /** * Generate an array of mock fonts with sequential naming */ export function generateMockFonts(count: number, options?: Omit): UnifiedFont[] { return Array.from({ length: count }, (_, i) => mockUnifiedFont({ ...options, id: `mock-font-${i + 1}`, name: `Mock Font ${i + 1}`, })); } /** * Generate an array of mock fonts with different categories */ export function generateMixedCategoryFonts(countPerCategory: number = 2): UnifiedFont[] { const categories: FontCategory[] = ['sans-serif', 'serif', 'display', 'handwriting', 'monospace']; const fonts: UnifiedFont[] = []; categories.forEach(category => { for (let i = 0; i < countPerCategory; i++) { fonts.push( mockUnifiedFont({ id: `${category}-${i + 1}`, name: `${category.replace('-', ' ')} ${i + 1}`, category, }), ); } }); return fonts; }