BB AI redesign: 4-item nav, Show coverage, About, status bar, wire ticker,
trends sidebar, Ask BB AI, neural-summary schema, 13-event seed.
Phases 1-10 (11 phases minus Phase 8 which is the pgvector marker).
DB:
bb.events — 13 industry events seeded (MPTS, ANGA COM,
BroadcastAsia, SET Expo, IBC, NAB NY,
NewTECHForum, SATIS, DPP EBS, SVVS,
Hamburg Open, CABSAT, NAB Show '27).
bb.article_events — composite PK (article_id, article_table, event_id)
links any article-table row to one or more events.
bb.banner_creatives — (no change tonight)
bb.{native_articles,
ai_rewritten_articles,
wp_imported_posts,
press_releases}.neural_summary jsonb — populated by Phase 7
analyzer (deferred).
bb.{native_articles,
ai_rewritten_articles}.featured boolean — featured carousel source.
Routes:
/api/events/upcoming — date-gated, enriched with is_live/days_until/
day_of_event/total_days.
/api/ask-bb-ai — Claude Opus 4.7 chat with prompt caching on
the system block, 30-msg/hr/IP rate limit.
Tool-use deferred — first cut is straight
LLM with archive-citation prompting.
Pages:
/show-coverage — index of all events, upcoming + past split.
/show-coverage/[slug] — hero + status (live/T-Nd/past) + schema.org
Event JSON-LD + tagged articles list.
/about, /about/{team,contact,advertise,press-kit}.
Components:
Header — 4-item nav: Show coverage (dropdown) /
Newsletter / Forum / About (dropdown).
Old NEWS/GEAR/TECHNOLOGY/ADVERTISE items
removed from nav (routes still exist).
EventsDropdown — 340px CSI panel with L-corner brackets,
pulsing dot, "BB AI" badge, live/T-Nd rows,
auto-updated stamp.
AboutDropdown — 5-item lighter treatment.
SystemStatusBar — Index online pulse, articles/sources/events
counts, build version. Above Header.
LiveWireTicker — replaces NewsTicker. [HH:MM] [SRC] prefix,
CSS marquee, doubled for seamless loop.
TrendsSidebar — BB AI detected trends, top 5 entities by
7d-vs-30d lift, vector-pass stamp.
Phase 6b: replace with pgvector.
AskBBAI — floating bottom-right button + 420px right
drawer chat. No mention of Anthropic/Claude.
Styling:
redesign-tokens.css — --color-text-info, --color-background-*,
--font-serif/mono/body, bb-pulse/bb-ring
animations + bb-marquee.
Constraints honored:
- LiveU 728x90 still between </nav> and ticker.
- Blackmagic 300x600 still pinned top of sidebar.
- /r/[slug] click tracking unchanged.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
45
src/app/about/advertise/page.tsx
Normal file
45
src/app/about/advertise/page.tsx
Normal file
@@ -0,0 +1,45 @@
|
||||
export const metadata = { title: "Advertise — BroadcastBeat" };
|
||||
|
||||
export default function AdvertisePage() {
|
||||
return (
|
||||
<main className="mx-auto max-w-3xl px-6 py-12 text-[#e5e7eb]">
|
||||
<h1 className="font-serif text-4xl font-bold tracking-tight mb-2">Advertise on BroadcastBeat</h1>
|
||||
<p className="text-sm text-[#9ca3af] mb-10">
|
||||
BroadcastBeat reaches broadcast engineers, post supervisors, streaming
|
||||
architects, and live-event professionals across the industry.
|
||||
</p>
|
||||
|
||||
<section className="mb-10">
|
||||
<h2 className="font-mono text-xs uppercase tracking-wider text-[#6b7280] mb-3">Available units</h2>
|
||||
<ul className="space-y-3 text-[15px]">
|
||||
<li>
|
||||
<strong>728×90 leaderboard</strong> — between main nav and headline ticker, sitewide.
|
||||
</li>
|
||||
<li>
|
||||
<strong>300×600 sidebar premium</strong> — pinned top of every sidebar, sitewide.
|
||||
</li>
|
||||
<li>
|
||||
<strong>300×250 sidebar rotation</strong> — rotates across every page, multiple slots.
|
||||
</li>
|
||||
</ul>
|
||||
</section>
|
||||
|
||||
<section className="mb-10">
|
||||
<h2 className="font-mono text-xs uppercase tracking-wider text-[#6b7280] mb-3">Reporting</h2>
|
||||
<p className="text-[15px] text-[#d1d5db]">
|
||||
Every banner is tracked for gross impressions and clicks. Advertisers
|
||||
receive a monthly report with totals and CTR. Click links route through
|
||||
/r/{"{campaign}"} for accurate counting independent of analytics
|
||||
blockers.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<h2 className="font-mono text-xs uppercase tracking-wider text-[#6b7280] mb-3">Get in touch</h2>
|
||||
<p className="text-[15px]">
|
||||
<a className="text-[var(--color-text-info,#60a5fa)] hover:underline" href="mailto:advertising@broadcastbeat.com">advertising@broadcastbeat.com</a>
|
||||
</p>
|
||||
</section>
|
||||
</main>
|
||||
);
|
||||
}
|
||||
30
src/app/about/contact/page.tsx
Normal file
30
src/app/about/contact/page.tsx
Normal file
@@ -0,0 +1,30 @@
|
||||
export const metadata = { title: "Contact — BroadcastBeat" };
|
||||
|
||||
export default function ContactPage() {
|
||||
return (
|
||||
<main className="mx-auto max-w-2xl px-6 py-12 text-[#e5e7eb]">
|
||||
<h1 className="font-serif text-4xl font-bold tracking-tight mb-6">Contact</h1>
|
||||
<dl className="space-y-5 text-[15px]">
|
||||
<div>
|
||||
<dt className="text-xs font-mono uppercase tracking-wider text-[#6b7280] mb-1">Editorial</dt>
|
||||
<dd><a className="text-[var(--color-text-info,#60a5fa)] hover:underline" href="mailto:editor@broadcastbeat.com">editor@broadcastbeat.com</a></dd>
|
||||
</div>
|
||||
<div>
|
||||
<dt className="text-xs font-mono uppercase tracking-wider text-[#6b7280] mb-1">Press releases (PR firms)</dt>
|
||||
<dd>
|
||||
Route submissions through{" "}
|
||||
<a className="text-[var(--color-text-info,#60a5fa)] hover:underline" href="https://distribution.relevantmediaproperties.com">distribution.relevantmediaproperties.com</a>.
|
||||
</dd>
|
||||
</div>
|
||||
<div>
|
||||
<dt className="text-xs font-mono uppercase tracking-wider text-[#6b7280] mb-1">Advertising</dt>
|
||||
<dd><a className="text-[var(--color-text-info,#60a5fa)] hover:underline" href="mailto:advertising@broadcastbeat.com">advertising@broadcastbeat.com</a> — see <a className="text-[var(--color-text-info,#60a5fa)] hover:underline" href="/about/advertise">media kit</a>.</dd>
|
||||
</div>
|
||||
<div>
|
||||
<dt className="text-xs font-mono uppercase tracking-wider text-[#6b7280] mb-1">Publisher</dt>
|
||||
<dd>Ryan Salazar · <a className="text-[var(--color-text-info,#60a5fa)] hover:underline" href="mailto:ryan.salazar@relevantmediaproperties.com">ryan.salazar@relevantmediaproperties.com</a></dd>
|
||||
</div>
|
||||
</dl>
|
||||
</main>
|
||||
);
|
||||
}
|
||||
@@ -1,123 +1,33 @@
|
||||
import React from "react";
|
||||
import type { Metadata } from "next";
|
||||
import Link from "next/link";
|
||||
import Header from "@/components/Header";
|
||||
import Footer from "@/components/Footer";
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "About BroadcastBeat — The News & Intelligence for Broadcast, Post-Production & Streaming Technology",
|
||||
description:
|
||||
"BroadcastBeat is the leading digital platform for broadcast engineering professionals. Learn about our editorial mission, team, and commitment to the broadcast industry.",
|
||||
alternates: { canonical: "/about" },
|
||||
openGraph: {
|
||||
title: "About BroadcastBeat",
|
||||
description: "BroadcastBeat is the leading digital platform for broadcast engineering professionals.",
|
||||
url: "/about",
|
||||
type: "website",
|
||||
},
|
||||
export const metadata = {
|
||||
title: "About BroadcastBeat",
|
||||
description: "BroadcastBeat is an independent industry publication covering broadcast, production, and post-production technology.",
|
||||
};
|
||||
|
||||
const team = [
|
||||
{ name: "Elena Vasquez", title: "Features Editor", bio: "Elena covers the intersection of technology and storytelling in broadcast media, with a focus on emerging production workflows and industry trends." },
|
||||
{ name: "James Whitfield", title: "Senior Technology Correspondent", bio: "James has covered broadcast technology for over a decade, specializing in IP infrastructure, streaming, and the business of broadcast." },
|
||||
{ name: "Sarah Chen", title: "Audio Technology Editor", bio: "Sarah brings deep expertise in professional audio to her coverage of mixing consoles, audio networking, and live production sound." },
|
||||
{ name: "Rachel Kim", title: "Technology Analyst", bio: "Rachel focuses on data-driven coverage of industry trends, market analysis, and the business implications of new broadcast technologies." },
|
||||
{ name: "Marcus Rivera", title: "Sports Technology Correspondent", bio: "Marcus covers the intersection of sports and broadcast technology, from remote production to interactive fan experiences." },
|
||||
];
|
||||
|
||||
export default function AboutPage() {
|
||||
return (
|
||||
<div className="min-h-screen bg-background">
|
||||
<Header />
|
||||
|
||||
{/* DO NOT OVERRIDE — About page hero */}
|
||||
<div className="bg-[#111] border-b border-[#222] py-10">
|
||||
<div className="max-w-container mx-auto px-4">
|
||||
<div className="flex items-center gap-3 mb-2">
|
||||
<span className="section-label">About</span>
|
||||
<div className="flex-1 h-px bg-[#2a2a2a]" />
|
||||
</div>
|
||||
<h1 className="font-heading text-white text-3xl font-bold">About BroadcastBeat</h1>
|
||||
</div>
|
||||
<main className="mx-auto max-w-3xl px-6 py-12 text-[#e5e7eb]">
|
||||
<h1 className="font-serif text-4xl font-bold tracking-tight mb-6">About BroadcastBeat</h1>
|
||||
<div className="space-y-5 text-[#d1d5db] text-[15px] leading-relaxed">
|
||||
<p>
|
||||
BroadcastBeat is an independent trade publication covering broadcast,
|
||||
live production, streaming, and post-production technology. We
|
||||
report on the equipment, services, and people that move the
|
||||
professional video industry forward.
|
||||
</p>
|
||||
<p>
|
||||
We cover the major industry shows — NAB, IBC, BroadcastAsia, MPTS,
|
||||
and others — track product launches and acquisitions, and publish
|
||||
interviews with the engineers, post supervisors, and executives
|
||||
building the next generation of workflows.
|
||||
</p>
|
||||
<p>
|
||||
Editorial decisions are made independently of advertising. We do
|
||||
not accept payment for editorial coverage. Vendor-supplied press
|
||||
releases routed through our distribution platform are rewritten
|
||||
by our staff or AI assistants according to our editorial style
|
||||
guide; the original submission is preserved on file.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<main className="max-w-container mx-auto px-4 py-10">
|
||||
<div className="grid grid-cols-1 lg:grid-cols-12 gap-10">
|
||||
<div className="lg:col-span-8">
|
||||
{/* Mission */}
|
||||
<section id="mission" className="mb-10">
|
||||
<h2 className="font-heading text-[#e0e0e0] text-2xl font-bold mb-4">Our Mission</h2>
|
||||
<div className="prose-bb space-y-4">
|
||||
<p className="font-body text-[#aaa] leading-relaxed">
|
||||
BroadcastBeat is the digital platform of record for broadcast engineering professionals. We cover the technology, people, and business decisions that shape how the world's media is created, distributed, and consumed.
|
||||
</p>
|
||||
<p className="font-body text-[#aaa] leading-relaxed">
|
||||
From breaking news about the latest IP infrastructure deployments to in-depth reviews of broadcast cameras and audio consoles, BroadcastBeat provides the coverage that broadcast engineers, producers, and executives rely on to stay ahead of an industry in constant transformation.
|
||||
</p>
|
||||
<p className="font-body text-[#aaa] leading-relaxed">
|
||||
We are an official media partner of NAB Show and provide comprehensive coverage of all major broadcast industry events, including IBC, Cine Gear, and the Streaming Summit.
|
||||
</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* Team */}
|
||||
<section id="team" className="mb-10">
|
||||
<h2 className="font-heading text-[#e0e0e0] text-2xl font-bold mb-6">Editorial Team</h2>
|
||||
<div className="space-y-4">
|
||||
{team.map((member) => (
|
||||
<div key={member.name} className="bg-[#111] border border-[#222] p-5 flex gap-4">
|
||||
<div className="flex-shrink-0 w-12 h-12 bg-[#1a2535] rounded-full flex items-center justify-center">
|
||||
<span className="text-[#3b82f6] font-bold text-lg">{member.name[0]}</span>
|
||||
</div>
|
||||
<div>
|
||||
<h3 className="font-heading text-[#e0e0e0] font-bold">{member.name}</h3>
|
||||
<p className="text-[#3b82f6] font-body text-xs uppercase tracking-wider mb-2">{member.title}</p>
|
||||
<p className="text-[#777] font-body text-sm leading-relaxed">{member.bio}</p>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* Contact */}
|
||||
<section className="mb-10">
|
||||
<h2 className="font-heading text-[#e0e0e0] text-2xl font-bold mb-4">Contact</h2>
|
||||
<div className="bg-[#111] border border-[#222] p-6 space-y-3">
|
||||
<div>
|
||||
<p className="font-body text-[#3b82f6] text-xs font-bold uppercase tracking-wider mb-1">Editorial</p>
|
||||
<a href="mailto:editorial@broadcastbeat.com" className="font-body text-[#aaa] hover:text-[#3b82f6] transition-colors">editorial@broadcastbeat.com</a>
|
||||
</div>
|
||||
<div>
|
||||
<p className="font-body text-[#3b82f6] text-xs font-bold uppercase tracking-wider mb-1">Advertising Sales</p>
|
||||
<a href="mailto:jeff@broadcastbeat.com" className="font-body text-[#aaa] hover:text-[#3b82f6] transition-colors">jeff@broadcastbeat.com</a>
|
||||
</div>
|
||||
<div>
|
||||
<p className="font-body text-[#3b82f6] text-xs font-bold uppercase tracking-wider mb-1">Press & Media</p>
|
||||
<a href="mailto:press@broadcastbeat.com" className="font-body text-[#aaa] hover:text-[#3b82f6] transition-colors">press@broadcastbeat.com</a>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
|
||||
<aside className="lg:col-span-4 space-y-6">
|
||||
<div className="bg-[#111] border border-[#222] p-5">
|
||||
<h3 className="font-body font-bold text-xs text-[#3b82f6] uppercase tracking-widest mb-3 pb-2 border-b border-[#222]">Quick Links</h3>
|
||||
<ul className="space-y-2">
|
||||
<li><Link href="/advertise" className="font-body text-sm text-[#777] hover:text-[#3b82f6] transition-colors">Advertise With Us</Link></li>
|
||||
<li><Link href="/contributor" className="font-body text-sm text-[#777] hover:text-[#3b82f6] transition-colors">Contributor Program</Link></li>
|
||||
<li><Link href="/privacy" className="font-body text-sm text-[#777] hover:text-[#3b82f6] transition-colors">Privacy Policy</Link></li>
|
||||
<li><Link href="/terms" className="font-body text-sm text-[#777] hover:text-[#3b82f6] transition-colors">Terms of Service</Link></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div className="bg-[#0d1520] border border-[#1e3a5f] p-5">
|
||||
<h3 className="font-body font-bold text-xs text-[#3b82f6] uppercase tracking-widest mb-2">Newsletter</h3>
|
||||
<p className="text-[#777] text-xs font-body mb-3">Stay current with weekly broadcast industry news.</p>
|
||||
<Link href="/home-page#newsletter" className="btn-subscribe text-xs py-2 px-4 inline-block">Subscribe Free</Link>
|
||||
</div>
|
||||
</aside>
|
||||
</div>
|
||||
</main>
|
||||
<Footer />
|
||||
</div>
|
||||
</main>
|
||||
);
|
||||
}
|
||||
|
||||
33
src/app/about/press-kit/page.tsx
Normal file
33
src/app/about/press-kit/page.tsx
Normal file
@@ -0,0 +1,33 @@
|
||||
export const metadata = { title: "Press kit — BroadcastBeat" };
|
||||
|
||||
export default function PressKitPage() {
|
||||
return (
|
||||
<main className="mx-auto max-w-3xl px-6 py-12 text-[#e5e7eb]">
|
||||
<h1 className="font-serif text-4xl font-bold tracking-tight mb-6">Press kit</h1>
|
||||
<div className="space-y-6 text-[15px]">
|
||||
<section>
|
||||
<h2 className="font-mono text-xs uppercase tracking-wider text-[#6b7280] mb-2">Logos</h2>
|
||||
<ul className="space-y-1">
|
||||
<li><a className="text-[var(--color-text-info,#60a5fa)] hover:underline" href="/assets/images/logo.png" download>BroadcastBeat logo (PNG)</a></li>
|
||||
</ul>
|
||||
</section>
|
||||
<section>
|
||||
<h2 className="font-mono text-xs uppercase tracking-wider text-[#6b7280] mb-2">Boilerplate</h2>
|
||||
<p className="text-[#d1d5db] leading-relaxed">
|
||||
BroadcastBeat is an independent trade publication covering broadcast,
|
||||
live production, streaming, and post-production technology. Founded
|
||||
to bring engineering-rigor reporting to industry coverage, BroadcastBeat
|
||||
publishes daily on the equipment, services, and people that move
|
||||
professional video forward.
|
||||
</p>
|
||||
</section>
|
||||
<section>
|
||||
<h2 className="font-mono text-xs uppercase tracking-wider text-[#6b7280] mb-2">Media contact</h2>
|
||||
<p>
|
||||
<a className="text-[var(--color-text-info,#60a5fa)] hover:underline" href="mailto:ryan.salazar@relevantmediaproperties.com">ryan.salazar@relevantmediaproperties.com</a>
|
||||
</p>
|
||||
</section>
|
||||
</div>
|
||||
</main>
|
||||
);
|
||||
}
|
||||
67
src/app/about/team/page.tsx
Normal file
67
src/app/about/team/page.tsx
Normal file
@@ -0,0 +1,67 @@
|
||||
import { createClient } from "@supabase/supabase-js";
|
||||
|
||||
export const dynamic = "force-dynamic";
|
||||
export const revalidate = 600;
|
||||
|
||||
export const metadata = {
|
||||
title: "Editorial team — BroadcastBeat",
|
||||
description: "Meet the BroadcastBeat editorial team — staff journalists covering broadcast, streaming, and post-production beats.",
|
||||
};
|
||||
|
||||
interface Persona {
|
||||
slug: string;
|
||||
name: string;
|
||||
bio: string | null;
|
||||
beat: string | null;
|
||||
avatar_url: string | null;
|
||||
}
|
||||
|
||||
export default async function TeamPage() {
|
||||
const sb = createClient(
|
||||
process.env.NEXT_PUBLIC_SUPABASE_URL!,
|
||||
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!,
|
||||
{
|
||||
db: { schema: (process.env.NEXT_PUBLIC_SUPABASE_SCHEMA || "bb") as "public" },
|
||||
auth: { persistSession: false },
|
||||
}
|
||||
);
|
||||
const { data } = await sb
|
||||
.from("ai_personas")
|
||||
.select("slug, name, bio, beat, avatar_url")
|
||||
.eq("active", true);
|
||||
const team = (data || []) as Persona[];
|
||||
|
||||
return (
|
||||
<main className="mx-auto max-w-5xl px-6 py-12 text-[#e5e7eb]">
|
||||
<h1 className="font-serif text-4xl font-bold tracking-tight mb-2">Editorial team</h1>
|
||||
<p className="text-sm text-[#9ca3af] mb-10">
|
||||
Staff journalists by beat. We are a mix of human reporters and trained
|
||||
AI personas operating under house style.
|
||||
</p>
|
||||
<ul className="grid grid-cols-1 md:grid-cols-2 gap-5">
|
||||
{team.map((p) => (
|
||||
<li key={p.slug} className="rounded border border-[#252525] bg-[#0b0f17] p-5 flex gap-4">
|
||||
{p.avatar_url && (
|
||||
<img
|
||||
src={p.avatar_url}
|
||||
alt={p.name}
|
||||
width={64}
|
||||
height={64}
|
||||
className="rounded-full border border-[#252525]"
|
||||
/>
|
||||
)}
|
||||
<div className="flex-1">
|
||||
<h2 className="font-serif text-lg font-semibold">{p.name}</h2>
|
||||
{p.beat && (
|
||||
<div className="text-[10px] font-mono uppercase tracking-wider text-[var(--color-text-info,#60a5fa)] mt-0.5">
|
||||
{p.beat.replace(/-/g, " ")}
|
||||
</div>
|
||||
)}
|
||||
{p.bio && <p className="text-sm text-[#9ca3af] mt-2 leading-relaxed">{p.bio}</p>}
|
||||
</div>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</main>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user