150 行
6.0 KiB
TypeScript
150 行
6.0 KiB
TypeScript
import { useAuth } from "@/_core/hooks/useAuth";
|
|
import { Button } from "@/components/ui/button";
|
|
import { useLocation, Redirect } from "wouter";
|
|
import {
|
|
Target, Video, Award, TrendingUp, Zap, Activity,
|
|
ChevronRight, Footprints, BarChart3
|
|
} from "lucide-react";
|
|
|
|
export default function Home() {
|
|
const { user, loading, isAuthenticated } = useAuth();
|
|
const [, setLocation] = useLocation();
|
|
|
|
if (loading) return null;
|
|
if (isAuthenticated) return <Redirect to="/dashboard" />;
|
|
|
|
return (
|
|
<div className="min-h-screen bg-gradient-to-b from-green-50 via-background to-emerald-50/30">
|
|
{/* Hero */}
|
|
<header className="container py-6 flex items-center justify-between">
|
|
<div className="flex items-center gap-2">
|
|
<Target className="h-6 w-6 text-primary" />
|
|
<span className="font-bold text-lg tracking-tight">Tennis Hub</span>
|
|
</div>
|
|
<Button onClick={() => setLocation("/login")} variant="default" size="sm">
|
|
开始使用
|
|
</Button>
|
|
</header>
|
|
|
|
<section className="container py-16 md:py-24">
|
|
<div className="max-w-3xl mx-auto text-center">
|
|
<div className="inline-flex items-center gap-2 px-3 py-1 rounded-full bg-primary/10 text-primary text-sm font-medium mb-6">
|
|
<Zap className="h-3.5 w-3.5" />
|
|
网球训练系统
|
|
</div>
|
|
<h1 className="text-4xl md:text-5xl lg:text-6xl font-bold tracking-tight leading-tight">
|
|
训练记录
|
|
<span className="text-primary block mt-1">分析与录制</span>
|
|
</h1>
|
|
<p className="text-lg text-muted-foreground mt-6 max-w-xl mx-auto leading-relaxed">
|
|
训练计划 · 姿势分析 · 实时录制 · 评分记录
|
|
</p>
|
|
<div className="flex items-center justify-center gap-3 mt-8">
|
|
<Button onClick={() => setLocation("/login")} size="lg" className="gap-2 h-12 px-6">
|
|
进入系统
|
|
<ChevronRight className="h-4 w-4" />
|
|
</Button>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
{/* Features */}
|
|
<section className="container py-16">
|
|
<h2 className="text-2xl font-bold text-center mb-12">功能</h2>
|
|
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6 max-w-5xl mx-auto">
|
|
{[
|
|
{
|
|
icon: Video,
|
|
title: "姿势识别",
|
|
desc: "使用 MediaPipe 分析 33 个关键点并记录挥拍数据",
|
|
color: "bg-blue-50 text-blue-600",
|
|
},
|
|
{
|
|
icon: Target,
|
|
title: "训练计划",
|
|
desc: "根据水平和分析结果生成训练安排",
|
|
color: "bg-green-50 text-green-600",
|
|
},
|
|
{
|
|
icon: Award,
|
|
title: "NTRP自动评分",
|
|
desc: "按 USTA 维度记录评分结果",
|
|
color: "bg-purple-50 text-purple-600",
|
|
},
|
|
{
|
|
icon: Zap,
|
|
title: "击球统计",
|
|
desc: "记录击球次数、挥拍速度和一致性",
|
|
color: "bg-orange-50 text-orange-600",
|
|
},
|
|
{
|
|
icon: Footprints,
|
|
title: "运动轨迹",
|
|
desc: "记录重心移动轨迹和脚步变化",
|
|
color: "bg-teal-50 text-teal-600",
|
|
},
|
|
{
|
|
icon: TrendingUp,
|
|
title: "进度追踪",
|
|
desc: "查看训练历史、趋势和评分变化",
|
|
color: "bg-indigo-50 text-indigo-600",
|
|
},
|
|
].map((feature) => (
|
|
<div key={feature.title} className="p-6 rounded-2xl border bg-card hover:shadow-md transition-shadow">
|
|
<div className={`h-12 w-12 rounded-xl ${feature.color} flex items-center justify-center mb-4`}>
|
|
<feature.icon className="h-6 w-6" />
|
|
</div>
|
|
<h3 className="font-semibold text-base mb-2">{feature.title}</h3>
|
|
<p className="text-sm text-muted-foreground leading-relaxed">{feature.desc}</p>
|
|
</div>
|
|
))}
|
|
</div>
|
|
</section>
|
|
|
|
{/* How it works */}
|
|
<section className="container py-16">
|
|
<h2 className="text-2xl font-bold text-center mb-12">使用步骤</h2>
|
|
<div className="grid grid-cols-1 md:grid-cols-4 gap-6 max-w-4xl mx-auto">
|
|
{[
|
|
{ step: "1", title: "输入用户名", desc: "用户名登录即可" },
|
|
{ step: "2", title: "生成计划", desc: "生成训练安排" },
|
|
{ step: "3", title: "上传视频", desc: "录制挥拍并分析" },
|
|
{ step: "4", title: "获取反馈", desc: "评分与矫正建议" },
|
|
].map((item) => (
|
|
<div key={item.step} className="text-center">
|
|
<div className="h-12 w-12 rounded-full bg-primary text-primary-foreground flex items-center justify-center text-lg font-bold mx-auto mb-3">
|
|
{item.step}
|
|
</div>
|
|
<h3 className="font-semibold text-sm mb-1">{item.title}</h3>
|
|
<p className="text-xs text-muted-foreground">{item.desc}</p>
|
|
</div>
|
|
))}
|
|
</div>
|
|
</section>
|
|
|
|
{/* CTA */}
|
|
<section className="container py-16">
|
|
<div className="max-w-2xl mx-auto text-center p-8 rounded-2xl bg-primary/5">
|
|
<h2 className="text-2xl font-bold mb-3">登录入口</h2>
|
|
<p className="text-muted-foreground mb-6">输入用户名后进入系统</p>
|
|
<Button onClick={() => setLocation("/login")} size="lg" className="gap-2">
|
|
前往登录
|
|
<ChevronRight className="h-4 w-4" />
|
|
</Button>
|
|
</div>
|
|
</section>
|
|
|
|
{/* Footer */}
|
|
<footer className="container py-8 border-t">
|
|
<div className="flex items-center justify-between text-xs text-muted-foreground">
|
|
<div className="flex items-center gap-2">
|
|
<Target className="h-4 w-4" />
|
|
<span>Tennis Hub</span>
|
|
</div>
|
|
<span>训练与分析</span>
|
|
</div>
|
|
</footer>
|
|
</div>
|
|
);
|
|
}
|