P0-3/4/5: route error boundary, null guards, slug fallback, search

P0-3 (category page crash):
- Add src/app/error.tsx and src/app/global-error.tsx so any future render
  error shows a real ref id instead of the bare client-exception toast.
- NewsPageClient: null-guard every field accessed during search/category/
  sort filtering and article render (title, excerpt, author, tags,
  category, date, image, alt). The user-visible link
  /news?category=live-production now also hydrates filter state from
  ?category= and ?search= search-params, so the dropdown actually filters.

P0-4 (/articles/[slug] 404s):
- /articles/[slug] and /news/[slug]: on slug miss, redirect("/news")
  instead of notFound(). Dead links from the hardcoded NewsTicker /
  FeaturedBento / ArticleFeed arrays now land on the news index instead
  of dead-ending on 404.
- legacy-source: add searchLegacyArticles() (title/excerpt/author ilike).

P0-5 (header search):
- Header: wire Enter on the desktop and mobile search inputs and make
  both search icons clickable buttons. Submits to /search?q=<query>.
- New /search route: server component that runs searchLegacyArticles
  and renders results in the same card style as /news.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Claude Code
2026-05-14 16:35:18 +00:00
parent 243f4855a1
commit 70e2aebb83
8 changed files with 335 additions and 66 deletions

42
src/app/error.tsx Normal file
View File

@@ -0,0 +1,42 @@
"use client";
import { useEffect } from "react";
import Link from "next/link";
export default function Error({
error,
reset,
}: {
error: Error & { digest?: string };
reset: () => void;
}) {
useEffect(() => {
console.error("[route error]", error);
}, [error]);
return (
<div className="min-h-screen flex items-center justify-center bg-[#0d0d0d] text-[#e0e0e0] p-6">
<div className="max-w-md text-center">
<h2 className="font-heading text-2xl mb-3">Something went wrong</h2>
<p className="text-[#888] text-sm mb-4 font-body">
We hit an error rendering this page. Try again, or head back to the home page.
</p>
{error?.digest && (
<p className="text-[#444] text-xs font-mono mb-4">ref: {error.digest}</p>
)}
<div className="flex gap-3 justify-center">
<button
onClick={() => reset()}
className="px-4 py-2 bg-[#3b82f6] text-white text-sm rounded-sm hover:bg-[#2563eb] transition-colors"
>
Try again
</button>
<Link
href="/home-page"
className="px-4 py-2 border border-[#333] text-sm rounded-sm hover:border-[#3b82f6] transition-colors"
>
Home
</Link>
</div>
</div>
</div>
);
}