wip
This commit is contained in:
@@ -1,15 +1,7 @@
|
||||
'use client';
|
||||
import { redirect } from 'next/navigation';
|
||||
|
||||
import { getAppMode } from '@/lib/mode';
|
||||
import { useRouter } from 'next/navigation';
|
||||
import { useEffect, useState } from 'react';
|
||||
import Card from '@/components/ui/Card';
|
||||
import Button from '@/components/ui/Button';
|
||||
import CompanionStatus from '@/components/alpha/CompanionStatus';
|
||||
import DataWarning from '@/components/alpha/DataWarning';
|
||||
import RaceCard from '@/components/alpha/RaceCard';
|
||||
import LeagueCard from '@/components/alpha/LeagueCard';
|
||||
import TeamCard from '@/components/alpha/TeamCard';
|
||||
import { getAuthService } from '@/lib/auth';
|
||||
import Hero from '@/components/landing/Hero';
|
||||
import AlternatingSection from '@/components/landing/AlternatingSection';
|
||||
import FeatureGrid from '@/components/landing/FeatureGrid';
|
||||
@@ -21,628 +13,347 @@ import RaceHistoryMockup from '@/components/mockups/RaceHistoryMockup';
|
||||
import CompanionAutomationMockup from '@/components/mockups/CompanionAutomationMockup';
|
||||
import SimPlatformMockup from '@/components/mockups/SimPlatformMockup';
|
||||
import MockupStack from '@/components/ui/MockupStack';
|
||||
import { getRaceRepository, getLeagueRepository } from '@/lib/di-container';
|
||||
import { getAllTeams, getTeamMembers } from '@/lib/team-data';
|
||||
import { getLeagueMembers } from '@/lib/membership-data';
|
||||
import type { Race } from '@gridpilot/racing-domain/entities/Race';
|
||||
import type { League } from '@gridpilot/racing-domain/entities/League';
|
||||
import Card from '@/components/ui/Card';
|
||||
import Button from '@/components/ui/Button';
|
||||
import {
|
||||
topLeagues,
|
||||
teams,
|
||||
getUpcomingRaces,
|
||||
} from '@gridpilot/testing-support';
|
||||
|
||||
function AlphaDashboard() {
|
||||
const router = useRouter();
|
||||
const [upcomingRaces, setUpcomingRaces] = useState<Race[]>([]);
|
||||
const [topLeagues, setTopLeagues] = useState<League[]>([]);
|
||||
const [featuredTeams, setFeaturedTeams] = useState<any[]>([]);
|
||||
const [recentActivity, setRecentActivity] = useState<any[]>([]);
|
||||
export default async function HomePage() {
|
||||
const authService = getAuthService();
|
||||
const session = await authService.getCurrentSession();
|
||||
|
||||
useEffect(() => {
|
||||
const raceRepo = getRaceRepository();
|
||||
const leagueRepo = getLeagueRepository();
|
||||
if (session) {
|
||||
redirect('/dashboard');
|
||||
}
|
||||
|
||||
// Get upcoming races
|
||||
raceRepo.findAll().then(races => {
|
||||
const upcoming = races
|
||||
.filter(r => r.status === 'scheduled')
|
||||
.sort((a, b) => new Date(a.scheduledAt).getTime() - new Date(b.scheduledAt).getTime())
|
||||
.slice(0, 5);
|
||||
setUpcomingRaces(upcoming);
|
||||
});
|
||||
const mode = getAppMode();
|
||||
const isAlpha = mode === 'alpha';
|
||||
const upcomingRaces = getUpcomingRaces(3);
|
||||
|
||||
// Get top leagues
|
||||
leagueRepo.findAll().then(leagues => {
|
||||
const sorted = leagues
|
||||
.map(league => ({
|
||||
league,
|
||||
memberCount: getLeagueMembers(league.id).length,
|
||||
}))
|
||||
.sort((a, b) => b.memberCount - a.memberCount)
|
||||
.slice(0, 4)
|
||||
.map(item => item.league);
|
||||
setTopLeagues(sorted);
|
||||
});
|
||||
|
||||
// Get featured teams
|
||||
const teams = getAllTeams();
|
||||
const featured = teams
|
||||
.map(team => ({
|
||||
...team,
|
||||
memberCount: getTeamMembers(team.id).length,
|
||||
}))
|
||||
.sort((a, b) => b.memberCount - a.memberCount)
|
||||
.slice(0, 4);
|
||||
setFeaturedTeams(featured);
|
||||
|
||||
// Generate recent activity
|
||||
const activities = [
|
||||
{ type: 'race', text: 'Max Verstappen won at Monza GP', time: '2 hours ago' },
|
||||
{ type: 'join', text: 'Lando Norris joined European GT Championship', time: '5 hours ago' },
|
||||
{ type: 'team', text: 'Charles Leclerc joined Weekend Warriors', time: '1 day ago' },
|
||||
{ type: 'race', text: 'Upcoming: Spa-Francorchamps in 2 days', time: '2 days ago' },
|
||||
{ type: 'league', text: 'European GT Championship: 4 active members', time: '3 days ago' },
|
||||
];
|
||||
setRecentActivity(activities);
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div className="max-w-7xl mx-auto">
|
||||
<DataWarning />
|
||||
|
||||
{/* Upcoming Races Section */}
|
||||
{upcomingRaces.length > 0 && (
|
||||
<div className="mb-12">
|
||||
<div className="flex items-center justify-between mb-6">
|
||||
<h2 className="text-3xl font-bold text-white">Upcoming Races</h2>
|
||||
<Button variant="secondary" onClick={() => router.push('/races')}>
|
||||
View All Races
|
||||
</Button>
|
||||
</div>
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
|
||||
{upcomingRaces.slice(0, 3).map(race => (
|
||||
<RaceCard
|
||||
key={race.id}
|
||||
race={race}
|
||||
onClick={() => router.push(`/races/${race.id}`)}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Top Leagues Section */}
|
||||
{topLeagues.length > 0 && (
|
||||
<div className="mb-12">
|
||||
<div className="flex items-center justify-between mb-6">
|
||||
<h2 className="text-3xl font-bold text-white">Top Leagues</h2>
|
||||
<Button variant="secondary" onClick={() => router.push('/leagues')}>
|
||||
Browse Leagues
|
||||
</Button>
|
||||
</div>
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-4">
|
||||
{topLeagues.map(league => (
|
||||
<LeagueCard
|
||||
key={league.id}
|
||||
league={league}
|
||||
onClick={() => router.push(`/leagues/${league.id}`)}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Featured Teams Section */}
|
||||
{featuredTeams.length > 0 && (
|
||||
<div className="mb-12">
|
||||
<div className="flex items-center justify-between mb-6">
|
||||
<h2 className="text-3xl font-bold text-white">Featured Teams</h2>
|
||||
<Button variant="secondary" onClick={() => router.push('/teams')}>
|
||||
Browse Teams
|
||||
</Button>
|
||||
</div>
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-4">
|
||||
{featuredTeams.map(team => (
|
||||
<TeamCard
|
||||
key={team.id}
|
||||
id={team.id}
|
||||
name={team.name}
|
||||
logo={undefined}
|
||||
memberCount={team.memberCount}
|
||||
leagues={team.leagues}
|
||||
onClick={() => router.push(`/teams/${team.id}`)}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Recent Activity Section */}
|
||||
{recentActivity.length > 0 && (
|
||||
<div className="mb-12">
|
||||
<h2 className="text-3xl font-bold text-white mb-6">Recent Activity</h2>
|
||||
<Card>
|
||||
<div className="space-y-4">
|
||||
{recentActivity.map((activity, idx) => (
|
||||
<div
|
||||
key={idx}
|
||||
className={`flex items-start gap-3 pb-4 ${
|
||||
idx < recentActivity.length - 1 ? 'border-b border-charcoal-outline' : ''
|
||||
}`}
|
||||
>
|
||||
<div className="w-2 h-2 rounded-full bg-primary-blue mt-2 flex-shrink-0" />
|
||||
<div className="flex-1">
|
||||
<p className="text-sm text-gray-300">{activity.text}</p>
|
||||
<p className="text-xs text-gray-500 mt-1">{activity.time}</p>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</Card>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="max-w-4xl mx-auto">
|
||||
{/* Welcome Header */}
|
||||
<div className="mb-8">
|
||||
<h1 className="text-4xl font-bold text-white mb-4">GridPilot Alpha</h1>
|
||||
<p className="text-gray-400 text-lg">
|
||||
Complete workflow prototype. Test freely — all data is temporary.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{/* Companion Status */}
|
||||
<div className="mb-8">
|
||||
<CompanionStatus />
|
||||
</div>
|
||||
|
||||
{/* What's in Alpha */}
|
||||
<Card className="mb-8">
|
||||
<h2 className="text-2xl font-semibold text-white mb-4">What's in Alpha</h2>
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-3 text-sm">
|
||||
<div className="flex items-start gap-2">
|
||||
<svg className="w-5 h-5 text-performance-green flex-shrink-0 mt-0.5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M5 13l4 4L19 7" />
|
||||
</svg>
|
||||
<span className="text-gray-300">Driver profile creation</span>
|
||||
</div>
|
||||
<div className="flex items-start gap-2">
|
||||
<svg className="w-5 h-5 text-performance-green flex-shrink-0 mt-0.5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M5 13l4 4L19 7" />
|
||||
</svg>
|
||||
<span className="text-gray-300">League management</span>
|
||||
</div>
|
||||
<div className="flex items-start gap-2">
|
||||
<svg className="w-5 h-5 text-performance-green flex-shrink-0 mt-0.5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M5 13l4 4L19 7" />
|
||||
</svg>
|
||||
<span className="text-gray-300">Race scheduling</span>
|
||||
</div>
|
||||
<div className="flex items-start gap-2">
|
||||
<svg className="w-5 h-5 text-performance-green flex-shrink-0 mt-0.5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M5 13l4 4L19 7" />
|
||||
</svg>
|
||||
<span className="text-gray-300">CSV result import</span>
|
||||
</div>
|
||||
<div className="flex items-start gap-2">
|
||||
<svg className="w-5 h-5 text-performance-green flex-shrink-0 mt-0.5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M5 13l4 4L19 7" />
|
||||
</svg>
|
||||
<span className="text-gray-300">Championship standings</span>
|
||||
</div>
|
||||
<div className="flex items-start gap-2">
|
||||
<svg className="w-5 h-5 text-performance-green flex-shrink-0 mt-0.5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M5 13l4 4L19 7" />
|
||||
</svg>
|
||||
<span className="text-gray-300">Full workflow end-to-end</span>
|
||||
</div>
|
||||
</div>
|
||||
</Card>
|
||||
|
||||
{/* What's Coming */}
|
||||
<Card className="mb-8 bg-iron-gray">
|
||||
<h2 className="text-2xl font-semibold text-white mb-4">What's Coming</h2>
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-3 text-sm">
|
||||
<div className="flex items-start gap-2">
|
||||
<svg className="w-5 h-5 text-primary-blue flex-shrink-0 mt-0.5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M13 7l5 5m0 0l-5 5m5-5H6" />
|
||||
</svg>
|
||||
<span className="text-gray-300">Persistent data storage</span>
|
||||
</div>
|
||||
<div className="flex items-start gap-2">
|
||||
<svg className="w-5 h-5 text-primary-blue flex-shrink-0 mt-0.5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M13 7l5 5m0 0l-5 5m5-5H6" />
|
||||
</svg>
|
||||
<span className="text-gray-300">Automated session creation</span>
|
||||
</div>
|
||||
<div className="flex items-start gap-2">
|
||||
<svg className="w-5 h-5 text-primary-blue flex-shrink-0 mt-0.5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M13 7l5 5m0 0l-5 5m5-5H6" />
|
||||
</svg>
|
||||
<span className="text-gray-300">Automated result import</span>
|
||||
</div>
|
||||
<div className="flex items-start gap-2">
|
||||
<svg className="w-5 h-5 text-primary-blue flex-shrink-0 mt-0.5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M13 7l5 5m0 0l-5 5m5-5H6" />
|
||||
</svg>
|
||||
<span className="text-gray-300">Multi-league memberships</span>
|
||||
</div>
|
||||
<div className="flex items-start gap-2">
|
||||
<svg className="w-5 h-5 text-primary-blue flex-shrink-0 mt-0.5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M13 7l5 5m0 0l-5 5m5-5H6" />
|
||||
</svg>
|
||||
<span className="text-gray-300">Team championships</span>
|
||||
</div>
|
||||
<div className="flex items-start gap-2">
|
||||
<svg className="w-5 h-5 text-primary-blue flex-shrink-0 mt-0.5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M13 7l5 5m0 0l-5 5m5-5H6" />
|
||||
</svg>
|
||||
<span className="text-gray-300">Advanced statistics</span>
|
||||
</div>
|
||||
<div className="flex items-start gap-2">
|
||||
<svg className="w-5 h-5 text-primary-blue flex-shrink-0 mt-0.5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M13 7l5 5m0 0l-5 5m5-5H6" />
|
||||
</svg>
|
||||
<span className="text-gray-300">Social features</span>
|
||||
</div>
|
||||
<div className="flex items-start gap-2">
|
||||
<svg className="w-5 h-5 text-primary-blue flex-shrink-0 mt-0.5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M13 7l5 5m0 0l-5 5m5-5H6" />
|
||||
</svg>
|
||||
<span className="text-gray-300">League discovery</span>
|
||||
</div>
|
||||
</div>
|
||||
</Card>
|
||||
|
||||
{/* Known Limitations */}
|
||||
<Card className="mb-8 border border-warning-amber/20 bg-iron-gray">
|
||||
<div className="flex items-start gap-3 mb-4">
|
||||
<div className="w-10 h-10 rounded-lg bg-warning-amber/10 flex items-center justify-center flex-shrink-0">
|
||||
<svg className="w-5 h-5 text-warning-amber" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z" />
|
||||
</svg>
|
||||
</div>
|
||||
<div className="flex-1">
|
||||
<h3 className="text-lg font-semibold text-white mb-2">Known Limitations</h3>
|
||||
<ul className="space-y-2 text-sm text-gray-400">
|
||||
<li className="flex items-start gap-2">
|
||||
<span className="text-warning-amber mt-0.5">•</span>
|
||||
<span>Data resets on page reload (in-memory only)</span>
|
||||
</li>
|
||||
<li className="flex items-start gap-2">
|
||||
<span className="text-warning-amber mt-0.5">•</span>
|
||||
<span>Manual iRacing session creation required</span>
|
||||
</li>
|
||||
<li className="flex items-start gap-2">
|
||||
<span className="text-warning-amber mt-0.5">•</span>
|
||||
<span>Manual CSV result upload required</span>
|
||||
</li>
|
||||
<li className="flex items-start gap-2">
|
||||
<span className="text-warning-amber mt-0.5">•</span>
|
||||
<span>Single league membership per driver</span>
|
||||
</li>
|
||||
<li className="flex items-start gap-2">
|
||||
<span className="text-warning-amber mt-0.5">•</span>
|
||||
<span>No user authentication</span>
|
||||
</li>
|
||||
<li className="flex items-start gap-2">
|
||||
<span className="text-warning-amber mt-0.5">•</span>
|
||||
<span>iRacing platform only</span>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</Card>
|
||||
|
||||
{/* Quick Start Guide */}
|
||||
<Card className="mb-8">
|
||||
<h2 className="text-2xl font-semibold text-white mb-4">Quick Start Guide</h2>
|
||||
<div className="space-y-4">
|
||||
<div className="flex items-start gap-4">
|
||||
<span className="flex items-center justify-center w-8 h-8 rounded-full bg-primary-blue/20 text-primary-blue font-semibold flex-shrink-0">
|
||||
1
|
||||
</span>
|
||||
<div>
|
||||
<h3 className="text-white font-medium mb-1">Create Your Profile</h3>
|
||||
<p className="text-sm text-gray-400">Set up your driver profile with racing number and iRacing ID.</p>
|
||||
<Button
|
||||
variant="secondary"
|
||||
onClick={() => router.push('/profile')}
|
||||
className="mt-2"
|
||||
>
|
||||
Go to Profile
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex items-start gap-4 pt-4 border-t border-charcoal-outline">
|
||||
<span className="flex items-center justify-center w-8 h-8 rounded-full bg-charcoal-outline text-gray-400 font-semibold flex-shrink-0">
|
||||
2
|
||||
</span>
|
||||
<div>
|
||||
<h3 className="text-white font-medium mb-1">Join or Create a League</h3>
|
||||
<p className="text-sm text-gray-400">Browse available leagues or create your own.</p>
|
||||
<Button
|
||||
variant="secondary"
|
||||
onClick={() => router.push('/leagues')}
|
||||
className="mt-2"
|
||||
>
|
||||
Browse Leagues
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex items-start gap-4 pt-4 border-t border-charcoal-outline">
|
||||
<span className="flex items-center justify-center w-8 h-8 rounded-full bg-charcoal-outline text-gray-400 font-semibold flex-shrink-0">
|
||||
3
|
||||
</span>
|
||||
<div>
|
||||
<h3 className="text-white font-medium mb-1">Schedule Races</h3>
|
||||
<p className="text-sm text-gray-400">Create race events and manage your schedule.</p>
|
||||
<Button
|
||||
variant="secondary"
|
||||
onClick={() => router.push('/races')}
|
||||
className="mt-2"
|
||||
>
|
||||
View Races
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Card>
|
||||
|
||||
{/* Navigation Cards */}
|
||||
<div className="grid grid-cols-1 md:grid-cols-3 gap-6">
|
||||
<div onClick={() => router.push('/profile')} className="cursor-pointer">
|
||||
<Card className="hover:border-primary-blue/30 transition-colors">
|
||||
<div className="flex flex-col items-center text-center py-4">
|
||||
<div className="w-12 h-12 rounded-lg bg-primary-blue/10 flex items-center justify-center mb-3">
|
||||
<svg className="w-6 h-6 text-primary-blue" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M16 7a4 4 0 11-8 0 4 4 0 018 0zM12 14a7 7 0 00-7 7h14a7 7 0 00-7-7z" />
|
||||
</svg>
|
||||
</div>
|
||||
<h3 className="text-white font-semibold mb-1">Profile</h3>
|
||||
<p className="text-sm text-gray-400">Manage your driver profile</p>
|
||||
</div>
|
||||
</Card>
|
||||
</div>
|
||||
|
||||
<div onClick={() => router.push('/leagues')} className="cursor-pointer">
|
||||
<Card className="hover:border-primary-blue/30 transition-colors">
|
||||
<div className="flex flex-col items-center text-center py-4">
|
||||
<div className="w-12 h-12 rounded-lg bg-primary-blue/10 flex items-center justify-center mb-3">
|
||||
<svg className="w-6 h-6 text-primary-blue" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M17 20h5v-2a3 3 0 00-5.356-1.857M17 20H7m10 0v-2c0-.656-.126-1.283-.356-1.857M7 20H2v-2a3 3 0 015.356-1.857M7 20v-2c0-.656.126-1.283.356-1.857m0 0a5.002 5.002 0 019.288 0M15 7a3 3 0 11-6 0 3 3 0 016 0zm6 3a2 2 0 11-4 0 2 2 0 014 0zM7 10a2 2 0 11-4 0 2 2 0 014 0z" />
|
||||
</svg>
|
||||
</div>
|
||||
<h3 className="text-white font-semibold mb-1">Leagues</h3>
|
||||
<p className="text-sm text-gray-400">Browse and join leagues</p>
|
||||
</div>
|
||||
</Card>
|
||||
</div>
|
||||
|
||||
<div onClick={() => router.push('/races')} className="cursor-pointer">
|
||||
<Card className="hover:border-primary-blue/30 transition-colors">
|
||||
<div className="flex flex-col items-center text-center py-4">
|
||||
<div className="w-12 h-12 rounded-lg bg-primary-blue/10 flex items-center justify-center mb-3">
|
||||
<svg className="w-6 h-6 text-primary-blue" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z" />
|
||||
</svg>
|
||||
</div>
|
||||
<h3 className="text-white font-semibold mb-1">Races</h3>
|
||||
<p className="text-sm text-gray-400">View race schedule</p>
|
||||
</div>
|
||||
</Card>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function LandingPage() {
|
||||
return (
|
||||
<main className="min-h-screen">
|
||||
<Hero />
|
||||
|
||||
{/* Section 1: A Persistent Identity */}
|
||||
<AlternatingSection
|
||||
heading="A Persistent Identity"
|
||||
backgroundVideo="/gameplay.mp4"
|
||||
description={
|
||||
<>
|
||||
<p>
|
||||
Your races, your seasons, your progress — finally in one place.
|
||||
</p>
|
||||
<div className="space-y-3 mt-4">
|
||||
<div className="group relative overflow-hidden rounded-lg bg-gradient-to-r from-slate-900/60 via-slate-800/40 to-slate-900/60 p-4 border border-slate-700/40 hover:border-primary-blue/50 transition-all duration-300 hover:shadow-[0_0_25px_rgba(59,130,246,0.15)]">
|
||||
<div className="absolute top-0 left-0 w-full h-0.5 bg-gradient-to-r from-transparent via-primary-blue/60 to-transparent opacity-0 group-hover:opacity-100 transition-opacity" />
|
||||
<div className="flex items-start gap-3">
|
||||
<div className="flex-shrink-0 w-9 h-9 rounded-lg bg-gradient-to-br from-primary-blue/20 to-blue-900/20 border border-primary-blue/30 flex items-center justify-center shadow-lg group-hover:scale-105 transition-transform">
|
||||
<svg className="w-5 h-5 text-primary-blue" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2.5} d="M5 13l4 4L19 7" />
|
||||
</svg>
|
||||
</div>
|
||||
<span className="text-slate-200 leading-relaxed font-light">Lifetime stats and season history across all your leagues</span>
|
||||
</div>
|
||||
</div>
|
||||
<div className="group relative overflow-hidden rounded-lg bg-gradient-to-r from-slate-900/60 via-slate-800/40 to-slate-900/60 p-4 border border-slate-700/40 hover:border-primary-blue/50 transition-all duration-300 hover:shadow-[0_0_25px_rgba(59,130,246,0.15)]">
|
||||
<div className="absolute top-0 left-0 w-full h-0.5 bg-gradient-to-r from-transparent via-primary-blue/60 to-transparent opacity-0 group-hover:opacity-100 transition-opacity" />
|
||||
<div className="flex items-start gap-3">
|
||||
<div className="flex-shrink-0 w-9 h-9 rounded-lg bg-gradient-to-br from-primary-blue/20 to-blue-900/20 border border-primary-blue/30 flex items-center justify-center shadow-lg group-hover:scale-105 transition-transform">
|
||||
<svg className="w-5 h-5 text-primary-blue" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2.5} d="M5 13l4 4L19 7" />
|
||||
</svg>
|
||||
</div>
|
||||
<span className="text-slate-200 leading-relaxed font-light">Track your performance, consistency, and team contributions</span>
|
||||
</div>
|
||||
</div>
|
||||
<div className="group relative overflow-hidden rounded-lg bg-gradient-to-r from-slate-900/60 via-slate-800/40 to-slate-900/60 p-4 border border-slate-700/40 hover:border-primary-blue/50 transition-all duration-300 hover:shadow-[0_0_25px_rgba(59,130,246,0.15)]">
|
||||
<div className="absolute top-0 left-0 w-full h-0.5 bg-gradient-to-r from-transparent via-primary-blue/60 to-transparent opacity-0 group-hover:opacity-100 transition-opacity" />
|
||||
<div className="flex items-start gap-3">
|
||||
<div className="flex-shrink-0 w-9 h-9 rounded-lg bg-gradient-to-br from-primary-blue/20 to-blue-900/20 border border-primary-blue/30 flex items-center justify-center shadow-lg group-hover:scale-105 transition-transform">
|
||||
<svg className="w-5 h-5 text-primary-blue" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2.5} d="M5 13l4 4L19 7" />
|
||||
</svg>
|
||||
</div>
|
||||
<span className="text-slate-200 leading-relaxed font-light">Your own rating that reflects real league competition</span>
|
||||
<Hero />
|
||||
|
||||
{/* Section 1: A Persistent Identity */}
|
||||
<AlternatingSection
|
||||
heading="A Persistent Identity"
|
||||
backgroundVideo="/gameplay.mp4"
|
||||
description={
|
||||
<>
|
||||
<p>
|
||||
Your races, your seasons, your progress — finally in one place.
|
||||
</p>
|
||||
<div className="space-y-3 mt-4">
|
||||
<div className="group relative overflow-hidden rounded-lg bg-gradient-to-r from-slate-900/60 via-slate-800/40 to-slate-900/60 p-4 border border-slate-700/40 hover:border-primary-blue/50 transition-all duration-300 hover:shadow-[0_0_25px_rgba(59,130,246,0.15)]">
|
||||
<div className="absolute top-0 left-0 w-full h-0.5 bg-gradient-to-r from-transparent via-primary-blue/60 to-transparent opacity-0 group-hover:opacity-100 transition-opacity" />
|
||||
<div className="flex items-start gap-3">
|
||||
<div className="flex-shrink-0 w-9 h-9 rounded-lg bg-gradient-to-br from-primary-blue/20 to-blue-900/20 border border-primary-blue/30 flex items-center justify-center shadow-lg group-hover:scale-105 transition-transform">
|
||||
<svg className="w-5 h-5 text-primary-blue" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2.5} d="M5 13l4 4L19 7" />
|
||||
</svg>
|
||||
</div>
|
||||
<span className="text-slate-200 leading-relaxed font-light">
|
||||
Lifetime stats and season history across all your leagues
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<p className="mt-4">
|
||||
iRacing gives you physics. GridPilot gives you a career.
|
||||
</p>
|
||||
</>
|
||||
}
|
||||
mockup={<CareerProgressionMockup />}
|
||||
layout="text-left"
|
||||
/>
|
||||
|
||||
<FeatureGrid />
|
||||
|
||||
{/* Section 2: Results That Actually Stay */}
|
||||
<AlternatingSection
|
||||
heading="Results That Actually Stay"
|
||||
backgroundImage="/images/ff1600.jpeg"
|
||||
description={
|
||||
<>
|
||||
<p className="text-sm md:text-base leading-relaxed">
|
||||
Every race you run stays with you.
|
||||
</p>
|
||||
<div className="space-y-3 mt-4 md:mt-6">
|
||||
<div className="group relative overflow-hidden rounded-lg bg-gradient-to-r from-slate-900/60 via-slate-800/40 to-slate-900/60 p-3.5 md:p-4 border border-slate-700/40 hover:border-red-600/50 transition-all duration-300 hover:shadow-[0_0_25px_rgba(220,38,38,0.15)]">
|
||||
<div className="absolute top-0 right-0 w-12 h-12 bg-gradient-to-bl from-red-600/10 to-transparent rounded-bl-3xl opacity-0 group-hover:opacity-100 transition-opacity" />
|
||||
<div className="flex items-start gap-2.5 md:gap-3">
|
||||
<div className="flex-shrink-0 w-8 h-8 md:w-9 md:h-9 rounded-lg bg-gradient-to-br from-red-600/20 to-red-900/20 border border-red-600/30 flex items-center justify-center shadow-lg group-hover:scale-105 transition-transform">
|
||||
<svg className="w-4 h-4 md:w-5 md:h-5 text-red-500" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2.5} d="M13.828 10.172a4 4 0 00-5.656 0l-4 4a4 4 0 105.656 5.656l1.102-1.101m-.758-4.899a4 4 0 005.656 0l4-4a4 4 0 00-5.656-5.656l-1.1 1.1" />
|
||||
</svg>
|
||||
</div>
|
||||
<span className="text-slate-200 text-sm md:text-base leading-relaxed font-light">Your stats, your team, your story — all connected</span>
|
||||
</div>
|
||||
</div>
|
||||
<div className="group relative overflow-hidden rounded-lg bg-gradient-to-r from-slate-900/60 via-slate-800/40 to-slate-900/60 p-3.5 md:p-4 border border-slate-700/40 hover:border-red-600/50 transition-all duration-300 hover:shadow-[0_0_25px_rgba(220,38,38,0.15)]">
|
||||
<div className="absolute top-0 right-0 w-12 h-12 bg-gradient-to-bl from-red-600/10 to-transparent rounded-bl-3xl opacity-0 group-hover:opacity-100 transition-opacity" />
|
||||
<div className="flex items-start gap-2.5 md:gap-3">
|
||||
<div className="flex-shrink-0 w-8 h-8 md:w-9 md:h-9 rounded-lg bg-gradient-to-br from-red-600/20 to-red-900/20 border border-red-600/30 flex items-center justify-center shadow-lg group-hover:scale-105 transition-transform">
|
||||
<svg className="w-4 h-4 md:w-5 md:h-5 text-red-500" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2.5} d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15" />
|
||||
</svg>
|
||||
</div>
|
||||
<span className="text-slate-200 text-sm md:text-base leading-relaxed font-light">One race result updates your profile, team points, rating, and season history</span>
|
||||
</div>
|
||||
</div>
|
||||
<div className="group relative overflow-hidden rounded-lg bg-gradient-to-r from-slate-900/60 via-slate-800/40 to-slate-900/60 p-3.5 md:p-4 border border-slate-700/40 hover:border-red-600/50 transition-all duration-300 hover:shadow-[0_0_25px_rgba(220,38,38,0.15)]">
|
||||
<div className="absolute top-0 right-0 w-12 h-12 bg-gradient-to-bl from-red-600/10 to-transparent rounded-bl-3xl opacity-0 group-hover:opacity-100 transition-opacity" />
|
||||
<div className="flex items-start gap-2.5 md:gap-3">
|
||||
<div className="flex-shrink-0 w-8 h-8 md:w-9 md:h-9 rounded-lg bg-gradient-to-br from-red-600/20 to-red-900/20 border border-red-600/30 flex items-center justify-center shadow-lg group-hover:scale-105 transition-transform">
|
||||
<svg className="w-4 h-4 md:w-5 md:h-5 text-red-500" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2.5} d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z" />
|
||||
</svg>
|
||||
</div>
|
||||
<span className="text-slate-200 text-sm md:text-base leading-relaxed font-light">No more fragmented data across spreadsheets and forums</span>
|
||||
<div className="group relative overflow-hidden rounded-lg bg-gradient-to-r from-slate-900/60 via-slate-800/40 to-slate-900/60 p-4 border border-slate-700/40 hover:border-primary-blue/50 transition-all duration-300 hover:shadow-[0_0_25px_rgba(59,130,246,0.15)]">
|
||||
<div className="absolute top-0 left-0 w-full h-0.5 bg-gradient-to-r from-transparent via-primary-blue/60 to-transparent opacity-0 group-hover:opacity-100 transition-opacity" />
|
||||
<div className="flex items-start gap-3">
|
||||
<div className="flex-shrink-0 w-9 h-9 rounded-lg bg-gradient-to-br from-primary-blue/20 to-blue-900/20 border border-primary-blue/30 flex items-center justify-center shadow-lg group-hover:scale-105 transition-transform">
|
||||
<svg className="w-5 h-5 text-primary-blue" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2.5} d="M5 13l4 4L19 7" />
|
||||
</svg>
|
||||
</div>
|
||||
<span className="text-slate-200 leading-relaxed font-light">
|
||||
Track your performance, consistency, and team contributions
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<p className="mt-4 md:mt-6 text-sm md:text-base leading-relaxed">
|
||||
Your racing career, finally in one place.
|
||||
</p>
|
||||
</>
|
||||
}
|
||||
mockup={<MockupStack index={1}><RaceHistoryMockup /></MockupStack>}
|
||||
layout="text-right"
|
||||
/>
|
||||
|
||||
{/* Section 3: Automatic Session Creation */}
|
||||
<AlternatingSection
|
||||
heading="Automatic Session Creation"
|
||||
description={
|
||||
<>
|
||||
<p className="text-sm md:text-base leading-relaxed">
|
||||
Setting up league races used to mean clicking through iRacing's wizard 20 times.
|
||||
</p>
|
||||
<div className="space-y-3 mt-4 md:mt-6">
|
||||
<div className="group relative overflow-hidden rounded-lg bg-gradient-to-br from-slate-900/70 to-slate-800/50 p-3.5 md:p-4 border border-slate-700/50 hover:border-primary-blue/60 transition-all duration-300 hover:shadow-[0_0_30px_rgba(59,130,246,0.2)]">
|
||||
<div className="absolute -top-12 -right-12 w-24 h-24 bg-gradient-to-br from-primary-blue/10 to-transparent rounded-full blur-2xl opacity-0 group-hover:opacity-100 transition-opacity" />
|
||||
<div className="flex items-start gap-2.5 md:gap-3 relative">
|
||||
<div className="flex-shrink-0 w-9 h-9 md:w-10 md:h-10 rounded-xl bg-gradient-to-br from-primary-blue/25 to-blue-900/25 border border-primary-blue/40 flex items-center justify-center shadow-lg group-hover:shadow-primary-blue/20 group-hover:scale-110 transition-all">
|
||||
<span className="text-primary-blue font-bold text-sm">1</span>
|
||||
</div>
|
||||
<span className="text-slate-200 text-sm md:text-base leading-relaxed font-light">Our companion app syncs with your league schedule</span>
|
||||
</div>
|
||||
</div>
|
||||
<div className="group relative overflow-hidden rounded-lg bg-gradient-to-br from-slate-900/70 to-slate-800/50 p-3.5 md:p-4 border border-slate-700/50 hover:border-primary-blue/60 transition-all duration-300 hover:shadow-[0_0_30px_rgba(59,130,246,0.2)]">
|
||||
<div className="absolute -top-12 -right-12 w-24 h-24 bg-gradient-to-br from-primary-blue/10 to-transparent rounded-full blur-2xl opacity-0 group-hover:opacity-100 transition-opacity" />
|
||||
<div className="flex items-start gap-2.5 md:gap-3 relative">
|
||||
<div className="flex-shrink-0 w-9 h-9 md:w-10 md:h-10 rounded-xl bg-gradient-to-br from-primary-blue/25 to-blue-900/25 border border-primary-blue/40 flex items-center justify-center shadow-lg group-hover:shadow-primary-blue/20 group-hover:scale-110 transition-all">
|
||||
<span className="text-primary-blue font-bold text-sm">2</span>
|
||||
</div>
|
||||
<span className="text-slate-200 text-sm md:text-base leading-relaxed font-light">When it's race time, it creates the iRacing session automatically</span>
|
||||
</div>
|
||||
</div>
|
||||
<div className="group relative overflow-hidden rounded-lg bg-gradient-to-br from-slate-900/70 to-slate-800/50 p-3.5 md:p-4 border border-slate-700/50 hover:border-primary-blue/60 transition-all duration-300 hover:shadow-[0_0_30px_rgba(59,130,246,0.2)]">
|
||||
<div className="absolute -top-12 -right-12 w-24 h-24 bg-gradient-to-br from-primary-blue/10 to-transparent rounded-full blur-2xl opacity-0 group-hover:opacity-100 transition-opacity" />
|
||||
<div className="flex items-start gap-2.5 md:gap-3 relative">
|
||||
<div className="flex-shrink-0 w-9 h-9 md:w-10 md:h-10 rounded-xl bg-gradient-to-br from-primary-blue/25 to-blue-900/25 border border-primary-blue/40 flex items-center justify-center shadow-lg group-hover:shadow-primary-blue/20 group-hover:scale-110 transition-all">
|
||||
<span className="text-primary-blue font-bold text-sm">3</span>
|
||||
</div>
|
||||
<span className="text-slate-200 text-sm md:text-base leading-relaxed font-light">No clicking through wizards. No manual setup</span>
|
||||
</div>
|
||||
</div>
|
||||
<div className="group relative overflow-hidden rounded-lg bg-gradient-to-br from-slate-900/70 to-slate-800/50 p-3.5 md:p-4 border border-slate-700/50 hover:border-green-600/60 transition-all duration-300 hover:shadow-[0_0_30px_rgba(34,197,94,0.2)]">
|
||||
<div className="absolute -top-12 -right-12 w-24 h-24 bg-gradient-to-br from-green-600/10 to-transparent rounded-full blur-2xl opacity-0 group-hover:opacity-100 transition-opacity" />
|
||||
<div className="flex items-start gap-2.5 md:gap-3 relative">
|
||||
<div className="flex-shrink-0 w-9 h-9 md:w-10 md:h-10 rounded-xl bg-gradient-to-br from-green-600/25 to-green-900/25 border border-green-600/40 flex items-center justify-center shadow-lg group-hover:shadow-green-600/20 group-hover:scale-110 transition-all">
|
||||
<svg className="w-4 h-4 md:w-5 md:h-5 text-green-500" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2.5} d="M9 12l2 2 4-4m5.618-4.016A11.955 11.955 0 0112 2.944a11.955 11.955 0 01-8.618 3.04A12.02 12.02 0 003 9c0 5.591 3.824 10.29 9 11.622 5.176-1.332 9-6.03 9-11.622 0-1.042-.133-2.052-.382-3.016z" />
|
||||
</svg>
|
||||
</div>
|
||||
<span className="text-slate-200 text-sm md:text-base leading-relaxed font-light">Runs on your machine, totally transparent, completely safe</span>
|
||||
<div className="group relative overflow-hidden rounded-lg bg-gradient-to-r from-slate-900/60 via-slate-800/40 to-slate-900/60 p-4 border border-slate-700/40 hover:border-primary-blue/50 transition-all duration-300 hover:shadow-[0_0_25px_rgba(59,130,246,0.15)]">
|
||||
<div className="absolute top-0 left-0 w-full h-0.5 bg-gradient-to-r from-transparent via-primary-blue/60 to-transparent opacity-0 group-hover:opacity-100 transition-opacity" />
|
||||
<div className="flex items-start gap-3">
|
||||
<div className="flex-shrink-0 w-9 h-9 rounded-lg bg-gradient-to-br from-primary-blue/20 to-blue-900/20 border border-primary-blue/30 flex items-center justify-center shadow-lg group-hover:scale-105 transition-transform">
|
||||
<svg className="w-5 h-5 text-primary-blue" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2.5} d="M5 13l4 4L19 7" />
|
||||
</svg>
|
||||
</div>
|
||||
<span className="text-slate-200 leading-relaxed font-light">
|
||||
Your own rating that reflects real league competition
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<p className="mt-4 md:mt-6 text-sm md:text-base leading-relaxed">
|
||||
Automation instead of repetition.
|
||||
</p>
|
||||
</>
|
||||
}
|
||||
mockup={<CompanionAutomationMockup />}
|
||||
layout="text-left"
|
||||
/>
|
||||
</div>
|
||||
<p className="mt-4">
|
||||
iRacing gives you physics. GridPilot gives you a career.
|
||||
</p>
|
||||
</>
|
||||
}
|
||||
mockup={<CareerProgressionMockup />}
|
||||
layout="text-left"
|
||||
/>
|
||||
|
||||
{/* Section 4: Game-Agnostic Platform */}
|
||||
<AlternatingSection
|
||||
heading="Built for iRacing. Ready for the future."
|
||||
backgroundImage="/images/lmp3.jpeg"
|
||||
description={
|
||||
<>
|
||||
<p className="text-sm md:text-base leading-relaxed">
|
||||
Right now, we're focused on making iRacing league racing better.
|
||||
<FeatureGrid />
|
||||
|
||||
{/* Section 2: Results That Actually Stay */}
|
||||
<AlternatingSection
|
||||
heading="Results That Actually Stay"
|
||||
backgroundImage="/images/ff1600.jpeg"
|
||||
description={
|
||||
<>
|
||||
<p className="text-sm md:text-base leading-relaxed">
|
||||
Every race you run stays with you.
|
||||
</p>
|
||||
<div className="space-y-3 mt-4 md:mt-6">
|
||||
<div className="group relative overflow-hidden rounded-lg bg-gradient-to-r from-slate-900/60 via-slate-800/40 to-slate-900/60 p-3.5 md:p-4 border border-slate-700/40 hover:border-red-600/50 transition-all duration-300 hover:shadow-[0_0_25px_rgba(220,38,38,0.15)]">
|
||||
<div className="absolute top-0 right-0 w-12 h-12 bg-gradient-to-bl from-red-600/10 to-transparent rounded-bl-3xl opacity-0 group-hover:opacity-100 transition-opacity" />
|
||||
<div className="flex items-start gap-2.5 md:gap-3">
|
||||
<div className="flex-shrink-0 w-8 h-8 md:w-9 md:h-9 rounded-lg bg-gradient-to-br from-red-600/20 to-red-900/20 border border-red-600/30 flex items-center justify-center shadow-lg group-hover:scale-105 transition-transform">
|
||||
<svg className="w-4 h-4 md:w-5 md:h-5 text-red-500" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2.5} d="M13.828 10.172a4 4 0 00-5.656 0l-4 4a4 4 0 105.656 5.656l1.102-1.101m-.758-4.899a4 4 0 005.656 0l4-4a4 4 0 00-5.656-5.656l-1.1 1.1" />
|
||||
</svg>
|
||||
</div>
|
||||
<span className="text-slate-200 text-sm md:text-base leading-relaxed font-light">
|
||||
Your stats, your team, your story — all connected
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div className="group relative overflow-hidden rounded-lg bg-gradient-to-r from-slate-900/60 via-slate-800/40 to-slate-900/60 p-3.5 md:p-4 border border-slate-700/40 hover:border-red-600/50 transition-all duration-300 hover:shadow-[0_0_25px_rgba(220,38,38,0.15)]">
|
||||
<div className="absolute top-0 right-0 w-12 h-12 bg-gradient-to-bl from-red-600/10 to-transparent rounded-bl-3xl opacity-0 group-hover:opacity-100 transition-opacity" />
|
||||
<div className="flex items-start gap-2.5 md:gap-3">
|
||||
<div className="flex-shrink-0 w-8 h-8 md:w-9 md:h-9 rounded-lg bg-gradient-to-br from-red-600/20 to-red-900/20 border border-red-600/30 flex items-center justify-center shadow-lg group-hover:scale-105 transition-transform">
|
||||
<svg className="w-4 h-4 md:w-5 md:h-5 text-red-500" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2.5} d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15" />
|
||||
</svg>
|
||||
</div>
|
||||
<span className="text-slate-200 text-sm md:text-base leading-relaxed font-light">
|
||||
One race result updates your profile, team points, rating, and season history
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div className="group relative overflow-hidden rounded-lg bg-gradient-to-r from-slate-900/60 via-slate-800/40 to-slate-900/60 p-3.5 md:p-4 border border-slate-700/40 hover:border-red-600/50 transition-all duration-300 hover:shadow-[0_0_25px_rgba(220,38,38,0.15)]">
|
||||
<div className="absolute top-0 right-0 w-12 h-12 bg-gradient-to-bl from-red-600/10 to-transparent rounded-bl-3xl opacity-0 group-hover:opacity-100 transition-opacity" />
|
||||
<div className="flex items-start gap-2.5 md:gap-3">
|
||||
<div className="flex-shrink-0 w-8 h-8 md:w-9 md:h-9 rounded-lg bg-gradient-to-br from-red-600/20 to-red-900/20 border border-red-600/30 flex items-center justify-center shadow-lg group-hover:scale-105 transition-transform">
|
||||
<svg className="w-4 h-4 md:w-5 md:h-5 text-red-500" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2.5} d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z" />
|
||||
</svg>
|
||||
</div>
|
||||
<span className="text-slate-200 text-sm md:text-base leading-relaxed font-light">
|
||||
No more fragmented data across spreadsheets and forums
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<p className="mt-4 md:mt-6 text-sm md:text-base leading-relaxed">
|
||||
Your racing career, finally in one place.
|
||||
</p>
|
||||
</>
|
||||
}
|
||||
mockup={<MockupStack index={1}><RaceHistoryMockup /></MockupStack>}
|
||||
layout="text-right"
|
||||
/>
|
||||
|
||||
{/* Section 3: Automatic Session Creation */}
|
||||
<AlternatingSection
|
||||
heading="Automatic Session Creation"
|
||||
description={
|
||||
<>
|
||||
<p className="text-sm md:text-base leading-relaxed">
|
||||
Setting up league races used to mean clicking through iRacing's wizard 20 times.
|
||||
</p>
|
||||
<div className="space-y-3 mt-4 md:mt-6">
|
||||
<div className="group relative overflow-hidden rounded-lg bg-gradient-to-br from-slate-900/70 to-slate-800/50 p-3.5 md:p-4 border border-slate-700/50 hover:border-primary-blue/60 transition-all duration-300 hover:shadow-[0_0_30px_rgba(59,130,246,0.2)]">
|
||||
<div className="absolute -top-12 -right-12 w-24 h-24 bg-gradient-to-br from-primary-blue/10 to-transparent rounded-full blur-2xl opacity-0 group-hover:opacity-100 transition-opacity" />
|
||||
<div className="flex items-start gap-2.5 md:gap-3 relative">
|
||||
<div className="flex-shrink-0 w-9 h-9 md:w-10 md:h-10 rounded-xl bg-gradient-to-br from-primary-blue/25 to-blue-900/25 border border-primary-blue/40 flex items-center justify-center shadow-lg group-hover:shadow-primary-blue/20 group-hover:scale-110 transition-all">
|
||||
<span className="text-primary-blue font-bold text-sm">1</span>
|
||||
</div>
|
||||
<span className="text-slate-200 text-sm md:text-base leading-relaxed font-light">
|
||||
Our companion app syncs with your league schedule
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div className="group relative overflow-hidden rounded-lg bg-gradient-to-br from-slate-900/70 to-slate-800/50 p-3.5 md:p-4 border border-slate-700/50 hover:border-primary-blue/60 transition-all duration-300 hover:shadow-[0_0_30px_rgba(59,130,246,0.2)]">
|
||||
<div className="absolute -top-12 -right-12 w-24 h-24 bg-gradient-to-br from-primary-blue/10 to-transparent rounded-full blur-2xl opacity-0 group-hover:opacity-100 transition-opacity" />
|
||||
<div className="flex items-start gap-2.5 md:gap-3 relative">
|
||||
<div className="flex-shrink-0 w-9 h-9 md:w-10 md:h-10 rounded-xl bg-gradient-to-br from-primary-blue/25 to-blue-900/25 border border-primary-blue/40 flex items-center justify-center shadow-lg group-hover:shadow-primary-blue/20 group-hover:scale-110 transition-all">
|
||||
<span className="text-primary-blue font-bold text-sm">2</span>
|
||||
</div>
|
||||
<span className="text-slate-200 text-sm md:text-base leading-relaxed font-light">
|
||||
When it's race time, it creates the iRacing session automatically
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div className="group relative overflow-hidden rounded-lg bg-gradient-to-br from-slate-900/70 to-slate-800/50 p-3.5 md:p-4 border border-slate-700/50 hover:border-primary-blue/60 transition-all duration-300 hover:shadow-[0_0_30px_rgba(59,130,246,0.2)]">
|
||||
<div className="absolute -top-12 -right-12 w-24 h-24 bg-gradient-to-br from-primary-blue/10 to-transparent rounded-full blur-2xl opacity-0 group-hover:opacity-100 transition-opacity" />
|
||||
<div className="flex items-start gap-2.5 md:gap-3 relative">
|
||||
<div className="flex-shrink-0 w-9 h-9 md:w-10 md:h-10 rounded-xl bg-gradient-to-br from-primary-blue/25 to-blue-900/25 border border-primary-blue/40 flex items-center justify-center shadow-lg group-hover:shadow-primary-blue/20 group-hover:scale-110 transition-all">
|
||||
<span className="text-primary-blue font-bold text-sm">3</span>
|
||||
</div>
|
||||
<span className="text-slate-200 text-sm md:text-base leading-relaxed font-light">
|
||||
No clicking through wizards. No manual setup
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<p className="mt-4 md:mt-6 text-sm md:text-base leading-relaxed">
|
||||
Automation instead of repetition.
|
||||
</p>
|
||||
</>
|
||||
}
|
||||
mockup={<CompanionAutomationMockup />}
|
||||
layout="text-left"
|
||||
/>
|
||||
|
||||
{/* Section 4: Game-Agnostic Platform */}
|
||||
<AlternatingSection
|
||||
heading="Built for iRacing. Ready for the future."
|
||||
backgroundImage="/images/lmp3.jpeg"
|
||||
description={
|
||||
<>
|
||||
<p className="text-sm md:text-base leading-relaxed">
|
||||
Right now, we're focused on making iRacing league racing better.
|
||||
</p>
|
||||
<p className="mt-4 md:mt-6 text-sm md:text-base leading-relaxed">
|
||||
But sims come and go. Your leagues, your teams, your rating — those stay.
|
||||
</p>
|
||||
<p className="mt-4 md:mt-6 text-sm md:text-base leading-relaxed">
|
||||
GridPilot is built to outlast any single platform.
|
||||
</p>
|
||||
<p className="mt-4 md:mt-6 text-sm md:text-base leading-relaxed">
|
||||
When the next sim arrives, your competitive identity moves with you.
|
||||
</p>
|
||||
</>
|
||||
}
|
||||
mockup={<SimPlatformMockup />}
|
||||
layout="text-right"
|
||||
/>
|
||||
|
||||
{/* Alpha-only discovery section */}
|
||||
{isAlpha && (
|
||||
<section className="max-w-7xl mx-auto mt-20 mb-20 px-6">
|
||||
<div className="flex items-baseline justify-between mb-8">
|
||||
<div>
|
||||
<h2 className="text-2xl font-semibold text-white">Discover the grid</h2>
|
||||
<p className="text-sm text-gray-400">
|
||||
Explore leagues, teams, and races that make up the GridPilot ecosystem.
|
||||
</p>
|
||||
<p className="mt-4 md:mt-6 text-sm md:text-base leading-relaxed">
|
||||
But sims come and go. Your leagues, your teams, your rating — those stay.
|
||||
</p>
|
||||
<p className="mt-4 md:mt-6 text-sm md:text-base leading-relaxed">
|
||||
GridPilot is built to outlast any single platform.
|
||||
</p>
|
||||
<p className="mt-4 md:mt-6 text-sm md:text-base leading-relaxed">
|
||||
When the next sim arrives, your competitive identity moves with you.
|
||||
</p>
|
||||
</>
|
||||
}
|
||||
mockup={<SimPlatformMockup />}
|
||||
layout="text-right"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="grid gap-8 lg:grid-cols-3">
|
||||
{/* Top leagues */}
|
||||
<Card className="bg-iron-gray/80">
|
||||
<div className="flex items-baseline justify-between mb-4">
|
||||
<h3 className="text-sm font-semibold text-white">Featured leagues</h3>
|
||||
<Button
|
||||
as="a"
|
||||
href="/leagues"
|
||||
variant="secondary"
|
||||
className="text-[11px] px-3 py-1.5"
|
||||
>
|
||||
View all
|
||||
</Button>
|
||||
</div>
|
||||
<ul className="space-y-3 text-sm">
|
||||
{topLeagues.slice(0, 4).map(league => (
|
||||
<li key={league.id} className="flex items-start gap-3">
|
||||
<div className="w-10 h-10 rounded-md bg-primary-blue/15 border border-primary-blue/30 flex items-center justify-center text-xs font-semibold text-primary-blue">
|
||||
{league.name
|
||||
.split(' ')
|
||||
.map(word => word[0])
|
||||
.join('')
|
||||
.slice(0, 3)
|
||||
.toUpperCase()}
|
||||
</div>
|
||||
<div className="flex-1 min-w-0">
|
||||
<p className="text-white truncate">{league.name}</p>
|
||||
<p className="text-xs text-gray-400 line-clamp-2">
|
||||
{league.description}
|
||||
</p>
|
||||
</div>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</Card>
|
||||
|
||||
{/* Teams */}
|
||||
<Card className="bg-iron-gray/80">
|
||||
<div className="flex items-baseline justify-between mb-4">
|
||||
<h3 className="text-sm font-semibold text-white">Teams on the grid</h3>
|
||||
<Button
|
||||
as="a"
|
||||
href="/teams"
|
||||
variant="secondary"
|
||||
className="text-[11px] px-3 py-1.5"
|
||||
>
|
||||
Browse teams
|
||||
</Button>
|
||||
</div>
|
||||
<ul className="space-y-3 text-sm">
|
||||
{teams.slice(0, 4).map(team => (
|
||||
<li key={team.id} className="flex items-start gap-3">
|
||||
<div className="w-10 h-10 rounded-md bg-charcoal-outline flex items-center justify-center text-xs font-semibold text-white">
|
||||
{team.tag}
|
||||
</div>
|
||||
<div className="flex-1 min-w-0">
|
||||
<p className="text-white truncate">{team.name}</p>
|
||||
<p className="text-xs text-gray-400 line-clamp-2">
|
||||
{team.description}
|
||||
</p>
|
||||
</div>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</Card>
|
||||
|
||||
{/* Upcoming races */}
|
||||
<Card className="bg-iron-gray/80">
|
||||
<div className="flex items-baseline justify-between mb-4">
|
||||
<h3 className="text-sm font-semibold text-white">Upcoming races</h3>
|
||||
<Button
|
||||
as="a"
|
||||
href="/races"
|
||||
variant="secondary"
|
||||
className="text-[11px] px-3 py-1.5"
|
||||
>
|
||||
View schedule
|
||||
</Button>
|
||||
</div>
|
||||
{upcomingRaces.length === 0 ? (
|
||||
<p className="text-xs text-gray-400">
|
||||
No races scheduled in this demo snapshot.
|
||||
</p>
|
||||
) : (
|
||||
<ul className="space-y-3 text-sm">
|
||||
{upcomingRaces.map(race => (
|
||||
<li key={race.id} className="flex items-start justify-between gap-3">
|
||||
<div className="flex-1 min-w-0">
|
||||
<p className="text-white truncate">{race.track}</p>
|
||||
<p className="text-xs text-gray-400 truncate">{race.car}</p>
|
||||
</div>
|
||||
<div className="text-right text-xs text-gray-500 whitespace-nowrap">
|
||||
{race.scheduledAt.toLocaleDateString(undefined, {
|
||||
month: 'short',
|
||||
day: 'numeric'
|
||||
})}
|
||||
</div>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
)}
|
||||
</Card>
|
||||
</div>
|
||||
</section>
|
||||
)}
|
||||
|
||||
<DiscordCTA />
|
||||
<FAQ />
|
||||
<Footer />
|
||||
</main>
|
||||
);
|
||||
}
|
||||
|
||||
export default function HomePage() {
|
||||
const mode = getAppMode();
|
||||
|
||||
if (mode === 'alpha') {
|
||||
return <AlphaDashboard />;
|
||||
}
|
||||
|
||||
return <LandingPage />;
|
||||
}
|
||||
Reference in New Issue
Block a user