cross-link: forum auto-link, NAB hub, sponsor strip, recent stories

Feature 3 — forum auto-linking
  Thread + reply bodies in /forum/thread/[id] now wrap company-name
  mentions with /manufacturers/<slug> links via a new client-side
  LinkifyPlainText component. Loads the directory list once per page
  (module-level promise cache), regex-scans each body, preserves
  whitespace, caps at 10 links per body to avoid clutter.
  CompanyMentionsHover mounted on the page so the same preview card
  pops on hover.
  Adds /api/public/companies/list — minimal { name, slug } directory
  feed, cached 10min.

Feature 4 — /nab-2026 live coverage hub
  New page aggregating every directory company with exhibits_nab=true.
  Three sections:
    - Coverage Partners — active advertisers exhibiting at NAB, larger
      tiles with emerald Sponsor border
    - Latest from the show floor — last 60 days of articles with NAB
      in the title, cinematic grid
    - All NAB 2026 exhibitors — alphabetical, capped at 200 with link
      to full /manufacturers directory
  Every company tile carries data-company-slug for hover previews.

Feature 5b — Sponsor logo strip on homepage
  New SponsorLogoStrip server component renders just above the footer
  on the homepage, showing logos of every current banner advertiser
  with a directory entry + logo. Each links to the manufacturer
  profile with the hover-card slug attribute.

Feature 5c — Recent coverage on manufacturer profiles
  /manufacturers/[slug] now includes a grid of the 6 most recent
  articles matching the company name in the title, with thumbnails.
  Renames the existing manufacturer_id-linked block to "Press
  releases" since it's a separate data source.
This commit is contained in:
Ryan Salazar
2026-05-27 12:55:25 +00:00
parent a59846a524
commit 2e78726291
7 changed files with 552 additions and 4 deletions

View File

@@ -0,0 +1,29 @@
import { NextResponse } from "next/server";
import { createAdminClient } from "@/lib/supabase/admin";
// Cache aggressively — directory rarely changes, and 1k+ companies is ~50KB.
export const revalidate = 600;
export async function GET() {
try {
const svc = createAdminClient();
const { data } = await svc
.from("tracked_companies")
.select("company_name, slug")
.eq("directory_visible", true)
.not("slug", "is", null)
.not("company_name", "is", null);
const rows = (data || [])
.filter((r: any) => r.company_name && r.slug)
.map((r: any) => ({ name: String(r.company_name).trim(), slug: String(r.slug) }))
.filter((r) => r.name.length >= 3);
return NextResponse.json(
{ companies: rows },
{ headers: { "Cache-Control": "public, s-maxage=600, stale-while-revalidate=1200" } },
);
} catch (e: any) {
return NextResponse.json({ companies: [], error: e?.message || "error" }, { status: 500 });
}
}