- forum/page.tsx: text-white → navy on TopThreads, Following feed, Discover feed cards, search input, select, category grid, Community Guidelines; greys lightened where applicable for new white surface - forum/[slug]/page.tsx: same sweep for category page (h1, h2, thread rows, new-thread form, search/sort bar) + hover:bg-[#1e2a3a] → slate-200 - forum/user/[username]/page.tsx: text-[#cccccc]/[#bfbfbf]/[#e0e0e0] + bg-[#222] tag chip + #9ca3af labels → readable on white card - authors/[slug]/page.tsx: profile contact/facts cards readable - search/page.tsx: h1 + h2 navy + hover slate - news/[slug]/NewsArticleDetailClient.tsx: toast color - news/NewsPageClient.tsx: import cleanExcerpt, strip HTML from listing excerpts - privacy/terms/page.tsx: h1 + h2 + body greys to readable navy/slate - error.tsx: page-level text to navy + button border slate - about/page.tsx: page body text + Stat/Block cards to white surface w/ navy text - Header.tsx: mobile hamburger + dropdown links → readable navy + slate border - NotificationCenter.tsx: hover + unread bg flipped to light blue - AISuggestedArticles.tsx: hover bg → slate-200 - Footer.tsx: link greys to #475569 + #DCE6F2 borders - AskBBAI.tsx: copy rename 'BB AI' → 'AV Beat AI' (greeting, button, header, aria) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
112 lines
4.6 KiB
TypeScript
112 lines
4.6 KiB
TypeScript
import type { Metadata } from "next";
|
|
import Link from "next/link";
|
|
import Header from "@/components/Header";
|
|
import Footer from "@/components/Footer";
|
|
import AppImage from "@/components/ui/AppImage";
|
|
import AdImage from "@/components/AdImage";
|
|
import { pickAds } from "@/lib/ads";
|
|
import { searchLegacyArticles } from "@/lib/articles/legacy-source";
|
|
import SidebarAdStack from "@/components/SidebarAdStack";
|
|
|
|
export const revalidate = 60;
|
|
|
|
export const metadata: Metadata = {
|
|
title: "Search — AV Beat",
|
|
description:
|
|
"Search AV Beat for pro AV news, gear reviews, show coverage, and live-production technology insights.",
|
|
alternates: { canonical: "/search" },
|
|
};
|
|
|
|
interface SearchPageProps {
|
|
searchParams: Promise<{ q?: string }>;
|
|
}
|
|
|
|
export default async function SearchPage({ searchParams }: SearchPageProps) {
|
|
const { q } = await searchParams;
|
|
const query = (q ?? "").trim();
|
|
const results = query ? await searchLegacyArticles(query, 5000) : [];
|
|
|
|
return (
|
|
<div className="min-h-screen bg-background">
|
|
<Header />
|
|
<div className="bg-[#111] border-b border-[#222] py-8">
|
|
<div className="max-w-container mx-auto px-4">
|
|
<div className="flex items-center gap-3 mb-2">
|
|
<span className="section-label">Search</span>
|
|
<div className="flex-1 h-px bg-[#DCE6F2]" />
|
|
</div>
|
|
<h1 className="font-heading text-[#0F172A] text-3xl font-bold">
|
|
{query ? `Results for "${query}"` : "Search AV Beat"}
|
|
</h1>
|
|
<p className="text-[#777] font-body text-sm mt-2">
|
|
{query
|
|
? `${results.length} article${results.length === 1 ? "" : "s"} found across news, gear, technology, and show coverage.`
|
|
: "Type in the header search box to find articles."}
|
|
</p>
|
|
</div>
|
|
</div>
|
|
|
|
<main className="max-w-container mx-auto px-4 py-8">
|
|
<aside className="float-right ml-6 mb-6 hidden lg:block max-w-[300px]"><SidebarAdStack /></aside>
|
|
{query && results.length === 0 && (
|
|
<div className="py-16 text-center">
|
|
<p className="text-[#555] font-body text-sm mb-3">No articles match your search.</p>
|
|
<Link href="/news" className="text-[#1D4ED8] text-xs font-body hover:underline">
|
|
Browse all news →
|
|
</Link>
|
|
</div>
|
|
)}
|
|
|
|
<div className="space-y-0">
|
|
{results.map((article) => {
|
|
if (!article?.slug) return null;
|
|
return (
|
|
<Link
|
|
key={article.slug}
|
|
href={`/news/${article.slug}`}
|
|
className="flex gap-4 py-5 border-b border-[#DCE6F2] group hover:bg-[#e2e8f0] transition-colors px-2 -mx-2 rounded-sm"
|
|
>
|
|
<div className="flex-shrink-0 w-[160px] h-[105px] relative overflow-hidden rounded-sm">
|
|
<AppImage
|
|
src={article.image || "/assets/images/article-placeholder.jpg"}
|
|
alt={article.alt || article.title || "AV Beat article"}
|
|
fill
|
|
className="object-cover group-hover:scale-105 transition-transform duration-300"
|
|
sizes="160px"
|
|
/>
|
|
</div>
|
|
<div className="flex-1 min-w-0">
|
|
<div className="flex items-center gap-2 mb-1.5">
|
|
<span className="text-[#1D4ED8] font-body text-[10px] font-bold uppercase tracking-wider">
|
|
{article.category || "NEWS"}
|
|
</span>
|
|
</div>
|
|
<h2 className="font-heading text-[#0F172A] text-base font-bold leading-snug mb-2 group-hover:text-[#1D4ED8] transition-colors line-clamp-2">
|
|
{article.title || "Untitled"}
|
|
</h2>
|
|
<p className="text-[#777] font-body text-sm leading-relaxed line-clamp-2">
|
|
{article.excerpt || ""}
|
|
</p>
|
|
<div className="flex items-center gap-2 mt-2">
|
|
<span className="text-[#555] font-body text-xs">By {article.author || "AV Beat"}</span>
|
|
<span className="text-[#444] text-[10px]">·</span>
|
|
<span className="text-[#555] font-body text-xs">{article.readTime || ""}</span>
|
|
</div>
|
|
</div>
|
|
</Link>
|
|
);
|
|
})}
|
|
</div>
|
|
|
|
{/* In-content 728x90 banner */}
|
|
{pickAds("728x90", 1).length > 0 && (
|
|
<div className="mt-10 hidden md:flex justify-center" aria-label="Advertisement">
|
|
<AdImage ad={pickAds("728x90", 1)[0]} page="search" />
|
|
</div>
|
|
)}
|
|
</main>
|
|
<Footer />
|
|
</div>
|
|
);
|
|
}
|