forum: rebrand to The Crew Lounge + scaffold Credits system

UI (targeted edits, no identifier renames):
- forum/layout.tsx: metadata title/OG/twitter/schema.org + breadcrumb name → The Crew Lounge
- forum/page.tsx: H1 + intro copy → The Crew Lounge (swapped 💬 for /logos/crew-lounge-logo.svg)

New assets:
- public/logos/crew-lounge-logo.svg — film-reel + CREW logo, #5B7C8D → #8FB0C3 gradient
- src/components/crew-lounge/CreditsDisplay.tsx — per-category totals + Crew Leader badge
- src/components/crew-lounge/CrewLoungeLogo.tsx — wrapper component

Database (4 new tables on supabase01, all TIMESTAMPTZ, IF NOT EXISTS guards):
- bb.user_credits — per-user/per-category daily credit ledger
- bb.user_credits_totals — cached leaderboard totals
- bb.crew_leader_badges — awarded at 10+ credits/category
- bb.credits_monthly_snapshot — monthly leaderboard captures

Docs:
- docs/guides/FORUM_SETUP_COMPLETE.md — replication guide
- docs/guides/FORUM_SETUP_CHECKLIST.md — per-property checklist

Forum tables (bb.forum_*) and TypeScript identifiers untouched.
Routes (/forum) unchanged — display-name rebrand only.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-16 16:07:06 +00:00
parent 82ae43ccf5
commit 83579523d1
7 changed files with 189 additions and 12 deletions

View File

@@ -1,19 +1,19 @@
import type { Metadata } from 'next';
export const metadata: Metadata = {
title: 'Industry Forum — Broadcast Beat',
description: 'Connect with broadcast, motion picture and post production professionals worldwide. Discuss live production, IP workflows, streaming, audio, cameras, AI automation, and more.',
title: 'The Crew Lounge — Broadcast Beat',
description: 'The Crew Lounge: connect with broadcast, motion picture and post production professionals worldwide. Discuss live production, IP workflows, streaming, audio, cameras, AI automation, and more.',
alternates: { canonical: '/forum' },
openGraph: {
title: 'Industry Forum — Broadcast Beat',
description: 'Connect with broadcast, motion picture and post production professionals worldwide. Ask questions, share expertise, and discuss broadcast technology.',
title: 'The Crew Lounge — Broadcast Beat',
description: 'The Crew Lounge: connect with broadcast, motion picture and post production professionals worldwide. Ask questions, share expertise, and discuss broadcast technology.',
url: '/forum',
type: 'website',
},
twitter: {
card: 'summary',
title: 'Industry Forum — Broadcast Beat',
description: 'Connect with broadcast, motion picture and post production professionals worldwide on Broadcast Beat.',
title: 'The Crew Lounge — Broadcast Beat',
description: 'The Crew Lounge: connect with broadcast, motion picture and post production professionals worldwide on Broadcast Beat.',
},
};
@@ -21,8 +21,8 @@ export default function ForumLayout({ children }: { children: React.ReactNode })
const schema = {
'@context': 'https://schema.org',
'@type': 'WebPage',
name: 'Broadcast Beat Industry Forum',
description: 'Industry forum for broadcast, motion picture and post production professionals worldwide.',
name: 'Broadcast Beat — The Crew Lounge',
description: 'The Crew Lounge: an industry community for broadcast, motion picture and post production professionals worldwide.',
url: 'https://broadcastb5322.builtwithrocket.new/forum',
isPartOf: {
'@type': 'WebSite',
@@ -33,7 +33,7 @@ export default function ForumLayout({ children }: { children: React.ReactNode })
'@type': 'BreadcrumbList',
itemListElement: [
{ '@type': 'ListItem', position: 1, name: 'Home', item: 'https://broadcastb5322.builtwithrocket.new' },
{ '@type': 'ListItem', position: 2, name: 'Forum', item: 'https://broadcastb5322.builtwithrocket.new/forum' },
{ '@type': 'ListItem', position: 2, name: 'The Crew Lounge', item: 'https://broadcastb5322.builtwithrocket.new/forum' },
],
},
};

View File

@@ -262,11 +262,11 @@ export default function ForumIndexPage() {
<div className="bg-[#1a2535] border-b border-[#2a3a50]">
<div className="max-w-container mx-auto px-4 py-10">
<div className="flex items-center gap-3 mb-2">
<span className="text-2xl">💬</span>
<h1 className="text-3xl font-heading font-bold text-white">Industry Forum</h1>
<img src="/logos/crew-lounge-logo.svg" alt="The Crew Lounge" className="w-8 h-8" />
<h1 className="text-3xl font-heading font-bold text-white">The Crew Lounge</h1>
</div>
<p className="text-[#aab4c4] font-body text-base max-w-2xl">
Connect with broadcast, motion picture and post production professionals worldwide. Ask questions, share expertise, and discuss the technology shaping the industry.
The Crew Lounge: connect with broadcast, motion picture and post production professionals worldwide. Ask questions, share expertise, and discuss the technology shaping the industry.
</p>
</div>
</div>

View File

@@ -0,0 +1,56 @@
'use client';
interface CreditsDisplayProps {
userName: string;
totalCredits: number;
categoryCredits: Record<string, number>;
isLeader: boolean;
}
export default function CreditsDisplay({
userName,
totalCredits,
categoryCredits,
isLeader,
}: CreditsDisplayProps) {
return (
<div className="bg-[#111] border border-[#2a3f5f] rounded-lg p-6">
<div className="flex items-center justify-between mb-6">
<div>
<h2 className="text-2xl font-bold text-white">{userName}</h2>
{isLeader && (
<span className="inline-block mt-2 px-3 py-1 bg-gradient-to-r from-[#5B7C8D] to-[#8FB0C3] text-white rounded-full text-xs font-bold">
Crew Leader
</span>
)}
</div>
<div className="text-right">
<p className="text-[#666] text-sm">Total Credits</p>
<p className="text-4xl font-bold text-[#5B7C8D]">{totalCredits}</p>
</div>
</div>
{Object.keys(categoryCredits).length > 0 && (
<div className="border-t border-[#2a3f5f] pt-6">
<p className="text-[#8FB0C3] font-bold mb-4">By Category</p>
<div className="grid grid-cols-2 gap-4">
{Object.entries(categoryCredits)
.sort(([, a], [, b]) => b - a)
.slice(0, 6)
.map(([category, credits]) => (
<div key={category} className="bg-[#0d0d0d] rounded p-3">
<p className="text-[#666] text-xs">{category}</p>
<p className="text-lg font-bold text-[#8FB0C3]">{credits}</p>
</div>
))}
</div>
</div>
)}
<div className="mt-6 text-[#666] text-xs">
<p>💡 Earn 1 credit per post in each category</p>
<p> Earn &quot;Crew Leader&quot; badge at 10+ credits</p>
</div>
</div>
);
}

View File

@@ -0,0 +1,10 @@
export default function CrewLoungeLogo({ size = 40 }: { size?: number }) {
return (
<img
src="/logos/crew-lounge-logo.svg"
alt="The Crew Lounge"
style={{ width: size, height: size }}
className="inline-block"
/>
);
}