Files
anthonyrawlins 7774d7ec98 feat(brand-system): Implement comprehensive CHORUS brand system with typography and design tokens
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>
2025-08-02 22:12:42 +10:00

488 lines
15 KiB
TypeScript

'use client';
import React, { useEffect, useRef, useState } from 'react';
import { motion, useScroll, useTransform, useSpring, useInView } from 'framer-motion';
import { Space } from 'antd';
import { PlayIcon, ArrowRightIcon, ChevronDownIcon } from 'lucide-react';
import { PrimaryButton, SecondaryButton } from '@/components/ui/Button';
import { Typography } from '@/components/ui/Typography';
import { useReducedMotion } from '@/hooks/useReducedMotion';
interface ParallaxLayerProps {
children: React.ReactNode;
speed: number;
className?: string;
}
const ParallaxLayer: React.FC<ParallaxLayerProps> = ({ children, speed, className = '' }) => {
const { scrollY } = useScroll();
const prefersReducedMotion = useReducedMotion();
const y = useTransform(scrollY, [0, 1000], [0, prefersReducedMotion ? 0 : speed * 100]);
const smoothY = useSpring(y, { stiffness: 100, damping: 30 });
return (
<motion.div
className={`${className} will-change-transform gpu-accelerated`}
style={{ y: prefersReducedMotion ? 0 : smoothY }}
>
{children}
</motion.div>
);
};
const FloatingElement: React.FC<{ delay: number; children: React.ReactNode }> = ({ delay, children }) => {
const prefersReducedMotion = useReducedMotion();
return (
<motion.div
className="will-change-transform gpu-accelerated"
animate={prefersReducedMotion ? {} : {
y: [-10, 10, -10],
rotate: [-2, 2, -2],
}}
transition={{
duration: prefersReducedMotion ? 0 : 6,
delay: prefersReducedMotion ? 0 : delay,
repeat: prefersReducedMotion ? 0 : Infinity,
ease: "easeInOut",
}}
>
{children}
</motion.div>
);
};
const GeometricPattern: React.FC = () => {
const [mousePosition, setMousePosition] = useState({ x: 0, y: 0 });
const prefersReducedMotion = useReducedMotion();
const heroRef = useRef<HTMLDivElement>(null);
useEffect(() => {
const handleMouseMove = (e: MouseEvent) => {
if (heroRef.current && !prefersReducedMotion) {
const rect = heroRef.current.getBoundingClientRect();
setMousePosition({
x: (e.clientX - rect.left) / rect.width,
y: (e.clientY - rect.top) / rect.height,
});
}
};
const heroElement = heroRef.current;
if (heroElement) {
heroElement.addEventListener('mousemove', handleMouseMove);
return () => {
heroElement.removeEventListener('mousemove', handleMouseMove);
};
}
}, [prefersReducedMotion]);
return (
<div ref={heroRef} className="absolute inset-0 overflow-hidden pointer-events-none" aria-hidden="true">
{/* Enhanced animated gradient background */}
<motion.div
className="absolute inset-0 opacity-30"
animate={prefersReducedMotion ? {} : {
background: [
'radial-gradient(circle at 20% 50%, rgba(0, 122, 255, 0.15) 0%, transparent 50%)',
'radial-gradient(circle at 80% 20%, rgba(48, 209, 88, 0.15) 0%, transparent 50%)',
'radial-gradient(circle at 40% 80%, rgba(0, 122, 255, 0.15) 0%, transparent 50%)',
'radial-gradient(circle at 60% 30%, rgba(48, 209, 88, 0.12) 0%, transparent 60%)',
],
}}
transition={{
duration: prefersReducedMotion ? 0 : 12,
repeat: prefersReducedMotion ? 0 : Infinity,
ease: "easeInOut",
}}
/>
{/* Particle system - responsive dots */}
{[...Array(16)].map((_, i) => (
<motion.div
key={`particle-${i}`}
className="absolute w-1 h-1 bg-white/20 rounded-full"
style={{
left: `${15 + (i * 5.5)}%`,
top: `${25 + Math.sin(i * 0.8) * 25}%`,
}}
animate={prefersReducedMotion ? {} : {
scale: [1, 1.8, 1],
opacity: [0.2, 0.7, 0.2],
x: mousePosition.x * (8 + i * 1.5),
y: mousePosition.y * (4 + i * 0.8),
}}
transition={{
duration: prefersReducedMotion ? 0 : 4 + i * 0.3,
repeat: prefersReducedMotion ? 0 : Infinity,
ease: "easeInOut",
}}
/>
))}
{/* Enhanced geometric shapes - hexagons */}
{[...Array(8)].map((_, i) => (
<motion.div
key={`hex-${i}`}
className="absolute w-6 h-6 border border-white/8"
style={{
left: `${8 + (i * 12)}%`,
top: `${15 + Math.cos(i * 0.6) * 35}%`,
clipPath: 'polygon(30% 0%, 70% 0%, 100% 50%, 70% 100%, 30% 100%, 0% 50%)',
}}
animate={prefersReducedMotion ? {} : {
rotate: [0, 360],
scale: [1, 1.3, 1],
opacity: [0.08, 0.25, 0.08],
}}
transition={{
duration: prefersReducedMotion ? 0 : 10 + i * 2.5,
repeat: prefersReducedMotion ? 0 : Infinity,
ease: "linear",
}}
/>
))}
{/* Grid pattern overlay */}
<motion.div
className="absolute inset-0 opacity-5"
style={{
backgroundImage: `
linear-gradient(rgba(255,255,255,0.1) 1px, transparent 1px),
linear-gradient(90deg, rgba(255,255,255,0.1) 1px, transparent 1px)
`,
backgroundSize: '50px 50px',
}}
animate={prefersReducedMotion ? {} : {
opacity: [0.02, 0.08, 0.02],
}}
transition={{
duration: prefersReducedMotion ? 0 : 8,
repeat: prefersReducedMotion ? 0 : Infinity,
ease: "easeInOut",
}}
/>
{/* Additional floating circles for depth */}
{[...Array(4)].map((_, i) => (
<motion.div
key={`circle-${i}`}
className="absolute rounded-full border border-white/5"
style={{
width: `${60 + i * 40}px`,
height: `${60 + i * 40}px`,
left: `${20 + i * 20}%`,
top: `${10 + i * 15}%`,
}}
animate={prefersReducedMotion ? {} : {
scale: [1, 1.1, 1],
opacity: [0.03, 0.12, 0.03],
rotate: [0, 180, 360],
}}
transition={{
duration: prefersReducedMotion ? 0 : 15 + i * 5,
repeat: prefersReducedMotion ? 0 : Infinity,
ease: "easeInOut",
}}
/>
))}
</div>
);
};
const AnimatedText: React.FC<{ children: React.ReactNode; delay?: number }> = ({ children, delay = 0 }) => {
const ref = useRef<HTMLDivElement>(null);
const isInView = useInView(ref, { once: true });
return (
<motion.div
ref={ref}
initial={{ opacity: 0, y: 50 }}
animate={isInView ? { opacity: 1, y: 0 } : { opacity: 0, y: 50 }}
transition={{
duration: 0.8,
delay,
ease: [0.21, 1.11, 0.81, 0.99], // Apple-style easing
}}
>
{children}
</motion.div>
);
};
const GradientText: React.FC<{ children: React.ReactNode }> = ({ children }) => (
<motion.span
className="text-gradient"
animate={{
backgroundPosition: ['0% 50%', '100% 50%', '0% 50%'],
}}
transition={{
duration: 5,
repeat: Infinity,
ease: "easeInOut",
}}
style={{
backgroundSize: '200% 200%',
}}
>
{children}
</motion.span>
);
const ScrollIndicator: React.FC = () => {
const prefersReducedMotion = useReducedMotion();
return (
<motion.div
className="absolute bottom-8 left-1/2 transform -translate-x-1/2 flex flex-col items-center text-white/60"
initial={{ opacity: 0, y: prefersReducedMotion ? 0 : 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ delay: prefersReducedMotion ? 0 : 2, duration: prefersReducedMotion ? 0.01 : 1 }}
role="button"
tabIndex={0}
aria-label="Scroll down to see more content"
onKeyDown={(e) => {
if (e.key === 'Enter' || e.key === ' ') {
window.scrollBy({ top: window.innerHeight, behavior: 'smooth' });
}
}}
onClick={() => {
window.scrollBy({ top: window.innerHeight, behavior: 'smooth' });
}}
className="cursor-pointer focus:outline-none focus:ring-2 focus:ring-chorus-blue focus:ring-opacity-50 rounded-lg p-3"
>
<motion.div
animate={prefersReducedMotion ? {} : { y: [0, 8, 0] }}
transition={{
duration: prefersReducedMotion ? 0 : 2,
repeat: prefersReducedMotion ? 0 : Infinity,
ease: "easeInOut"
}}
>
<ChevronDownIcon size={24} />
</motion.div>
<Typography.Interface size="small" className="mt-2" style={{ letterSpacing: '0.2em' }}>
SCROLL
</Typography.Interface>
</motion.div>
);
};
const EnhancedHero: React.FC = () => {
const containerRef = useRef<HTMLDivElement>(null);
const { scrollY } = useScroll();
const opacity = useTransform(scrollY, [0, 500], [1, 0]);
const scale = useTransform(scrollY, [0, 500], [1, 0.95]);
const prefersReducedMotion = useReducedMotion();
// Staggered animation variants with reduced motion support
const containerVariants = {
hidden: {},
visible: {
transition: {
staggerChildren: prefersReducedMotion ? 0 : 0.2,
delayChildren: prefersReducedMotion ? 0 : 0.3,
},
},
};
const itemVariants = {
hidden: {
opacity: 0,
y: prefersReducedMotion ? 0 : 60,
scale: prefersReducedMotion ? 1 : 0.95,
},
visible: {
opacity: 1,
y: 0,
scale: 1,
transition: {
duration: prefersReducedMotion ? 0.01 : 0.8,
ease: [0.21, 1.11, 0.81, 0.99], // Apple cubic-bezier
},
},
};
const buttonVariants = {
hidden: {
opacity: 0,
y: prefersReducedMotion ? 0 : 30
},
visible: {
opacity: 1,
y: 0,
transition: {
duration: prefersReducedMotion ? 0.01 : 0.6,
ease: [0.21, 1.11, 0.81, 0.99],
},
},
hover: {
scale: prefersReducedMotion ? 1 : 1.05,
transition: {
duration: 0.2,
ease: "easeOut",
},
},
tap: {
scale: prefersReducedMotion ? 1 : 0.98,
transition: {
duration: 0.1,
},
},
};
return (
<section
ref={containerRef}
className="relative min-h-screen flex items-center justify-center overflow-hidden bg-gradient-to-br from-chorus-charcoal via-chorus-charcoal to-chorus-charcoal-dark"
aria-label="CHORUS Services Hero Section"
role="banner"
>
{/* Geometric Background Pattern */}
<GeometricPattern />
{/* Main Content with Parallax */}
<motion.div
className="relative z-10 text-center max-w-6xl mx-auto px-6"
style={{ opacity, scale }}
initial="hidden"
animate="visible"
variants={containerVariants}
>
{/* Background floating elements */}
<ParallaxLayer speed={-0.3} className="absolute -top-20 -left-20">
<FloatingElement delay={0}>
<div className="w-32 h-32 rounded-full border border-white/5 bg-gradient-to-r from-slate-400/8 to-slate-500/6" />
</FloatingElement>
</ParallaxLayer>
<ParallaxLayer speed={-0.5} className="absolute -top-40 -right-32">
<FloatingElement delay={1}>
<div className="w-48 h-48 rounded-full border border-white/5 bg-gradient-to-l from-slate-500/6 to-slate-400/8" />
</FloatingElement>
</ParallaxLayer>
{/* Main Headline - Exo Thin for maximum impact */}
<motion.div variants={itemVariants} className="mb-8">
<Typography.Hero
className="mb-6"
role="heading"
aria-level={1}
gradient
>
CHORUS Services
</Typography.Hero>
</motion.div>
{/* Subtitle */}
<motion.div variants={itemVariants} className="mb-12">
<Typography.Body
size="large"
color="secondary"
className="max-w-4xl mx-auto"
style={{ fontSize: 'clamp(18px, 3vw, 24px)' }}
>
Distributed AI Orchestration Without the Hallucinations
</Typography.Body>
</motion.div>
{/* CTA Buttons */}
<motion.div variants={itemVariants}>
<Space size="large" className="flex flex-wrap justify-center gap-4">
<motion.div
variants={buttonVariants}
whileHover="hover"
whileTap="tap"
>
<PrimaryButton
size="large"
icon={<PlayIcon size={20} />}
className="text-lg px-8 py-4 h-auto min-w-[180px] shadow-2xl shadow-chorus-blue/25"
aria-label="Explore CHORUS Platform"
>
Explore Platform
</PrimaryButton>
</motion.div>
<motion.div
variants={buttonVariants}
whileHover="hover"
whileTap="tap"
>
<SecondaryButton
size="large"
icon={<ArrowRightIcon size={20} />}
className="text-lg px-8 py-4 h-auto min-w-[180px] backdrop-blur-sm"
aria-label="View CHORUS Documentation"
>
View Documentation
</SecondaryButton>
</motion.div>
</Space>
</motion.div>
{/* Technical Capabilities */}
<motion.div
variants={itemVariants}
className="mt-16 grid grid-cols-1 sm:grid-cols-3 gap-8 max-w-3xl mx-auto"
>
{[
{ label: 'Distributed Architecture', value: 'P2P Mesh', color: 'slate-400' },
{ label: 'Context Persistence', value: 'Hypercore', color: 'slate-400' },
{ label: 'Enterprise Ready', value: 'Production', color: 'slate-400' },
].map((capability, index) => (
<motion.div
key={capability.label}
className="text-center p-4 glass-effect rounded-lg"
whileHover={{ scale: 1.02 }}
transition={{ duration: 0.2 }}
>
<div className={`text-lg font-semibold text-${capability.color} mb-2`}>
{capability.value}
</div>
<div className="text-gray-400 text-sm uppercase tracking-wider">
{capability.label}
</div>
</motion.div>
))}
</motion.div>
</motion.div>
{/* Scroll Indicator */}
<ScrollIndicator />
{/* Ambient lighting effects */}
<div className="absolute inset-0 pointer-events-none" aria-hidden="true">
<motion.div
className="absolute top-1/4 left-1/4 w-96 h-96 bg-slate-400/3 rounded-full blur-3xl"
animate={prefersReducedMotion ? {} : {
scale: [1, 1.2, 1],
opacity: [0.2, 0.3, 0.2],
}}
transition={{
duration: prefersReducedMotion ? 0 : 8,
repeat: prefersReducedMotion ? 0 : Infinity,
ease: "easeInOut",
}}
/>
<motion.div
className="absolute bottom-1/4 right-1/4 w-96 h-96 bg-slate-500/3 rounded-full blur-3xl"
animate={prefersReducedMotion ? {} : {
scale: [1.2, 1, 1.2],
opacity: [0.3, 0.2, 0.3],
}}
transition={{
duration: prefersReducedMotion ? 0 : 8,
repeat: prefersReducedMotion ? 0 : Infinity,
ease: "easeInOut",
delay: prefersReducedMotion ? 0 : 2,
}}
/>
</div>
</section>
);
};
export default EnhancedHero;