website landing page

This commit is contained in:
2025-12-02 19:44:18 +01:00
parent fd3b4171aa
commit 895318ac40
33 changed files with 2226 additions and 842 deletions

View File

@@ -1,10 +1,15 @@
'use client';
import { motion, useReducedMotion, useMotionValue, useSpring, useTransform } from 'framer-motion';
import { useEffect } from 'react';
import { useEffect, useState } from 'react';
export default function DriverProfileMockup() {
const shouldReduceMotion = useReducedMotion();
const [isMobile, setIsMobile] = useState(false);
useEffect(() => {
setIsMobile(window.innerWidth < 768);
}, []);
const stats = [
{ label: 'Wins', value: 24 },
@@ -16,6 +21,69 @@ export default function DriverProfileMockup() {
const formData = [85, 72, 68, 91, 88, 95, 88, 79, 82, 91];
if (isMobile) {
return (
<div className="relative w-full h-full bg-gradient-to-br from-deep-graphite via-iron-gray to-deep-graphite rounded-lg p-3 overflow-hidden">
<div className="space-y-4">
<div>
<div className="flex items-center justify-between mb-2">
<div className="flex items-center gap-3">
<div className="relative h-12 w-12 rounded-full border-2 border-primary-blue/50 overflow-hidden bg-charcoal-outline">
<div className="absolute inset-0 flex items-center justify-center text-2xl">🏎</div>
</div>
<div>
<div className="text-base font-bold text-white">Driver Profile</div>
<div className="text-xs text-white/50">Cross-league</div>
</div>
</div>
<div className="text-2xl font-bold text-charcoal-outline">#33</div>
</div>
<div className="relative h-2 bg-charcoal-outline rounded-full overflow-hidden mb-1">
<div
className="absolute inset-y-0 left-0 bg-gradient-to-r from-primary-blue to-neon-aqua rounded-full"
style={{ width: '86%' }}
/>
</div>
<div className="flex justify-end">
<span className="text-xs text-gray-400">2150 GP Rating</span>
</div>
</div>
<div>
<div className="text-sm font-semibold text-white mb-2">Career Stats</div>
<div className="grid grid-cols-3 gap-2">
{stats.slice(0, 3).map((stat) => (
<div
key={stat.label}
className="bg-iron-gray/50 border border-charcoal-outline rounded-lg p-2 text-center"
>
<div className="text-base font-bold text-white font-mono">
{stat.value}{stat.suffix}
</div>
<div className="text-xs text-gray-400 mt-0.5">{stat.label}</div>
</div>
))}
</div>
</div>
<div>
<div className="text-sm font-semibold text-white mb-2">Recent Form</div>
<div className="h-16 bg-iron-gray/30 border border-charcoal-outline rounded-lg p-2 flex items-end gap-1">
{formData.slice(-6).map((value, i) => (
<div
key={i}
className="flex-1 bg-gradient-to-t from-performance-green to-primary-blue rounded-sm"
style={{ height: `${value}%` }}
/>
))}
</div>
</div>
</div>
</div>
);
}
const containerVariants = {
hidden: { opacity: 0 },
visible: {
@@ -34,28 +102,33 @@ export default function DriverProfileMockup() {
};
return (
<div className="relative w-full h-full bg-gradient-to-br from-deep-graphite via-iron-gray to-deep-graphite rounded-lg p-6 md:p-8 overflow-hidden">
<div className="relative w-full h-full bg-gradient-to-br from-deep-graphite via-iron-gray to-deep-graphite rounded-lg p-1.5 sm:p-3 md:p-5 lg:p-8 overflow-hidden">
<motion.div
initial={{ opacity: 0, y: shouldReduceMotion ? 0 : -10 }}
animate={{ opacity: 1, y: 0 }}
className="mb-6"
className="mb-1.5 sm:mb-3 md:mb-4 lg:mb-6"
>
<div className="flex items-center justify-between mb-4">
<div>
<div className="h-6 w-48 bg-white/10 rounded mb-2"></div>
<div className="h-4 w-24 bg-white/5 rounded"></div>
<div className="flex items-center justify-between mb-1.5 sm:mb-2 md:mb-3 lg:mb-4">
<div className="flex items-center gap-1.5 sm:gap-2 md:gap-3 lg:gap-4">
<div className="relative h-8 w-8 sm:h-10 sm:w-10 md:h-12 md:w-12 lg:h-16 lg:w-16 rounded-full border-2 border-primary-blue/50 overflow-hidden bg-charcoal-outline">
<div className="absolute inset-0 flex items-center justify-center text-base sm:text-xl md:text-2xl lg:text-3xl">🏎</div>
</div>
<div>
<div className="text-sm sm:text-base md:text-lg lg:text-xl font-bold text-white mb-1 sm:mb-1.5 md:mb-2">Driver Profile</div>
<div className="text-[8px] sm:text-[10px] md:text-xs text-white/50">Cross-league racing identity</div>
</div>
</div>
<div className="text-4xl font-bold text-charcoal-outline">#33</div>
<div className="text-xl sm:text-2xl md:text-3xl lg:text-4xl font-bold text-charcoal-outline">#33</div>
</div>
<div className="flex items-center gap-4 mb-2">
<div className="text-xs text-gray-400">GridPilot Rating:</div>
<div className="flex flex-wrap items-center gap-1 sm:gap-2 md:gap-3 lg:gap-4 mb-1 sm:mb-1.5 md:mb-2">
<div className="text-[8px] sm:text-[10px] md:text-xs text-gray-400">GridPilot Rating:</div>
<AnimatedRating shouldReduceMotion={shouldReduceMotion ?? false} value={2150} />
<div className="text-xs text-gray-400 ml-4">iRating:</div>
<div className="text-[8px] sm:text-[10px] md:text-xs text-gray-400">iRating:</div>
<AnimatedRating shouldReduceMotion={shouldReduceMotion ?? false} value={3200} />
</div>
<div className="relative h-3 bg-charcoal-outline rounded-full overflow-hidden">
<div className="relative h-1.5 sm:h-2 md:h-2.5 lg:h-3 bg-charcoal-outline rounded-full overflow-hidden">
<motion.div
className="absolute inset-y-0 left-0 bg-gradient-to-r from-primary-blue to-neon-aqua rounded-full"
initial={{ width: '0%' }}
@@ -64,7 +137,7 @@ export default function DriverProfileMockup() {
/>
</div>
<div className="flex justify-end mt-1">
<span className="text-xs text-gray-400">86%</span>
<span className="text-[8px] sm:text-[10px] md:text-xs text-gray-400">86%</span>
</div>
</motion.div>
@@ -72,16 +145,17 @@ export default function DriverProfileMockup() {
variants={containerVariants}
initial="hidden"
animate="visible"
className="mb-6"
className="mb-1.5 sm:mb-3 md:mb-4 lg:mb-6"
>
<div className="h-4 w-32 bg-white/10 rounded mb-3"></div>
<div className="text-[9px] sm:text-xs md:text-sm font-semibold text-white mb-1">Career Statistics</div>
<div className="text-[8px] sm:text-[10px] md:text-xs text-white/50 mb-1 sm:mb-2 md:mb-3">Aggregated across all leagues</div>
<div className="grid grid-cols-2 md:grid-cols-5 gap-3">
<div className="grid grid-cols-2 md:grid-cols-5 gap-1.5 sm:gap-2 md:gap-3">
{stats.map((stat, index) => (
<motion.div
key={stat.label}
variants={itemVariants}
className="bg-iron-gray/50 border border-charcoal-outline rounded-lg p-3 text-center"
className="bg-iron-gray/50 border border-charcoal-outline rounded-lg p-1.5 sm:p-2 md:p-3 text-center"
>
<AnimatedCounter
value={stat.value}
@@ -89,7 +163,7 @@ export default function DriverProfileMockup() {
delay={index * 0.1}
suffix={stat.suffix}
/>
<div className="text-xs text-gray-400 mt-1">{stat.label}</div>
<div className="text-[8px] sm:text-[10px] md:text-xs text-gray-400 mt-0.5">{stat.label}</div>
</motion.div>
))}
</div>
@@ -99,11 +173,12 @@ export default function DriverProfileMockup() {
initial={{ opacity: 0, y: shouldReduceMotion ? 0 : 10 }}
animate={{ opacity: 1, y: 0 }}
transition={{ delay: shouldReduceMotion ? 0 : 0.6 }}
className="mb-6"
className="mb-1.5 sm:mb-3 md:mb-4 lg:mb-6"
>
<div className="h-4 w-28 bg-white/10 rounded mb-3"></div>
<div className="text-[9px] sm:text-xs md:text-sm font-semibold text-white mb-1">Recent Form</div>
<div className="text-[8px] sm:text-[10px] md:text-xs text-white/50 mb-1 sm:mb-2 md:mb-3">Performance trend over last 10 races</div>
<div className="h-20 bg-iron-gray/30 border border-charcoal-outline rounded-lg p-3 flex items-end gap-1">
<div className="h-12 sm:h-16 md:h-20 bg-iron-gray/30 border border-charcoal-outline rounded-lg p-1.5 sm:p-2 md:p-3 flex items-end gap-0.5">
{formData.map((value, i) => (
<motion.div
key={i}
@@ -118,7 +193,7 @@ export default function DriverProfileMockup() {
/>
))}
</div>
<div className="flex justify-between mt-1 text-xs text-gray-500">
<div className="flex justify-between mt-0.5 text-[8px] sm:text-[10px] md:text-xs text-gray-500">
<span>Last 10 races</span>
<span>Recent</span>
</div>
@@ -129,9 +204,10 @@ export default function DriverProfileMockup() {
animate={{ opacity: 1, y: 0 }}
transition={{ delay: shouldReduceMotion ? 0 : 0.8 }}
>
<div className="h-4 w-20 bg-white/10 rounded mb-3"></div>
<div className="text-[9px] sm:text-xs md:text-sm font-semibold text-white mb-1">Teams</div>
<div className="text-[8px] sm:text-[10px] md:text-xs text-white/50 mb-1 sm:mb-2 md:mb-3">Current and past team memberships</div>
<div className="space-y-2">
<div className="space-y-1 sm:space-y-1.5 md:space-y-2">
{[
{ team: 'Red Bull Racing', status: 'Current', color: 'primary-blue' },
{ team: 'Mercedes AMG', status: '2023', color: 'charcoal-outline' }
@@ -141,12 +217,17 @@ export default function DriverProfileMockup() {
initial={{ opacity: 0, x: shouldReduceMotion ? 0 : -10 }}
animate={{ opacity: 1, x: 0 }}
transition={{ delay: shouldReduceMotion ? 0 : 0.9 + i * 0.1 }}
className="flex items-center justify-between bg-iron-gray/30 border border-charcoal-outline rounded-lg p-2 text-sm"
className="flex items-center justify-between bg-iron-gray/30 border border-charcoal-outline rounded-lg p-1 sm:p-1.5 md:p-2 text-[10px] sm:text-xs md:text-sm"
>
<div className="h-3 w-32 bg-white/10 rounded"></div>
<span className={`text-xs px-2 py-0.5 rounded ${
team.status === 'Current'
? 'bg-primary-blue/20 text-primary-blue'
<div className="flex items-center gap-2 sm:gap-3">
<div className="h-5 w-5 sm:h-6 sm:w-6 md:h-8 md:w-8 rounded border border-primary-blue/30 bg-charcoal-outline flex items-center justify-center text-sm sm:text-base md:text-lg">
🏁
</div>
<div className="h-1.5 sm:h-2 md:h-3 w-16 sm:w-20 md:w-32 bg-white/10 rounded"></div>
</div>
<span className={`text-[8px] sm:text-[10px] md:text-xs px-1 sm:px-1.5 md:px-2 py-0.5 rounded ${
team.status === 'Current'
? 'bg-primary-blue/20 text-primary-blue'
: 'bg-charcoal-outline text-gray-400'
}`}>
{team.status}
@@ -159,7 +240,7 @@ export default function DriverProfileMockup() {
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
transition={{ delay: shouldReduceMotion ? 0 : 1.2 }}
className="mt-4 text-center text-xs text-gray-400"
className="mt-2 sm:mt-3 md:mt-4 text-center text-[8px] sm:text-[10px] md:text-xs text-gray-400"
>
Active in 3 leagues
</motion.div>
@@ -183,7 +264,7 @@ function AnimatedRating({ shouldReduceMotion, value }: { shouldReduceMotion: boo
}, [shouldReduceMotion, count, value]);
return (
<motion.span className="text-lg font-bold text-primary-blue font-mono">
<motion.span className="text-sm sm:text-base md:text-lg font-bold text-primary-blue font-mono">
{shouldReduceMotion ? value : <motion.span>{rounded}</motion.span>}
</motion.span>
);
@@ -213,7 +294,7 @@ function AnimatedCounter({
}, [shouldReduceMotion, count, value, delay]);
return (
<div className="text-xl font-bold text-white font-mono">
<div className="text-sm sm:text-base md:text-lg lg:text-xl font-bold text-white font-mono">
{shouldReduceMotion ? value : <motion.span>{rounded}</motion.span>}{suffix}
</div>
);