home: merge FeatureStoryHero design into FeaturedBentoFromDb
Replace the bento's old hero+side-rail layout with a full-width cinematic 21:9 hero on top + 4-up vertical-card rail below. Single DB query, single component. Standalone FeatureStoryHero component removed (was rendered above the bento; design now lives inside the bento itself). - FeaturedBentoFromDb.tsx: new hero (gradient overlay, Feature Story badge, large overlaid title, "Read full story" cue) + 4-card grid below - home-page/page.tsx: drop <FeatureStoryHero /> import + JSX block - src/components/FeatureStoryHero.tsx: deleted (composition replaced by inline JSX in the bento for single-query efficiency) Accent uses var(--color-text-info, #60a5fa) — the existing blue from the codebase, matching the rest of the post-Slice-4-revert site. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -3,7 +3,6 @@ import type { Metadata } from "next";
|
|||||||
import Header from "@/components/Header";
|
import Header from "@/components/Header";
|
||||||
import Footer from "@/components/Footer";
|
import Footer from "@/components/Footer";
|
||||||
import FeaturedBentoFromDb from '@/components/FeaturedBentoFromDb';
|
import FeaturedBentoFromDb from '@/components/FeaturedBentoFromDb';
|
||||||
import FeatureStoryHero from '@/components/FeatureStoryHero';
|
|
||||||
import FeaturedCarouselServer from '@/components/FeaturedCarouselServer';
|
import FeaturedCarouselServer from '@/components/FeaturedCarouselServer';
|
||||||
import TrendsSidebar from '@/components/TrendsSidebar';
|
import TrendsSidebar from '@/components/TrendsSidebar';
|
||||||
import LiveWireTicker from '@/components/LiveWireTicker';
|
import LiveWireTicker from '@/components/LiveWireTicker';
|
||||||
@@ -157,14 +156,7 @@ export default function HomePage() {
|
|||||||
</Suspense>
|
</Suspense>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Top feature story hero — single prominent card above the bento */}
|
{/* Featured: cinematic hero + 4-up rail below (FeaturedBentoFromDb) */}
|
||||||
<ScrollRevealSection className="section-enter section-enter-2">
|
|
||||||
<Suspense fallback={<BentoSkeleton />}>
|
|
||||||
<FeatureStoryHero />
|
|
||||||
</Suspense>
|
|
||||||
</ScrollRevealSection>
|
|
||||||
|
|
||||||
{/* Featured articles bento */}
|
|
||||||
<ScrollRevealSection className="section-enter section-enter-3">
|
<ScrollRevealSection className="section-enter section-enter-3">
|
||||||
<Suspense fallback={<BentoSkeleton />}>
|
<Suspense fallback={<BentoSkeleton />}>
|
||||||
<FeaturedBentoFromDb />
|
<FeaturedBentoFromDb />
|
||||||
|
|||||||
@@ -1,105 +0,0 @@
|
|||||||
import Link from "next/link";
|
|
||||||
import { createClient } from "@supabase/supabase-js";
|
|
||||||
import { rewriteLegacyImageUrl } from "@/lib/legacy-image";
|
|
||||||
|
|
||||||
export const dynamic = "force-dynamic";
|
|
||||||
|
|
||||||
interface Row {
|
|
||||||
wp_slug: string;
|
|
||||||
title: string;
|
|
||||||
excerpt: string | null;
|
|
||||||
category: string | null;
|
|
||||||
featured_image: string | null;
|
|
||||||
featured_image_alt: string | null;
|
|
||||||
author_name: string | null;
|
|
||||||
wp_published_at: string | null;
|
|
||||||
}
|
|
||||||
|
|
||||||
export default async function FeatureStoryHero() {
|
|
||||||
const sb = createClient(
|
|
||||||
process.env.NEXT_PUBLIC_SUPABASE_URL!,
|
|
||||||
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!,
|
|
||||||
{
|
|
||||||
db: { schema: (process.env.NEXT_PUBLIC_SUPABASE_SCHEMA || "bb") as "public" },
|
|
||||||
auth: { persistSession: false },
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
const { data } = await sb
|
|
||||||
.from("wp_imported_posts")
|
|
||||||
.select(
|
|
||||||
"wp_slug, title, excerpt, category, featured_image, featured_image_alt, author_name, wp_published_at",
|
|
||||||
)
|
|
||||||
.eq("status", "published")
|
|
||||||
.ilike("category", "featured")
|
|
||||||
.order("featured", { ascending: false })
|
|
||||||
.order("wp_published_at", { ascending: false, nullsFirst: false })
|
|
||||||
.limit(1);
|
|
||||||
|
|
||||||
const story = data?.[0] as Row | undefined;
|
|
||||||
if (!story) return null;
|
|
||||||
|
|
||||||
const image = story.featured_image
|
|
||||||
? rewriteLegacyImageUrl(story.featured_image)
|
|
||||||
: "/assets/images/article-placeholder.svg";
|
|
||||||
|
|
||||||
return (
|
|
||||||
<section
|
|
||||||
className="max-w-container mx-auto px-4 mt-6 mb-2"
|
|
||||||
aria-label="Top feature story"
|
|
||||||
>
|
|
||||||
<Link
|
|
||||||
href={`/news/${story.wp_slug}`}
|
|
||||||
className="group block relative overflow-hidden rounded border border-[#252525] bg-[#0b0f17] hover:border-[#5B7C8D] transition-colors"
|
|
||||||
>
|
|
||||||
<div className="relative aspect-[21/9] md:aspect-[21/8] bg-[#111]">
|
|
||||||
<img
|
|
||||||
src={image}
|
|
||||||
alt={story.featured_image_alt || story.title}
|
|
||||||
className="w-full h-full object-cover"
|
|
||||||
/>
|
|
||||||
<div className="absolute inset-0 bg-gradient-to-t from-black via-black/65 to-transparent" />
|
|
||||||
|
|
||||||
<span className="absolute top-4 left-4 inline-flex items-center gap-1.5 bg-[#5B7C8D] text-white px-3 py-1 rounded font-mono text-[11px] uppercase tracking-widest font-bold shadow-md">
|
|
||||||
<svg width="11" height="11" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true">
|
|
||||||
<path d="M12 2l2.6 7.6H22l-6.2 4.5L18.4 22 12 17.3 5.6 22l2.6-7.9L2 9.6h7.4z" />
|
|
||||||
</svg>
|
|
||||||
Feature Story
|
|
||||||
</span>
|
|
||||||
|
|
||||||
<div className="absolute bottom-0 left-0 right-0 p-6 md:p-10">
|
|
||||||
{story.category && (
|
|
||||||
<div className="text-[10px] font-mono uppercase tracking-widest text-[#5B7C8D] mb-2">
|
|
||||||
{story.category}
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
<h2 className="font-serif text-2xl md:text-4xl lg:text-5xl text-white leading-tight max-w-3xl group-hover:text-[#C8D9E6] transition-colors">
|
|
||||||
{story.title}
|
|
||||||
</h2>
|
|
||||||
{story.excerpt && (
|
|
||||||
<p className="font-serif text-base md:text-lg text-[#cbd5e1] mt-3 max-w-2xl line-clamp-2">
|
|
||||||
{story.excerpt}
|
|
||||||
</p>
|
|
||||||
)}
|
|
||||||
<div className="mt-4 flex items-center gap-3 text-[11px] font-mono text-[#9ca3af]">
|
|
||||||
<span>{story.author_name || "Staff Reporter"}</span>
|
|
||||||
{story.wp_published_at && (
|
|
||||||
<>
|
|
||||||
<span>·</span>
|
|
||||||
<span>
|
|
||||||
{new Date(story.wp_published_at).toLocaleDateString("en-US", {
|
|
||||||
month: "short",
|
|
||||||
day: "numeric",
|
|
||||||
year: "numeric",
|
|
||||||
})}
|
|
||||||
</span>
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
<span aria-hidden="true" className="text-[#5B7C8D] ml-2">→ Read full story</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</Link>
|
|
||||||
</section>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -69,67 +69,78 @@ export default async function FeaturedBento() {
|
|||||||
</Link>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="grid grid-cols-1 lg:grid-cols-3 gap-4">
|
{/* Cinematic 21:9 hero — full width, image fills, gradient + overlaid title */}
|
||||||
<Link
|
<Link
|
||||||
href={`/news/${hero.wp_slug}`}
|
href={`/news/${hero.wp_slug}`}
|
||||||
className="lg:col-span-2 group block rounded border border-[#252525] bg-[#0b0f17] overflow-hidden hover:border-[var(--color-text-info,#60a5fa)] transition-colors"
|
className="group block relative overflow-hidden rounded border border-[#252525] bg-[#0b0f17] hover:border-[var(--color-text-info,#60a5fa)] transition-colors"
|
||||||
>
|
>
|
||||||
<div className="relative aspect-[16/9] bg-[#111]">
|
<div className="relative aspect-[21/9] md:aspect-[21/8] bg-[#111]">
|
||||||
<img
|
<img
|
||||||
src={img(hero)}
|
src={img(hero)}
|
||||||
alt={hero.featured_image_alt || hero.title}
|
alt={hero.featured_image_alt || hero.title}
|
||||||
className="w-full h-full object-cover"
|
className="w-full h-full object-cover"
|
||||||
/>
|
/>
|
||||||
<div className="absolute top-2 left-2 flex gap-1 text-[10px] font-mono">
|
<div className="absolute inset-0 bg-gradient-to-t from-black via-black/65 to-transparent" />
|
||||||
<span className="bg-[var(--color-text-info,#60a5fa)] text-black px-2 py-0.5 rounded uppercase tracking-wider font-semibold">
|
|
||||||
Featured
|
<span className="absolute top-4 left-4 inline-flex items-center gap-1.5 bg-[var(--color-text-info,#60a5fa)] text-black px-3 py-1 rounded font-mono text-[11px] uppercase tracking-widest font-bold shadow-md">
|
||||||
</span>
|
<svg width="11" height="11" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true">
|
||||||
<span className="bg-black/60 text-white px-2 py-0.5 rounded uppercase tracking-wider">
|
<path d="M12 2l2.6 7.6H22l-6.2 4.5L18.4 22 12 17.3 5.6 22l2.6-7.9L2 9.6h7.4z" />
|
||||||
{hero.category || "News"}
|
</svg>
|
||||||
</span>
|
Feature Story
|
||||||
</div>
|
</span>
|
||||||
</div>
|
|
||||||
<div className="p-5">
|
<div className="absolute bottom-0 left-0 right-0 p-6 md:p-10">
|
||||||
<h3 className="font-serif text-2xl md:text-3xl leading-snug text-[#e5e7eb] group-hover:text-[var(--color-text-info,#60a5fa)]">
|
{hero.category && (
|
||||||
|
<div className="text-[10px] font-mono uppercase tracking-widest text-[var(--color-text-info,#60a5fa)] mb-2">
|
||||||
|
{hero.category}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
<h3 className="font-serif text-2xl md:text-4xl lg:text-5xl text-white leading-tight max-w-3xl group-hover:text-[var(--color-text-info,#60a5fa)] transition-colors">
|
||||||
{hero.title}
|
{hero.title}
|
||||||
</h3>
|
</h3>
|
||||||
{hero.excerpt && (
|
{hero.excerpt && (
|
||||||
<p className="font-serif text-[15px] text-[#b0b0b0] mt-3 line-clamp-3">
|
<p className="font-serif text-base md:text-lg text-[#cbd5e1] mt-3 max-w-2xl line-clamp-2">
|
||||||
{hero.excerpt}
|
{hero.excerpt}
|
||||||
</p>
|
</p>
|
||||||
)}
|
)}
|
||||||
<div className="mt-4 text-[11px] font-mono text-[#6b7280] flex items-center gap-2">
|
<div className="mt-4 flex flex-wrap items-center gap-3 text-[11px] font-mono text-[#9ca3af]">
|
||||||
<span>{hero.author_name || "Staff Reporter"}</span>
|
<span>{hero.author_name || "Staff Reporter"}</span>
|
||||||
<span>·</span>
|
<span>·</span>
|
||||||
<span>{ago(hero.wp_published_at)}</span>
|
<span>{ago(hero.wp_published_at)}</span>
|
||||||
|
<span aria-hidden="true" className="text-[var(--color-text-info,#60a5fa)] ml-2">→ Read full story</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Link>
|
|
||||||
|
|
||||||
<div className="grid grid-cols-1 gap-3">
|
|
||||||
{rail.map((r) => (
|
|
||||||
<Link
|
|
||||||
key={r.wp_slug}
|
|
||||||
href={`/news/${r.wp_slug}`}
|
|
||||||
className="group flex gap-3 rounded border border-[#252525] bg-[#0b0f17] overflow-hidden hover:border-[var(--color-text-info,#60a5fa)] transition-colors"
|
|
||||||
>
|
|
||||||
<div className="shrink-0 w-[120px] aspect-square bg-[#111] relative">
|
|
||||||
<img src={img(r)} alt={r.featured_image_alt || r.title} className="w-full h-full object-cover" />
|
|
||||||
</div>
|
|
||||||
<div className="flex-1 p-2 pr-3">
|
|
||||||
<div className="text-[9px] font-mono uppercase tracking-wider text-[var(--color-text-info,#60a5fa)] mb-1">
|
|
||||||
{r.category || "News"}
|
|
||||||
</div>
|
|
||||||
<h4 className="font-serif text-sm leading-tight text-[#e5e7eb] group-hover:text-[var(--color-text-info,#60a5fa)] line-clamp-3">
|
|
||||||
{r.title}
|
|
||||||
</h4>
|
|
||||||
<div className="text-[10px] font-mono text-[#6b7280] mt-2">
|
|
||||||
{ago(r.wp_published_at)}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</Link>
|
|
||||||
))}
|
|
||||||
</div>
|
</div>
|
||||||
|
</Link>
|
||||||
|
|
||||||
|
{/* 4-up rail BELOW the hero, vertical cards */}
|
||||||
|
<div className="grid grid-cols-2 md:grid-cols-4 gap-4 mt-4">
|
||||||
|
{rail.map((r) => (
|
||||||
|
<Link
|
||||||
|
key={r.wp_slug}
|
||||||
|
href={`/news/${r.wp_slug}`}
|
||||||
|
className="group block rounded border border-[#252525] bg-[#0b0f17] overflow-hidden hover:border-[var(--color-text-info,#60a5fa)] transition-colors"
|
||||||
|
>
|
||||||
|
<div className="aspect-[16/10] bg-[#111] relative">
|
||||||
|
<img
|
||||||
|
src={img(r)}
|
||||||
|
alt={r.featured_image_alt || r.title}
|
||||||
|
className="w-full h-full object-cover"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="p-3">
|
||||||
|
<div className="text-[9px] font-mono uppercase tracking-wider text-[var(--color-text-info,#60a5fa)] mb-1">
|
||||||
|
{r.category || "News"}
|
||||||
|
</div>
|
||||||
|
<h4 className="font-serif text-sm leading-tight text-[#e5e7eb] group-hover:text-[var(--color-text-info,#60a5fa)] line-clamp-3">
|
||||||
|
{r.title}
|
||||||
|
</h4>
|
||||||
|
<div className="text-[10px] font-mono text-[#6b7280] mt-2">
|
||||||
|
{ago(r.wp_published_at)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Link>
|
||||||
|
))}
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
);
|
);
|
||||||
|
|||||||
Reference in New Issue
Block a user