import Image from "next/image"; import Link from "next/link"; import { formatCompactNumber } from "@/utils/format"; import { useBaseRoms } from "@/contexts/BaseRomContext"; import type { Hack } from "@/data/hacks"; import { useEffect, useState } from "react"; import useEmblaCarousel from "embla-carousel-react"; import { usePathname } from "next/navigation"; // Using shared Hack type from data export default function HackCard({ hack, clickable = true, className = "" }: { hack: Hack; clickable?: boolean; className?: string }) { const { isLinked, hasPermission, hasCached } = useBaseRoms(); const linked = isLinked(hack.baseRom); const ready = hasPermission(hack.baseRom) || hasCached(hack.baseRom); const images = (hack.covers && hack.covers.length > 0 ? hack.covers : []).filter(Boolean); const isCarousel = images.length > 1; const pathname = usePathname(); const showTitlePlaceholder = (pathname || "").startsWith("/submit") && images.length === 0; const [emblaRef, emblaApi] = useEmblaCarousel({ loop: true }); const [selectedIndex, setSelectedIndex] = useState(0); useEffect(() => { if (!emblaApi) return; const onSelect = () => setSelectedIndex(emblaApi.selectedScrollSnap()); emblaApi.on("select", onSelect); onSelect(); return () => { emblaApi.off("select", onSelect); }; }, [emblaApi]); const cardClass = `rounded-[12px] overflow-hidden ${ clickable ? "transition-transform duration-300 hover:-translate-y-0.5 hover:shadow-xl anim-float" : "" } ring-1 ${ready ? "ring-emerald-400/50 bg-emerald-500/10" : "card ring-[var(--border)]"}`; const content = (
{showTitlePlaceholder ? (
{hack.title}
) : isCarousel ? (
{images.map((src, idx) => (
{hack.title}
))}
) : images[0] ? ( {hack.title} ) : null} {!showTitlePlaceholder &&
}
{hack.tags.slice(0, 2).map((t) => ( {t} ))} {ready ? "Ready" : linked ? "Permission needed" : "Base ROM needed"}
{isCarousel && (
{images.map((_, i) => (
)}

{hack.title}

{hack.version}

By {hack.author}

{formatCompactNumber(hack.downloads)}

{(() => { const text = (hack as any).summary ?? (hack as any).description ?? ""; return text.length > 120 ? text.slice(0, 120).trimEnd() + "…" : text; })()}

Base: {hack.baseRom}
); if (clickable) { return ( {content} ); } return
{content}
; }