From f6fa7570c4c2374357dd1aa80860ccd60e70cefd Mon Sep 17 00:00:00 2001 From: "Ryan Salazar (via Claude)" Date: Fri, 15 May 2026 21:58:52 +0000 Subject: [PATCH] =?UTF-8?q?slice=203:=20FeatureStoryHero=20=E2=80=94=20sin?= =?UTF-8?q?gle=20cinematic=20hero=20card=20above=20bento?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit New component src/components/FeatureStoryHero.tsx renders a wide 21:9 hero of the top-pinned featured article (same query shape as FeaturedBentoFromDb). Wired into home-page/page.tsx above the bento. Teal accent (#5B7C8D) used intentionally โ€” Slice 4 will sweep the rest of the site to match. Bento remains intact and may share its top article with the hero; that's the magazine "lead story emphasized" treatment, not a bug. Co-Authored-By: Claude Opus 4.7 (1M context) --- src/app/home-page/page.tsx | 8 +++ src/components/FeatureStoryHero.tsx | 105 ++++++++++++++++++++++++++++ 2 files changed, 113 insertions(+) create mode 100644 src/components/FeatureStoryHero.tsx diff --git a/src/app/home-page/page.tsx b/src/app/home-page/page.tsx index 7f0b5b9..9d7e1d7 100644 --- a/src/app/home-page/page.tsx +++ b/src/app/home-page/page.tsx @@ -3,6 +3,7 @@ import type { Metadata } from "next"; import Header from "@/components/Header"; import Footer from "@/components/Footer"; import FeaturedBentoFromDb from '@/components/FeaturedBentoFromDb'; +import FeatureStoryHero from '@/components/FeatureStoryHero'; import FeaturedCarouselServer from '@/components/FeaturedCarouselServer'; import TrendsSidebar from '@/components/TrendsSidebar'; import LiveWireTicker from '@/components/LiveWireTicker'; @@ -156,6 +157,13 @@ export default function HomePage() { + {/* Top feature story hero โ€” single prominent card above the bento */} + + }> + + + + {/* Featured articles bento */} }> diff --git a/src/components/FeatureStoryHero.tsx b/src/components/FeatureStoryHero.tsx new file mode 100644 index 0000000..b5ee249 --- /dev/null +++ b/src/components/FeatureStoryHero.tsx @@ -0,0 +1,105 @@ +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 ( +
+ +
+ {story.featured_image_alt +
+ + + + Feature Story + + +
+ {story.category && ( +
+ {story.category} +
+ )} +

+ {story.title} +

+ {story.excerpt && ( +

+ {story.excerpt} +

+ )} +
+ {story.author_name || "Staff Reporter"} + {story.wp_published_at && ( + <> + ยท + + {new Date(story.wp_published_at).toLocaleDateString("en-US", { + month: "short", + day: "numeric", + year: "numeric", + })} + + + )} + +
+
+
+ +
+ ); +}