/** * Typography System * Phase 7: CMS Styling System * Typography scale, font families, and text styles */ export interface TypographyScale { xs: string; sm: string; base: string; lg: string; xl: string; '2xl': string; '3xl': string; '4xl': string; '5xl': string; '6xl': string; } export interface TypographyConfig { fontFamilies: { sans: string[]; serif: string[]; mono: string[]; display: string[]; }; fontSizes: TypographyScale; lineHeights: TypographyScale; fontWeights: { light: number; normal: number; medium: number; semibold: number; bold: number; extrabold: number; }; letterSpacing: { tighter: string; tight: string; normal: string; wide: string; wider: string; widest: string; }; } export const TYPOGRAPHY_CONFIG: TypographyConfig = { fontFamilies: { sans: ['Inter', 'system-ui', '-apple-system', 'BlinkMacSystemFont', 'Segoe UI', 'Roboto', 'sans-serif'], serif: ['Georgia', 'Cambria', 'Times New Roman', 'Times', 'serif'], mono: ['Menlo', 'Monaco', 'Consolas', 'Liberation Mono', 'Courier New', 'monospace'], display: ['Inter', 'system-ui', 'sans-serif'], }, fontSizes: { xs: '0.75rem', // 12px sm: '0.875rem', // 14px base: '1rem', // 16px lg: '1.125rem', // 18px xl: '1.25rem', // 20px '2xl': '1.5rem', // 24px '3xl': '1.875rem', // 30px '4xl': '2.25rem', // 36px '5xl': '3rem', // 48px '6xl': '3.75rem', // 60px }, lineHeights: { xs: '1rem', sm: '1.25rem', base: '1.5rem', lg: '1.75rem', xl: '2rem', '2xl': '2.25rem', '3xl': '2.5rem', '4xl': '2.75rem', '5xl': '1', '6xl': '1', }, fontWeights: { light: 300, normal: 400, medium: 500, semibold: 600, bold: 700, extrabold: 800, }, letterSpacing: { tighter: '-0.05em', tight: '-0.025em', normal: '0em', wide: '0.025em', wider: '0.05em', widest: '0.1em', }, }; export interface TypographyPreset { id: string; name: string; description: string; headingFont: string; bodyFont: string; baseSize: string; lineHeight: string; } export const TYPOGRAPHY_PRESETS: TypographyPreset[] = [ { id: 'modern', name: 'Modern Sans', description: 'Clean, modern sans-serif typography', headingFont: 'Inter, system-ui, sans-serif', bodyFont: 'Inter, system-ui, sans-serif', baseSize: '16px', lineHeight: '1.6', }, { id: 'classic', name: 'Classic Serif', description: 'Traditional serif typography', headingFont: 'Georgia, serif', bodyFont: 'Georgia, serif', baseSize: '18px', lineHeight: '1.7', }, { id: 'editorial', name: 'Editorial', description: 'Magazine-style typography', headingFont: 'Playfair Display, serif', bodyFont: 'Lora, serif', baseSize: '17px', lineHeight: '1.75', }, { id: 'minimal', name: 'Minimal', description: 'Minimalist typography with high readability', headingFont: 'Helvetica, Arial, sans-serif', bodyFont: 'Helvetica, Arial, sans-serif', baseSize: '16px', lineHeight: '1.8', }, { id: 'tech', name: 'Tech', description: 'Modern tech typography', headingFont: 'SF Pro Display, system-ui, sans-serif', bodyFont: 'SF Pro Text, system-ui, sans-serif', baseSize: '16px', lineHeight: '1.6', }, ]; export function getTypographyPreset(presetId: string): TypographyPreset | undefined { return TYPOGRAPHY_PRESETS.find((preset) => preset.id === presetId); } export function generateTypographyCSS(config: TypographyConfig, preset?: TypographyPreset): string { const headingFont = preset?.headingFont || config.fontFamilies.display.join(', '); const bodyFont = preset?.bodyFont || config.fontFamilies.sans.join(', '); const baseSize = preset?.baseSize || config.fontSizes.base; const lineHeight = preset?.lineHeight || config.lineHeights.base; return ` :root { --font-heading: ${headingFont}; --font-body: ${bodyFont}; --font-size-base: ${baseSize}; --line-height-base: ${lineHeight}; ${Object.entries(config.fontSizes) .map(([key, value]) => `--font-size-${key}: ${value};`) .join('\n ')} ${Object.entries(config.fontWeights) .map(([key, value]) => `--font-weight-${key}: ${value};`) .join('\n ')} } `.trim(); }