reaminig 5-t-9
This commit is contained in:
325
frontend/src/styles/cms/colors.ts
Normal file
325
frontend/src/styles/cms/colors.ts
Normal file
@@ -0,0 +1,325 @@
|
||||
/**
|
||||
* Color Schemes System
|
||||
* Phase 7: CMS Styling System
|
||||
* Color palette management and theme generation
|
||||
*/
|
||||
|
||||
export interface ColorScheme {
|
||||
id: string;
|
||||
name: string;
|
||||
description: string;
|
||||
colors: {
|
||||
primary: ColorPalette;
|
||||
secondary: ColorPalette;
|
||||
accent: ColorPalette;
|
||||
neutral: ColorPalette;
|
||||
semantic: SemanticColors;
|
||||
};
|
||||
}
|
||||
|
||||
export interface ColorPalette {
|
||||
50: string;
|
||||
100: string;
|
||||
200: string;
|
||||
300: string;
|
||||
400: string;
|
||||
500: string;
|
||||
600: string;
|
||||
700: string;
|
||||
800: string;
|
||||
900: string;
|
||||
950: string;
|
||||
}
|
||||
|
||||
export interface SemanticColors {
|
||||
success: string;
|
||||
warning: string;
|
||||
error: string;
|
||||
info: string;
|
||||
}
|
||||
|
||||
export const COLOR_SCHEMES: ColorScheme[] = [
|
||||
{
|
||||
id: 'blue',
|
||||
name: 'Blue',
|
||||
description: 'Professional blue color scheme',
|
||||
colors: {
|
||||
primary: {
|
||||
50: '#eff6ff',
|
||||
100: '#dbeafe',
|
||||
200: '#bfdbfe',
|
||||
300: '#93c5fd',
|
||||
400: '#60a5fa',
|
||||
500: '#3b82f6',
|
||||
600: '#2563eb',
|
||||
700: '#1d4ed8',
|
||||
800: '#1e40af',
|
||||
900: '#1e3a8a',
|
||||
950: '#172554',
|
||||
},
|
||||
secondary: {
|
||||
50: '#f0f9ff',
|
||||
100: '#e0f2fe',
|
||||
200: '#bae6fd',
|
||||
300: '#7dd3fc',
|
||||
400: '#38bdf8',
|
||||
500: '#0ea5e9',
|
||||
600: '#0284c7',
|
||||
700: '#0369a1',
|
||||
800: '#075985',
|
||||
900: '#0c4a6e',
|
||||
950: '#082f49',
|
||||
},
|
||||
accent: {
|
||||
50: '#f0fdf4',
|
||||
100: '#dcfce7',
|
||||
200: '#bbf7d0',
|
||||
300: '#86efac',
|
||||
400: '#4ade80',
|
||||
500: '#22c55e',
|
||||
600: '#16a34a',
|
||||
700: '#15803d',
|
||||
800: '#166534',
|
||||
900: '#14532d',
|
||||
950: '#052e16',
|
||||
},
|
||||
neutral: {
|
||||
50: '#f9fafb',
|
||||
100: '#f3f4f6',
|
||||
200: '#e5e7eb',
|
||||
300: '#d1d5db',
|
||||
400: '#9ca3af',
|
||||
500: '#6b7280',
|
||||
600: '#4b5563',
|
||||
700: '#374151',
|
||||
800: '#1f2937',
|
||||
900: '#111827',
|
||||
950: '#030712',
|
||||
},
|
||||
semantic: {
|
||||
success: '#10b981',
|
||||
warning: '#f59e0b',
|
||||
error: '#ef4444',
|
||||
info: '#3b82f6',
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'purple',
|
||||
name: 'Purple',
|
||||
description: 'Creative purple color scheme',
|
||||
colors: {
|
||||
primary: {
|
||||
50: '#faf5ff',
|
||||
100: '#f3e8ff',
|
||||
200: '#e9d5ff',
|
||||
300: '#d8b4fe',
|
||||
400: '#c084fc',
|
||||
500: '#a855f7',
|
||||
600: '#9333ea',
|
||||
700: '#7e22ce',
|
||||
800: '#6b21a8',
|
||||
900: '#581c87',
|
||||
950: '#3b0764',
|
||||
},
|
||||
secondary: {
|
||||
50: '#fdf4ff',
|
||||
100: '#fae8ff',
|
||||
200: '#f5d0fe',
|
||||
300: '#f0abfc',
|
||||
400: '#e879f9',
|
||||
500: '#d946ef',
|
||||
600: '#c026d3',
|
||||
700: '#a21caf',
|
||||
800: '#86198f',
|
||||
900: '#701a75',
|
||||
950: '#4a044e',
|
||||
},
|
||||
accent: {
|
||||
50: '#fef3c7',
|
||||
100: '#fde68a',
|
||||
200: '#fcd34d',
|
||||
300: '#fbbf24',
|
||||
400: '#f59e0b',
|
||||
500: '#d97706',
|
||||
600: '#b45309',
|
||||
700: '#92400e',
|
||||
800: '#78350f',
|
||||
900: '#451a03',
|
||||
950: '#292524',
|
||||
},
|
||||
neutral: {
|
||||
50: '#f9fafb',
|
||||
100: '#f3f4f6',
|
||||
200: '#e5e7eb',
|
||||
300: '#d1d5db',
|
||||
400: '#9ca3af',
|
||||
500: '#6b7280',
|
||||
600: '#4b5563',
|
||||
700: '#374151',
|
||||
800: '#1f2937',
|
||||
900: '#111827',
|
||||
950: '#030712',
|
||||
},
|
||||
semantic: {
|
||||
success: '#10b981',
|
||||
warning: '#f59e0b',
|
||||
error: '#ef4444',
|
||||
info: '#a855f7',
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'green',
|
||||
name: 'Green',
|
||||
description: 'Natural green color scheme',
|
||||
colors: {
|
||||
primary: {
|
||||
50: '#f0fdf4',
|
||||
100: '#dcfce7',
|
||||
200: '#bbf7d0',
|
||||
300: '#86efac',
|
||||
400: '#4ade80',
|
||||
500: '#22c55e',
|
||||
600: '#16a34a',
|
||||
700: '#15803d',
|
||||
800: '#166534',
|
||||
900: '#14532d',
|
||||
950: '#052e16',
|
||||
},
|
||||
secondary: {
|
||||
50: '#ecfdf5',
|
||||
100: '#d1fae5',
|
||||
200: '#a7f3d0',
|
||||
300: '#6ee7b7',
|
||||
400: '#34d399',
|
||||
500: '#10b981',
|
||||
600: '#059669',
|
||||
700: '#047857',
|
||||
800: '#065f46',
|
||||
900: '#064e3b',
|
||||
950: '#022c22',
|
||||
},
|
||||
accent: {
|
||||
50: '#fef3c7',
|
||||
100: '#fde68a',
|
||||
200: '#fcd34d',
|
||||
300: '#fbbf24',
|
||||
400: '#f59e0b',
|
||||
500: '#d97706',
|
||||
600: '#b45309',
|
||||
700: '#92400e',
|
||||
800: '#78350f',
|
||||
900: '#451a03',
|
||||
950: '#292524',
|
||||
},
|
||||
neutral: {
|
||||
50: '#f9fafb',
|
||||
100: '#f3f4f6',
|
||||
200: '#e5e7eb',
|
||||
300: '#d1d5db',
|
||||
400: '#9ca3af',
|
||||
500: '#6b7280',
|
||||
600: '#4b5563',
|
||||
700: '#374151',
|
||||
800: '#1f2937',
|
||||
900: '#111827',
|
||||
950: '#030712',
|
||||
},
|
||||
semantic: {
|
||||
success: '#22c55e',
|
||||
warning: '#f59e0b',
|
||||
error: '#ef4444',
|
||||
info: '#3b82f6',
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'dark',
|
||||
name: 'Dark',
|
||||
description: 'Dark mode color scheme',
|
||||
colors: {
|
||||
primary: {
|
||||
50: '#18181b',
|
||||
100: '#27272a',
|
||||
200: '#3f3f46',
|
||||
300: '#52525b',
|
||||
400: '#71717a',
|
||||
500: '#a1a1aa',
|
||||
600: '#d4d4d8',
|
||||
700: '#e4e4e7',
|
||||
800: '#f4f4f5',
|
||||
900: '#fafafa',
|
||||
950: '#ffffff',
|
||||
},
|
||||
secondary: {
|
||||
50: '#0f172a',
|
||||
100: '#1e293b',
|
||||
200: '#334155',
|
||||
300: '#475569',
|
||||
400: '#64748b',
|
||||
500: '#94a3b8',
|
||||
600: '#cbd5e1',
|
||||
700: '#e2e8f0',
|
||||
800: '#f1f5f9',
|
||||
900: '#f8fafc',
|
||||
950: '#ffffff',
|
||||
},
|
||||
accent: {
|
||||
50: '#fef3c7',
|
||||
100: '#fde68a',
|
||||
200: '#fcd34d',
|
||||
300: '#fbbf24',
|
||||
400: '#f59e0b',
|
||||
500: '#d97706',
|
||||
600: '#b45309',
|
||||
700: '#92400e',
|
||||
800: '#78350f',
|
||||
900: '#451a03',
|
||||
950: '#292524',
|
||||
},
|
||||
neutral: {
|
||||
50: '#030712',
|
||||
100: '#111827',
|
||||
200: '#1f2937',
|
||||
300: '#374151',
|
||||
400: '#4b5563',
|
||||
500: '#6b7280',
|
||||
600: '#9ca3af',
|
||||
700: '#d1d5db',
|
||||
800: '#e5e7eb',
|
||||
900: '#f3f4f6',
|
||||
950: '#f9fafb',
|
||||
},
|
||||
semantic: {
|
||||
success: '#10b981',
|
||||
warning: '#f59e0b',
|
||||
error: '#ef4444',
|
||||
info: '#3b82f6',
|
||||
},
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
export function getColorScheme(schemeId: string): ColorScheme | undefined {
|
||||
return COLOR_SCHEMES.find((scheme) => scheme.id === schemeId);
|
||||
}
|
||||
|
||||
export function generateCSSVariables(scheme: ColorScheme): string {
|
||||
const vars: string[] = [];
|
||||
|
||||
Object.entries(scheme.colors).forEach(([category, palette]) => {
|
||||
if (category === 'semantic') {
|
||||
Object.entries(palette as SemanticColors).forEach(([name, value]) => {
|
||||
vars.push(`--color-${category}-${name}: ${value};`);
|
||||
});
|
||||
} else {
|
||||
Object.entries(palette as ColorPalette).forEach(([shade, value]) => {
|
||||
vars.push(`--color-${category}-${shade}: ${value};`);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
return `:root {\n ${vars.join('\n ')}\n}`;
|
||||
}
|
||||
|
||||
250
frontend/src/styles/cms/components.ts
Normal file
250
frontend/src/styles/cms/components.ts
Normal file
@@ -0,0 +1,250 @@
|
||||
/**
|
||||
* Component Styles
|
||||
* Phase 7: CMS Styling System
|
||||
* Reusable component style definitions
|
||||
*/
|
||||
|
||||
export interface ComponentStyles {
|
||||
button: ButtonStyles;
|
||||
card: CardStyles;
|
||||
input: InputStyles;
|
||||
heading: HeadingStyles;
|
||||
link: LinkStyles;
|
||||
}
|
||||
|
||||
export interface ButtonStyles {
|
||||
primary: ButtonVariant;
|
||||
secondary: ButtonVariant;
|
||||
outline: ButtonVariant;
|
||||
ghost: ButtonVariant;
|
||||
}
|
||||
|
||||
export interface ButtonVariant {
|
||||
background: string;
|
||||
color: string;
|
||||
border?: string;
|
||||
hover: {
|
||||
background: string;
|
||||
color: string;
|
||||
border?: string;
|
||||
};
|
||||
active: {
|
||||
background: string;
|
||||
color: string;
|
||||
};
|
||||
}
|
||||
|
||||
export interface CardStyles {
|
||||
background: string;
|
||||
border: string;
|
||||
borderRadius: string;
|
||||
padding: string;
|
||||
shadow: string;
|
||||
}
|
||||
|
||||
export interface InputStyles {
|
||||
background: string;
|
||||
border: string;
|
||||
borderRadius: string;
|
||||
padding: string;
|
||||
focus: {
|
||||
border: string;
|
||||
ring: string;
|
||||
};
|
||||
}
|
||||
|
||||
export interface HeadingStyles {
|
||||
fontFamily: string;
|
||||
fontWeight: string;
|
||||
lineHeight: string;
|
||||
color: string;
|
||||
}
|
||||
|
||||
export interface LinkStyles {
|
||||
color: string;
|
||||
hoverColor: string;
|
||||
underline: boolean;
|
||||
}
|
||||
|
||||
export const DEFAULT_COMPONENT_STYLES: ComponentStyles = {
|
||||
button: {
|
||||
primary: {
|
||||
background: '#3b82f6',
|
||||
color: '#ffffff',
|
||||
hover: {
|
||||
background: '#2563eb',
|
||||
color: '#ffffff',
|
||||
},
|
||||
active: {
|
||||
background: '#1d4ed8',
|
||||
color: '#ffffff',
|
||||
},
|
||||
},
|
||||
secondary: {
|
||||
background: '#6b7280',
|
||||
color: '#ffffff',
|
||||
hover: {
|
||||
background: '#4b5563',
|
||||
color: '#ffffff',
|
||||
},
|
||||
active: {
|
||||
background: '#374151',
|
||||
color: '#ffffff',
|
||||
},
|
||||
},
|
||||
outline: {
|
||||
background: 'transparent',
|
||||
color: '#3b82f6',
|
||||
border: '#3b82f6',
|
||||
hover: {
|
||||
background: '#3b82f6',
|
||||
color: '#ffffff',
|
||||
border: '#3b82f6',
|
||||
},
|
||||
active: {
|
||||
background: '#2563eb',
|
||||
color: '#ffffff',
|
||||
},
|
||||
},
|
||||
ghost: {
|
||||
background: 'transparent',
|
||||
color: '#6b7280',
|
||||
hover: {
|
||||
background: '#f3f4f6',
|
||||
color: '#1f2937',
|
||||
},
|
||||
active: {
|
||||
background: '#e5e7eb',
|
||||
color: '#111827',
|
||||
},
|
||||
},
|
||||
},
|
||||
card: {
|
||||
background: '#ffffff',
|
||||
border: '#e5e7eb',
|
||||
borderRadius: '0.5rem',
|
||||
padding: '1.5rem',
|
||||
shadow: '0 1px 3px 0 rgba(0, 0, 0, 0.1)',
|
||||
},
|
||||
input: {
|
||||
background: '#ffffff',
|
||||
border: '#d1d5db',
|
||||
borderRadius: '0.375rem',
|
||||
padding: '0.5rem 0.75rem',
|
||||
focus: {
|
||||
border: '#3b82f6',
|
||||
ring: '0 0 0 3px rgba(59, 130, 246, 0.1)',
|
||||
},
|
||||
},
|
||||
heading: {
|
||||
fontFamily: 'Inter, system-ui, sans-serif',
|
||||
fontWeight: '700',
|
||||
lineHeight: '1.2',
|
||||
color: '#111827',
|
||||
},
|
||||
link: {
|
||||
color: '#3b82f6',
|
||||
hoverColor: '#2563eb',
|
||||
underline: false,
|
||||
},
|
||||
};
|
||||
|
||||
export function generateComponentCSS(styles: ComponentStyles): string {
|
||||
return `
|
||||
/* Button Styles */
|
||||
.btn-primary {
|
||||
background-color: ${styles.button.primary.background};
|
||||
color: ${styles.button.primary.color};
|
||||
}
|
||||
|
||||
.btn-primary:hover {
|
||||
background-color: ${styles.button.primary.hover.background};
|
||||
color: ${styles.button.primary.hover.color};
|
||||
}
|
||||
|
||||
.btn-secondary {
|
||||
background-color: ${styles.button.secondary.background};
|
||||
color: ${styles.button.secondary.color};
|
||||
}
|
||||
|
||||
.btn-outline {
|
||||
background-color: ${styles.button.outline.background};
|
||||
color: ${styles.button.outline.color};
|
||||
border: 1px solid ${styles.button.outline.border};
|
||||
}
|
||||
|
||||
.btn-outline:hover {
|
||||
background-color: ${styles.button.outline.hover.background};
|
||||
color: ${styles.button.outline.hover.color};
|
||||
}
|
||||
|
||||
/* Card Styles */
|
||||
.card {
|
||||
background-color: ${styles.card.background};
|
||||
border: 1px solid ${styles.card.border};
|
||||
border-radius: ${styles.card.borderRadius};
|
||||
padding: ${styles.card.padding};
|
||||
box-shadow: ${styles.card.shadow};
|
||||
}
|
||||
|
||||
/* Input Styles */
|
||||
.input {
|
||||
background-color: ${styles.input.background};
|
||||
border: 1px solid ${styles.input.border};
|
||||
border-radius: ${styles.input.borderRadius};
|
||||
padding: ${styles.input.padding};
|
||||
}
|
||||
|
||||
.input:focus {
|
||||
border-color: ${styles.input.focus.border};
|
||||
box-shadow: ${styles.input.focus.ring};
|
||||
outline: none;
|
||||
}
|
||||
|
||||
/* Heading Styles */
|
||||
h1, h2, h3, h4, h5, h6 {
|
||||
font-family: ${styles.heading.fontFamily};
|
||||
font-weight: ${styles.heading.fontWeight};
|
||||
line-height: ${styles.heading.lineHeight};
|
||||
color: ${styles.heading.color};
|
||||
}
|
||||
|
||||
/* Link Styles */
|
||||
a {
|
||||
color: ${styles.link.color};
|
||||
text-decoration: ${styles.link.underline ? 'underline' : 'none'};
|
||||
}
|
||||
|
||||
a:hover {
|
||||
color: ${styles.link.hoverColor};
|
||||
}
|
||||
`.trim();
|
||||
}
|
||||
|
||||
export function applyComponentStyles(styles: Partial<ComponentStyles>): ComponentStyles {
|
||||
return {
|
||||
...DEFAULT_COMPONENT_STYLES,
|
||||
...styles,
|
||||
button: {
|
||||
...DEFAULT_COMPONENT_STYLES.button,
|
||||
...styles.button,
|
||||
},
|
||||
card: {
|
||||
...DEFAULT_COMPONENT_STYLES.card,
|
||||
...styles.card,
|
||||
},
|
||||
input: {
|
||||
...DEFAULT_COMPONENT_STYLES.input,
|
||||
...styles.input,
|
||||
},
|
||||
heading: {
|
||||
...DEFAULT_COMPONENT_STYLES.heading,
|
||||
...styles.heading,
|
||||
},
|
||||
link: {
|
||||
...DEFAULT_COMPONENT_STYLES.link,
|
||||
...styles.link,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
11
frontend/src/styles/cms/index.ts
Normal file
11
frontend/src/styles/cms/index.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
/**
|
||||
* CMS Theme System
|
||||
* Phase 7: CMS Styling System
|
||||
* Central export for CMS theme system
|
||||
*/
|
||||
|
||||
export * from './presets';
|
||||
export * from './colors';
|
||||
export * from './typography';
|
||||
export * from './components';
|
||||
|
||||
181
frontend/src/styles/cms/presets.ts
Normal file
181
frontend/src/styles/cms/presets.ts
Normal file
@@ -0,0 +1,181 @@
|
||||
/**
|
||||
* Style Presets
|
||||
* Phase 7: CMS Styling System
|
||||
* Predefined style presets for quick theme application
|
||||
*/
|
||||
|
||||
export interface StylePreset {
|
||||
id: string;
|
||||
name: string;
|
||||
description: string;
|
||||
colors: {
|
||||
primary: string;
|
||||
secondary: string;
|
||||
accent: string;
|
||||
background: string;
|
||||
text: string;
|
||||
border: string;
|
||||
};
|
||||
typography: {
|
||||
fontFamily: string;
|
||||
headingFont: string;
|
||||
fontSize: string;
|
||||
lineHeight: string;
|
||||
};
|
||||
spacing: {
|
||||
base: string;
|
||||
scale: string;
|
||||
};
|
||||
}
|
||||
|
||||
export const STYLE_PRESETS: StylePreset[] = [
|
||||
{
|
||||
id: 'modern',
|
||||
name: 'Modern',
|
||||
description: 'Clean, contemporary design with vibrant colors',
|
||||
colors: {
|
||||
primary: '#3b82f6',
|
||||
secondary: '#8b5cf6',
|
||||
accent: '#10b981',
|
||||
background: '#ffffff',
|
||||
text: '#1f2937',
|
||||
border: '#e5e7eb',
|
||||
},
|
||||
typography: {
|
||||
fontFamily: 'Inter, system-ui, sans-serif',
|
||||
headingFont: 'Inter, system-ui, sans-serif',
|
||||
fontSize: '16px',
|
||||
lineHeight: '1.6',
|
||||
},
|
||||
spacing: {
|
||||
base: '8px',
|
||||
scale: '1.5',
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'classic',
|
||||
name: 'Classic',
|
||||
description: 'Traditional, professional design',
|
||||
colors: {
|
||||
primary: '#1e40af',
|
||||
secondary: '#6b7280',
|
||||
accent: '#059669',
|
||||
background: '#f9fafb',
|
||||
text: '#111827',
|
||||
border: '#d1d5db',
|
||||
},
|
||||
typography: {
|
||||
fontFamily: 'Georgia, serif',
|
||||
headingFont: 'Georgia, serif',
|
||||
fontSize: '18px',
|
||||
lineHeight: '1.7',
|
||||
},
|
||||
spacing: {
|
||||
base: '10px',
|
||||
scale: '1.618',
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'minimal',
|
||||
name: 'Minimal',
|
||||
description: 'Minimalist design with ample whitespace',
|
||||
colors: {
|
||||
primary: '#000000',
|
||||
secondary: '#4b5563',
|
||||
accent: '#6b7280',
|
||||
background: '#ffffff',
|
||||
text: '#111827',
|
||||
border: '#f3f4f6',
|
||||
},
|
||||
typography: {
|
||||
fontFamily: 'Helvetica, Arial, sans-serif',
|
||||
headingFont: 'Helvetica, Arial, sans-serif',
|
||||
fontSize: '16px',
|
||||
lineHeight: '1.8',
|
||||
},
|
||||
spacing: {
|
||||
base: '12px',
|
||||
scale: '2',
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'bold',
|
||||
name: 'Bold',
|
||||
description: 'High contrast, bold design',
|
||||
colors: {
|
||||
primary: '#dc2626',
|
||||
secondary: '#ea580c',
|
||||
accent: '#f59e0b',
|
||||
background: '#ffffff',
|
||||
text: '#000000',
|
||||
border: '#000000',
|
||||
},
|
||||
typography: {
|
||||
fontFamily: 'Arial Black, sans-serif',
|
||||
headingFont: 'Arial Black, sans-serif',
|
||||
fontSize: '16px',
|
||||
lineHeight: '1.5',
|
||||
},
|
||||
spacing: {
|
||||
base: '8px',
|
||||
scale: '1.25',
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'elegant',
|
||||
name: 'Elegant',
|
||||
description: 'Sophisticated, refined design',
|
||||
colors: {
|
||||
primary: '#7c3aed',
|
||||
secondary: '#a855f7',
|
||||
accent: '#ec4899',
|
||||
background: '#faf5ff',
|
||||
text: '#1e1b4b',
|
||||
border: '#e9d5ff',
|
||||
},
|
||||
typography: {
|
||||
fontFamily: 'Playfair Display, serif',
|
||||
headingFont: 'Playfair Display, serif',
|
||||
fontSize: '17px',
|
||||
lineHeight: '1.75',
|
||||
},
|
||||
spacing: {
|
||||
base: '10px',
|
||||
scale: '1.618',
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'tech',
|
||||
name: 'Tech',
|
||||
description: 'Modern tech startup aesthetic',
|
||||
colors: {
|
||||
primary: '#06b6d4',
|
||||
secondary: '#3b82f6',
|
||||
accent: '#8b5cf6',
|
||||
background: '#0f172a',
|
||||
text: '#f1f5f9',
|
||||
border: '#1e293b',
|
||||
},
|
||||
typography: {
|
||||
fontFamily: 'SF Pro Display, system-ui, sans-serif',
|
||||
headingFont: 'SF Pro Display, system-ui, sans-serif',
|
||||
fontSize: '16px',
|
||||
lineHeight: '1.6',
|
||||
},
|
||||
spacing: {
|
||||
base: '8px',
|
||||
scale: '1.5',
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
export function getPreset(presetId: string): StylePreset | undefined {
|
||||
return STYLE_PRESETS.find((preset) => preset.id === presetId);
|
||||
}
|
||||
|
||||
export function applyPreset(presetId: string): StylePreset | null {
|
||||
const preset = getPreset(presetId);
|
||||
if (!preset) return null;
|
||||
return preset;
|
||||
}
|
||||
|
||||
181
frontend/src/styles/cms/typography.ts
Normal file
181
frontend/src/styles/cms/typography.ts
Normal file
@@ -0,0 +1,181 @@
|
||||
/**
|
||||
* 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();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user