ux: dark-theme conversion + forum hero + ticker cleanup

- /manufacturers index + DirectoryClient: convert white/light-ink theme
  to BB dark theme so it stops standing out against the rest of the site
- /manufacturers/[slug]: same conversion, includes the new executives
  card grid and Headquarters block
- /nab-2026: same conversion, including hero gradient and sponsor tile
  borders (amber on dark instead of amber on white)
- Forum: remove "Top Performing Threads" widget from both /forum and
  /forum/[slug] (display only — TopThreadsWidget component preserved
  in case admins want to re-enable later)
- Forum hero: vertical padding py-10 → py-5, tagline reduced from
  three sentences to one. Adds a "Sign in to post" or "Start a thread"
  CTA in the hero's top-right depending on auth state.
- Recent Forum Posts ticker: drop replies entirely, surface only thread
  titles so breadth of conversation shows instead of the loudest
  threads dominating with reply chatter.
This commit is contained in:
Ryan Salazar
2026-05-27 14:52:08 +00:00
parent 52a6792c9e
commit 3460baa8b9
7 changed files with 147 additions and 159 deletions

View File

@@ -22,65 +22,32 @@ export async function GET() {
auth: { persistSession: false },
});
// Newest threads + newest replies, interleaved by timestamp.
const [threadsRes, repliesRes] = await Promise.all([
sb
.from('forum_threads')
.select('id, title, author_name, created_at')
.order('created_at', { ascending: false })
.limit(20),
sb
.from('forum_replies')
.select('id, body, thread_id, author_name, created_at, forum_threads(title)')
.order('created_at', { ascending: false })
.limit(20),
]);
// Threads only — per editorial direction we surface unique topics, not
// reply chatter, so the ticker shows breadth of discussion.
const threadsRes = await sb
.from('forum_threads')
.select('id, title, author_name, created_at')
.order('created_at', { ascending: false })
.limit(40);
if (threadsRes.error && repliesRes.error) {
if (threadsRes.error) {
return NextResponse.json(
{ error: threadsRes.error?.message || repliesRes.error?.message, items: [] },
{ status: 500 }
{ error: threadsRes.error.message, items: [] },
{ status: 500 },
);
}
const items: TickerItem[] = [];
for (const t of threadsRes.data || []) {
items.push({
id: t.id,
href: `/forum/thread/${t.id}`,
title: t.title,
kind: 'thread',
author_name: t.author_name,
created_at: t.created_at,
});
}
for (const r of (repliesRes.data || []) as Array<{
id: string;
body: string;
thread_id: string;
author_name: string | null;
created_at: string;
forum_threads?: { title: string } | { title: string }[] | null;
}>) {
const parent =
Array.isArray(r.forum_threads) ? r.forum_threads[0] : r.forum_threads;
const parentTitle = parent?.title || 'forum reply';
items.push({
id: r.id,
href: `/forum/thread/${r.thread_id}`,
title: `Re: ${parentTitle}`,
kind: 'reply',
author_name: r.author_name,
created_at: r.created_at,
});
}
items.sort((a, b) => (a.created_at < b.created_at ? 1 : -1));
const items: TickerItem[] = (threadsRes.data || []).map((t: any) => ({
id: t.id,
href: `/forum/thread/${t.id}`,
title: t.title,
kind: 'thread',
author_name: t.author_name,
created_at: t.created_at,
}));
return NextResponse.json(
{ items: items.slice(0, 30) },
{ items: items.slice(0, 40) },
{
headers: {
'Cache-Control': 'public, s-maxage=300, stale-while-revalidate=600',