Files
avbeat-com/src/components/CompaniesInThisStory.tsx
Ryan Salazar d67a2bd48d AV Beat rebrand: theme swap (orange #E67E22 / near-black), logo, schema default → avb
- public/assets/images/logo.png + public/brand/logo*.png replaced with the 1320x310 AV Beat logo
- public/assets/logos/avbeat.png added as the canonical source
- tailwind.config.js + src/styles/tailwind.css + src/styles/redesign-tokens.css palette swapped (primary #0F0E0E, secondary #1D1A1A, accent #E67E22 orange, foreground #F0EBE6 warm white)
- Layout / robots / sitemap / home-page / about / contact / press-kit / team / global-error metadata switched to AV Beat (Where AV Meets IT)
- Bulk replaced 'Broadcast Beat'/'BroadcastBeat.com'/'broadcastbeat.com' across user-facing news/forum/marketplace/advertise/search/newsletter pages
- src/lib/supabase/{admin,server,client} now default to schema 'avb' (was 'bb') — overridable via NEXT_PUBLIC_SUPABASE_SCHEMA
- package.json renamed to 'avbeat'
- Single d60701 reference in about/team swapped to E67E22

Design-only replica — no article content migrated.
2026-06-01 15:30:16 +00:00

120 lines
4.3 KiB
TypeScript

import Link from "next/link";
import { createAdminClient } from "@/lib/supabase/admin";
interface CompanyTile {
slug: string;
name: string;
logoUrl: string | null;
bioShort: string;
isActiveAdvertiser: boolean;
exhibitsNab: boolean;
exhibitsIbc: boolean;
}
async function loadTiles(slugs: string[]): Promise<CompanyTile[]> {
if (slugs.length === 0) return [];
try {
const svc = createAdminClient();
const { data } = await svc
.from("tracked_companies")
.select("slug, company_name, logo_url, bio, exhibits_nab, exhibits_ibc")
.in("slug", slugs);
// Active advertiser lookup (set of company_name_lower) in adv schema.
let advNames = new Set<string>();
try {
const adv = createAdminClient("adv");
const { data: ads } = await adv
.from("active_advertisers_by_property")
.select("company_name_lower")
.eq("property", "broadcastbeat");
advNames = new Set((ads || []).map((r: any) => r.company_name_lower));
} catch { /* tolerate */ }
const bySlug = new Map<string, CompanyTile>();
for (const r of (data || []) as any[]) {
const name = String(r.company_name || "").trim();
bySlug.set(r.slug, {
slug: r.slug,
name,
logoUrl: r.logo_url || null,
bioShort: (r.bio || "").split(/(?<=[.!?])\s+/).slice(0, 1).join(" ").slice(0, 160),
isActiveAdvertiser: advNames.has(name.toLowerCase()),
exhibitsNab: !!r.exhibits_nab,
exhibitsIbc: !!r.exhibits_ibc,
});
}
// Preserve the mention order
return slugs.map((s) => bySlug.get(s)).filter(Boolean) as CompanyTile[];
} catch {
return [];
}
}
export default async function CompaniesInThisStory({ slugs }: { slugs: string[] }) {
const tiles = await loadTiles(slugs);
if (tiles.length === 0) return null;
return (
<div className="bg-[#111] border border-[#222] p-5">
<h3 className="font-body font-bold text-xs text-[#E67E22] uppercase tracking-widest mb-4 pb-2 border-b border-[#222]">
Companies in this story
</h3>
<ul className="space-y-3">
{tiles.map((t) => (
<li key={t.slug}>
<Link
href={`/manufacturers/${t.slug}`}
data-company-slug={t.slug}
className="flex items-start gap-3 group hover:bg-[#161616] -mx-2 px-2 py-1.5 rounded-sm"
>
{t.logoUrl ? (
/* eslint-disable-next-line @next/next/no-img-element */
<img
src={t.logoUrl}
alt=""
className="w-10 h-10 rounded bg-white p-1 object-contain flex-shrink-0"
loading="lazy"
/>
) : (
<div className="w-10 h-10 rounded bg-[#222] flex items-center justify-center text-[#666] font-bold text-sm flex-shrink-0">
{(t.name || "?").trim().charAt(0).toUpperCase()}
</div>
)}
<div className="min-w-0 flex-1">
<div className="flex items-center gap-1 flex-wrap">
<span className="font-heading text-[#e0e0e0] text-sm font-bold group-hover:text-[#E67E22] transition-colors truncate">
{t.name}
</span>
</div>
<div className="flex items-center gap-1 flex-wrap mt-0.5 text-[9px] uppercase tracking-wider font-semibold">
{t.isActiveAdvertiser && (
<span className="bg-emerald-500/15 text-emerald-300 px-1.5 py-0.5 rounded">
Sponsor
</span>
)}
{t.exhibitsNab && (
<span className="bg-amber-500/15 text-amber-300 px-1.5 py-0.5 rounded">
2026 NAB Show
</span>
)}
{t.exhibitsIbc && (
<span className="bg-blue-500/15 text-blue-300 px-1.5 py-0.5 rounded">
IBC 2026
</span>
)}
</div>
{t.bioShort && (
<p className="text-[#888] text-[11px] leading-snug mt-1 line-clamp-2">
{t.bioShort}
</p>
)}
</div>
</Link>
</li>
))}
</ul>
</div>
);
}