From 95eba5794bdb65b3c688dcd7eee38ab2779d1193 Mon Sep 17 00:00:00 2001 From: Ryan Salazar Date: Wed, 27 May 2026 22:07:29 +0000 Subject: [PATCH] manufacturers + NAB Show naming sweep - Standardize "NAB Show" / "2026 NAB Show" across badges, filter chips, and headings; never bare "NAB" in user-facing copy. - /manufacturers/[slug]: normalize show name at render, strip randomstring suffix on booth, hide booth unless the show is within 90 days, filter single-letter junk out of category display. - News filter "NAB Show" chip loose-matches any nab-tagged article so legacy "NAB 2026" tags still surface. Co-Authored-By: Claude Opus 4.7 (1M context) --- src/app/manufacturers/DirectoryClient.tsx | 4 +- src/app/manufacturers/[slug]/page.tsx | 106 +++++++++++++++------- src/app/nab-2026/page.tsx | 14 +-- src/app/news/NewsPageClient.tsx | 13 ++- src/components/AISuggestedArticles.tsx | 2 +- src/components/CompaniesInThisStory.tsx | 4 +- src/components/CompanyMentionsHover.tsx | 4 +- src/components/Header.tsx | 2 +- src/lib/ads.ts | 2 +- 9 files changed, 101 insertions(+), 50 deletions(-) diff --git a/src/app/manufacturers/DirectoryClient.tsx b/src/app/manufacturers/DirectoryClient.tsx index d049e60..92fb8dd 100644 --- a/src/app/manufacturers/DirectoryClient.tsx +++ b/src/app/manufacturers/DirectoryClient.tsx @@ -129,12 +129,12 @@ export default function ManufacturerDirectoryClient({
{m.exhibits_nab && ( - NAB 26 + 2026 NAB Show )} {m.exhibits_ibc && ( - IBC + IBC 2026 )} {m.featured && ( diff --git a/src/app/manufacturers/[slug]/page.tsx b/src/app/manufacturers/[slug]/page.tsx index 4d0c542..285b9b8 100644 --- a/src/app/manufacturers/[slug]/page.tsx +++ b/src/app/manufacturers/[slug]/page.tsx @@ -9,6 +9,36 @@ export const revalidate = 1800; type Params = { slug: string }; +// Known show date ranges. Booth numbers only render when the show is +// upcoming within 90 days; otherwise the row is shown without a booth. +const SHOW_DATES: Record = { + "NAB Show:2026": { start: "2026-04-11", end: "2026-04-16" }, + "NAB Show NY:2026": { start: "2026-10-21", end: "2026-10-23" }, + "IBC:2026": { start: "2026-09-11", end: "2026-09-14" }, + "NAB Show:2027": { start: "2027-04-17", end: "2027-04-22" }, +}; + +function normaliseShowName(raw: string | null | undefined): string { + const s = (raw || "").trim(); + if (!s) return s; + if (/^nab(\s*show)?$/i.test(s)) return "NAB Show"; + if (/^nab\s*(show\s*)?(ny|new\s*york)$/i.test(s)) return "NAB Show NY"; + if (/^ibc(\s*show)?$/i.test(s)) return "IBC"; + return s; +} + +function shouldShowBooth(show: string, year: number | null): boolean { + if (!year) return false; + const dates = SHOW_DATES[`${show}:${year}`]; + if (!dates) return false; + const today = new Date(); + const start = new Date(dates.start + "T00:00:00Z"); + const end = new Date(dates.end + "T23:59:59Z"); + if (today > end) return false; + const daysUntilStart = (start.getTime() - today.getTime()) / 86_400_000; + return daysUntilStart <= 90; +} + async function loadManufacturer(slug: string) { const supabase = await createClient(); const { data } = await supabase @@ -163,12 +193,12 @@ export default async function ManufacturerProfile({
{company.exhibits_nab && ( - NAB Show 2026 + 2026 NAB Show )} {company.exhibits_ibc && ( - IBC + IBC 2026 )} {(company.hq_city || company.hq_country) && ( @@ -315,21 +345,27 @@ export default async function ManufacturerProfile({ )} - {company.categories && company.categories.length > 0 && ( -
-

Categories

-
- {company.categories.map((c: string) => ( - - {c} - - ))} -
-
- )} + {(() => { + const cleanCategories = (company.categories || []).filter( + (c: string) => typeof c === "string" && c.trim().length >= 2 + ); + if (cleanCategories.length === 0) return null; + return ( +
+

Categories

+
+ {cleanCategories.map((c: string) => ( + + {c} + + ))} +
+
+ ); + })()} {shows.length > 0 && (
@@ -337,21 +373,27 @@ export default async function ManufacturerProfile({ Trade-show appearances
    - {shows.map((s) => ( -
  • -
    - - {s.show} {s.show_year} - - {s.booth && ( - Booth {s.booth} - )} -
    -
  • - ))} + {shows.map((s) => { + const showName = normaliseShowName(s.show); + const label = showName === "NAB Show" + ? `${s.show_year} NAB Show` + : `${showName} ${s.show_year}`; + const cleanBooth = (s.booth || "").replace(/randomstring\s*$/i, "").trim(); + const renderBooth = cleanBooth && shouldShowBooth(showName, s.show_year); + return ( +
  • +
    + {label} + {renderBooth && ( + Booth {cleanBooth} + )} +
    +
  • + ); + })}
)} diff --git a/src/app/nab-2026/page.tsx b/src/app/nab-2026/page.tsx index 47a8543..58854ee 100644 --- a/src/app/nab-2026/page.tsx +++ b/src/app/nab-2026/page.tsx @@ -9,14 +9,14 @@ import CompanyMentionsHover from "@/components/CompanyMentionsHover"; export const revalidate = 600; export const metadata: Metadata = { - title: "NAB Show 2026 — Live Coverage Hub | Broadcast Beat", + title: "2026 NAB Show — Live Coverage Hub | Broadcast Beat", description: - "Broadcast Beat's live coverage of NAB Show 2026: 1,100+ exhibitors, the latest product launches, booth-by-booth news, and editorial pick stories from the show floor.", + "Broadcast Beat's live coverage of 2026 NAB Show: 1,100+ exhibitors, the latest product launches, booth-by-booth news, and editorial pick stories from the show floor.", alternates: { canonical: "/nab-2026" }, openGraph: { - title: "NAB Show 2026 — Live Coverage Hub", + title: "2026 NAB Show — Live Coverage Hub", description: - "Live coverage, exhibitor list, and breaking product news from NAB Show 2026.", + "Live coverage, exhibitor list, and breaking product news from 2026 NAB Show.", type: "website", url: "https://broadcastbeat.com/nab-2026", }, @@ -101,7 +101,7 @@ export default async function NabHub() { April 11–16, 2026 · Las Vegas

- NAB Show 2026 + 2026 NAB Show

{exhibitors.length.toLocaleString()} exhibitors confirmed. @@ -118,7 +118,7 @@ export default async function NabHub() {

- Coverage Partners at NAB + Coverage Partners at the 2026 NAB Show

{sponsorRows.length} exhibiting partner{sponsorRows.length === 1 ? "" : "s"}
@@ -193,7 +193,7 @@ export default async function NabHub() {

- All NAB 2026 exhibitors + All 2026 NAB Show exhibitors

Full directory → diff --git a/src/app/news/NewsPageClient.tsx b/src/app/news/NewsPageClient.tsx index 82ddb4d..d080e3f 100644 --- a/src/app/news/NewsPageClient.tsx +++ b/src/app/news/NewsPageClient.tsx @@ -10,7 +10,7 @@ import type { Article } from "@/lib/articles/types"; import AISuggestedArticles from "@/components/AISuggestedArticles"; import SidebarAdStack from "@/components/SidebarAdStack"; -const CATEGORIES = ["All", "Cloud", "AI", "IP Workflows", "Live Production", "Streaming", "Audio", "Cameras", "NAB 2026", "EAS", "Sports Broadcasting", "Ad Tech"]; +const CATEGORIES = ["All", "Cloud", "AI", "IP Workflows", "Live Production", "Streaming", "Audio", "Cameras", "NAB Show", "EAS", "Sports Broadcasting", "Ad Tech"]; // Map URL category slugs (?category=live-production) to a matching CATEGORIES label. function categoryFromSlug(slug: string | null): string { @@ -72,9 +72,18 @@ export default function NewsPage({ articles }: { articles: Article[] }) { // Category filter if (activeCategory !== "All") { const cat = activeCategory.toLowerCase(); + // The NAB Show chip should match any NAB-tagged article regardless of + // year suffix in the legacy tag (e.g. "NAB 2026", "NAB", "NAB Show"). + const isNabChip = /\bnab\b/.test(cat); result = result.filter((a) => { const tags = Array.isArray(a?.tags) ? a.tags : []; const category = (a?.category ?? "").toLowerCase(); + if (isNabChip) { + return ( + tags.some((t) => /\bnab\b/.test((t ?? "").toLowerCase())) || + /\bnab\b/.test(category) + ); + } return ( tags.some((t) => (t ?? "").toLowerCase() === cat) || category.includes(cat) @@ -302,7 +311,7 @@ export default function NewsPage({ articles }: { articles: Article[] }) { Popular Tags
- {["IP Workflows", "Cloud", "AI", "Live Production", "Streaming", "NAB 2026", "Audio", "Cameras"].map((tag) => ( + {["IP Workflows", "Cloud", "AI", "Live Production", "Streaming", "NAB Show", "Audio", "Cameras"].map((tag) => (
diff --git a/src/components/CompanyMentionsHover.tsx b/src/components/CompanyMentionsHover.tsx index cd13b14..f08c82b 100644 --- a/src/components/CompanyMentionsHover.tsx +++ b/src/components/CompanyMentionsHover.tsx @@ -125,10 +125,10 @@ export default function CompanyMentionsHover() { Sponsor )} {preview.exhibitsNab && ( - NAB 26 + 2026 NAB Show )} {preview.exhibitsIbc && ( - IBC + IBC 2026 )} {preview.hq && {preview.hq}}
diff --git a/src/components/Header.tsx b/src/components/Header.tsx index c0102ee..7429cc0 100644 --- a/src/components/Header.tsx +++ b/src/components/Header.tsx @@ -619,7 +619,7 @@ export default function Header() { Sponsor )} {c.exhibitsNab && !c.isSponsor && ( - NAB 26 + 2026 NAB Show )} diff --git a/src/lib/ads.ts b/src/lib/ads.ts index 43f6900..39a8372 100644 --- a/src/lib/ads.ts +++ b/src/lib/ads.ts @@ -57,7 +57,7 @@ const FALLBACK: Ad[] = [ alt: "Zixi", click_url: "https://zixi.com/" }, { slug: "telycam-300x250", label: "Telycam MixOne / ExploreXE", size: "300x250", src: "/legacy/ads/Telycam_Broadcast Beat_300x250_MixOne-ExploreXE_with_NAB2026_2f30157f.gif", - alt: "Telycam MixOne / ExploreXE — NAB 2026", click_url: "https://telycam.com/" }, + alt: "Telycam MixOne / ExploreXE — 2026 NAB Show", click_url: "https://telycam.com/" }, { slug: "lectrosonics-300x250", label: "Lectrosonics", size: "300x250", src: "/legacy/ads/300x250-banner-Our-Story-film_resize.jpg", alt: "Lectrosonics Our Story", click_url: "https://www.lectrosonics.com/" },