From 3f23447af78d4f2a8d82275e8fdc7a3b3090c52e Mon Sep 17 00:00:00 2001 From: Local Administrator Date: Thu, 25 Jun 2026 16:22:40 +0000 Subject: [PATCH] Manufacturers directory: fix light-theme text contrast and filter bar --- src/app/manufacturers/DirectoryClient.tsx | 380 +++++++++++----------- 1 file changed, 194 insertions(+), 186 deletions(-) diff --git a/src/app/manufacturers/DirectoryClient.tsx b/src/app/manufacturers/DirectoryClient.tsx index 16be752..9cd6305 100644 --- a/src/app/manufacturers/DirectoryClient.tsx +++ b/src/app/manufacturers/DirectoryClient.tsx @@ -1,21 +1,21 @@ -"use client"; - -import { useMemo, useState } from "react"; -import Link from "next/link"; - -type Manufacturer = { - slug: string; - company_name: string; - bio: string | null; - logo_url: string | null; - categories: string[] | null; - exhibits_nab: boolean; - exhibits_ibc: boolean; - shows_attending: string[] | null; - mention_count: number; - featured: boolean; -}; - +"use client"; + +import { useMemo, useState } from "react"; +import Link from "next/link"; + +type Manufacturer = { + slug: string; + company_name: string; + bio: string | null; + logo_url: string | null; + categories: string[] | null; + exhibits_nab: boolean; + exhibits_ibc: boolean; + shows_attending: string[] | null; + mention_count: number; + featured: boolean; +}; + type ShowOption = { slug: string; short_name: string | null; @@ -25,184 +25,192 @@ type ShowOption = { status: string; }; -export default function ManufacturerDirectoryClient({ - manufacturers, - shows = [], -}: { - manufacturers: Manufacturer[]; - shows?: ShowOption[]; -}) { - const [q, setQ] = useState(""); - // showFilter is now a show slug from bb.events (e.g. 'nab-show-2026') or - // 'all' / 'both-major' (NAB+IBC overlap). - const [showFilter, setShowFilter] = useState("all"); - const [letter, setLetter] = useState("All"); +const LOGO_OVERRIDES: Record = { + "blackmagic-design": "/img/partners/blackmagic-design.png", +}; - // Per-show exhibitor counts for badge display + auto-hiding empty shows. - const showCounts = useMemo(() => { - const counts: Record = {}; - for (const m of manufacturers) { - for (const s of m.shows_attending || []) { - counts[s] = (counts[s] || 0) + 1; - } - } - return counts; - }, [manufacturers]); - - const filtered = useMemo(() => { - const needle = q.trim().toLowerCase(); - return manufacturers.filter((m) => { - if (needle) { - const hay = `${m.company_name} ${m.bio || ""}`.toLowerCase(); - if (!hay.includes(needle)) return false; - } - if (showFilter === "both-major") { - if (!(m.exhibits_nab && m.exhibits_ibc)) return false; - } else if (showFilter !== "all") { - if (!(m.shows_attending || []).includes(showFilter)) return false; - } - if (letter !== "All") { - const c = (m.company_name || "").trim().charAt(0).toUpperCase(); - if (letter === "#") { - if (/^[A-Z]/.test(c)) return false; - } else if (c !== letter) { - return false; - } - } - return true; - }); - }, [manufacturers, q, showFilter, letter]); - - const letters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ".split(""); - - return ( -
-
+function resolveLogoUrl(slug: string, logoUrl: string | null): string | null { + return LOGO_OVERRIDES[slug] || logoUrl || null; +} + +export default function ManufacturerDirectoryClient({ + manufacturers, + shows = [], +}: { + manufacturers: Manufacturer[]; + shows?: ShowOption[]; +}) { + const [q, setQ] = useState(""); + // showFilter is now a show slug from bb.events (e.g. 'nab-show-2026') or + // 'all' / 'both-major' (NAB+IBC overlap). + const [showFilter, setShowFilter] = useState("all"); + const [letter, setLetter] = useState("All"); + + // Per-show exhibitor counts for badge display + auto-hiding empty shows. + const showCounts = useMemo(() => { + const counts: Record = {}; + for (const m of manufacturers) { + for (const s of m.shows_attending || []) { + counts[s] = (counts[s] || 0) + 1; + } + } + return counts; + }, [manufacturers]); + + const filtered = useMemo(() => { + const needle = q.trim().toLowerCase(); + return manufacturers.filter((m) => { + if (needle) { + const hay = `${m.company_name} ${m.bio || ""}`.toLowerCase(); + if (!hay.includes(needle)) return false; + } + if (showFilter === "both-major") { + if (!(m.exhibits_nab && m.exhibits_ibc)) return false; + } else if (showFilter !== "all") { + if (!(m.shows_attending || []).includes(showFilter)) return false; + } + if (letter !== "All") { + const c = (m.company_name || "").trim().charAt(0).toUpperCase(); + if (letter === "#") { + if (/^[A-Z]/.test(c)) return false; + } else if (c !== letter) { + return false; + } + } + return true; + }); + }, [manufacturers, q, showFilter, letter]); + + const letters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ".split(""); + + return ( +
+
setQ(e.target.value)} placeholder="Search by company or product…" - className="w-full bg-[#F8FAFC] border border-[#DCE6F2] rounded-md px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-[#1D4ED8]/40" + className="w-full bg-[#F8FAFC] border border-[#DCE6F2] rounded-md px-3 py-2 text-sm text-[#0F172A] placeholder:text-[#94A3B8] focus:outline-none focus:ring-2 focus:ring-[#1D4ED8]/40" /> -
-
- - {/* Per-show filter chips. Every event from bb.events shows up; ones - without exhibitor mappings yet render a "(soon)" badge so the - admin can see what's still missing data. */} -
- - {shows.map((s) => { - const count = showCounts[s.slug] || 0; - const active = showFilter === s.slug; - const label = s.short_name || s.name; - return ( - - ); - })} -
- - - -

- Showing {filtered.length.toLocaleString()} of {manufacturers.length.toLocaleString()} manufacturers -

- -
- {filtered.map((m) => ( - -
- {m.logo_url ? ( +
+
+ + {/* Per-show filter chips. Every event from bb.events shows up; ones + without exhibitor mappings yet render a "(soon)" badge so the + admin can see what's still missing data. */} +
+ + {shows.map((s) => { + const count = showCounts[s.slug] || 0; + const active = showFilter === s.slug; + const label = s.short_name || s.name; + return ( + + ); + })} +
+ + + +

+ Showing {filtered.length.toLocaleString()} of {manufacturers.length.toLocaleString()} manufacturers +

+ +
+ {filtered.map((m) => ( + +
+ {resolveLogoUrl(m.slug, m.logo_url) ? ( /* eslint-disable-next-line @next/next/no-img-element */ {`${m.company_name} - ) : ( - - {(m.company_name || "?").trim().charAt(0).toUpperCase()} - - )} -
-
-

- {m.company_name} -

-
- {(m.shows_attending || []).slice(0, 3).map((slug) => { - const ev = shows.find((s) => s.slug === slug); - if (!ev) return null; - return ( - - {ev.short_name || ev.name} - - ); - })} - {m.featured && ( - - Featured - - )} -
-

- {m.bio || "Profile coming soon."} -

-
- - ))} -
- - {filtered.length === 0 && ( -
- No manufacturers match these filters. -
- )} -
- ); -} + ) : ( + + {(m.company_name || "?").trim().charAt(0).toUpperCase()} + + )} +
+
+

+ {m.company_name} +

+
+ {(m.shows_attending || []).slice(0, 3).map((slug) => { + const ev = shows.find((s) => s.slug === slug); + if (!ev) return null; + return ( + + {ev.short_name || ev.name} + + ); + })} + {m.featured && ( + + Featured + + )} +
+

+ {m.bio || "Profile coming soon."} +

+
+ + ))} +
+ + {filtered.length === 0 && ( +
+ No manufacturers match these filters. +
+ )} + + ); +}