Commit Graph

153 Commits

Author SHA1 Message Date
Ryan Salazar
04efa3933a ads: switch to centralized RMP banner source; impression beacon → advertising.rmp; rearm viewport observer (12s debounce) for re-entry counting 2026-05-22 05:51:54 +00:00
Ryan Salazar
e5b09fe6d7 ui: solid Read More button + neon palette site-wide (not just homepage) so header/footer stays consistent on all pages 2026-05-22 05:40:54 +00:00
Ryan Salazar
d4016a3c91 ratings + typography + icons: StarRating ★★★★½ 4.7 (212) widget on cards + article headers; NYT/WaPo bb-article-prose body (Georgia 19/1.75, 720px col, drop cap, pull quotes, italic captions); bump homepage share icons to 32px/15px to match article page 2026-05-22 05:34:24 +00:00
Ryan Salazar
9342db7a16 ask-bb-ai: lower from bottom-24 (96px) to bottom-16 (64px) — was too high 2026-05-22 05:19:50 +00:00
Ryan Salazar
ede00da858 homepage feed: remove duplicate category+date in advanced panel (kept author/source only); article page: render SidebarAdStack instead of placeholder 2026-05-22 05:19:13 +00:00
Ryan Salazar
3ca38afebb homepage industry news: add LinkedIn/X/Facebook/Reddit/WhatsApp/Email share row under Read More on every article card 2026-05-22 05:17:19 +00:00
Ryan Salazar
ae6af2ca56 technology: dynamic header + filter for ?category=ai/cloud/ip-workflows/streaming/atsc-3; add sub-category chip row 2026-05-22 05:15:05 +00:00
Ryan Salazar
984ff5d4a9 homepage: add topic chips + date filters to Industry News section (matches /news page UX) 2026-05-22 05:13:27 +00:00
Ryan Salazar
07b0f387ed show-coverage: rename header 'Show coverage' → 'Industry Show Coverage' (h1 + title) 2026-05-22 05:10:21 +00:00
Ryan Salazar
bd34b0cb06 gear: rename 'Broadcast Gear & Reviews' → 'Production Gear & Reviews' (h1 + metadata) 2026-05-22 05:09:35 +00:00
Ryan Salazar
8a296edcbc buttons: invert neon-green CTA text to dark-gray (#1a1a1a) for readability; bump Ask BB AI above cookie bar (bottom-6→bottom-24) 2026-05-22 05:08:01 +00:00
Ryan Salazar
d674149486 layout: align top tagline bar + newsletter section to max-w-container featured-card edges 2026-05-22 05:04:14 +00:00
Ryan Salazar
06390db497 sitewide: rename THE LATEST → INDUSTRY NEWS; add social shares to /articles/<slug> template too 2026-05-22 05:02:59 +00:00
Ryan Salazar
66880b2d6e article: add LinkedIn, X, Facebook, Reddit, WhatsApp, Copy-Link share buttons next to email 2026-05-22 04:41:39 +00:00
Ryan Salazar
e95dea4ff3 ticker: slow 'THE LATEST' row 163→228s (+40%) 2026-05-22 04:15:33 +00:00
Ryan Salazar
9f23e9d753 docker: expose NEXT_PUBLIC_* build args as ENV so Next.js inlines them in client bundle (GA + Supabase + site URL) 2026-05-22 03:03:04 +00:00
Ryan Salazar
aac57bdc1b search: widen browse-bar search by 20% (320→384px) + placeholder "Search all content sitewide" 2026-05-22 02:48:58 +00:00
Ryan Salazar
fcb3a00104 ticker: rename bottom row label FORUM → RECENT FORUM POSTS 2026-05-22 02:47:57 +00:00
Ryan Salazar
ff9fe20d16 search: square the search box + suggest dropdown (border-radius 999px→2px) to match the rest of the site 2026-05-22 02:41:48 +00:00
Ryan Salazar
55baf7004f ticker: top 130→163s (+25%) / bottom 187→206s (+10%) 2026-05-22 02:37:22 +00:00
Ryan Salazar
c6bf372b50 header: align ticker + browse bar to featured card's visual edges (px-4 inside max-w-container) 2026-05-22 01:42:21 +00:00
Ryan Salazar
ca062eb4c8 team: pin Ryan Salazar first w/ FOUNDER / EDITOR-IN-CHIEF title 2026-05-22 01:38:57 +00:00
Ryan Salazar
836bd1de0e ticker: slow both rows by 30% (THE LATEST 100→130s, FORUM 144→187s) 2026-05-22 01:37:21 +00:00
Ryan Salazar
a92aa38b78 ticker: top row 50s→100s (50% slower) + rename BEAT→THE LATEST; bottom 120s→144s (20% slower) 2026-05-22 01:33:31 +00:00
Ryan Salazar
9da8122871 header: align About dropdown vertically + slow ticker scroll (BEAT 17→50s, FORUM 40→120s) 2026-05-22 01:29:00 +00:00
Ryan Salazar
d2ef1ba6c3 header: constrain ticker + browse bar to max-w-container (1200px) aligned with featured box 2026-05-22 01:23:55 +00:00
Ryan Salazar
e6eb3cc99c header+ticker: new menu (HOME/FEATURED/THE LATEST/SHOW COVERAGE/FORUM/ABOUT) + drop reduced-motion rule that was freezing ticker animation 2026-05-22 01:22:12 +00:00
Ryan Salazar
00a79f12b7 header: move browse bar (main menu) below the ticker 2026-05-22 01:16:17 +00:00
Ryan Salazar
7abd613113 header: move 728x90 banner inline between logo and right-side icons 2026-05-22 01:12:16 +00:00
Ryan Salazar
e7b5c29a07 header: revert to original logo.png wordmark 2026-05-22 01:09:04 +00:00
Ryan Salazar
729547764e ticker: query wp_imported_posts (not native_articles) + fallback when 7d window empty 2026-05-22 00:46:44 +00:00
Ryan Salazar
ef1470a58b css: drop escaped-slash selectors that broke cssnano 2026-05-22 00:41:28 +00:00
Ryan Salazar
6e7e660927 brand: neon BROADCAST BEAT wordmark (SVG + PNG)
- SVG logo at public/brand/logo.svg with pink-magenta BROADCAST,
  cyan BEAT, cyan heartbeat waveform underline, ™ mark, and
  "THE PULSE OF PRODUCTION INTELLIGENCE" tagline
- PNG renders at 1x (1200x320), 2x (2400x640), small (600x160)
- Header swapped from /assets/images/logo.png to /brand/logo.svg

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-22 00:30:35 +00:00
Ryan Salazar
aee67ef9f6 homepage: neon dual-speed ticker + emerald/cyan palette pass
- New DualSpeedTicker component (CSS keyframes, GPU-accelerated,
  pause on hover, 28px rows, 17s BEAT / 40s FORUM, refresh 5min)
- /api/ticker/beat-news: last 7 days from bb.native_articles
- /api/ticker/forum-posts: latest threads + replies interleaved
- Mounted at the bottom of Header so every page gets it
- Scoped .bb-neon palette on homepage root: section heads +
  text-shadow glow, neon-tinted card borders, emerald→cyan button
  gradient, cyan hover state on links, subscribe boxes neon-bordered
- CSS-only — no layout changes

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-21 23:58:12 +00:00
Ryan Salazar
5eaf64925f homepage: remove news ticker
Per request.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-21 23:24:02 +00:00
Ryan Salazar
a8b75593c2 forum: require auth for posting + add login/register/edit pages
- API: require auth on thread+reply POST (401 if !user); lazy-create
  forum_user_profile via service-role; author_name = display_name
- UI: surface API errors (kill silent catch); auto-redirect to login
  on 401; gate new-thread + reply forms with "Sign in to post" CTA
- /forum/login + /forum/register: forum-themed Supabase Auth pages
  with ?next= redirect support
- /forum/profile/edit + /api/forum/profile/me: edit own forum profile
  (username, display_name, bio, role, company, location, avatar)
- Header: logout button + sign-in/join links when not authed
- forum/user/[username]: show Edit Profile button when viewing own

Fixes posting bug: RLS rejected anon inserts with cryptic message
that the UI silently swallowed; now blocked with friendly 401 + redirect.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-21 22:41:28 +00:00
Ryan Salazar
585a9503ab homepage: make '/' the canonical route, 301 /home-page → /
Previous state: '/' was 307-redirected to '/home-page', and the
home-page route declared canonical='/home-page'. Net effect on
SEO: Google indexed '/home-page' as the canonical homepage and
treated '/' as a transient redirect (no link equity passed).

Changes:
- next.config.mjs: replace the source:'/' destination:'/home-page'
  temporary redirect with source:'/home-page' destination:'/'
  permanent (301). Any existing crawler entry for /home-page now
  consolidates onto '/'.
- src/app/page.tsx (new): re-exports default + metadata from
  ./home-page/page so '/' serves the homepage directly. No file
  moves required, no relative-import breakage in the home-page
  component subtree.
- src/app/home-page/page.tsx: canonical and openGraph.url
  '/home-page' → '/'. The page still builds at /home-page but
  the 301 above will redirect any hit before render.
- src/app/sitemap.ts: drop the duplicate /home-page entry — Google
  shouldn't be told about a URL that just redirects.
2026-05-21 17:37:45 +00:00
Ryan Salazar
78c2ee656e homepage: typography upgrade + ArticleFeed polish
- layout.tsx: load Lora (serif) + Inter (sans) via next/font/google,
  self-hosted at build time, exposed as --font-serif / --font-sans
  CSS variables on <html>. No CDN fetch, no FOIT, no GDPR concern.
- tailwind.css: --font-heading and --font-body now reference the
  next/font variables with Georgia / -apple-system fallbacks for the
  brief window before the self-hosted face is ready. --font-mono
  upgraded to IBM Plex Mono → ui-monospace → Courier New fallback
  (DoubleTicker chips already specify IBM Plex Mono directly).
- ArticleFeed: drop the FEATURED filter chip (duplicates the
  Staff Editorial section above), add publish date alongside the
  byline on every card, lift the homepage feed cap from 200 → 5000.
- api/public/posts: lift MAX_LIMIT to 10000 so client-side
  pagination + infinite-scroll see the full archive.
2026-05-21 01:51:29 +00:00
Ryan Salazar
567a45079f homepage: shrink Staff Editorial header to match The Latest
Earlier this evening I bumped the Staff Editorial header to a
font-serif 2xl/3xl bold — too loud, fought with The Latest section
header below it on the same page.

Reverted to the same shape The Latest uses:
  <span class="section-label">Staff Editorial</span>
  <div class="flex-1 h-px bg-[#2a2a2a]" />
  <Link>All featured →</Link>

That's the global .section-label utility (font-body 13px,
font-weight:700, letter-spacing:0.08em, uppercase, color
accent-blue, with a 3px accent border on the left). Now the two
section headers on the homepage are visually consistent.
2026-05-20 21:52:53 +00:00
Ryan Salazar
74677a80b8 homepage: remove top bar + fix subscribe + Staff Editorial header
1. Remove SystemStatusBar from root layout. The "29,220 articles
   indexed / 13 events tracked / [v2.0.0]" strip ate vertical space
   above the fold without serving readers.

2. /api/newsletter/subscribe was returning 500 "Failed to save
   subscription" because:
   - The route used the anon-session client and tried to UPSERT on
     bb.newsletter_subscribers, but the table's RLS only has an
     INSERT policy for the public role. Upsert needs INSERT+UPDATE,
     so the second branch failed RLS.
   - Switched to createAdminClient (service-role) — bypasses RLS,
     which is fine because this is a server-side endpoint with
     server-side email validation.
   - Welcome email now sends via nodemailer in a non-blocking
     background task so a slow SMTP doesn't hold up the response.
     Newer HTML template, brand-aligned, with a real CTA back to
     /news.

   Side work to wire SMTP (done out-of-band):
   - Created newsletter@broadcastbeat.com mailbox in Mailcow via
     the API (2GB quota, active, no force-pw-update).
   - Set SMTP_HOST=mail.onsethost.com, SMTP_PORT=587,
     SMTP_USER/PASS/FROM_EMAIL/FROM_NAME in Coolify env so the
     welcome email actually fires after the next deploy.

3. FeaturedBentoFromDb section header: "Featured · staff editorial"
   (small mono caps) → "Staff Editorial" (font-serif 2xl/3xl, bold,
   with a thin metadata line "Selected by our newsroom" beside it
   and a 2px bottom rule). Matches the editorial typography on the
   article pages.
2026-05-20 18:51:25 +00:00
Ryan Salazar
8f8eaa5fe8 newsletter: site-wide signup modal with 7-day dismiss
Renders on every page via root layout. Behavior:
- 5s delay after first paint so it doesn't slam the user.
- Animates from a pill into the full card (bb-modal-pop keyframe);
  respects prefers-reduced-motion.
- Heading "Get the latest in broadcast & media", email field,
  Subscribe + "Not now" + close (X).
- Subscribe POSTs to the existing /api/newsletter/subscribe route
  (native system — newsletter_subscribers table + SMTP welcome
  via Mailcow/SMTP2GO). Listmonk wasn't installed anywhere on the
  infra; switching to it later is a one-line URL change.
- "Not now" + backdrop click + Escape + X all dismiss for 7 days
  via localStorage["bb_newsletter_dismissed"].
- On success → "Check your email" panel + auto-close at 4s;
  subscribed flag stored in localStorage so the modal never
  re-prompts that visitor.

Styling matches the site's dark-navy + electric-blue palette
(NOT the neon ticker palette). No layout/page shifts — overlay
only.
2026-05-20 17:55:29 +00:00
Ryan Salazar
418027b469 search: real autocomplete previews + clearer placeholder
PLACEHOLDER: "Search broadcast news…" → "Search articles, gear,
vendors". Drops the weird ellipsis and the "we're a broadcast site
so 'broadcast news' is redundant" feel.

API (/api/search/suggest):
- Match expanded from {title, author_name} to
  {title, excerpt, content, author_name} — surfaces hits when the
  phrase lives deep in the article body.
- Returns a snippet object {text, matchStart, matchEnd} sliced
  from the first hit (HTML-stripped), with ~80 chars of context on
  either side and "…" markers when truncated.
- Returns matched_in: 'title' | 'excerpt' | 'content' | 'author' so
  the UI can show "match in article body" / "match in byline".
- Returns date + author_name on each result.

UI dropdown (Header.tsx):
- Each suggestion now renders three rows:
  1) Title (bold) + category chip
  2) Snippet with the matched substring wrapped in <mark>
  3) Author byline + date + (if match wasn't in title) a tag
     showing where the match occurred
- Vertical stacking with a colored left-border on hover so the
  active suggestion is visible.

CSS:
- Stack item layout, snippet with -webkit-line-clamp:2 so long
  matches don't overflow.
- <mark> background uses the accent blue at 28% so the highlight
  reads against the dark card.
2026-05-20 16:22:04 +00:00
Ryan Salazar
c1705e1a4b ai: bump hybridRouter connection timeout 8s → 30s
Manual fire of bb-company-coverage-scan tonight failed because the
8s connect timeout was tripping on llama3.1:70b cold-load when
another model was resident in VRAM on AI_001. Bumped to 30s so
the orchestrator can wait through a model swap.

Also bumped background request timeout 120s → 180s for the same
reason — story generation against the 70B can take >2 min on a
saturated GPU.

Coolify env OLLAMA_ENDPOINT was simultaneously flipped from
AI_001 (10.10.0.66) to AI_002 (10.10.0.67) since AI_002 is less
loaded — AI_001 is doing author enrichment and scrubber work.
2026-05-20 13:32:09 +00:00
Ryan Salazar
78e08046a7 ticker: redesign — news-wire aesthetic, drop the bright label box
The previous version used solid neon-green / neon-cyan blocks for
the "Live Wire" / "On Calendar" labels which read as too aggressive
against the otherwise dark-navy site. Replaced with a real news-wire
look:

- Pulse-dot indicator (animated breathing dot) + small-caps mono
  label on the left, separated from the feed by a thin rule.
- Item codes (SONY / MTRX / NAB) become small bordered chips with
  subtle neon background tint instead of bare colored text.
- Timestamps are mid-gray monospace; titles are clean Inter at
  13px with slight letter-spacing.
- Top + bottom of each bar get a hairline gradient (neon→cyan
  on row 1, dimmer cyan-only between rows) instead of a hard
  border.
- Items are separated by faint vertical hairlines, padded
  consistently.
- Marquee slowed slightly (110s / 170s) so titles are legible.

Same data sources (news + events), same scroll directions, just
better visual integration with the rest of the dark-navy site.
2026-05-20 13:13:25 +00:00
Ryan Salazar
097181eb43 forum: render threads on /forum default view (not just search mode)
Bug: the index page only fetched threads when user was actively
searching, filtering by category, or sorting non-default. Default
load → setThreads([]) → forum looked empty even though 50+
threads existed in the DB.

Fix: always fetch on mount + filter changes (drop the
isSearchMode gate on the effect), and add a Recent Threads
section in the default view above the Browse Categories list,
showing the 12 most recent threads with author + reply count.

API + DB unchanged.
2026-05-20 13:11:32 +00:00
Ryan Salazar
f6b52f7c2d forum: user profile pages + clickable bylines + neon pulse favicon
USER PROFILES (/forum/user/[username]):
- New API at /api/forum/user-by-username/[username] resolves by
  username OR display_name (URL-encoded), since forum threads/replies
  store author_name = display_name. Returns the persona's profile,
  thread history (up to 50), and recent replies (up to 20).
- New page renders the persona card with archetype badge
  (Audio Engineer / Colorist / etc.) + expertise level badge
  (beginner/intermediate/senior) + role title, company, location,
  years_experience, join date, and an expertise-tags chip row.
- Two columns underneath: "Threads started" and "Recent replies"
  with proper deep-links into each thread.
- Author names in /forum, /forum/[slug], and /forum/thread/[id] are
  now <Link> elements pointing to /forum/user/<displayname>, with
  onClick=stopPropagation so the card-level click handler doesn't
  also fire.

FAVICON:
- Hand-built neon pulse waveform — emerald→cyan→purple gradient on
  dark navy background, designed to read at 16×16 to 256×256.
- Multi-resolution favicon.ico (16/32/48/64) + SVG + PNGs at
  16/32/48/64/96/192/256 under /static/favicons/.
- layout.tsx icons block now references all sizes including the
  apple-touch sizes (192, 256).

No env / DB changes here — pure deploy.
2026-05-20 12:56:56 +00:00
Ryan Salazar
dc166dfb10 forum: fix API + UI column-name mismatch against bb.forum_threads
The schema has upvotes / downvotes / vote_score; API + UI were
querying/reading upvote_count / downvote_count (non-existent
columns). Threads existed in the DB but didn't render.

- /api/forum/threads route.ts:
  - 'top-voted' sort: order by vote_score (was upvote_count)
  - 'newest' default sort: forum_threads has no 'status' column,
    so order pinned-first via is_pinned, then last_reply_at desc
- UI ForumThread interface + components: rename
  upvote_count → upvotes, add downvotes + vote_score so the
  vote display in the thread cards and the admin moderation
  list pulls live data from the existing columns.

After this lands and the deploy completes, the 50 seeded
threads + the 9 ai-seeded new threads + 253 backfilled replies
already in the DB will all render at /forum.
2026-05-20 08:34:05 +00:00
Ryan Salazar
4e11438963 seo: open site to search engines + expand sitemap to full catalog
- layout.tsx: flip robots.index from false→true (and the matching
  googleBot block). Drop the manual <meta name="robots"
  content="index, follow"> in the JSX head — it was duplicating
  (and conflicting with) the metadata-driven tag, so Google was
  seeing both "index, follow" AND "noindex, nofollow" and taking
  the more restrictive one. Now the metadata block is the single
  source of truth.
- sitemap.ts: expand from 5,000 articles to up to 45,000 (catalog
  is ~26k; cap leaves room for static + authors + events under
  Google's 50k-per-file ceiling). Add /authors/[slug] entries
  pulled from bb.author_profiles, and /events/[slug] entries
  pulled from bb.events. Drop the duplicate /articles/[slug]
  emissions — /news/[slug] is the canonical news URL.
- legacy-source.ts: page through the supabase query in 1,000-row
  chunks via Range headers so the 25k cap actually returns the
  full catalog (the previous `.limit(25000)` was getting silently
  truncated at PostgREST's default 1,000 max_rows).

Phase B (Ollama rewriter) is live; the press-release scrubber +
AI featured-image jobs are running in background to clean the
catalog. User explicitly chose to open SEO now rather than wait
for those jobs to finish.
2026-05-20 07:17:59 +00:00
Ryan Salazar
a9823b1d8a ticker: replace LiveWire with dual-row neon ticker (news + events)
Row 1 (Live Wire, scrolls →): most recent imported + AI-rewritten
articles, neon-green label, monospaced [HH:MM] [SOURCE_CODE] prefix.
Row 2 (On Calendar, scrolls ←, slower): upcoming events from
bb.events (confirmed/tentative, start_date >= today), neon-cyan
label, [Mon DD] [SHORT_NAME] prefix.

Defensive: each query is in its own try/catch so a partial failure
renders an empty row rather than crashing the page — that was the
silent build crash that took down the prior DoubleTicker incarnation.
If BOTH queries return zero rows we render nothing instead of two
blank bars.

CSS tokens added to redesign-tokens.css:
- bb-marquee--reverse + bb-marquee--slow modifiers
- .bb-neon-bar / .bb-neon-label / .bb-neon-time / .bb-neon-code
  (scoped class names so this is the ONLY place on the site that
  uses the neon palette — rest of the site keeps dark-navy + blue)

User cancelled the wholesale neon redesign; only the dual-ticker
keeps the neon green/cyan styling.
2026-05-20 07:02:15 +00:00
Ryan Salazar
5c3432915a preview: drop neon redesign sample at /previews/neon.html 2026-05-20 06:57:01 +00:00