av: clone broadcastbeat sources + AV Beat rebrand (Phase 1)
- Replaces the prior Rocket scaffold (saved on pre-bb-clone-rollback branch) - Domain: broadcastbeat.com -> avbeat.com - Brand: Broadcast Beat -> AV Beat - Slug: broadcastbeat -> avbeat (package, identifiers) - Schema fallback: bb -> av (env var name unchanged) - Placeholder AV BEAT logo (gold->red gradient) at /assets/logos/av.svg - All BB/RMP logo references repointed Outstanding before public DNS swap: - Supabase av schema bootstrap (mirror of bb tables) - WordPress archive import (avbeat-com -> av.articles) - Coolify env vars - dev-avbeat.onsethost.com staging deploy + visual review
This commit is contained in:
@@ -47,7 +47,7 @@ interface Stats {
|
||||
}
|
||||
|
||||
const PUBLICATIONS = [
|
||||
{ id: 'broadcast-beat', name: 'Broadcast Beat', short: 'BB' },
|
||||
{ id: 'broadcast-beat', name: 'AV Beat', short: 'BB' },
|
||||
{ id: 'av-beat', name: 'AV Beat', short: 'AV' },
|
||||
];
|
||||
|
||||
@@ -218,7 +218,7 @@ export default function AdOpsDashboard() {
|
||||
</button>
|
||||
<span className="inline-flex items-center gap-1.5 px-2.5 py-1 rounded-full text-xs font-medium bg-orange-900/50 text-orange-300 border border-orange-700">
|
||||
<span className="w-1.5 h-1.5 rounded-full bg-orange-400" />
|
||||
adops@broadcastbeat.com
|
||||
adops@avbeat.com
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -191,9 +191,9 @@ const QUICK_ACTIONS = [
|
||||
];
|
||||
|
||||
const QUICK_ACTION_TEMPLATES: Record<string, string> = {
|
||||
url_story: `Write a news story for [Broadcast Beat / AV Beat] based on this URL: [URL]. Use the byline [pen name]. Target length: [400-600] words. Focus angle: [product launch / company news / industry trend].`,
|
||||
url_story: `Write a news story for [AV Beat / AV Beat] based on this URL: [URL]. Use the byline [pen name]. Target length: [400-600] words. Focus angle: [product launch / company news / industry trend].`,
|
||||
exhibitor_preview: `Write a pre-show exhibitor preview for [company name] at [NAB Show / InfoComm] [year]. They will be showing [product/technology]. Booth: [number if known]. Use [pen name] byline. 400-500 words.`,
|
||||
press_release: `Rewrite the following press release as a real news story for [Broadcast Beat / AV Beat]. Remove marketing language, lead with the news hook, add industry context. Byline: [pen name].
|
||||
press_release: `Rewrite the following press release as a real news story for [AV Beat / AV Beat]. Remove marketing language, lead with the news hook, add industry context. Byline: [pen name].
|
||||
|
||||
[PASTE PRESS RELEASE HERE]`,
|
||||
nab_story: `Write a [story type: preview / announcement / recap] story about [topic/company] for NAB Show [year]. Include relevant SEO keywords. Byline: James Mercer. [400-800] words.`,
|
||||
@@ -203,7 +203,7 @@ Story headline: [HEADLINE]
|
||||
Story summary: [SUMMARY]`,
|
||||
headlines: `Generate 8 headline options for this story. Include 2 SEO-optimized versions targeting [keyword], 2 social media-friendly versions, 2 trade publication style versions, and 2 alternatives. Story summary: [SUMMARY]`,
|
||||
translate: `Translate the following story into [language]. Maintain the professional trade publication tone. Keep technical terms in their internationally recognized form. [PASTE STORY HERE]`,
|
||||
company_bio: `Write a 150-word company bio for [company name] suitable for use as a boilerplate paragraph at the end of news stories on [Broadcast Beat / AV Beat]. The company makes [products/services]. Website: [URL].`,
|
||||
company_bio: `Write a 150-word company bio for [company name] suitable for use as a boilerplate paragraph at the end of news stories on [AV Beat / AV Beat]. The company makes [products/services]. Website: [URL].`,
|
||||
product_desc: `Write a 200-word product description for [product name] by [company]. Key features: [features]. Target audience: [integrators / broadcast engineers / etc]. Suitable for use in a product announcement story.`,
|
||||
};
|
||||
|
||||
@@ -243,7 +243,7 @@ function DraftPreviewModal({ content, title, penName, siteId, onClose, onSave }:
|
||||
<div className="flex items-center justify-between px-5 py-4 border-b border-[#1e2a3a]">
|
||||
<div>
|
||||
<h2 className="text-white font-semibold text-sm">Draft Preview</h2>
|
||||
<p className="text-[#555] text-xs mt-0.5">Review before saving to {siteId === 1 ? 'Broadcast Beat' : 'AV Beat'}</p>
|
||||
<p className="text-[#555] text-xs mt-0.5">Review before saving to {siteId === 1 ? 'AV Beat' : 'AV Beat'}</p>
|
||||
</div>
|
||||
<button onClick={onClose} className="text-[#555] hover:text-white transition-colors text-lg leading-none">✕</button>
|
||||
</div>
|
||||
@@ -256,7 +256,7 @@ function DraftPreviewModal({ content, title, penName, siteId, onClose, onSave }:
|
||||
<div className="flex items-center gap-2">
|
||||
<span className="text-[#555] text-xs">Site:</span>
|
||||
<span className={`text-xs font-bold px-1.5 py-0.5 rounded ${siteId === 2 ? 'bg-orange-900/40 text-orange-400' : 'bg-blue-900/40 text-blue-400'}`}>
|
||||
{siteId === 2 ? 'AV Beat' : 'Broadcast Beat'}
|
||||
{siteId === 2 ? 'AV Beat' : 'AV Beat'}
|
||||
</span>
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
@@ -487,7 +487,7 @@ function StyleGuidesPanel({ onClose, onSelectPenName }: StyleGuidesPanelProps) {
|
||||
onClick={() => setFilterSite(f)}
|
||||
className={`text-xs px-2.5 py-1 rounded transition-colors ${filterSite === f ? 'bg-[#3b82f6] text-white' : 'bg-[#1e2a3a] text-[#aaa] hover:text-white'}`}
|
||||
>
|
||||
{f === 'ALL' ? 'All Writers' : f === 'BB' ? 'Broadcast Beat' : 'AV Beat'}
|
||||
{f === 'ALL' ? 'All Writers' : f === 'BB' ? 'AV Beat' : 'AV Beat'}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
@@ -670,7 +670,7 @@ export default function AIConsolePage() {
|
||||
const penNames = selectedSite === 1 ? BB_PEN_NAMES : AV_PEN_NAMES;
|
||||
|
||||
const buildSystemPrompt = () => {
|
||||
const siteName = selectedSite === 1 ? 'Broadcast Beat' : 'AV Beat';
|
||||
const siteName = selectedSite === 1 ? 'AV Beat' : 'AV Beat';
|
||||
const siteDesc = selectedSite === 1
|
||||
? 'a professional B2B trade publication for broadcast engineers, production professionals, and industry executives'
|
||||
: 'a professional B2B trade publication for AV integrators, technology managers, and AV industry professionals';
|
||||
@@ -1068,7 +1068,7 @@ Respond conversationally and helpfully. If asked to write a story, write the ful
|
||||
onChange={e => setSelectedSite(Number(e.target.value) as 1 | 2)}
|
||||
className="bg-[#1e2a3a] border border-[#2a3a50] text-white text-xs rounded px-2 py-1 focus:outline-none focus:border-[#3b82f6]"
|
||||
>
|
||||
<option value={1}>Broadcast Beat</option>
|
||||
<option value={1}>AV Beat</option>
|
||||
<option value={2}>AV Beat</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
@@ -303,12 +303,12 @@ export default function AIConsoleSettingsPage() {
|
||||
onChange={e => update('default_site_id', Number(e.target.value))}
|
||||
className="w-full bg-[#0d1117] border border-[#2a3a50] text-white text-sm rounded-lg px-3 py-2.5 focus:outline-none focus:border-[#3b82f6]"
|
||||
>
|
||||
<option value={1}>Broadcast Beat</option>
|
||||
<option value={1}>AV Beat</option>
|
||||
<option value={2}>AV Beat</option>
|
||||
</select>
|
||||
</div>
|
||||
<div>
|
||||
<label className="block text-[#aaa] text-xs font-medium mb-1.5">Default Pen Name (Broadcast Beat)</label>
|
||||
<label className="block text-[#aaa] text-xs font-medium mb-1.5">Default Pen Name (AV Beat)</label>
|
||||
<select
|
||||
value={settings.default_pen_name_bb}
|
||||
onChange={e => update('default_pen_name_bb', e.target.value)}
|
||||
|
||||
@@ -256,7 +256,7 @@ export default function ShowCalendarPage() {
|
||||
if (loading) {
|
||||
return (
|
||||
<div className="min-h-screen bg-[#0a0a0a] flex items-center justify-center">
|
||||
<div className="w-8 h-8 border-2 border-[#E67E22] border-t-transparent rounded-full animate-spin" />
|
||||
<div className="w-8 h-8 border-2 border-[#3b82f6] border-t-transparent rounded-full animate-spin" />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -294,7 +294,7 @@ export default function ShowCalendarPage() {
|
||||
<div className="flex items-center gap-3">
|
||||
<button
|
||||
onClick={() => { setEditingEvent({ site_id: 1, year: new Date().getFullYear(), seo_tier: 3, event_type: 'trade_show' }); setShowEventModal(true); }}
|
||||
className="px-3 py-1.5 bg-[#E67E22] hover:bg-blue-500 text-white text-sm rounded-lg transition-colors"
|
||||
className="px-3 py-1.5 bg-[#3b82f6] hover:bg-blue-500 text-white text-sm rounded-lg transition-colors"
|
||||
>
|
||||
+ Add Event
|
||||
</button>
|
||||
@@ -316,7 +316,7 @@ export default function ShowCalendarPage() {
|
||||
onClick={() => setSiteFilter(s)}
|
||||
className={`px-3 py-1 rounded text-xs font-medium transition-colors ${
|
||||
siteFilter === s
|
||||
? 'bg-[#E67E22] text-white'
|
||||
? 'bg-[#3b82f6] text-white'
|
||||
: 'bg-[#1a1a1a] text-[#888] hover:text-white border border-[#333]'
|
||||
}`}
|
||||
>
|
||||
@@ -333,7 +333,7 @@ export default function ShowCalendarPage() {
|
||||
onClick={() => setActiveTab(tab.id)}
|
||||
className={`px-4 py-2 text-sm font-medium transition-colors border-b-2 -mb-px ${
|
||||
activeTab === tab.id
|
||||
? 'border-[#E67E22] text-white'
|
||||
? 'border-[#3b82f6] text-white'
|
||||
: 'border-transparent text-[#666] hover:text-white'
|
||||
}`}
|
||||
>
|
||||
@@ -347,7 +347,7 @@ export default function ShowCalendarPage() {
|
||||
<div className="max-w-7xl mx-auto px-4 py-6">
|
||||
{loadingData ? (
|
||||
<div className="flex items-center justify-center py-20">
|
||||
<div className="w-8 h-8 border-2 border-[#E67E22] border-t-transparent rounded-full animate-spin" />
|
||||
<div className="w-8 h-8 border-2 border-[#3b82f6] border-t-transparent rounded-full animate-spin" />
|
||||
</div>
|
||||
) : (
|
||||
<>
|
||||
@@ -383,7 +383,7 @@ export default function ShowCalendarPage() {
|
||||
<span>Engine: {formatDate(event.story_engine_start_date)} – {formatDate(event.story_engine_end_date)}</span>
|
||||
{event.official_site && (
|
||||
<a href={`https://${event.official_site}`} target="_blank" rel="noopener noreferrer"
|
||||
className="text-[#E67E22] hover:underline">{event.official_site}</a>
|
||||
className="text-[#3b82f6] hover:underline">{event.official_site}</a>
|
||||
)}
|
||||
</div>
|
||||
<div className="flex items-center gap-3 mt-2 text-xs text-[#555]">
|
||||
@@ -440,7 +440,7 @@ export default function ShowCalendarPage() {
|
||||
onClick={() => setQueueStatus(s)}
|
||||
className={`px-3 py-1 rounded text-xs font-medium transition-colors ${
|
||||
queueStatus === s
|
||||
? 'bg-[#E67E22] text-white'
|
||||
? 'bg-[#3b82f6] text-white'
|
||||
: 'bg-[#1a1a1a] text-[#888] hover:text-white border border-[#333]'
|
||||
}`}
|
||||
>
|
||||
@@ -779,7 +779,7 @@ export default function ShowCalendarPage() {
|
||||
<button
|
||||
type="submit"
|
||||
disabled={actionLoading === 'save-event'}
|
||||
className="flex-1 py-2 bg-[#E67E22] hover:bg-blue-500 text-white text-sm rounded-lg transition-colors disabled:opacity-50"
|
||||
className="flex-1 py-2 bg-[#3b82f6] hover:bg-blue-500 text-white text-sm rounded-lg transition-colors disabled:opacity-50"
|
||||
>
|
||||
{actionLoading === 'save-event' ? 'Saving...' : 'Save Event'}
|
||||
</button>
|
||||
@@ -857,7 +857,7 @@ export default function ShowCalendarPage() {
|
||||
<button
|
||||
type="submit"
|
||||
disabled={actionLoading === 'generate'}
|
||||
className="flex-1 py-2 bg-[#E67E22] hover:bg-blue-500 text-white text-sm rounded-lg transition-colors disabled:opacity-50"
|
||||
className="flex-1 py-2 bg-[#3b82f6] hover:bg-blue-500 text-white text-sm rounded-lg transition-colors disabled:opacity-50"
|
||||
>
|
||||
{actionLoading === 'generate' ? 'Generating...' : 'Generate Story'}
|
||||
</button>
|
||||
|
||||
Reference in New Issue
Block a user