V3 landing: white + violet + yellow accent, bold editorial. Markdown-driven content: 3 yarışma formatı (hands-on, ideathon, robo-soccer), 5 edisyon (Ataköy, Çemberlitaş Ideathon '25, Çemberlitaş HoC '26, İstanbul/Ankara Robo Soccer). Sayfalar: anasayfa, yarışma/edisyon detayları, sponsor, hakkımızda, iletişim. 40 Çemberlitaş fotoğrafı (1600px optimize, ~6.4 MB). Content helper (gray-matter + marked), reviews/photos registry, iletişim/ekip tek kaynak lib/contact.ts. Next.js 16 standalone build, Docker + compose hazır. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
62
src/components/EditionCard.tsx
Normal file
62
src/components/EditionCard.tsx
Normal file
@@ -0,0 +1,62 @@
|
||||
import Link from "next/link";
|
||||
import type { Edition } from "@/lib/content";
|
||||
import { formatDateRange } from "@/lib/content";
|
||||
|
||||
const statusLabel = {
|
||||
upcoming: "Yaklaşan",
|
||||
announced: "Duyuruldu",
|
||||
past: "Geçmiş",
|
||||
} as const;
|
||||
|
||||
export function EditionCard({ e }: { e: Edition }) {
|
||||
const isPast = e.status === "past";
|
||||
return (
|
||||
<Link
|
||||
href={`/edisyonlar/${e.slug}`}
|
||||
className="group flex flex-col border-2 border-neutral-900 bg-white p-5 transition hover:-translate-y-1 hover:bg-yellow-50"
|
||||
>
|
||||
<div className="flex items-center justify-between">
|
||||
<span
|
||||
className={`border border-neutral-900 px-2 py-0.5 text-[10px] font-black uppercase tracking-[0.2em] ${
|
||||
isPast ? "bg-white text-neutral-900" : "bg-yellow-300 text-neutral-900"
|
||||
}`}
|
||||
>
|
||||
{statusLabel[e.status]}
|
||||
</span>
|
||||
{e.city && (
|
||||
<span className="text-xs font-black uppercase tracking-[0.2em] text-neutral-500">
|
||||
{e.city}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
<div className="mt-4 text-xl font-black leading-tight tracking-tight">{e.name}</div>
|
||||
<div className="mt-1 text-sm font-semibold text-neutral-600">
|
||||
{formatDateRange(e.startDate, e.endDate)}
|
||||
</div>
|
||||
{e.venue && (
|
||||
<div className="text-xs text-neutral-500">{e.venue}</div>
|
||||
)}
|
||||
{e.stats && (
|
||||
<div className="mt-5 grid grid-cols-3 gap-3 border-t-2 border-neutral-900 pt-4 text-xs">
|
||||
{e.stats.teams != null && <Stat v={e.stats.teams} l="Takım" />}
|
||||
{e.stats.participants != null && <Stat v={`${e.stats.participants}+`} l="Katılımcı" />}
|
||||
{e.stats.volunteers != null && <Stat v={e.stats.volunteers} l="Gönüllü" />}
|
||||
</div>
|
||||
)}
|
||||
<span className="mt-4 inline-flex items-center gap-1 text-xs font-black uppercase tracking-[0.2em] text-violet-700 transition group-hover:translate-x-0.5">
|
||||
Aç →
|
||||
</span>
|
||||
</Link>
|
||||
);
|
||||
}
|
||||
|
||||
function Stat({ v, l }: { v: string | number; l: string }) {
|
||||
return (
|
||||
<div>
|
||||
<div className="text-lg font-black text-neutral-900">{v}</div>
|
||||
<div className="text-[10px] font-black uppercase tracking-[0.15em] text-neutral-500">
|
||||
{l}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user