优化网页交互逻辑和框架

This commit is contained in:
HelixCopex 2025-04-17 19:38:27 +08:00
parent f71751bbbf
commit c6f2acd462
7 changed files with 245 additions and 298 deletions

View File

@ -1,8 +1,10 @@
"use client"
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"
export default function HistoryPage() {
// 历届队员数据
@ -11,31 +13,109 @@ export default function HistoryPage() {
year: "2024-2025",
captain: "彭戈",
members: [
{ name: "彭戈", role: "队长 / 机械组", photo: "/placeholder.svg?height=100&width=100" },
{ name: "陈卓文", role: "电控组组长", photo: "/placeholder.svg?height=100&width=100" },
{ name: "黄瑞", role: "视觉组组长", photo: "/placeholder.svg?height=100&width=100" },
{ name: "李佳睿", role: "宣筹组组长", photo: "/placeholder.svg?height=100&width=100" },
{ name: "韩翔宇", role: "视觉工程师", photo: "/placeholder.svg?height=100&width=100" },
{ name: "闫芃森", role: "机械工程师", photo: "/placeholder.svg?height=100&width=100" },
{
name: "彭戈",
role: "队长 / 机械组",
photo: "/placeholder.svg?height=100&width=100",
destination: "华为 2012 实验室",
message: "在 Simba Robotics 的经历让我学会了如何将理论知识应用到实际工程中,感谢团队给我的成长机会。",
},
{
name: "陈卓文",
role: "电控组组长",
photo: "/placeholder.svg?height=100&width=100",
destination: "上海交通大学 - 机器人研究所",
message: "团队合作是最宝贵的财富,希望 Simba Robotics 越来越好!",
},
{
name: "黄瑞",
role: "视觉组组长",
photo: "/placeholder.svg?height=100&width=100",
destination: "腾讯 AI Lab",
message: "感谢战队给我提供的平台,让我在计算机视觉领域找到了自己的方向。",
},
{
name: "李佳睿",
role: "宣筹组组长",
photo: "/placeholder.svg?height=100&width=100",
destination: "字节跳动 - 产品经理",
message: "在战队的经历锻炼了我的沟通能力和项目管理能力,这些都是职场中的宝贵财富。",
},
{
name: "韩翔宇",
role: "视觉工程师",
photo: "/placeholder.svg?height=100&width=100",
destination: "清华大学 - 人工智能研究院",
message: "感谢战队的培养,让我有机会接触前沿技术,为我的学术道路打下基础。",
},
{
name: "闫芃森",
role: "机械工程师",
photo: "/placeholder.svg?height=100&width=100",
destination: "大疆创新 - 机械设计工程师",
message: "在战队的日日夜夜是我最珍贵的回忆,希望学弟学妹们继续努力!",
},
],
},
{
year: "2022-2023",
captain: "陈志强",
members: [
{ name: "陈志强", role: "队长 / 电控组", photo: "/placeholder.svg?height=100&width=100" },
{ name: "林小明", role: "机械组组长", photo: "/placeholder.svg?height=100&width=100" },
{ name: "黄海", role: "视觉组组长", photo: "/placeholder.svg?height=100&width=100" },
{ name: "张丽", role: "宣筹组组长", photo: "/placeholder.svg?height=100&width=100" },
{
name: "陈志强",
role: "队长 / 电控组",
photo: "/placeholder.svg?height=100&width=100",
destination: "上海微电子装备有限公司",
message: "战队是我大学时光中最重要的一部分,希望 Simba Robotics 在未来的比赛中取得更好的成绩!",
},
{
name: "林小明",
role: "机械组组长",
photo: "/placeholder.svg?height=100&width=100",
destination: "哈尔滨工业大学 - 机器人研究所",
message: "感谢战队给我提供的锻炼机会,让我在机械设计方面有了长足的进步。",
},
{
name: "黄海",
role: "视觉组组长",
photo: "/placeholder.svg?height=100&width=100",
destination: "商汤科技 - 计算机视觉工程师",
message: "在战队的经历是我求职路上的重要资本,感谢团队的每一位成员。",
},
{
name: "张丽",
role: "宣筹组组长",
photo: "/placeholder.svg?height=100&width=100",
destination: "阿里巴巴 - 市场营销",
message: "战队教会了我如何在有限的资源下实现最大的价值,这是职场中非常重要的能力。",
},
],
},
{
year: "2021-2022",
captain: "王建国",
members: [
{ name: "王建国", role: "队长 / 视觉组", photo: "/placeholder.svg?height=100&width=100" },
{ name: "李明", role: "机械组组长", photo: "/placeholder.svg?height=100&width=100" },
{ name: "张伟", role: "电控组组长", photo: "/placeholder.svg?height=100&width=100" },
{
name: "王建国",
role: "队长 / 视觉组",
photo: "/placeholder.svg?height=100&width=100",
destination: "百度 - 自动驾驶部门",
message: "创建战队的初衷是为了让更多学生有机会接触机器人技术,看到现在的发展,我感到非常欣慰。",
},
{
name: "李明",
role: "机械组组长",
photo: "/placeholder.svg?height=100&width=100",
destination: "中国科学院 - 自动化研究所",
message: "希望战队能够继续发扬技术创新的精神,在比赛中取得更好的成绩。",
},
{
name: "张伟",
role: "电控组组长",
photo: "/placeholder.svg?height=100&width=100",
destination: "特斯拉中国 - 电气工程师",
message: "战队的经历让我明白了团队合作的重要性,这是任何成功项目的基础。",
},
],
},
]
@ -113,19 +193,37 @@ export default function HistoryPage() {
<div className="grid grid-cols-2 md:grid-cols-3 lg:grid-cols-6 gap-4">
{team.members.map((member, idx) => (
<div key={idx} className="border border-white/10 p-4 card-hover-effect text-center">
<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>
<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>
))}
</div>
</div>

View File

@ -1,5 +1,5 @@
import Image from "next/image"
import { Shield, Zap, Brain, Users } from "lucide-react"
import { Code, Cpu, Database, Layers } from "lucide-react"
export default function AboutSection() {
return (
@ -45,38 +45,42 @@ export default function AboutSection() {
</div>
<div className="mt-8 border border-white/10 bg-white/5 card-hover-effect p-6">
<h3 className="text-2xl font-bold mb-4 text-primary"></h3>
<h3 className="text-2xl font-bold mb-4 text-primary"></h3>
<p className="text-muted-foreground mb-4 leading-relaxed">
Simba Robotics
便
Simba
Robotics沿
</p>
<div className="grid grid-cols-1 md:grid-cols-2 gap-4 mt-6">
<div className="flex items-start gap-3">
<Shield className="h-6 w-6 text-primary mt-1" />
<Layers className="h-6 w-6 text-primary mt-1" />
<div>
<h5 className="font-bold mb-1"></h5>
<p className="text-sm text-muted-foreground"></p>
<h5 className="font-bold mb-1"></h5>
<p className="text-sm text-muted-foreground">CAD建模3D打印CNC加工</p>
</div>
</div>
<div className="flex items-start gap-3">
<Zap className="h-6 w-6 text-primary mt-1" />
<Cpu className="h-6 w-6 text-primary mt-1" />
<div>
<h5 className="font-bold mb-1"></h5>
<p className="text-sm text-muted-foreground">齿</p>
<h5 className="font-bold mb-1"></h5>
<p className="text-sm text-muted-foreground">
PCB设计
</p>
</div>
</div>
<div className="flex items-start gap-3">
<Brain className="h-6 w-6 text-primary mt-1" />
<Code className="h-6 w-6 text-primary mt-1" />
<div>
<h5 className="font-bold mb-1"></h5>
<p className="text-sm text-muted-foreground"></p>
<h5 className="font-bold mb-1">AI</h5>
<p className="text-sm text-muted-foreground">
SLAM定位导航
</p>
</div>
</div>
<div className="flex items-start gap-3">
<Users className="h-6 w-6 text-primary mt-1" />
<Database className="h-6 w-6 text-primary mt-1" />
<div>
<h5 className="font-bold mb-1"></h5>
<p className="text-sm text-muted-foreground"></p>
<h5 className="font-bold mb-1"></h5>
<p className="text-sm text-muted-foreground"></p>
</div>
</div>
</div>

View File

@ -1,5 +1,7 @@
"use client"
import { Card, CardContent } from "@/components/ui/card"
import { Mail, MapPin, Phone, Github, Youtube, Twitter } from "lucide-react"
import { Mail, MapPin, Phone, Github, MessageSquare } from "lucide-react"
export default function ContactSection() {
const contactInfo = [
@ -30,14 +32,32 @@ export default function ContactSection() {
link: "https://github.com/simbarobotics",
},
{
icon: <Youtube className="h-5 w-5" />,
name: "YouTube",
link: "https://youtube.com/simbarobotics",
icon: (
<svg
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
className="h-5 w-5"
>
<path d="M17.8 4.8H6.2c-1.2 0-2.2 1-2.2 2.2v10c0 1.2 1 2.2 2.2 2.2h11.6c1.2 0 2.2-1 2.2-2.2V7c0-1.2-1-2.2-2.2-2.2Z" />
<path d="m9 10 3 3 3-3" />
</svg>
),
name: "Bilibili",
link: "https://space.bilibili.com/simbarobotics",
},
{
icon: <Twitter className="h-5 w-5" />,
name: "Twitter",
link: "https://twitter.com/simbarobotics",
icon: <MessageSquare className="h-5 w-5" />,
name: "微信公众号",
link: "#wechat-qrcode",
onClick: (e) => {
e.preventDefault()
// 这里可以添加显示微信二维码的逻辑,例如打开一个模态框
alert("扫描二维码关注我们的微信公众号SimbaRobotics")
},
},
]
@ -89,6 +109,7 @@ 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>
@ -102,7 +123,8 @@ export default function ContactSection() {
<CardContent className="p-6">
<h3 className="text-xl font-bold mb-4"></h3>
<p className="text-muted-foreground mb-6 leading-relaxed">
Simba Robotics
Simba Robotics
</p>
<p className="text-muted-foreground mb-6 leading-relaxed">
@ -110,7 +132,7 @@ export default function ContactSection() {
<p className="text-muted-foreground mb-6 leading-relaxed">
Simba Robotics
</p>
<p className="text-primary font-bold font-mono"> </p>
<p className="text-primary font-bold font-sans"> </p>
</CardContent>
</Card>
</div>

View File

@ -80,43 +80,6 @@ export default function Header() {
</nav>
<div className="flex items-center gap-2">
<Button variant="ghost" size="icon" className="button-hover-effect">
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
className="h-5 w-5"
>
<path d="M3 18v-6a9 9 0 0 1 18 0v6"></path>
<path d="M21 19a2 2 0 0 1-2 2h-1a2 2 0 0 1-2-2v-3a2 2 0 0 1 2-2h3zM3 19a2 2 0 0 0 2 2h1a2 2 0 0 0 2-2v-3a2 2 0 0 0-2-2H3z"></path>
</svg>
</Button>
<Button variant="ghost" size="icon" className="button-hover-effect">
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
className="h-5 w-5"
>
<circle cx="12" cy="12" r="10"></circle>
<circle cx="12" cy="10" r="3"></circle>
<path d="M7 20.662V19a2 2 0 0 1 2-2h6a2 2 0 0 1 2 2v1.662"></path>
</svg>
</Button>
{/* Mobile Menu Button */}
<Button variant="ghost" size="icon" className="md:hidden button-hover-effect" onClick={toggleMenu}>
{isMenuOpen ? <X className="h-6 w-6" /> : <Menu className="h-6 w-6" />}

View File

@ -139,10 +139,29 @@ export default function HeroSection() {
</p>
<div className="flex flex-col sm:flex-row gap-4 mb-16">
<Button size="lg" className="px-8 bg-primary text-primary-foreground hover:bg-primary/90 button-hover-effect">
<Button
size="lg"
className="px-8 bg-primary text-primary-foreground hover:bg-primary/90 button-hover-effect"
onClick={() => {
const robotsSection = document.getElementById("robots")
if (robotsSection) {
robotsSection.scrollIntoView({ behavior: "smooth" })
}
}}
>
</Button>
<Button size="lg" variant="outline" className="px-8 border-white/20 hover:bg-white/5 button-hover-effect">
<Button
size="lg"
variant="outline"
className="px-8 border-white/20 hover:bg-white/5 button-hover-effect"
onClick={() => {
const contactSection = document.getElementById("contact")
if (contactSection) {
contactSection.scrollIntoView({ behavior: "smooth" })
}
}}
>
</Button>
<Link href="/history">

View File

@ -1,6 +1,6 @@
"use client"
import { useRef, useState } from "react"
import { useRef, useState, useEffect } from "react"
import Image from "next/image"
import { Card, CardContent } from "@/components/ui/card"
import { Button } from "@/components/ui/button"
@ -9,8 +9,6 @@ import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "@/comp
export default function RobotsShowcase() {
const scrollContainerRef = useRef<HTMLDivElement>(null)
const [showLeftArrow, setShowLeftArrow] = useState(false)
const [showRightArrow, setShowRightArrow] = useState(true)
const [activeIndex, setActiveIndex] = useState(0)
const robots = [
@ -50,67 +48,41 @@ export default function RobotsShowcase() {
},
]
// 创建一个循环数组,用于无限滚动
const displayRobots = [...robots]
const scroll = (direction: "left" | "right") => {
if (scrollContainerRef.current) {
const { current: container } = scrollContainerRef
const scrollAmount = container.clientWidth * 0.8
const cardWidth = container.querySelector(".card-hover-effect")?.clientWidth || 0
const gap = 24 // 6 * 4px (gap-6)
const cardWidth = container.querySelector(".robot-card")?.clientWidth || 350
// 更新活跃索引
if (direction === "left") {
container.scrollBy({ left: -scrollAmount, behavior: "smooth" })
setActiveIndex((prev) => (prev === 0 ? robots.length - 1 : prev - 1))
} else {
container.scrollBy({ left: scrollAmount, behavior: "smooth" })
setActiveIndex((prev) => (prev === robots.length - 1 ? 0 : prev + 1))
}
// 检查是否需要无限滚动
setTimeout(() => {
if (container) {
// 如果滚动到最左边(克隆的最后一个元素)
if (container.scrollLeft < cardWidth / 2) {
// 无动画地跳到真正的最后一组元素
container.scrollTo({
left: container.scrollWidth - cardWidth * 2,
behavior: "auto",
})
}
// 如果滚动到最右边(克隆的第一个元素)
else if (container.scrollLeft > container.scrollWidth - cardWidth * 1.5) {
// 无动画地跳到真正的第一组元素
container.scrollTo({
left: cardWidth,
behavior: "auto",
})
}
setShowLeftArrow(container.scrollLeft > 0)
setShowRightArrow(container.scrollLeft < container.scrollWidth - container.clientWidth - 10)
}
}, 500)
// 滚动到新的活跃卡片
const newScrollPosition = activeIndex * (cardWidth + 24) // 24 是 gap-6
container.scrollTo({
left: newScrollPosition,
behavior: "smooth",
})
}
}
const handleScroll = () => {
// 使用 useEffect 监听活跃索引变化,滚动到对应位置
useEffect(() => {
if (scrollContainerRef.current) {
const { current: container } = scrollContainerRef
const cardWidth = container.querySelector(".card-hover-effect")?.clientWidth || 0
const gap = 24 // 6 * 4px (gap-6)
// 计算当前查看的卡片索引
const scrollPosition = container.scrollLeft
const itemWidth = cardWidth + gap
const index = Math.round(scrollPosition / itemWidth) - 1 // -1 因为有一个克隆元素在开头
if (index >= 0 && index < robots.length) {
setActiveIndex(index)
}
setShowLeftArrow(container.scrollLeft > 0)
setShowRightArrow(container.scrollLeft < container.scrollWidth - container.clientWidth - 10)
const cardWidth = scrollContainerRef.current.querySelector(".robot-card")?.clientWidth || 350
const newScrollPosition = activeIndex * (cardWidth + 24) // 24 是 gap-6
scrollContainerRef.current.scrollTo({
left: newScrollPosition,
behavior: "smooth",
})
}
}
}, [activeIndex])
return (
<section id="robots" className="py-20 relative overflow-hidden">
@ -133,84 +105,20 @@ export default function RobotsShowcase() {
</div>
<div className="relative">
{showLeftArrow && (
<Button
variant="outline"
size="icon"
className="absolute left-0 top-1/2 -translate-y-1/2 z-10 bg-background/80 backdrop-blur-sm border-white/10 button-hover-effect"
onClick={() => scroll("left")}
>
<ChevronLeft className="h-6 w-6" />
</Button>
)}
<div
ref={scrollContainerRef}
className="flex gap-6 overflow-x-auto scrollbar-hide py-4 px-2 snap-x snap-mandatory"
onScroll={handleScroll}
<Button
variant="outline"
size="icon"
className="absolute left-0 top-1/2 -translate-y-1/2 z-10 bg-background/80 backdrop-blur-sm border-white/10 button-hover-effect"
onClick={() => scroll("left")}
>
{/* 添加末尾项到开头 */}
<Card
key={`clone-end-${robots[robots.length - 1].id}`}
className="min-w-[300px] md:min-w-[350px] border-white/10 bg-background/60 backdrop-blur-sm flex-shrink-0 card-hover-effect snap-center"
>
<CardContent className="p-0">
<div className="relative">
<Image
src={robots[robots.length - 1].image || "/placeholder.svg"}
alt={robots[robots.length - 1].name}
width={350}
height={200}
className="w-full h-48 object-cover"
/>
<div className="absolute top-0 right-0 bg-primary text-primary-foreground text-xs px-3 py-1">
{robots[robots.length - 1].category}
</div>
<div className="absolute bottom-0 left-0 p-2">
<p className="text-xs text-primary font-mono">{`0${robots.length}/0${robots.length}`}</p>
</div>
</div>
<ChevronLeft className="h-6 w-6" />
</Button>
<div className="p-4">
<div className="flex justify-between items-start mb-2">
<h3 className="text-xl font-bold">{robots[robots.length - 1].name}</h3>
<TooltipProvider>
<Tooltip>
<TooltipTrigger asChild>
<Button variant="ghost" size="icon" className="h-8 w-8 button-hover-effect">
<Info className="h-4 w-4" />
</Button>
</TooltipTrigger>
<TooltipContent className="max-w-[250px]">
<div className="space-y-2">
<p className="font-bold">Technical Specifications:</p>
<ul className="text-xs space-y-1">
{robots[robots.length - 1].specs.map((spec, index) => (
<li key={index}>{spec}</li>
))}
</ul>
</div>
</TooltipContent>
</Tooltip>
</TooltipProvider>
</div>
<p className="text-sm text-muted-foreground mb-4 leading-relaxed">
{robots[robots.length - 1].description}
</p>
<Button variant="outline" size="sm" className="w-full border-white/10 button-hover-effect">
View Details
</Button>
</div>
</CardContent>
</Card>
{robots.map((robot, index) => (
<div ref={scrollContainerRef} className="flex gap-6 overflow-x-auto scrollbar-hide py-4 px-2">
{displayRobots.map((robot, index) => (
<Card
key={robot.id}
className="min-w-[300px] md:min-w-[350px] border-white/10 bg-background/60 backdrop-blur-sm flex-shrink-0 card-hover-effect snap-center"
onMouseEnter={() => setActiveIndex(index)}
className="min-w-[300px] md:min-w-[350px] border-white/10 bg-background/60 backdrop-blur-sm flex-shrink-0 card-hover-effect robot-card"
>
<CardContent className="p-0">
<div className="relative">
@ -243,8 +151,8 @@ export default function RobotsShowcase() {
<div className="space-y-2">
<p className="font-bold">Technical Specifications:</p>
<ul className="text-xs space-y-1">
{robot.specs.map((spec, index) => (
<li key={index}>{spec}</li>
{robot.specs.map((spec, specIndex) => (
<li key={specIndex}>{spec}</li>
))}
</ul>
</div>
@ -262,73 +170,16 @@ export default function RobotsShowcase() {
</CardContent>
</Card>
))}
{/* 添加开头项到末尾 */}
<Card
key={`clone-start-${robots[0].id}`}
className="min-w-[300px] md:min-w-[350px] border-white/10 bg-background/60 backdrop-blur-sm flex-shrink-0 card-hover-effect snap-center"
>
<CardContent className="p-0">
<div className="relative">
<Image
src={robots[0].image || "/placeholder.svg"}
alt={robots[0].name}
width={350}
height={200}
className="w-full h-48 object-cover"
/>
<div className="absolute top-0 right-0 bg-primary text-primary-foreground text-xs px-3 py-1">
{robots[0].category}
</div>
<div className="absolute bottom-0 left-0 p-2">
<p className="text-xs text-primary font-mono">{`01/0${robots.length}`}</p>
</div>
</div>
<div className="p-4">
<div className="flex justify-between items-start mb-2">
<h3 className="text-xl font-bold">{robots[0].name}</h3>
<TooltipProvider>
<Tooltip>
<TooltipTrigger asChild>
<Button variant="ghost" size="icon" className="h-8 w-8 button-hover-effect">
<Info className="h-4 w-4" />
</Button>
</TooltipTrigger>
<TooltipContent className="max-w-[250px]">
<div className="space-y-2">
<p className="font-bold">:</p>
<ul className="text-xs space-y-1">
{robots[0].specs.map((spec, index) => (
<li key={index}>{spec}</li>
))}
</ul>
</div>
</TooltipContent>
</Tooltip>
</TooltipProvider>
</div>
<p className="text-sm text-muted-foreground mb-4 leading-relaxed">{robots[0].description}</p>
<Button variant="outline" size="sm" className="w-full border-white/10 button-hover-effect">
View Details
</Button>
</div>
</CardContent>
</Card>
</div>
{showRightArrow && (
<Button
variant="outline"
size="icon"
className="absolute right-0 top-1/2 -translate-y-1/2 z-10 bg-background/80 backdrop-blur-sm border-white/10 button-hover-effect"
onClick={() => scroll("right")}
>
<ChevronRight className="h-6 w-6" />
</Button>
)}
<Button
variant="outline"
size="icon"
className="absolute right-0 top-1/2 -translate-y-1/2 z-10 bg-background/80 backdrop-blur-sm border-white/10 button-hover-effect"
onClick={() => scroll("right")}
>
<ChevronRight className="h-6 w-6" />
</Button>
{/* 添加索引指示器 */}
<div className="flex justify-center mt-6 gap-2">
@ -338,17 +189,7 @@ export default function RobotsShowcase() {
className={`w-2 h-2 rounded-full transition-all ${
activeIndex === index ? "bg-primary w-4" : "bg-gray-500"
}`}
onClick={() => {
if (scrollContainerRef.current) {
const cardWidth = scrollContainerRef.current.querySelector(".card-hover-effect")?.clientWidth || 0
const gap = 24 // 6 * 4px (gap-6)
scrollContainerRef.current.scrollTo({
left: (index + 1) * (cardWidth + gap), // +1 for the cloned element at start
behavior: "smooth",
})
setActiveIndex(index)
}
}}
onClick={() => setActiveIndex(index)}
/>
))}
</div>

View File

@ -8,7 +8,7 @@
version="1.1"
id="svg1"
inkscape:version="1.3.2 (091e20e, 2023-11-25, custom)"
sodipodi:docname="s_icon.svg"
sodipodi:docname="logo.svg"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
@ -39,16 +39,16 @@
inkscape:groupmode="layer"
id="layer1">
<path
d="m 121.35487,81.142851 -6.11022,10.583333 h 21.20645 l 0.0413,0.07183 23.48539,40.678656 -27.03504,46.82608 -0.006,0.0109 -6.10402,10.57248 -0.006,0.0109 h 12.22045 33.60415 l -4.43229,7.67705 h -51.11006 l -0.005,0.008 h -4.95008 l 4.43849,-7.6879 6.11022,-10.58334 22.01467,-38.12997 6.11023,-10.58333 H 138.60655 117.07246 111.30124 93.26771 81.047269 l -6.110738,10.58333 -32.493624,56.2808 -6.110221,10.58334 H 48.553129 93.89248 l -0.0698,0.1204 h 12.22044 8.67337 l 0.005,-0.008 h 47.38729 12.22096 l 0.008,-0.0134 h 31.42702 11.49542 12.22045 l -6.11022,-10.58334 -4.43694,-7.6848 -6.11022,-10.58333 h -12.22045 -9.60768 -12.22096 l -0.0119,0.0212 h -1.24799 -0.61495 -9.41855 l 20.91759,-36.23035 6.11022,-10.58333 -3.90415,-6.76238 -8.98137,-15.55616 h 24.15667 l 3.86694,-6.6983 2.24328,-3.885036 h -11.55433 -37.06596 l 6.11022,10.583336 h 0.0227 l 12.885,22.31854 -27.02781,46.81368 h -10.10222 l 20.93102,-36.25412 6.11022,-10.58282 -6.11022,-10.58333 -17.37517,-30.095326 h 46.00805 L 188.61123,81.21481 H 163.8546 V 81.14298 Z M 87.156954,141.18105 h 18.034046 5.7707 21.53461 l -22.01468,38.12997 -6.11022,10.58334 -3.90312,6.76031 -3.90261,-6.76031 -6.11074,-10.58334 H 78.234501 65.142794 l 6.545853,-11.33781 6.110222,-10.58333 z"
style="fill:#ffffff;stroke-width:0.690852;paint-order:stroke fill markers"
d="m 120.18387,65.065937 -8.00358,13.862771 h 27.77765 l 0.0541,0.09409 30.76276,53.283672 -35.41234,61.33599 -0.008,0.0143 -7.99546,13.84855 -0.008,0.0143 h 16.00718 44.01701 l -5.80572,10.05592 h -66.94744 l -0.007,0.0105 h -6.48395 l 5.81384,-10.07013 8.00358,-13.86278 28.83631,-49.94524 8.0036,-13.86276 H 142.78056 114.57375 107.01421 83.392663 67.385498 l -8.004262,13.86276 -42.562363,73.72043 -8.0035837,13.86278 H 24.822458 84.211033 l -0.0914,0.15771 h 16.007157 11.36098 l 0.007,-0.0105 h 62.07111 16.00784 l 0.0105,-0.0175 h 41.16526 15.05748 16.00718 l -8.00358,-13.86278 -5.81181,-10.06608 -8.00358,-13.86276 h -16.00718 -12.5848 -16.00784 l -0.0156,0.0278 h -1.6347 -0.80551 -12.33705 l 27.39928,-47.45699 8.00358,-13.86276 -5.11392,-8.85783 -11.76441,-20.37651 h 31.64205 l 5.06519,-8.773893 2.9384,-5.088885 h -15.13465 -48.55152 l 8.00358,13.862778 h 0.0297 l 16.87765,29.23434 -35.40286,61.31975 h -13.23258 l 27.41688,-47.48812 8.00358,-13.8621 -8.00358,-13.86276 -22.75918,-39.420912 h 60.26447 l -8.00332,-13.862894 h -32.42792 v -0.09409 z M 75.389113,143.70806 h 23.62222 7.558857 28.2075 l -28.83633,49.94523 -8.003587,13.86278 -5.11257,8.85512 -5.1119,-8.85512 -8.00427,-13.86278 H 63.701872 46.553462 l 8.574205,-14.85103 8.003585,-13.86277 z"
style="fill:#ffffff;stroke-width:0.904925;paint-order:stroke fill markers"
id="path24" />
<path
d="m 132.45755,63.009591 -6.11022,10.583333 h 48.01515 12.22045 24.09723 l -6.11022,-10.583333 h -24.09723 -12.22045 z"
style="fill:#ffffff;stroke-width:0.894431;paint-order:stroke fill markers"
d="m 134.72691,41.313757 -8.00358,13.862771 h 62.89352 16.00718 31.56419 l -8.00358,-13.862771 h -31.5642 -16.00717 z"
style="fill:#ffffff;stroke-width:1.17159;paint-order:stroke fill markers"
id="path26" />
<path
d="m 215.32071,77.350834 a 8.8895941,8.8895941 0 0 0 -8.88938,8.88938 8.8895941,8.8895941 0 0 0 8.88938,8.88938 8.8895941,8.8895941 0 0 0 8.88989,-8.88938 8.8895941,8.8895941 0 0 0 -8.88989,-8.88938 z"
style="fill:#ff0000;stroke-width:0.392006;paint-order:stroke fill markers"
d="M 243.26673,60.098895 A 11.644196,11.644196 0 0 0 231.62281,71.742811 11.644196,11.644196 0 0 0 243.26673,83.386727 11.644196,11.644196 0 0 0 254.91131,71.742811 11.644196,11.644196 0 0 0 243.26673,60.098895 Z"
style="fill:#ff0000;stroke-width:0.513476;paint-order:stroke fill markers"
id="path25" />
</g>
</svg>

Before

Width:  |  Height:  |  Size: 3.1 KiB

After

Width:  |  Height:  |  Size: 3.1 KiB