74 lines
3.4 KiB
TypeScript
74 lines
3.4 KiB
TypeScript
"use client";
|
|
|
|
import Link from "next/link";
|
|
import { ArrowRight, ArrowUpRight } from "lucide-react";
|
|
|
|
import type { NavGroup, NavItem } from "@/lib/navigation";
|
|
|
|
const GROUP_THEME: Record<string, { gradient: string; accent: string; label: string }> = {
|
|
core: { gradient: "from-primary/12 to-primary/4", accent: "bg-primary/10 text-primary group-hover:bg-primary group-hover:text-primary-foreground", label: "data" },
|
|
practice: { gradient: "from-success/12 to-success/4", accent: "bg-success/10 text-success group-hover:bg-success group-hover:text-success-foreground", label: "practice" },
|
|
advance: { gradient: "from-chart-4/12 to-chart-4/4", accent: "bg-chart-4/10 text-chart-4 group-hover:bg-chart-4 group-hover:text-white", label: "advance" },
|
|
insight: { gradient: "from-chart-3/12 to-chart-3/4", accent: "bg-chart-3/10 text-chart-3 group-hover:bg-chart-3 group-hover:text-white", label: "insight" },
|
|
};
|
|
|
|
function FeatureCard({ item, groupKey }: { item: NavItem; groupKey: string }) {
|
|
const Icon = item.icon;
|
|
const theme = GROUP_THEME[groupKey] ?? GROUP_THEME.core;
|
|
|
|
return (
|
|
<Link
|
|
href={item.href}
|
|
className="group relative flex h-full flex-col gap-3 overflow-hidden rounded-2xl bg-card p-5 shadow-sm ring-1 ring-foreground/[0.06] transition-all duration-300 hover:-translate-y-1 hover:shadow-xl hover:ring-primary/30"
|
|
>
|
|
<div className={`pointer-events-none absolute inset-0 bg-gradient-to-br ${theme.gradient} opacity-0 transition-opacity duration-300 group-hover:opacity-100`} />
|
|
|
|
<div className="relative flex items-center justify-between">
|
|
<span className={`flex size-11 items-center justify-center rounded-xl transition-colors duration-300 ${theme.accent}`}>
|
|
<Icon className="size-5" />
|
|
</span>
|
|
<ArrowUpRight className="size-4 text-muted-foreground/40 transition-all duration-300 group-hover:translate-x-0.5 group-hover:-translate-y-0.5 group-hover:text-primary" />
|
|
</div>
|
|
<div className="relative">
|
|
<h3 className="text-base font-semibold text-foreground">{item.label}</h3>
|
|
<p className="mt-1.5 text-sm leading-relaxed text-muted-foreground">
|
|
{item.desc}
|
|
</p>
|
|
</div>
|
|
</Link>
|
|
);
|
|
}
|
|
|
|
export function FeatureGrid({ items }: { items: NavItem[] }) {
|
|
const features = items.filter((i) => i.desc);
|
|
return (
|
|
<div className="stagger grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3">
|
|
{features.map((f) => (
|
|
<FeatureCard key={f.href} item={f} groupKey={f.group ?? "core"} />
|
|
))}
|
|
</div>
|
|
);
|
|
}
|
|
|
|
export function GroupedFeatureGrid({ groups }: { groups: NavGroup[] }) {
|
|
return (
|
|
<div className="space-y-8">
|
|
{groups.map((g) => (
|
|
<section key={g.key} className="animate-fade-in-up">
|
|
<div className="mb-4 flex items-center gap-2">
|
|
<div className="h-5 w-1 rounded-full bg-primary" />
|
|
<h2 className="text-sm font-bold tracking-wide text-foreground">{g.label}</h2>
|
|
<span className="text-xs text-muted-foreground">({g.items.length})</span>
|
|
<ArrowRight className="ml-auto size-3.5 text-muted-foreground/50" />
|
|
</div>
|
|
<div className="stagger grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3">
|
|
{g.items.map((item) => (
|
|
<FeatureCard key={item.href} item={item} groupKey={g.key} />
|
|
))}
|
|
</div>
|
|
</section>
|
|
))}
|
|
</div>
|
|
);
|
|
}
|