8 hand-picked UFO incidents that any enthusiast recognises:
- Kenneth Arnold 1947 (the genesis — "flying saucers" coined)
- Roswell 1947 (the original Army press release)
- Maury Island 1947 (Puget Sound, slag drop, FBI plane crash)
- Mantell 1948 (first known UFO casualty)
- Rendlesham Forest 1980 (USAF security police, deputy commander tape)
- Phoenix Lights 1997 (V-formation across Arizona, governor's reversal)
- Nimitz Tic-Tac 2004 (USS Nimitz F/A-18, gun-cam released 2017)
- Green Fireballs Sandia 1948 (copper salts, nuclear-site overflights)
Each case has:
- Bilingual hand-written editorial blurb (PT-BR + EN, no LLM)
- Painterly editorial hero illustration at 2K
- Year + tag chips (military / civilian / modern / early / naval /
aviation / mass-sighting)
- Link to /e/events/<id> when indexed in corpus, /search?q=... when not,
/c/<slug> for the green-fireballs narrative case
Components:
lib/iconic-cases.ts — IconicCase type + ICONIC_CASES editorial list
components/iconic-cases.tsx — magazine grid: first two as wide hero pair,
rest as 3-up tiles below. Hover scale on images, gradient overlays,
aspect-16/11 hero + 16/10 compact, lazy-loaded.
app/page.tsx — inserted between <FeaturedCase /> and <PortalGrid />
4 new hero illustrations generated this session:
- iconic-nimitz-tic-tac-2004.png (Nano Banana Pro)
- iconic-phoenix-lights-1997.png (Nano Banana Pro)
- iconic-rendlesham-forest-1980.png (gpt-image-1.5 via Codex)
- iconic-mantell-1948.png (Nano Banana Pro)
Per user direction: mixed generators (Nano Banana primary, Codex
co-pilot) so the homepage has stylistic variety while keeping the
painterly editorial register.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
119 lines
4.8 KiB
TypeScript
119 lines
4.8 KiB
TypeScript
/**
|
|
* IconicCases — the curated cover-story rail.
|
|
*
|
|
* Magazine grid of hand-picked iconic UFO incidents with painterly hero
|
|
* illustrations. Sits high on the homepage so the casual reader lands on
|
|
* recognisable history within two seconds: Roswell, Nimitz, Phoenix,
|
|
* Rendlesham.
|
|
*/
|
|
import Link from "next/link";
|
|
import { ICONIC_CASES, type IconicCase } from "@/lib/iconic-cases";
|
|
|
|
const ART_BASE = "/api/static/processing/case-art";
|
|
|
|
export function IconicCases({ locale }: { locale: "pt-br" | "en" }) {
|
|
const cases = ICONIC_CASES;
|
|
if (cases.length === 0) return null;
|
|
|
|
// Split: first 2 go into a wide hero pair, the rest tile below in a 3-up grid.
|
|
const [first, second, ...rest] = cases;
|
|
|
|
return (
|
|
<section className="mx-auto max-w-7xl px-4 md:px-8 py-12 md:py-16">
|
|
<div className="flex items-end justify-between mb-6 flex-wrap gap-3">
|
|
<div>
|
|
<div className="text-[10px] font-mono uppercase tracking-[0.18em] text-[#5a6678] mb-2">
|
|
{locale === "en" ? "// The iconic record" : "// Os clássicos da divulgação"}
|
|
</div>
|
|
<h2 className="font-display text-2xl md:text-4xl text-[#e7ecf3] tracking-tight">
|
|
{locale === "en"
|
|
? "The cases every UFO enthusiast knows"
|
|
: "Os casos que todo entusiasta UFO conhece"}
|
|
</h2>
|
|
</div>
|
|
<div className="text-[11px] font-mono text-[#5a6678]">
|
|
{cases.length} {locale === "en" ? "stories" : "histórias"}
|
|
</div>
|
|
</div>
|
|
|
|
{/* Hero pair */}
|
|
<div className="grid md:grid-cols-2 gap-4 md:gap-5 mb-4 md:mb-5">
|
|
{[first, second].filter(Boolean).map((c) => (
|
|
<HeroCard key={c.slug} c={c} locale={locale} />
|
|
))}
|
|
</div>
|
|
|
|
{/* Rest grid */}
|
|
{rest.length > 0 && (
|
|
<div className="grid sm:grid-cols-2 lg:grid-cols-3 gap-4 md:gap-5">
|
|
{rest.map((c) => <CompactCard key={c.slug} c={c} locale={locale} />)}
|
|
</div>
|
|
)}
|
|
</section>
|
|
);
|
|
}
|
|
|
|
function HeroCard({ c, locale }: { c: IconicCase; locale: "pt-br" | "en" }) {
|
|
const title = locale === "pt-br" ? c.title_pt_br : c.title_en;
|
|
const blurb = locale === "pt-br" ? c.blurb_pt_br : c.blurb_en;
|
|
return (
|
|
<Link
|
|
href={c.link}
|
|
className="group relative block rounded-2xl overflow-hidden border border-[rgba(224,192,128,0.15)] bg-[#0d1220] aspect-[16/11]"
|
|
>
|
|
{/* eslint-disable-next-line @next/next/no-img-element */}
|
|
<img
|
|
src={`${ART_BASE}/${c.image}`}
|
|
alt={title}
|
|
loading="lazy"
|
|
className="absolute inset-0 w-full h-full object-cover group-hover:scale-[1.03] transition-transform duration-700"
|
|
/>
|
|
<div className="absolute inset-0 bg-gradient-to-t from-[#0a0e1a] via-[#0a0e1a]/40 to-transparent" />
|
|
<div className="absolute inset-0 bg-gradient-to-r from-[#0a0e1a]/60 via-transparent to-transparent" />
|
|
<div className="absolute bottom-0 left-0 right-0 p-5 md:p-7">
|
|
<div className="text-[10px] font-mono uppercase tracking-[0.18em] text-[#e0c080] mb-2">
|
|
{c.year} · {c.tags.slice(0, 3).join(" · ")}
|
|
</div>
|
|
<h3 className="font-display text-2xl md:text-3xl text-white leading-tight mb-2 group-hover:text-[#e0c080] transition-colors">
|
|
{title}
|
|
</h3>
|
|
<p className="text-[13px] md:text-sm text-[#cbd2dd] leading-relaxed line-clamp-3 max-w-prose">
|
|
{blurb}
|
|
</p>
|
|
</div>
|
|
</Link>
|
|
);
|
|
}
|
|
|
|
function CompactCard({ c, locale }: { c: IconicCase; locale: "pt-br" | "en" }) {
|
|
const title = locale === "pt-br" ? c.title_pt_br : c.title_en;
|
|
const blurb = locale === "pt-br" ? c.blurb_pt_br : c.blurb_en;
|
|
return (
|
|
<Link
|
|
href={c.link}
|
|
className="group block rounded-xl overflow-hidden border border-[rgba(224,192,128,0.15)] bg-[#0d1220] hover:border-[#e0c080]/50 transition-all"
|
|
>
|
|
<div className="relative aspect-[16/10] overflow-hidden">
|
|
{/* eslint-disable-next-line @next/next/no-img-element */}
|
|
<img
|
|
src={`${ART_BASE}/${c.image}`}
|
|
alt={title}
|
|
loading="lazy"
|
|
className="absolute inset-0 w-full h-full object-cover group-hover:scale-[1.05] transition-transform duration-500"
|
|
/>
|
|
<div className="absolute inset-0 bg-gradient-to-t from-[#0a0e1a]/60 via-transparent to-transparent" />
|
|
<div className="absolute top-3 left-3 px-2 py-0.5 rounded bg-[#0a0e1a]/80 text-[10px] font-mono text-[#e0c080]">
|
|
{c.year}
|
|
</div>
|
|
</div>
|
|
<div className="p-4 md:p-5">
|
|
<h3 className="font-display text-lg md:text-xl text-[#e7ecf3] leading-snug mb-2 group-hover:text-[#e0c080] transition-colors">
|
|
{title}
|
|
</h3>
|
|
<p className="text-[12px] text-[#9aa6b8] leading-relaxed line-clamp-3">
|
|
{blurb}
|
|
</p>
|
|
</div>
|
|
</Link>
|
|
);
|
|
}
|