Files
netrunner-landing/components/sections/Features.tsx
T
2026-04-19 16:05:05 +10:00

164 lines
6.6 KiB
TypeScript

"use client";
import { EyeOff, Lock, Globe, Gauge, Cpu } from "lucide-react";
import { motion, Variants } from "framer-motion";
import { Dictionary } from "@/lib/IDict";
export function Features({ dict }: { dict: Dictionary["features"] }) {
// Универсальные классы для переиспользования и чистоты кода
const verticalCardClass =
"min-h-[320px] md:min-h-[360px] group bg-card/40 backdrop-blur-xl border border-border/50 rounded-[2.5rem] p-8 md:p-10 flex flex-col hover:border-primary/50 transition-all duration-500 hover:shadow-[0_0_40px_rgba(139,61,255,0.15)] relative overflow-hidden";
const iconContainerClass =
"bg-secondary/10 w-14 h-14 rounded-[1.2rem] flex items-center justify-center border border-secondary/20 shadow-[0_0_15px_rgba(0,229,242,0.15)] relative z-10 transition-transform duration-500 group-hover:scale-110";
const bentoConfig = [
{
// 1: DPI Evasion
className: `md:col-span-2 ${verticalCardClass}`,
icon: (
<div className={iconContainerClass}>
<EyeOff className="w-7 h-7 text-secondary drop-shadow-[0_0_10px_rgba(0,229,242,0.8)]" />
</div>
),
bgElement: (
<EyeOff className="absolute -bottom-10 -right-10 w-64 h-64 text-primary opacity-[0.03] group-hover:opacity-[0.08] group-hover:scale-110 group-hover:-rotate-12 transition-all duration-700 pointer-events-none" />
),
},
{
// 2: Cryptography
className: `md:col-span-1 ${verticalCardClass}`,
icon: (
<div className={iconContainerClass}>
<Lock className="w-7 h-7 text-secondary drop-shadow-[0_0_10px_rgba(0,229,242,0.8)]" />
</div>
),
bgElement: (
<div className="absolute top-0 right-0 w-40 h-40 bg-primary/10 blur-[70px] opacity-0 group-hover:opacity-100 transition-opacity duration-700 pointer-events-none" />
),
},
{
// 3: Adaptive Backpressure
className: `md:col-span-1 ${verticalCardClass}`,
icon: (
<div className={iconContainerClass}>
<Gauge className="w-7 h-7 text-secondary drop-shadow-[0_0_10px_rgba(0,229,242,0.8)]" />
</div>
),
bgElement: (
<Gauge className="absolute top-10 -right-8 w-48 h-48 text-primary opacity-[0.02] group-hover:opacity-[0.08] transition-all duration-700 pointer-events-none" />
),
},
{
// 4: Multi-Platform Core
className: `md:col-span-2 ${verticalCardClass}`,
icon: (
<div className={iconContainerClass}>
<Cpu className="w-7 h-7 text-secondary drop-shadow-[0_0_10px_rgba(0,229,242,0.8)]" />
</div>
),
bgElement: (
<div className="absolute inset-0 bg-[radial-gradient(circle_at_bottom_right,_var(--tw-gradient-stops))] from-primary/10 via-transparent to-transparent opacity-0 group-hover:opacity-100 transition-opacity duration-700 pointer-events-none" />
),
},
{
// 5: Global Network (Горизонтальная карточка)
className:
"md:col-span-3 bg-card/40 backdrop-blur-xl border border-border/50 rounded-[2.5rem] p-8 md:p-10 flex flex-col md:flex-row items-start md:items-center gap-8 md:gap-12 group hover:border-primary/50 transition-all duration-500 hover:shadow-[0_0_40px_rgba(139,61,255,0.15)] relative overflow-hidden",
icon: (
<div className="bg-secondary/10 w-16 h-16 md:w-20 md:h-20 rounded-[1.5rem] md:rounded-[1.8rem] shrink-0 flex items-center justify-center border border-secondary/20 shadow-[0_0_20px_rgba(0,229,242,0.15)] relative z-10 transition-transform duration-500 group-hover:scale-105">
<Globe className="w-8 h-8 md:w-10 md:h-10 text-secondary drop-shadow-[0_0_10px_rgba(0,229,242,0.8)]" />
</div>
),
bgElement: (
<div className="absolute inset-0 bg-[radial-gradient(circle_at_left,_var(--tw-gradient-stops))] from-primary/10 via-transparent to-transparent opacity-0 group-hover:opacity-100 transition-opacity duration-700 pointer-events-none" />
),
},
];
const containerVariants: Variants = {
hidden: { opacity: 0 },
show: {
opacity: 1,
transition: {
staggerChildren: 0.15,
},
},
};
const itemVariants: Variants = {
hidden: {
opacity: 0,
y: 40,
},
show: {
opacity: 1,
y: 0,
transition: {
type: "spring",
stiffness: 260,
damping: 20,
},
},
};
if (!dict || !dict.items || dict.items.length < 5) return null;
return (
<section
id="features"
className="py-24 px-4 w-full mx-auto relative overflow-hidden"
>
<div className="container max-w-6xl mx-auto relative z-10">
{/* Центральное мягкое свечение секции */}
<div className="absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 w-[100vw] md:w-[600px] h-[600px] bg-primary/5 blur-[100px] md:blur-[120px] rounded-full pointer-events-none -z-10" />
<div className="mb-16 md:mb-20 text-center">
<h2 className="text-4xl md:text-5xl font-extrabold tracking-tight text-foreground">
{dict.title}
</h2>
</div>
<motion.div
variants={containerVariants}
initial="hidden"
whileInView="show"
viewport={{ once: true, margin: "-100px" }}
className="grid grid-cols-1 md:grid-cols-3 gap-6"
>
{bentoConfig.map((config, idx) => {
const feature = dict.items[idx];
// Проверяем, это последняя горизонтальная карточка или нет
const isHorizontal = idx === 4;
return (
<motion.div
key={idx}
variants={itemVariants}
className={config.className}
>
{config.bgElement}
{config.icon}
{/* mt-auto прижимает текст к низу, pt-8 дает гарантированный отступ от иконки */}
<div
className={`relative z-10 ${
isHorizontal ? "" : "mt-auto pt-8"
}`}
>
<h3 className="text-xl md:text-2xl font-bold text-foreground mb-3 tracking-tight">
{feature.title}
</h3>
<p className="text-muted-foreground text-sm md:text-base leading-relaxed max-w-lg">
{feature.description}
</p>
</div>
</motion.div>
);
})}
</motion.div>
</div>
</section>
);
}