Files
2026-08-01 16:07:57 +02:00

147 lines
5.3 KiB
TypeScript

"use client";
import { motion } from "framer-motion";
import { Layers, Cpu, Database, Server } from "lucide-react";
import GlassCard from "@/components/ui/GlassCard";
import { fadeUp, stagger, viewportConfig } from "@/lib/animations";
import type { Dictionary, Locale } from "@/lib/dictionaries";
const skillGroups = [
{
icon: Layers,
category: "Frontend",
items: ["Next.js", "React", "React Native", "Tailwind CSS"],
color: "from-blue-400/20 to-blue-500/5",
border: "group-hover:border-blue-400/40",
iconBg: "bg-blue-500/10 border-blue-400/20 text-blue-300",
iconHover: "group-hover:bg-blue-500/20 group-hover:border-blue-400/50",
},
{
icon: Cpu,
category: "Backend",
items: ["Java", "Spring Boot", "Node.js", "TypeScript", "C++", "Bash"],
color: "from-emerald-400/20 to-emerald-500/5",
border: "group-hover:border-emerald-400/40",
iconBg: "bg-emerald-500/10 border-emerald-400/20 text-emerald-300",
iconHover:
"group-hover:bg-emerald-500/20 group-hover:border-emerald-400/50",
},
{
icon: Database,
category: "Databases",
items: ["PostgreSQL", "MySQL"],
color: "from-amber-400/20 to-amber-500/5",
border: "group-hover:border-amber-400/40",
iconBg: "bg-amber-500/10 border-amber-400/20 text-amber-300",
iconHover: "group-hover:bg-amber-500/20 group-hover:border-amber-400/50",
},
{
icon: Server,
category: "Infrastructure & DevOps",
items: ["Linux", "CI/CD", "Docker", "Traefik", "NGINX", "VPS"],
color: "from-purple-400/20 to-purple-500/5",
border: "group-hover:border-purple-400/40",
iconBg: "bg-purple-500/10 border-purple-400/20 text-purple-300",
iconHover: "group-hover:bg-purple-500/20 group-hover:border-purple-400/50",
},
];
interface TechStackProps {
locale: Locale;
dict: Dictionary;
}
export default function TechStack({ dict }: TechStackProps) {
return (
<section className="relative w-full py-24 sm:py-32">
{/* Subtle grid background */}
<div className="pointer-events-none absolute inset-0 grid-bg [mask-image:radial-gradient(ellipse_at_center,#000_20%,transparent_70%)] opacity-30" />
<div className="relative mx-auto w-full max-w-7xl px-6 lg:px-8">
{/* Header */}
<motion.div
initial="hidden"
whileInView="visible"
viewport={viewportConfig}
variants={stagger(0.06)}
className="mx-auto mb-16 max-w-3xl text-center"
>
<motion.span
variants={fadeUp}
className="mb-6 inline-flex items-center gap-2 rounded-full border border-purple-400/30 bg-purple-500/10 px-3.5 py-1.5 font-mono text-xs tracking-tight text-purple-300 backdrop-blur-md"
>
{dict.techStack.badge}
</motion.span>
<motion.h2
variants={fadeUp}
className="font-display text-display-lg font-medium tracking-tight"
>
<span className="text-gradient-fade">
{dict.techStack.title}
</span>{" "}
<span className="text-gradient-purple">
{dict.techStack.titleAccent}
</span>
</motion.h2>
<motion.p
variants={fadeUp}
className="mx-auto mt-6 max-w-xl text-base leading-relaxed text-text-secondary"
>
{dict.techStack.subtitle}
</motion.p>
</motion.div>
{/* Skill cards */}
<motion.div
initial="hidden"
whileInView="visible"
viewport={viewportConfig}
variants={stagger(0.1)}
className="grid grid-cols-1 gap-4 md:grid-cols-2"
>
{skillGroups.map((group) => (
<motion.div
key={group.category}
variants={fadeUp}
className="group h-full"
>
<GlassCard className={`h-full ${group.border}`}>
{/* Gradient accent on hover */}
<div
className={`absolute inset-0 rounded-2xl bg-gradient-to-br ${group.color} opacity-0 transition-opacity duration-500 group-hover:opacity-100`}
/>
<div className="relative">
<div className="mb-5 flex items-center gap-3">
<div
className={`flex h-10 w-10 items-center justify-center rounded-lg border transition-all duration-500 ${group.iconBg} ${group.iconHover}`}
>
<group.icon className="h-5 w-5" strokeWidth={1.5} />
</div>
<h3 className="text-base font-medium text-text-primary">
{group.category}
</h3>
</div>
<div className="flex flex-wrap gap-2">
{group.items.map((item) => (
<span
key={item}
className="rounded-lg border border-border/60 bg-surface/60 px-3 py-1.5 font-mono text-xs text-text-secondary transition-all duration-300 hover:border-purple-400/40 hover:text-purple-200"
>
{item}
</span>
))}
</div>
</div>
</GlassCard>
</motion.div>
))}
</motion.div>
</div>
</section>
);
}