182 lines
4.3 KiB
TypeScript
182 lines
4.3 KiB
TypeScript
/**
|
|
* 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();
|
|
}
|
|
|