This commit implements a complete brand system overhaul including: TYPOGRAPHY SYSTEM: - Add Exo font family (Thin, Light, Regular, ExtraLight) as primary brand font - Implement SF Pro Display/Text hierarchy for UI components - Create comprehensive Typography component with all brand variants - Update all components to use new typography tokens DESIGN TOKEN SYSTEM: - Create complete design token system in theme/designTokens.ts - Define Carbon Black (#1a1a1a), Walnut Brown (#8B4513), Brushed Aluminum (#A8A8A8) palette - Implement CSS custom properties for consistent theming - Update Ant Design theme integration COMPONENT UPDATES: - Enhance Hero section with Exo Thin typography and improved layout - Update navigation with SF Pro font hierarchy - Redesign Button component with new variants and accessibility - Apply brand colors and typography across all showcase sections - Improve Footer with consistent brand application PERFORMANCE & ACCESSIBILITY: - Self-host Exo fonts for optimal loading performance - Implement proper font-display strategies - Add comprehensive accessibility audit documentation - Include responsive testing verification DOCUMENTATION: - Add brand system demo and implementation guides - Include QA testing reports and accessibility audits - Document design token usage and component patterns 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
423 lines
11 KiB
TypeScript
423 lines
11 KiB
TypeScript
'use client';
|
|
|
|
import React from 'react';
|
|
import { Typography as AntTypography } from 'antd';
|
|
import { designTokens } from '../../theme/designTokens';
|
|
|
|
const { Title, Paragraph, Text } = AntTypography;
|
|
|
|
// =============================================================================
|
|
// TYPOGRAPHY COMPONENT INTERFACES
|
|
// =============================================================================
|
|
|
|
interface BaseTypographyProps {
|
|
children: React.ReactNode;
|
|
className?: string;
|
|
style?: React.CSSProperties;
|
|
id?: string;
|
|
}
|
|
|
|
interface HeadingProps extends BaseTypographyProps {
|
|
level?: 1 | 2 | 3 | 4 | 5;
|
|
color?: 'primary' | 'secondary' | 'tertiary' | 'inverse';
|
|
gradient?: boolean;
|
|
}
|
|
|
|
interface BodyTextProps extends BaseTypographyProps {
|
|
size?: 'large' | 'regular' | 'small';
|
|
color?: 'primary' | 'secondary' | 'tertiary' | 'disabled' | 'inverse';
|
|
weight?: 'light' | 'regular' | 'medium' | 'semibold' | 'bold';
|
|
}
|
|
|
|
interface CodeTextProps extends BaseTypographyProps {
|
|
inline?: boolean;
|
|
language?: string;
|
|
}
|
|
|
|
interface ButtonTextProps extends BaseTypographyProps {
|
|
size?: 'small' | 'regular' | 'large';
|
|
}
|
|
|
|
// =============================================================================
|
|
// HERO DISPLAY TYPOGRAPHY
|
|
// =============================================================================
|
|
|
|
export const HeroDisplay: React.FC<HeadingProps> = ({
|
|
children,
|
|
className = '',
|
|
style = {},
|
|
color = 'primary',
|
|
gradient = false,
|
|
...props
|
|
}) => {
|
|
const colorMap = {
|
|
primary: 'var(--text-primary)',
|
|
secondary: 'var(--text-secondary)',
|
|
tertiary: 'var(--text-tertiary)',
|
|
inverse: 'var(--text-inverse)',
|
|
};
|
|
|
|
const heroStyles: React.CSSProperties = {
|
|
fontFamily: 'var(--font-display)',
|
|
fontSize: 'var(--text-hero)',
|
|
fontWeight: 100, // Exo Thin
|
|
lineHeight: 'var(--leading-tight)',
|
|
letterSpacing: 'var(--tracking-tight)',
|
|
color: gradient ? 'transparent' : colorMap[color],
|
|
background: gradient ? 'linear-gradient(135deg, var(--color-primary) 0%, var(--color-success) 100%)' : 'none',
|
|
WebkitBackgroundClip: gradient ? 'text' : 'initial',
|
|
backgroundClip: gradient ? 'text' : 'initial',
|
|
margin: 0,
|
|
...style,
|
|
};
|
|
|
|
return (
|
|
<h1
|
|
className={`text-hero ${gradient ? 'text-gradient' : ''} ${className}`}
|
|
style={heroStyles}
|
|
{...props}
|
|
>
|
|
{children}
|
|
</h1>
|
|
);
|
|
};
|
|
|
|
// =============================================================================
|
|
// DISPLAY TYPOGRAPHY HIERARCHY
|
|
// =============================================================================
|
|
|
|
export const DisplayHeading: React.FC<HeadingProps> = ({
|
|
children,
|
|
level = 1,
|
|
className = '',
|
|
style = {},
|
|
color = 'primary',
|
|
gradient = false,
|
|
...props
|
|
}) => {
|
|
const colorMap = {
|
|
primary: 'var(--text-primary)',
|
|
secondary: 'var(--text-secondary)',
|
|
tertiary: 'var(--text-tertiary)',
|
|
inverse: 'var(--text-inverse)',
|
|
};
|
|
|
|
const levelStyles = {
|
|
1: {
|
|
fontSize: 'var(--text-display-1)',
|
|
fontWeight: 200, // Exo ExtraLight
|
|
lineHeight: 'var(--leading-snug)',
|
|
},
|
|
2: {
|
|
fontSize: 'var(--text-display-2)',
|
|
fontWeight: 300, // Exo Light
|
|
lineHeight: 'var(--leading-normal)',
|
|
},
|
|
3: {
|
|
fontSize: 'clamp(20px, 3vw, 28px)',
|
|
fontWeight: 400, // Exo Regular
|
|
lineHeight: 'var(--leading-normal)',
|
|
},
|
|
4: {
|
|
fontSize: 'clamp(18px, 2.5vw, 24px)',
|
|
fontWeight: 400,
|
|
lineHeight: 'var(--leading-normal)',
|
|
},
|
|
5: {
|
|
fontSize: 'clamp(16px, 2vw, 20px)',
|
|
fontWeight: 500,
|
|
lineHeight: 'var(--leading-normal)',
|
|
},
|
|
};
|
|
|
|
const displayStyles: React.CSSProperties = {
|
|
fontFamily: 'var(--font-display)',
|
|
color: gradient ? 'transparent' : colorMap[color],
|
|
background: gradient ? 'linear-gradient(135deg, var(--color-primary) 0%, var(--color-success) 100%)' : 'none',
|
|
WebkitBackgroundClip: gradient ? 'text' : 'initial',
|
|
backgroundClip: gradient ? 'text' : 'initial',
|
|
letterSpacing: 'var(--tracking-snug)',
|
|
margin: 0,
|
|
...levelStyles[level],
|
|
...style,
|
|
};
|
|
|
|
const Tag = `h${level}` as keyof JSX.IntrinsicElements;
|
|
|
|
return (
|
|
<Tag
|
|
className={`text-display-${level} ${gradient ? 'text-gradient' : ''} ${className}`}
|
|
style={displayStyles}
|
|
{...props}
|
|
>
|
|
{children}
|
|
</Tag>
|
|
);
|
|
};
|
|
|
|
// =============================================================================
|
|
// INTERFACE TYPOGRAPHY
|
|
// =============================================================================
|
|
|
|
export const InterfaceText: React.FC<BodyTextProps> = ({
|
|
children,
|
|
size = 'regular',
|
|
className = '',
|
|
style = {},
|
|
color = 'primary',
|
|
weight = 'medium',
|
|
...props
|
|
}) => {
|
|
const colorMap = {
|
|
primary: 'var(--text-primary)',
|
|
secondary: 'var(--text-secondary)',
|
|
tertiary: 'var(--text-tertiary)',
|
|
disabled: 'var(--text-disabled)',
|
|
inverse: 'var(--text-inverse)',
|
|
};
|
|
|
|
const sizeMap = {
|
|
small: 'var(--text-interface-small)',
|
|
regular: 'var(--text-interface)',
|
|
large: 'var(--text-interface)',
|
|
};
|
|
|
|
const weightMap = {
|
|
light: 300,
|
|
regular: 400,
|
|
medium: 500,
|
|
semibold: 600,
|
|
bold: 700,
|
|
};
|
|
|
|
const interfaceStyles: React.CSSProperties = {
|
|
fontFamily: 'var(--font-interface)',
|
|
fontSize: sizeMap[size],
|
|
fontWeight: weightMap[weight],
|
|
lineHeight: 'var(--leading-normal)',
|
|
letterSpacing: size === 'small' ? 'var(--tracking-wider)' : 'var(--tracking-wide)',
|
|
color: colorMap[color],
|
|
margin: 0,
|
|
...style,
|
|
};
|
|
|
|
return (
|
|
<span
|
|
className={`text-interface ${className}`}
|
|
style={interfaceStyles}
|
|
{...props}
|
|
>
|
|
{children}
|
|
</span>
|
|
);
|
|
};
|
|
|
|
// =============================================================================
|
|
// BODY TYPOGRAPHY
|
|
// =============================================================================
|
|
|
|
export const BodyText: React.FC<BodyTextProps> = ({
|
|
children,
|
|
size = 'regular',
|
|
className = '',
|
|
style = {},
|
|
color = 'primary',
|
|
weight = 'regular',
|
|
...props
|
|
}) => {
|
|
const colorMap = {
|
|
primary: 'var(--text-primary)',
|
|
secondary: 'var(--text-secondary)',
|
|
tertiary: 'var(--text-tertiary)',
|
|
disabled: 'var(--text-disabled)',
|
|
inverse: 'var(--text-inverse)',
|
|
};
|
|
|
|
const sizeMap = {
|
|
large: 'var(--text-body-large)',
|
|
regular: 'var(--text-body)',
|
|
small: 'var(--text-body-small)',
|
|
};
|
|
|
|
const weightMap = {
|
|
light: 300,
|
|
regular: 400,
|
|
medium: 500,
|
|
semibold: 600,
|
|
bold: 700,
|
|
};
|
|
|
|
const lineHeightMap = {
|
|
large: 'var(--leading-reading)',
|
|
regular: 'var(--leading-loose)',
|
|
small: 'var(--leading-relaxed)',
|
|
};
|
|
|
|
const bodyStyles: React.CSSProperties = {
|
|
fontFamily: 'var(--font-body)',
|
|
fontSize: sizeMap[size],
|
|
fontWeight: weightMap[weight],
|
|
lineHeight: lineHeightMap[size],
|
|
letterSpacing: size === 'small' ? 'var(--tracking-wide)' : 'var(--tracking-normal)',
|
|
color: colorMap[color],
|
|
margin: 0,
|
|
...style,
|
|
};
|
|
|
|
return (
|
|
<p
|
|
className={`text-body text-body-${size} ${className}`}
|
|
style={bodyStyles}
|
|
{...props}
|
|
>
|
|
{children}
|
|
</p>
|
|
);
|
|
};
|
|
|
|
// =============================================================================
|
|
// CODE TYPOGRAPHY
|
|
// =============================================================================
|
|
|
|
export const CodeText: React.FC<CodeTextProps> = ({
|
|
children,
|
|
inline = false,
|
|
className = '',
|
|
style = {},
|
|
language,
|
|
...props
|
|
}) => {
|
|
const codeStyles: React.CSSProperties = {
|
|
fontFamily: 'var(--font-mono)',
|
|
fontSize: inline ? '0.9em' : 'var(--text-code)',
|
|
lineHeight: 'var(--leading-relaxed)',
|
|
letterSpacing: 'var(--tracking-normal)',
|
|
color: 'var(--text-primary)',
|
|
backgroundColor: inline ? 'var(--bg-tertiary)' : 'var(--bg-secondary)',
|
|
padding: inline ? '2px 6px' : 'var(--space-md)',
|
|
borderRadius: inline ? '4px' : 'var(--radius-md)',
|
|
border: inline ? '1px solid var(--border-secondary)' : 'none',
|
|
margin: 0,
|
|
...style,
|
|
};
|
|
|
|
if (inline) {
|
|
return (
|
|
<code
|
|
className={`text-code ${className}`}
|
|
style={codeStyles}
|
|
{...props}
|
|
>
|
|
{children}
|
|
</code>
|
|
);
|
|
}
|
|
|
|
return (
|
|
<pre
|
|
className={`text-code ${className}`}
|
|
style={{
|
|
...codeStyles,
|
|
display: 'block',
|
|
overflow: 'auto',
|
|
whiteSpace: 'pre-wrap',
|
|
}}
|
|
{...props}
|
|
>
|
|
<code>{children}</code>
|
|
</pre>
|
|
);
|
|
};
|
|
|
|
// =============================================================================
|
|
// BUTTON TYPOGRAPHY
|
|
// =============================================================================
|
|
|
|
export const ButtonText: React.FC<ButtonTextProps> = ({
|
|
children,
|
|
size = 'regular',
|
|
className = '',
|
|
style = {},
|
|
...props
|
|
}) => {
|
|
const sizeMap = {
|
|
small: 'var(--text-interface-small)',
|
|
regular: 'var(--text-interface)',
|
|
large: 'var(--text-interface)',
|
|
};
|
|
|
|
const buttonStyles: React.CSSProperties = {
|
|
fontFamily: 'var(--font-body)',
|
|
fontSize: sizeMap[size],
|
|
fontWeight: 600,
|
|
lineHeight: 'var(--leading-tight)',
|
|
letterSpacing: 'var(--tracking-wider)',
|
|
margin: 0,
|
|
...style,
|
|
};
|
|
|
|
return (
|
|
<span
|
|
className={`text-button ${className}`}
|
|
style={buttonStyles}
|
|
{...props}
|
|
>
|
|
{children}
|
|
</span>
|
|
);
|
|
};
|
|
|
|
// =============================================================================
|
|
// UTILITY COMPONENTS
|
|
// =============================================================================
|
|
|
|
export const Gradient: React.FC<BaseTypographyProps> = ({
|
|
children,
|
|
className = '',
|
|
style = {},
|
|
...props
|
|
}) => {
|
|
const gradientStyles: React.CSSProperties = {
|
|
background: 'linear-gradient(135deg, var(--color-primary) 0%, var(--color-success) 100%)',
|
|
WebkitBackgroundClip: 'text',
|
|
backgroundClip: 'text',
|
|
color: 'transparent',
|
|
backgroundSize: '200% 200%',
|
|
animation: 'gradient-shift 5s ease-in-out infinite',
|
|
...style,
|
|
};
|
|
|
|
return (
|
|
<span
|
|
className={`text-gradient ${className}`}
|
|
style={gradientStyles}
|
|
{...props}
|
|
>
|
|
{children}
|
|
</span>
|
|
);
|
|
};
|
|
|
|
// =============================================================================
|
|
// COMPOUND COMPONENTS
|
|
// =============================================================================
|
|
|
|
export const Typography = {
|
|
Hero: HeroDisplay,
|
|
Display: DisplayHeading,
|
|
Interface: InterfaceText,
|
|
Body: BodyText,
|
|
Code: CodeText,
|
|
Button: ButtonText,
|
|
Gradient,
|
|
|
|
// Legacy compatibility with existing components
|
|
H1: (props: HeadingProps) => <DisplayHeading level={1} {...props} />,
|
|
H2: (props: HeadingProps) => <DisplayHeading level={2} {...props} />,
|
|
H3: (props: HeadingProps) => <DisplayHeading level={3} {...props} />,
|
|
H4: (props: HeadingProps) => <DisplayHeading level={4} {...props} />,
|
|
H5: (props: HeadingProps) => <DisplayHeading level={5} {...props} />,
|
|
P: (props: BodyTextProps) => <BodyText {...props} />,
|
|
};
|
|
|
|
export default Typography; |