优化数据结构和交互逻辑,添加方便编辑数据的机器人/参赛历史数据文件

This commit is contained in:
HelixCopex 2025-04-19 20:18:53 +08:00
parent d9da27ce1f
commit c906a2c013
21 changed files with 1069 additions and 299 deletions

View File

@ -1,10 +1,11 @@
"use client"
import { useState } from "react"
import Image from "next/image"
import Link from "next/link"
import { ArrowLeft } from "lucide-react"
import { Button } from "@/components/ui/button"
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "@/components/ui/tooltip"
import { robotsByYear } from "@/lib/robot-data"
export default function HistoryPage() {
// 历届队员数据
@ -120,54 +121,58 @@ export default function HistoryPage() {
},
]
// 历届机器人数据
const robots = [
{
year: "2023-2024",
models: [
{
name: "Sentinel MK-III",
image: "/placeholder.svg?height=300&width=400",
description: "我们的旗舰防御机器人配备先进装甲板和360°旋转炮塔系统。",
achievements: ["区域赛最佳设计奖", "全国赛技术挑战赛亚军"],
},
{
name: "Striker X2",
image: "/placeholder.svg?height=300&width=400",
description: "高机动性攻击单元,设计用于快速交战和战略定位。",
achievements: ["区域赛最佳性能奖"],
},
],
},
{
year: "2022-2023",
models: [
{
name: "Sentinel MK-II",
image: "/placeholder.svg?height=300&width=400",
description: "Sentinel系列的第二代增强了火力和防御能力。",
achievements: ["全国赛最佳工程奖", "区域赛冠军"],
},
{
name: "Scout Drone Alpha",
image: "/placeholder.svg?height=300&width=400",
description: "我们的第一款侦察无人机,提供战场情报和有限的攻击能力。",
achievements: ["创新设计奖"],
},
],
},
{
year: "2021-2022",
models: [
{
name: "Sentinel MK-I",
image: "/placeholder.svg?height=300&width=400",
description: "Sentinel系列的初代机型为后续发展奠定了基础。",
achievements: ["区域赛最佳新秀奖"],
},
],
},
]
// 使用 useState 来跟踪当前悬停的成员
const [hoveredMember, setHoveredMember] = useState<number | null>(null)
// 成员卡片组件
const MemberCard = ({ member, index }: { member: any; index: number }) => {
const isHovered = hoveredMember === index
return (
<div
className="relative"
onMouseEnter={() => setHoveredMember(index)}
onMouseLeave={() => setHoveredMember(null)}
>
<div
className={`border border-white/10 p-4 card-hover-effect text-center cursor-pointer transition-all duration-200 ${isHovered ? "bg-background/80" : ""}`}
>
<div className="w-20 h-20 rounded-full overflow-hidden mx-auto mb-3">
<Image
src={member.photo || "/placeholder.svg"}
alt={member.name}
width={80}
height={80}
className="object-cover w-full h-full"
/>
</div>
<h4 className="font-bold">{member.name}</h4>
<p className="text-xs text-muted-foreground">{member.role}</p>
</div>
{/* 优化的扩展信息部分 - 更自然的动画 */}
<div
className={`absolute left-0 right-0 bg-primary/10 backdrop-blur-md border border-primary/30 p-4 transition-all duration-300 ease-out z-20 ${
isHovered
? "opacity-100 transform translate-y-0 scale-100"
: "opacity-0 transform -translate-y-4 scale-95 pointer-events-none"
}`}
style={{
top: "100%",
transformOrigin: "top center",
}}
>
<div className="space-y-2">
<h5 className="font-bold text-primary">{member.name} - </h5>
<p className="text-sm font-medium">{member.destination}</p>
<div className="pt-2 border-t border-white/10">
<p className="text-sm italic">"{member.message}"</p>
</div>
</div>
</div>
</div>
)
}
return (
<main className="min-h-screen bg-background">
@ -186,61 +191,35 @@ export default function HistoryPage() {
<section className="mb-16">
<h2 className="text-2xl font-bold mb-6 border-l-4 border-primary pl-4"></h2>
{teamMembers.map((team, index) => (
<div key={index} className="mb-12">
{teamMembers.map((team, teamIndex) => (
<div key={teamIndex} className="mb-12">
<h3 className="text-xl font-bold mb-4 text-primary">{team.year} </h3>
<p className="mb-4">: {team.captain}</p>
<div className="grid grid-cols-2 md:grid-cols-3 lg:grid-cols-6 gap-4">
{team.members.map((member, idx) => (
<TooltipProvider key={idx}>
<Tooltip>
<TooltipTrigger asChild>
<div className="border border-white/10 p-4 card-hover-effect text-center cursor-pointer">
<div className="w-20 h-20 rounded-full overflow-hidden mx-auto mb-3">
<Image
src={member.photo || "/placeholder.svg"}
alt={member.name}
width={80}
height={80}
className="object-cover w-full h-full"
/>
</div>
<h4 className="font-bold">{member.name}</h4>
<p className="text-xs text-muted-foreground">{member.role}</p>
</div>
</TooltipTrigger>
<TooltipContent
side="right"
className="max-w-xs p-4 bg-background/95 backdrop-blur-md border border-white/10"
>
<div className="space-y-2">
<h5 className="font-bold text-primary">{member.name} - </h5>
<p className="text-sm font-medium">{member.destination}</p>
<div className="pt-2 border-t border-white/10">
<p className="text-sm italic">"{member.message}"</p>
</div>
</div>
</TooltipContent>
</Tooltip>
</TooltipProvider>
{team.members.map((member, memberIndex) => (
<MemberCard
key={memberIndex}
member={member}
index={teamIndex * 100 + memberIndex} // 创建唯一索引
/>
))}
</div>
</div>
))}
</section>
{/* 历届机器人部分 */}
{/* 历届机器人部分 - 使用共享数据 */}
<section>
<h2 className="text-2xl font-bold mb-6 border-l-4 border-primary pl-4"></h2>
{robots.map((year, index) => (
{robotsByYear.map((year, index) => (
<div key={index} className="mb-12">
<h3 className="text-xl font-bold mb-4 text-primary">{year.year} </h3>
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
{year.models.map((robot, idx) => (
<Card key={idx} className="border-white/10 bg-background/60 backdrop-blur-sm card-hover-effect">
{year.models.map((robot) => (
<Card key={robot.id} className="border-white/10 bg-background/60 backdrop-blur-sm card-hover-effect">
<CardHeader>
<CardTitle>{robot.name}</CardTitle>
</CardHeader>
@ -265,6 +244,13 @@ export default function HistoryPage() {
))}
</ul>
</div>
<div className="mt-4">
<Link href={`/robots#${robot.id}`}>
<Button variant="outline" size="sm" className="w-full border-white/10 button-hover-effect">
</Button>
</Link>
</div>
</CardContent>
</Card>
))}

View File

@ -19,9 +19,7 @@ const notoSansSC = Noto_Sans_SC({
export const metadata: Metadata = {
title: "Simba Robotics | RoboMaster Team",
description:
"Simba Robotics official website, a competitive robotics team participating in the RoboMaster competition.",
generator: 'v0.dev'
}
"Simba Robotics 是来自黑龙江大学的 RoboMaster 竞赛团队,致力于推动机器人技术的创新与发展。我们专注于设计和开发高性能的机器人系统,参与国内外各类机器人竞赛。",}
export default function RootLayout({
children,
@ -41,6 +39,3 @@ export default function RootLayout({
</html>
)
}
import './globals.css'

23
app/privacy/layout.tsx Normal file
View File

@ -0,0 +1,23 @@
import type React from "react"
import type { Metadata } from "next"
import Header from "@/components/header"
import Footer from "@/components/footer"
export const metadata: Metadata = {
title: "Privacy Policy | Simba Robotics",
description: "Privacy policy for Simba Robotics website and services.",
}
export default function PrivacyLayout({
children,
}: Readonly<{
children: React.ReactNode
}>) {
return (
<>
<Header />
{children}
<Footer />
</>
)
}

95
app/privacy/page.tsx Normal file
View File

@ -0,0 +1,95 @@
import Link from "next/link"
import { ArrowLeft } from "lucide-react"
import { Button } from "@/components/ui/button"
export default function PrivacyPolicy() {
return (
<main className="min-h-screen bg-background pt-16">
<div className="container mx-auto px-4 py-16">
<div className="mb-8">
<Link href="/">
<Button variant="ghost" className="button-hover-effect mb-4">
<ArrowLeft className="mr-2 h-4 w-4" />
</Button>
</Link>
<h1 className="text-4xl font-bold mb-2"></h1>
<p className="text-muted-foreground">最后更新: 2023年12月1日</p>
</div>
<div className="prose prose-invert max-w-none">
<p>
Simba
Robotics"我们"使
</p>
<h2></h2>
<p></p>
<ul>
<li>
<strong></strong>
</li>
<li>
<strong>使</strong>
访使IP地址访
</li>
<li>
<strong></strong>
访
</li>
</ul>
<h2>使</h2>
<p></p>
<ul>
<li></li>
<li></li>
<li></li>
<li>使</li>
<li></li>
</ul>
<h2></h2>
<p></p>
<ul>
<li></li>
<li></li>
<li></li>
<li></li>
</ul>
<h2></h2>
<p>
访使100%
</p>
<h2>Cookie使用</h2>
<p>
使"cookies"cookies放在您的硬盘上以记录目的cookies使
</p>
<h2></h2>
<p>
访
</p>
<h2></h2>
<p>
1313
</p>
<h2></h2>
<p></p>
<h2></h2>
<p></p>
<p>
<strong></strong>contact@simbarobotics.com
<br />
<strong></strong>Room 602, Physics Building, Heilongjiang University
</p>
</div>
</div>
</main>
)
}

23
app/robots/layout.tsx Normal file
View File

@ -0,0 +1,23 @@
import type React from "react"
import type { Metadata } from "next"
import Header from "@/components/header"
import Footer from "@/components/footer"
export const metadata: Metadata = {
title: "Robots | Simba Robotics",
description: "Explore the robots developed by Simba Robotics team for RoboMaster competitions.",
}
export default function RobotsLayout({
children,
}: Readonly<{
children: React.ReactNode
}>) {
return (
<>
<Header />
{children}
<Footer />
</>
)
}

3
app/robots/loading.tsx Normal file
View File

@ -0,0 +1,3 @@
export default function Loading() {
return null
}

138
app/robots/page.tsx Normal file
View File

@ -0,0 +1,138 @@
"use client"
import { useEffect, useRef } from "react"
import Image from "next/image"
import Link from "next/link"
import { useSearchParams } from "next/navigation"
import { ArrowLeft } from "lucide-react"
import { Button } from "@/components/ui/button"
import { Card, CardContent } from "@/components/ui/card"
import { robots } from "@/lib/robot-data"
export default function RobotsPage() {
const searchParams = useSearchParams()
const highlightedRobot = searchParams.get("highlight")
const robotRefs = useRef<{ [key: string]: HTMLDivElement | null }>({})
// 滚动到高亮的机器人
useEffect(() => {
if (highlightedRobot && robotRefs.current[highlightedRobot]) {
robotRefs.current[highlightedRobot]?.scrollIntoView({
behavior: "smooth",
block: "start",
})
}
}, [highlightedRobot])
return (
<main className="min-h-screen bg-background pt-16">
<div className="container mx-auto px-4 py-16">
<div className="mb-8">
<Link href="/">
<Button variant="ghost" className="button-hover-effect mb-4">
<ArrowLeft className="mr-2 h-4 w-4" />
</Button>
</Link>
<h1 className="text-4xl font-bold mb-2"></h1>
<p className="text-muted-foreground"> Simba Robotics RoboMaster </p>
</div>
{/* 机器人列表 */}
<div className="space-y-16">
{robots.map((robot) => (
<div
key={robot.id}
id={robot.id}
ref={(el) => (robotRefs.current[robot.id] = el)}
className={`scroll-mt-24 ${highlightedRobot === robot.id ? "ring-2 ring-primary p-4" : ""}`}
>
<div className="flex flex-col lg:flex-row gap-8">
<div className="lg:w-1/2">
<div className="relative">
<div className="absolute -inset-4 bg-primary/10 blur-xl"></div>
<div className="overflow-hidden border border-white/10 relative z-10">
<Image
src={robot.image || "/placeholder.svg"}
alt={robot.name}
width={600}
height={400}
className="w-full h-auto"
/>
<div className="absolute top-0 right-0 bg-primary text-primary-foreground text-xs px-3 py-1">
{robot.category}
</div>
<div className="absolute bottom-0 left-0 p-4">
<p className="text-xs text-primary font-mono">{robot.year}</p>
<h3 className="text-xl font-bold">{robot.name}</h3>
</div>
</div>
</div>
<div className="grid grid-cols-2 gap-4 mt-4">
{robot.gallery.map((image, idx) => (
<div key={idx} className="overflow-hidden border border-white/10 card-hover-effect">
<Image
src={image || "/placeholder.svg"}
alt={`${robot.name} gallery ${idx + 1}`}
width={300}
height={200}
className="w-full h-auto"
/>
</div>
))}
</div>
</div>
<div className="lg:w-1/2">
<h2 className="text-3xl font-bold mb-4">{robot.name}</h2>
<p className="text-muted-foreground mb-6 leading-relaxed">{robot.description}</p>
<div className="grid grid-cols-2 md:grid-cols-4 gap-4 mb-6">
{robot.specs.map((spec, idx) => (
<Card key={idx} className="border-white/10 bg-background/60 backdrop-blur-sm card-hover-effect">
<CardContent className="p-4 flex flex-col items-center text-center">
<div className="p-2 bg-primary/10 rounded-full mb-2">{spec.icon}</div>
<h4 className="text-xs font-bold">{spec.name}</h4>
<p className="text-sm text-muted-foreground">{spec.value}</p>
</CardContent>
</Card>
))}
</div>
<div className="mb-6">
<h3 className="font-bold mb-2 text-primary">:</h3>
<ul className="space-y-1 pl-5 list-disc text-muted-foreground">
{robot.features.map((feature, idx) => (
<li key={idx}>{feature}</li>
))}
</ul>
</div>
<div className="mb-6">
<h3 className="font-bold mb-2 text-primary">:</h3>
<ul className="space-y-1 pl-5 list-disc text-muted-foreground">
{robot.achievements.map((achievement, idx) => (
<li key={idx}>{achievement}</li>
))}
</ul>
</div>
<div>
<h3 className="font-bold mb-2 text-primary">:</h3>
<div className="flex flex-wrap gap-2">
{robot.team.map((member, idx) => (
<div key={idx} className="px-3 py-1 bg-primary/10 text-sm flex items-center gap-1">
<span>{member.name}</span>
<span className="text-xs text-muted-foreground">({member.role})</span>
</div>
))}
</div>
</div>
</div>
</div>
</div>
))}
</div>
</div>
</main>
)
}

23
app/teams/layout.tsx Normal file
View File

@ -0,0 +1,23 @@
import type React from "react"
import type { Metadata } from "next"
import Header from "@/components/header"
import Footer from "@/components/footer"
export const metadata: Metadata = {
title: "Team Groups | Simba Robotics",
description: "Learn more about the specialized groups within Simba Robotics team.",
}
export default function TeamsLayout({
children,
}: Readonly<{
children: React.ReactNode
}>) {
return (
<>
<Header />
{children}
<Footer />
</>
)
}

260
app/teams/page.tsx Normal file
View File

@ -0,0 +1,260 @@
"use client"
import { useState } from "react"
import Image from "next/image"
import Link from "next/link"
import { ArrowLeft } from "lucide-react"
import { Button } from "@/components/ui/button"
import { Tabs, TabsList, TabsTrigger } from "@/components/ui/tabs"
export default function TeamsPage() {
const [activeTab, setActiveTab] = useState("mest")
const teams = [
{
id: "mest",
name: "机械架构组",
code: "MEST",
icon: "/icons/mest.svg",
description:
"机械架构组负责设计和制造机器人的物理结构,包括底盘、武器系统和机械部件。我们的工作是机器人的骨骼和肌肉,确保它们能够承受比赛中的各种挑战。",
responsibilities: ["3D 建模与 CAD 出图", "CNC 加工制造", "机械结构分析与优化", "结构装配与测试"],
projects: [
{
title: "轻量化底盘设计",
description: "通过拓扑优化和材料选择减轻机器人底盘重量30%,同时保持结构强度。",
image: "/placeholder.svg?height=300&width=400",
},
{
title: "模块化武器系统",
description: "开发可快速更换的模块化武器系统,适应不同比赛场景和对手特点。",
image: "/placeholder.svg?height=300&width=400",
},
],
skills: ["SolidWorks", "AutoCAD", "有限元分析", "材料学", "加工工艺", "3D打印"],
members: [
{
name: "彭戈",
role: "组长",
photo: "/placeholder.svg?height=100&width=100",
},
{
name: "闫芃森",
role: "机械工程师",
photo: "/placeholder.svg?height=100&width=100",
},
],
},
{
id: "elct",
name: "电传测控组",
code: "ELCT",
icon: "/icons/elct.svg",
description:
"电传测控组开发机器人的配电与控制系统,涵盖电路设计、功率管理和嵌入式开发。我们是机器人的神经系统,使其能够感知环境并执行精确动作。",
responsibilities: [
"电路设计与 PCB Layout",
"功率管理系统设计",
"电机控制和驱动开发",
"传感器集成与信号处理",
"控制理论应用",
],
projects: [
{
title: "高效功率管理系统",
description: "设计能够优化电池使用的功率管理系统延长机器人作战时间20%。",
image: "/placeholder.svg?height=300&width=400",
},
{
title: "实时控制系统",
description: "基于STM32的实时控制系统实现毫秒级响应和精确的运动控制。",
image: "/placeholder.svg?height=300&width=400",
},
],
skills: ["电路设计", "PCB Layout", "嵌入式编程", "控制理论", "信号处理", "RTOS"],
members: [
{
name: "陈卓文",
role: "组长",
photo: "/placeholder.svg?height=100&width=100",
},
],
},
{
id: "vsag",
name: "视觉算法组",
code: "VSAG",
icon: "/icons/vsag.svg",
description:
"视觉算法组开发计算机视觉和人工智能系统,使机器人能够感知和理解周围环境,实现自主操作。我们是机器人的眼睛和大脑,赋予它智能决策能力。",
responsibilities: ["计算机视觉算法开发", "对象识别与跟踪", "机器学习模型训练", "实时图像处理优化"],
projects: [
{
title: "实时目标检测系统",
description: "基于深度学习的目标检测系统,能够在复杂背景下识别和跟踪对手机器人。",
image: "/placeholder.svg?height=300&width=400",
},
{
title: "自主导航算法",
description: "结合视觉和传感器数据的自主导航算法,使机器人能够在场地中精确定位和规划路径。",
image: "/placeholder.svg?height=300&width=400",
},
],
skills: ["Python", "OpenCV", "TensorFlow/PyTorch", "SLAM", "ROS", "C++"],
members: [
{
name: "黄瑞",
role: "组长",
photo: "/placeholder.svg?height=100&width=100",
},
{
name: "韩翔宇",
role: "视觉工程师",
photo: "/placeholder.svg?height=100&width=100",
},
],
},
{
id: "pram",
name: "宣传筹划组",
code: "PRAM",
icon: "/icons/pram.svg",
description:
"宣传筹划组管理团队品牌、文档、社交媒体和外联工作,以宣传我们的团队并获得赞助,并规划赛季任务、维护战队开发环境。我们是团队的声音和桥梁。",
responsibilities: ["平面与视觉设计", "社交媒体运营", "招商引资", "战队开发平台运维与项目管理"],
projects: [
{
title: "品牌重塑计划",
description: "重新设计团队视觉识别系统,提升品牌形象和认知度。",
image: "/placeholder.svg?height=300&width=400",
},
{
title: "赞助合作项目",
description: "与多家企业建立赞助合作关系,为团队提供资金和技术支持。",
image: "/placeholder.svg?height=300&width=400",
},
],
skills: ["平面设计", "内容创作", "项目管理", "商务谈判", "社交媒体运营", "活动策划"],
members: [
{
name: "李佳睿",
role: "组长",
photo: "/placeholder.svg?height=100&width=100",
},
],
},
]
const activeTeam = teams.find((team) => team.id === activeTab) || teams[0]
return (
<main className="min-h-screen bg-background pt-16">
<div className="container mx-auto px-4 py-16">
<div className="mb-8">
<Link href="/">
<Button variant="ghost" className="button-hover-effect mb-4">
<ArrowLeft className="mr-2 h-4 w-4" />
</Button>
</Link>
<h1 className="text-4xl font-bold mb-2"></h1>
<p className="text-muted-foreground"> Simba Robotics </p>
</div>
<Tabs defaultValue="mest" value={activeTab} onValueChange={setActiveTab} className="w-full">
<TabsList className="grid grid-cols-2 md:grid-cols-4 gap-2 bg-transparent">
{teams.map((team) => (
<TabsTrigger
key={team.id}
value={team.id}
className="data-[state=active]:bg-primary/20 data-[state=active]:text-primary border border-white/10"
>
<div className="flex items-center gap-2">
<Image src={team.icon || "/placeholder.svg"} alt={team.name} width={24} height={24} />
<span className="hidden md:inline">{team.name}</span>
<span className="md:hidden">{team.code}</span>
</div>
</TabsTrigger>
))}
</TabsList>
<div className="mt-8 border border-white/10 p-6 card-hover-effect">
<div className="flex flex-col md:flex-row gap-6 items-start">
<div className="md:w-1/3">
<div className="flex items-center gap-4 mb-6">
<div className="p-4 bg-primary/10">
<Image src={activeTeam.icon || "/placeholder.svg"} alt={activeTeam.name} width={48} height={48} />
</div>
<div>
<h2 className="text-2xl font-bold">{activeTeam.name}</h2>
<p className="text-sm font-mono text-primary">{activeTeam.code}</p>
</div>
</div>
<p className="text-muted-foreground mb-6 leading-relaxed">{activeTeam.description}</p>
<div className="mb-6">
<h3 className="font-bold mb-2 text-primary">:</h3>
<ul className="space-y-1 pl-5 list-disc text-muted-foreground">
{activeTeam.responsibilities.map((item, idx) => (
<li key={idx}>{item}</li>
))}
</ul>
</div>
<div>
<h3 className="font-bold mb-2 text-primary">:</h3>
<div className="flex flex-wrap gap-2">
{activeTeam.skills.map((skill, idx) => (
<span key={idx} className="px-2 py-1 bg-primary/10 text-xs rounded-sm">
{skill}
</span>
))}
</div>
</div>
</div>
<div className="md:w-2/3">
<h3 className="text-xl font-bold mb-4 border-l-4 border-primary pl-4"></h3>
<div className="grid grid-cols-1 md:grid-cols-2 gap-4 mb-8">
{activeTeam.projects.map((project, idx) => (
<div key={idx} className="border border-white/10 overflow-hidden card-hover-effect">
<Image
src={project.image || "/placeholder.svg"}
alt={project.title}
width={400}
height={300}
className="w-full h-48 object-cover"
/>
<div className="p-4">
<h4 className="font-bold mb-2">{project.title}</h4>
<p className="text-sm text-muted-foreground">{project.description}</p>
</div>
</div>
))}
</div>
<h3 className="text-xl font-bold mb-4 border-l-4 border-primary pl-4"></h3>
<div className="grid grid-cols-2 md:grid-cols-4 gap-4">
{activeTeam.members.map((member, idx) => (
<div key={idx} className="border border-white/10 p-4 text-center card-hover-effect">
<div className="w-16 h-16 rounded-full overflow-hidden mx-auto mb-2">
<Image
src={member.photo || "/placeholder.svg"}
alt={member.name}
width={64}
height={64}
className="w-full h-full object-cover"
/>
</div>
<h4 className="font-bold">{member.name}</h4>
<p className="text-xs text-muted-foreground">{member.role}</p>
</div>
))}
</div>
</div>
</div>
</div>
</Tabs>
</div>
</main>
)
}

23
app/terms/layout.tsx Normal file
View File

@ -0,0 +1,23 @@
import type React from "react"
import type { Metadata } from "next"
import Header from "@/components/header"
import Footer from "@/components/footer"
export const metadata: Metadata = {
title: "Terms of Service | Simba Robotics",
description: "Terms of service for Simba Robotics website and services.",
}
export default function TermsLayout({
children,
}: Readonly<{
children: React.ReactNode
}>) {
return (
<>
<Header />
{children}
<Footer />
</>
)
}

94
app/terms/page.tsx Normal file
View File

@ -0,0 +1,94 @@
import Link from "next/link"
import { ArrowLeft } from "lucide-react"
import { Button } from "@/components/ui/button"
export default function TermsOfService() {
return (
<main className="min-h-screen bg-background pt-16">
<div className="container mx-auto px-4 py-16">
<div className="mb-8">
<Link href="/">
<Button variant="ghost" className="button-hover-effect mb-4">
<ArrowLeft className="mr-2 h-4 w-4" />
</Button>
</Link>
<h1 className="text-4xl font-bold mb-2"></h1>
<p className="text-muted-foreground">最后更新: 2025年4月19日</p>
</div>
<div className="prose prose-invert max-w-none">
<p>
访 Simba Robotics
访使访使使
</p>
<h2>使</h2>
<p>
Simba Robotics
访使
</p>
<ul>
<li>使</li>
<li>使</li>
<li>使</li>
<li></li>
<li>使</li>
</ul>
<p>
访
</p>
<h2></h2>
<p>
Simba Robotics
</p>
<h2></h2>
<p>使</p>
<ul>
<li></li>
<li></li>
<li></li>
<li>访</li>
<li></li>
</ul>
<h2></h2>
<p>
"原样""可用"Simba Robotics
</p>
<h2></h2>
<p>
Simba Robotics
使使
</p>
<h2></h2>
<p>
Simba Robotics
</p>
<h2></h2>
<p>
使
</p>
<h2></h2>
<p> Simba Robotics </p>
<h2></h2>
<p></p>
<p>
<strong></strong>contact@simba-robotics.com
<br />
<strong></strong>602 , ,
</p>
</div>
</div>
</main>
)
}

View File

@ -1,34 +1,8 @@
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"
import { Trophy, Medal, Award, Star } from "lucide-react"
import Link from "next/link"
import { achievements } from "@/lib/achievement-data"
export default function AchievementsSection() {
const achievements = [
{
year: "2025",
title: "RoboMaster 高校联盟赛 辽宁站",
position: "三等奖",
icon: <Award className="h-8 w-8 text-primary" />,
description:
"与 32 支来自辽宁周边城市的大学参赛队伍同台竞技,直接对阵的队伍有:哈尔滨工业大学 I Hiter 战队、北京邮电大学 鸿雁 战队、沈阳工业大学辽阳分校 赫兹矩阵战队。",
},
{
year: "2024",
title: "RoboMaster 高校联盟赛 山东站",
position: "三等奖",
icon: <Award className="h-8 w-8 text-primary" />,
description:
"与 32 支来自山东周边城市的大学参赛队伍同台竞技,直接对阵的队伍有:北方工业大学 DreamTeam 战队、哈尔滨工业大学威海 HERO 战队。",
},
{
year: "2017",
title: "RoboMaster 区域赛 东部赛区",
position: "三等奖",
icon: <Star className="h-8 w-8 text-primary" />,
description:
"与 29 支大学参赛队伍同台竞技。",
},
]
return (
<section id="achievements" className="py-20 relative overflow-hidden">
<div className="absolute inset-0 grid-pattern opacity-20" />
@ -52,22 +26,24 @@ export default function AchievementsSection() {
<div className="md:w-2/3">
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
{achievements.map((achievement, index) => (
<Card key={index} className="border-white/10 bg-background/60 backdrop-blur-sm card-hover-effect">
<CardHeader className="flex flex-row items-center gap-4 pb-2 border-b border-white/10">
<div className="p-2 bg-primary/10">{achievement.icon}</div>
<div>
<CardTitle className="text-xl">{achievement.title}</CardTitle>
<div className="flex items-center gap-2 text-sm text-muted-foreground">
<span className="text-primary font-mono">{achievement.year}</span>
<span></span>
<span>{achievement.position}</span>
<Link key={index} href={achievement.link} target="_blank" rel="noopener noreferrer">
<Card className="border-white/10 bg-background/60 backdrop-blur-sm card-hover-effect transition-all duration-300 hover:translate-y-[-5px]">
<CardHeader className="flex flex-row items-center gap-4 pb-2 border-b border-white/10">
<div className="p-2 bg-primary/10">{achievement.icon}</div>
<div>
<CardTitle className="text-xl">{achievement.title}</CardTitle>
<div className="flex items-center gap-2 text-sm text-muted-foreground">
<span className="text-primary font-mono">{achievement.year}</span>
<span></span>
<span>{achievement.position}</span>
</div>
</div>
</div>
</CardHeader>
<CardContent className="pt-4">
<p className="text-muted-foreground leading-relaxed">{achievement.description}</p>
</CardContent>
</Card>
</CardHeader>
<CardContent className="pt-4">
<p className="text-muted-foreground leading-relaxed">{achievement.description}</p>
</CardContent>
</Card>
</Link>
))}
</div>
</div>

View File

@ -7,20 +7,20 @@ export default function ContactSection() {
const contactInfo = [
{
icon: <Mail className="h-5 w-5 text-primary" />,
title: "邮件",
title: "Email",
details: "contact@simbarobotics.com",
link: "mailto:contact@simbarobotics.com",
},
{
icon: <Phone className="h-5 w-5 text-primary" />,
title: "电话",
details: "+86 139 3616 9908",
link: "tel:+8613936169908",
title: "Phone",
details: "+1 (123) 456-7890",
link: "tel:+11234567890",
},
{
icon: <MapPin className="h-5 w-5 text-primary" />,
title: "地址",
details: "602实验室, 物理实验楼, 黑龙江大学",
details: "602 实验室, 电子工程学院, 黑龙江大学",
link: "https://www.bing.com/maps?&ty=18&q=%E9%BB%91%E9%BE%99%E6%B1%9F%E5%A4%A7%E5%AD%A6-%E7%94%B5%E5%AD%90%E5%B7%A5%E7%A8%8B%E5%AD%A6%E9%99%A2&ss=ypid.YN4067x5856225&mb=45.709873~126.616074~45.704718~126.624132&description=%E9%BB%91%E9%BE%99%E6%B1%9F%E7%9C%81%E5%93%88%E5%B0%94%E6%BB%A8%E5%B8%82%E5%AD%A6%E5%BA%9C%E8%B7%AF74%E5%8F%B7&cardbg=%23333333&dt=1744891200000&tt=%E9%BB%91%E9%BE%99%E6%B1%9F%E5%A4%A7%E5%AD%A6-%E7%94%B5%E5%AD%90%E5%B7%A5%E7%A8%8B%E5%AD%A6%E9%99%A2&tsts0=%2526ty%253D18%2526q%253D%2525E9%2525BB%252591%2525E9%2525BE%252599%2525E6%2525B1%25259F%2525E5%2525A4%2525A7%2525E5%2525AD%2525A6-%2525E7%252594%2525B5%2525E5%2525AD%252590%2525E5%2525B7%2525A5%2525E7%2525A8%25258B%2525E5%2525AD%2525A6%2525E9%252599%2525A2%2526ss%253Dypid.YN4067x5856225%2526mb%253D45.709873~126.616074~45.704718~126.624132%2526description%253D%2525E9%2525BB%252591%2525E9%2525BE%252599%2525E6%2525B1%25259F%2525E7%25259C%252581%2525E5%252593%252588%2525E5%2525B0%252594%2525E6%2525BB%2525A8%2525E5%2525B8%252582%2525E5%2525AD%2525A6%2525E5%2525BA%25259C%2525E8%2525B7%2525AF74%2525E5%25258F%2525B7%2526cardbg%253D%252523333333%2526dt%253D1744891200000&tstt0=%E9%BB%91%E9%BE%99%E6%B1%9F%E5%A4%A7%E5%AD%A6-%E7%94%B5%E5%AD%90%E5%B7%A5%E7%A8%8B%E5%AD%A6%E9%99%A2&cp=45.707282~126.619347&lvl=18.469374&pi=0&ftst=0&ftics=False&v=2&sV=2&form=S00027",
},
]
@ -52,12 +52,7 @@ export default function ContactSection() {
{
icon: <MessageSquare className="h-5 w-5" />,
name: "微信公众号",
link: "#wechat-qrcode",
onClick: (e: { preventDefault: () => void }) => {
e.preventDefault()
// 这里可以添加显示微信二维码的逻辑,例如打开一个模态框
alert("扫描二维码关注我们的微信公众号SimbaRobotics")
},
link: "https://weixin.qq.com/r/simbarobotics",
},
]
@ -109,7 +104,6 @@ export default function ContactSection() {
rel="noopener noreferrer"
className="p-3 bg-primary/10 hover:bg-primary/20 transition-colors card-hover-effect"
aria-label={social.name}
onClick={social.onClick}
>
{social.icon}
</a>

View File

@ -95,10 +95,10 @@ export default function Footer() {
<div className="border-t border-white/10 mt-12 pt-6 flex flex-col md:flex-row justify-between items-center">
<p className="text-sm text-muted-foreground">© {currentYear} Simba Robotics. </p>
<div className="flex gap-4 mt-4 md:mt-0">
<Link href="#" className="text-xs text-muted-foreground hover:text-primary transition-colors">
<Link href="/privacy" className="text-xs text-muted-foreground hover:text-primary transition-colors">
</Link>
<Link href="#" className="text-xs text-muted-foreground hover:text-primary transition-colors">
<Link href="/terms" className="text-xs text-muted-foreground hover:text-primary transition-colors">
</Link>
</div>

View File

@ -3,6 +3,7 @@
import { useState, useEffect } from "react"
import Link from "next/link"
import Image from "next/image"
import { usePathname } from "next/navigation"
import { Menu, X } from "lucide-react"
import { Button } from "@/components/ui/button"
import { cn } from "@/lib/utils"
@ -11,37 +12,42 @@ export default function Header() {
const [isMenuOpen, setIsMenuOpen] = useState(false)
const [scrolled, setScrolled] = useState(false)
const [activeSection, setActiveSection] = useState("home")
const pathname = usePathname()
const isHomePage = pathname === "/"
useEffect(() => {
const handleScroll = () => {
setScrolled(window.scrollY > 10)
// Determine active section based on scroll position
const sections = ["home", "about", "team-groups", "achievements", "robots", "contact"]
for (const section of sections.reverse()) {
const element = document.getElementById(section)
if (element && window.scrollY >= element.offsetTop - 100) {
setActiveSection(section)
break
// 只在主页上确定活动部分
if (isHomePage) {
// Determine active section based on scroll position
const sections = ["home", "about", "team-groups", "achievements", "robots", "contact"]
for (const section of sections.reverse()) {
const element = document.getElementById(section)
if (element && window.scrollY >= element.offsetTop - 100) {
setActiveSection(section)
break
}
}
}
}
window.addEventListener("scroll", handleScroll)
return () => window.removeEventListener("scroll", handleScroll)
}, [])
}, [isHomePage])
const toggleMenu = () => {
setIsMenuOpen(!isMenuOpen)
}
const navLinks = [
{ name: "主页", href: "#home", id: "home", en: "INDEX" },
{ name: "关于", href: "#about", id: "about", en: "INFORMATION" },
{ name: "团队", href: "#team-groups", id: "team-groups", en: "OPERATOR" },
{ name: "成就", href: "#achievements", id: "achievements", en: "GAMEPLAY" },
{ name: "机器人", href: "#robots", id: "robots", en: "ROBOTS" },
{ name: "联系我们", href: "#contact", id: "contact", en: "NEWS" },
{ name: "主页", href: isHomePage ? "#home" : "/#home", id: "home", en: "INDEX" },
{ name: "关于", href: isHomePage ? "#about" : "/#about", id: "about", en: "INFORMATION" },
{ name: "团队", href: isHomePage ? "#team-groups" : "/#team-groups", id: "team-groups", en: "OPERATOR" },
{ name: "成就", href: isHomePage ? "#achievements" : "/#achievements", id: "achievements", en: "GAMEPLAY" },
{ name: "机器人", href: isHomePage ? "#robots" : "/#robots", id: "robots", en: "ROBOTS" },
{ name: "联系我们", href: isHomePage ? "#contact" : "/#contact", id: "contact", en: "NEWS" },
]
return (
@ -68,7 +74,7 @@ export default function Header() {
href={link.href}
className={cn(
"px-6 py-2 flex flex-col items-center text-sm transition-colors",
activeSection === link.id
isHomePage && activeSection === link.id
? "text-foreground nav-active"
: "text-muted-foreground hover:text-foreground",
)}
@ -97,7 +103,7 @@ export default function Header() {
href={link.href}
className={cn(
"px-4 py-3 border-b border-border/30 transition-colors flex items-center justify-between",
activeSection === link.id ? "text-primary" : "text-muted-foreground",
isHomePage && activeSection === link.id ? "text-primary" : "text-muted-foreground",
)}
onClick={() => setIsMenuOpen(false)}
>

View File

@ -2,52 +2,17 @@
import { useRef, useState, useEffect } from "react"
import Image from "next/image"
import Link from "next/link"
import { Card, CardContent } from "@/components/ui/card"
import { Button } from "@/components/ui/button"
import { ChevronLeft, ChevronRight, Info } from "lucide-react"
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "@/components/ui/tooltip"
import { robots } from "@/lib/robot-data"
export default function RobotsShowcase() {
const scrollContainerRef = useRef<HTMLDivElement>(null)
const [activeIndex, setActiveIndex] = useState(0)
const robots = [
{
id: 1,
name: "初号步兵",
image: "/placeholder.svg?height=400&width=600",
category: "INFANTRY",
description:
"Our flagship defense robot, equipped with advanced armor plating and a 360° rotating turret system.",
specs: ["Weight: 15kg", "Max Speed: 3m/s", "Battery Life: 30min", "Weapon: Launcher"],
},
{
id: 2,
name: "初号英雄",
image: "/placeholder.svg?height=400&width=600",
category: "HERO",
description: "High-mobility attack unit designed for rapid engagement and strategic positioning.",
specs: ["Weight: 12kg", "Max Speed: 4.5m/s", "Battery Life: 25min", "Weapon: Dual Launcher System"],
},
{
id: 3,
name: "零号哨兵",
image: "/placeholder.svg?height=400&width=600",
category: "SENTRY",
description:
"Lightweight reconnaissance drone providing battlefield intelligence and limited attack capabilities.",
specs: ["Weight: 2kg", "Max Speed: 10m/s", "Flight Time: 15min", "Sensors: 4K Camera, Infrared"],
},
{
id: 4,
name: "零号工程",
image: "/placeholder.svg?height=400&width=600",
category: "ENGINEER",
description: "Specialized support unit capable of on-field repairs and resource management during matches.",
specs: ["Weight: 18kg", "Max Speed: 2m/s", "Battery Life: 40min", "Tools: Mechanical Arm, Repair Module"],
},
]
// 创建一个循环数组,用于无限滚动
const displayRobots = [...robots]
@ -124,7 +89,7 @@ export default function RobotsShowcase() {
<div className="relative">
<Image
src={robot.image || "/placeholder.svg"}
alt={robot.name}
alt={robot.displayName}
width={350}
height={200}
className="w-full h-48 object-cover"
@ -139,7 +104,7 @@ export default function RobotsShowcase() {
<div className="p-4">
<div className="flex justify-between items-start mb-2">
<h3 className="text-xl font-bold">{robot.name}</h3>
<h3 className="text-xl font-bold">{robot.displayName}</h3>
<TooltipProvider>
<Tooltip>
<TooltipTrigger asChild>
@ -151,7 +116,7 @@ export default function RobotsShowcase() {
<div className="space-y-2">
<p className="font-bold">:</p>
<ul className="text-xs space-y-1">
{robot.specs.map((spec, specIndex) => (
{robot.simpleSpecs.map((spec, specIndex) => (
<li key={specIndex}>{spec}</li>
))}
</ul>
@ -161,11 +126,13 @@ export default function RobotsShowcase() {
</TooltipProvider>
</div>
<p className="text-sm text-muted-foreground mb-4 leading-relaxed">{robot.description}</p>
<p className="text-sm text-muted-foreground mb-4 leading-relaxed">{robot.shortDescription}</p>
<Button variant="outline" size="sm" className="w-full border-white/10 button-hover-effect">
</Button>
<Link href={`/robots#${robot.id}`}>
<Button variant="outline" size="sm" className="w-full border-white/10 button-hover-effect">
</Button>
</Link>
</div>
</CardContent>
</Card>

View File

@ -1,5 +1,8 @@
import { Card, CardContent } from "@/components/ui/card"
import { Button } from "@/components/ui/button"
import { ChevronRight } from "lucide-react"
import Image from "next/image"
import Link from "next/link"
export default function TeamGroupsSection() {
const groups = [
@ -7,21 +10,14 @@ export default function TeamGroupsSection() {
name: "机械架构组",
code: "MEST",
icon: "/icons/mest.svg",
description:
"负责设计和制造机器人的物理结构,包括底盘、武器系统和机械部件。",
responsibilities: [
"3D 建模与 CAD 出图",
"CNC 加工制造",
"机械结构分析与优化",
"结构装配与测试",
],
description: "负责设计和制造机器人的物理结构,包括底盘、武器系统和机械部件。",
responsibilities: ["3D 建模与 CAD 出图", "CNC 加工制造", "机械结构分析与优化", "结构装配与测试"],
},
{
name: "电传测控组",
code: "ELCT",
icon: "/icons/elct.svg",
description:
"开发机器人的配电与控制系统, 涵盖电路设计、功率管理和嵌入式开发。",
description: "开发机器人的配电与控制系统, 涵盖电路设计、功率管理和嵌入式开发。",
responsibilities: [
"电路设计与 PCB Layout",
"功率管理系统设计",
@ -34,14 +30,8 @@ export default function TeamGroupsSection() {
name: "视觉算法组",
code: "VSAG",
icon: "/icons/vsag.svg",
description:
"开发计算机视觉和人工智能系统,使机器人能够感知和理解周围环境,实现自主操作。",
responsibilities: [
"计算机视觉算法开发",
"对象识别与跟踪",
"机器学习模型训练",
"实时图像处理优化",
],
description: "开发计算机视觉和人工智能系统,使机器人能够感知和理解周围环境,实现自主操作。",
responsibilities: ["计算机视觉算法开发", "对象识别与跟踪", "机器学习模型训练", "实时图像处理优化"],
},
{
name: "宣传筹划组",
@ -49,12 +39,7 @@ export default function TeamGroupsSection() {
icon: "/icons/pram.svg",
description:
"管理团队品牌、文档、社交媒体和外联工作,以宣传我们的团队并获得赞助,并规划赛季任务、维护战队开发环境。",
responsibilities: [
"平面与视觉设计",
"社交媒体运营",
"招商引资",
"战队开发平台运维与项目管理",
],
responsibilities: ["平面与视觉设计", "社交媒体运营", "招商引资", "战队开发平台运维与项目管理"],
},
]
@ -108,6 +93,16 @@ export default function TeamGroupsSection() {
<li key={idx}>{item}</li>
))}
</ul>
<Link href={`/teams?tab=${group.code.toLowerCase()}`}>
<Button
variant="ghost"
size="sm"
className="mt-4 w-full border border-white/10 button-hover-effect"
>
<ChevronRight className="ml-1 h-4 w-4" />
</Button>
</Link>
</div>
</CardContent>
</Card>

31
lib/achievement-data.ts Normal file
View File

@ -0,0 +1,31 @@
import { Trophy, Medal, Award, Star } from "lucide-react"
import React from "react"
export const achievements = [
{
year: "2025",
title: "RoboMaster 高校联盟赛 辽宁站 3V3对抗赛",
position: "三等奖",
icon: React.createElement(Award, { className: "h-8 w-8 text-primary" }),
description:
"与 32 支来自辽宁周边城市的大学参赛队伍同台竞技,直接对阵的队伍有:哈尔滨工业大学 I Hiter 战队、北京邮电大学 鸿雁 战队、沈阳工业大学辽阳分校 赫兹矩阵战队。",
link: "https://www.robomaster.com/zh-CN/resource/pages/announcement/1830",
},
{
year: "2024",
title: "RoboMaster 高校联盟赛 山东站 3V3对抗赛",
position: "三等奖",
icon: React.createElement(Award, { className: "h-8 w-8 text-primary" }),
description:
"与 32 支来自山东周边城市的大学参赛队伍同台竞技,直接对阵的队伍有:北方工业大学 DreamTeam 战队、哈尔滨工业大学威海 HERO 战队。",
link: "https://www.robomaster.com/zh-CN/resource/pages/announcement/1802",
},
{
year: "2023",
title: "RoboMaster 高校联盟赛 黑龙江站 步兵对抗赛",
position: "三等奖",
icon: React.createElement(Star, { className: "h-8 w-8 text-primary" }),
description: "与多支来自黑龙江周边城市的大学参赛队伍同台竞技。 ",
link: "https://www.robomaster.com/zh-CN/resource/pages/announcement/1596",
},
]

176
lib/robot-data.ts Normal file
View File

@ -0,0 +1,176 @@
import { Shield, Gauge, Zap, Cpu } from "lucide-react"
import React from "react"
export const robots = [
{
id: "sentinel-mk-iii",
name: "Sentinel MK-III",
displayName: "初号步兵",
category: "INFANTRY",
year: "2023-2024",
image: "/placeholder.svg?height=400&width=600",
description:
"我们的旗舰防御机器人配备先进装甲板和360°旋转炮塔系统。Sentinel MK-III 是我们最新一代的步兵机器人专为RoboMaster比赛设计具有出色的防御能力和火力输出。",
shortDescription:
"Our flagship defense robot, equipped with advanced armor plating and a 360° rotating turret system.",
specs: [
{ icon: React.createElement(Shield, { className: "h-8 w-8 text-primary" }), name: "装甲", value: "复合装甲板" },
{ icon: React.createElement(Gauge, { className: "h-8 w-8 text-primary" }), name: "最大速度", value: "3m/s" },
{ icon: React.createElement(Zap, { className: "h-8 w-8 text-primary" }), name: "电池续航", value: "30分钟" },
{ icon: React.createElement(Cpu, { className: "h-8 w-8 text-primary" }), name: "控制系统", value: "STM32F4" },
],
simpleSpecs: ["Weight: 15kg", "Max Speed: 3m/s", "Battery Life: 30min", "Weapon: Launcher"],
features: [
"高精度云台系统,实现毫秒级目标锁定",
"模块化设计,便于快速维修和更换部件",
"先进的散热系统,确保长时间作战能力",
"自主导航和目标识别能力",
],
achievements: ["区域赛最佳设计奖", "全国赛技术挑战赛亚军"],
gallery: [
"/placeholder.svg?height=300&width=400",
"/placeholder.svg?height=300&width=400",
"/placeholder.svg?height=300&width=400",
],
team: [
{ name: "彭戈", role: "机械设计" },
{ name: "陈卓文", role: "电控系统" },
{ name: "黄瑞", role: "视觉算法" },
],
},
{
id: "striker-x2",
name: "Striker X2",
displayName: "初号英雄",
category: "HERO",
year: "2023-2024",
image: "/placeholder.svg?height=400&width=600",
description:
"高机动性攻击单元设计用于快速交战和战略定位。Striker X2 是我们的英雄机器人,具有更高的火力和机动性,能够在比赛中担任进攻核心的角色。",
shortDescription: "High-mobility attack unit designed for rapid engagement and strategic positioning.",
specs: [
{ icon: React.createElement(Shield, { className: "h-8 w-8 text-primary" }), name: "装甲", value: "轻量化装甲" },
{ icon: React.createElement(Gauge, { className: "h-8 w-8 text-primary" }), name: "最大速度", value: "4.5m/s" },
{ icon: React.createElement(Zap, { className: "h-8 w-8 text-primary" }), name: "电池续航", value: "25分钟" },
{ icon: React.createElement(Cpu, { className: "h-8 w-8 text-primary" }), name: "控制系统", value: "STM32H7" },
],
simpleSpecs: ["Weight: 12kg", "Max Speed: 4.5m/s", "Battery Life: 25min", "Weapon: Dual Launcher System"],
features: [
"双发射机构,提供更高的火力输出",
"高性能底盘,实现快速机动和精确控制",
"先进的弹道计算系统,提高射击精度",
"轻量化设计,提升整体性能",
],
achievements: ["区域赛最佳性能奖"],
gallery: ["/placeholder.svg?height=300&width=400", "/placeholder.svg?height=300&width=400"],
team: [
{ name: "闫芃森", role: "机械设计" },
{ name: "陈卓文", role: "电控系统" },
{ name: "韩翔宇", role: "视觉算法" },
],
},
{
id: "sentinel-mk-ii",
name: "Sentinel MK-II",
displayName: "二号步兵",
category: "INFANTRY",
year: "2022-2023",
image: "/placeholder.svg?height=400&width=600",
description:
"Sentinel系列的第二代增强了火力和防御能力。MK-II 在前代基础上进行了全面升级,特别是在控制系统和火力输出方面有显著提升。",
shortDescription: "Second generation of the Sentinel series with enhanced firepower and defensive capabilities.",
specs: [
{ icon: React.createElement(Shield, { className: "h-8 w-8 text-primary" }), name: "装甲", value: "标准装甲板" },
{ icon: React.createElement(Gauge, { className: "h-8 w-8 text-primary" }), name: "最大速度", value: "2.8m/s" },
{ icon: React.createElement(Zap, { className: "h-8 w-8 text-primary" }), name: "电池续航", value: "28分钟" },
{ icon: React.createElement(Cpu, { className: "h-8 w-8 text-primary" }), name: "控制系统", value: "STM32F4" },
],
simpleSpecs: ["Weight: 14kg", "Max Speed: 2.8m/s", "Battery Life: 28min", "Weapon: Standard Launcher"],
features: ["改进的云台稳定系统", "优化的弹道计算算法", "增强的装甲防护", "更高效的功率管理系统"],
achievements: ["全国赛最佳工程奖", "区域赛冠军"],
gallery: ["/placeholder.svg?height=300&width=400", "/placeholder.svg?height=300&width=400"],
team: [
{ name: "林小明", role: "机械设计" },
{ name: "陈志强", role: "电控系统" },
{ name: "黄海", role: "视觉算法" },
],
},
{
id: "scout-drone-alpha",
name: "Scout Drone Alpha",
displayName: "零号哨兵",
category: "AERIAL",
year: "2022-2023",
image: "/placeholder.svg?height=400&width=600",
description:
"我们的第一款侦察无人机提供战场情报和有限的攻击能力。Scout Drone Alpha 是我们首次尝试空中单元,为地面机器人提供战场态势感知。",
shortDescription:
"Lightweight reconnaissance drone providing battlefield intelligence and limited attack capabilities.",
specs: [
{ icon: React.createElement(Shield, { className: "h-8 w-8 text-primary" }), name: "装甲", value: "最小化装甲" },
{ icon: React.createElement(Gauge, { className: "h-8 w-8 text-primary" }), name: "最大速度", value: "10m/s" },
{ icon: React.createElement(Zap, { className: "h-8 w-8 text-primary" }), name: "电池续航", value: "15分钟" },
{ icon: React.createElement(Cpu, { className: "h-8 w-8 text-primary" }), name: "控制系统", value: "Pixhawk" },
],
simpleSpecs: ["Weight: 2kg", "Max Speed: 10m/s", "Flight Time: 15min", "Sensors: 4K Camera, Infrared"],
features: [
"高清摄像头,提供实时战场画面",
"轻量化设计,提高机动性和续航时间",
"自主避障系统",
"与地面单元的数据链路系统",
],
achievements: ["创新设计奖"],
gallery: ["/placeholder.svg?height=300&width=400"],
team: [
{ name: "林小明", role: "机械设计" },
{ name: "黄海", role: "视觉算法" },
],
},
{
id: "sentinel-mk-i",
name: "Sentinel MK-I",
displayName: "零号工程",
category: "ENGINEER",
year: "2021-2022",
image: "/placeholder.svg?height=400&width=600",
description:
"Sentinel系列的初代机型为后续发展奠定了基础。作为我们的第一代步兵机器人MK-I 虽然在技术上相对简单,但建立了团队的基础设计理念。",
shortDescription: "Specialized support unit capable of on-field repairs and resource management during matches.",
specs: [
{ icon: React.createElement(Shield, { className: "h-8 w-8 text-primary" }), name: "装甲", value: "基础装甲板" },
{ icon: React.createElement(Gauge, { className: "h-8 w-8 text-primary" }), name: "最大速度", value: "2.5m/s" },
{ icon: React.createElement(Zap, { className: "h-8 w-8 text-primary" }), name: "电池续航", value: "25分钟" },
{ icon: React.createElement(Cpu, { className: "h-8 w-8 text-primary" }), name: "控制系统", value: "STM32F1" },
],
simpleSpecs: ["Weight: 18kg", "Max Speed: 2m/s", "Battery Life: 40min", "Tools: Mechanical Arm, Repair Module"],
features: ["基础云台系统", "手动控制为主,辅助自动化功能", "模块化底盘设计", "简单的视觉识别系统"],
achievements: ["区域赛最佳新秀奖"],
gallery: ["/placeholder.svg?height=300&width=400"],
team: [
{ name: "王建国", role: "视觉算法" },
{ name: "李明", role: "机械设计" },
{ name: "张伟", role: "电控系统" },
],
},
]
// 按年份分组的机器人数据,用于历史页面
export const robotsByYear = [
{
year: "2023-2024",
models: robots.filter((robot) => robot.year === "2023-2024"),
},
{
year: "2022-2023",
models: robots.filter((robot) => robot.year === "2022-2023"),
},
{
year: "2021-2022",
models: robots.filter((robot) => robot.year === "2021-2022"),
},
]
// 获取单个机器人数据
export function getRobotById(id: string) {
return robots.find((robot) => robot.id === id) || null
}

View File

@ -1,19 +1,5 @@
let userConfig = undefined
try {
// try to import ESM first
userConfig = await import('./v0-user-next.config.mjs')
} catch (e) {
try {
// fallback to CJS import
userConfig = await import("./v0-user-next.config");
} catch (innerError) {
// ignore error
}
}
/** @type {import('next').NextConfig} */
const nextConfig = {
output: 'export',
eslint: {
ignoreDuringBuilds: true,
},
@ -23,30 +9,6 @@ const nextConfig = {
images: {
unoptimized: true,
},
experimental: {
webpackBuildWorker: true,
parallelServerBuildTraces: true,
parallelServerCompiles: true,
},
}
if (userConfig) {
// ESM imports will have a "default" property
const config = userConfig.default || userConfig
for (const key in config) {
if (
typeof nextConfig[key] === 'object' &&
!Array.isArray(nextConfig[key])
) {
nextConfig[key] = {
...nextConfig[key],
...config[key],
}
} else {
nextConfig[key] = config[key]
}
}
}
export default nextConfig

View File

@ -10,33 +10,33 @@
},
"dependencies": {
"@hookform/resolvers": "^3.9.1",
"@radix-ui/react-accordion": "^1.2.2",
"@radix-ui/react-alert-dialog": "^1.1.4",
"@radix-ui/react-aspect-ratio": "^1.1.1",
"@radix-ui/react-avatar": "^1.1.2",
"@radix-ui/react-checkbox": "^1.1.3",
"@radix-ui/react-collapsible": "^1.1.2",
"@radix-ui/react-context-menu": "^2.2.4",
"@radix-ui/react-dialog": "^1.1.4",
"@radix-ui/react-dropdown-menu": "^2.1.4",
"@radix-ui/react-hover-card": "^1.1.4",
"@radix-ui/react-label": "^2.1.1",
"@radix-ui/react-menubar": "^1.1.4",
"@radix-ui/react-navigation-menu": "^1.2.3",
"@radix-ui/react-popover": "^1.1.4",
"@radix-ui/react-progress": "^1.1.1",
"@radix-ui/react-radio-group": "^1.2.2",
"@radix-ui/react-scroll-area": "^1.2.2",
"@radix-ui/react-select": "^2.1.4",
"@radix-ui/react-separator": "^1.1.1",
"@radix-ui/react-slider": "^1.2.2",
"@radix-ui/react-slot": "^1.1.1",
"@radix-ui/react-switch": "^1.1.2",
"@radix-ui/react-tabs": "^1.1.2",
"@radix-ui/react-toast": "^1.2.4",
"@radix-ui/react-toggle": "^1.1.1",
"@radix-ui/react-toggle-group": "^1.1.1",
"@radix-ui/react-tooltip": "^1.1.6",
"@radix-ui/react-accordion": "1.2.2",
"@radix-ui/react-alert-dialog": "1.1.4",
"@radix-ui/react-aspect-ratio": "1.1.1",
"@radix-ui/react-avatar": "1.1.2",
"@radix-ui/react-checkbox": "1.1.3",
"@radix-ui/react-collapsible": "1.1.2",
"@radix-ui/react-context-menu": "2.2.4",
"@radix-ui/react-dialog": "1.1.4",
"@radix-ui/react-dropdown-menu": "2.1.4",
"@radix-ui/react-hover-card": "1.1.4",
"@radix-ui/react-label": "2.1.1",
"@radix-ui/react-menubar": "1.1.4",
"@radix-ui/react-navigation-menu": "1.2.3",
"@radix-ui/react-popover": "1.1.4",
"@radix-ui/react-progress": "1.1.1",
"@radix-ui/react-radio-group": "1.2.2",
"@radix-ui/react-scroll-area": "1.2.2",
"@radix-ui/react-select": "2.1.4",
"@radix-ui/react-separator": "1.1.1",
"@radix-ui/react-slider": "1.2.2",
"@radix-ui/react-slot": "1.1.1",
"@radix-ui/react-switch": "1.1.2",
"@radix-ui/react-tabs": "1.1.2",
"@radix-ui/react-toast": "1.2.4",
"@radix-ui/react-toggle": "1.1.1",
"@radix-ui/react-toggle-group": "1.1.1",
"@radix-ui/react-tooltip": "1.1.6",
"autoprefixer": "^10.4.20",
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",