feat(brand): AV BEAT 2026 rebrand — blue/navy/white identity

- New AvBeatLogo inline-SVG component (rounded-square emblem with
  forward-leaning AV monogram + horizontal beam detail) at
  src/components/AvBeatLogo.tsx, three variants (full/wordmark/icon).
- Header.tsx now uses the responsive AV BEAT logo lockup in the
  top-left, links to /, full lockup on desktop (emblem+wordmark+tagline),
  emblem+wordmark on tablet, emblem-only on mobile.
- Removed DualSpeedTicker (the 'RECENT FORUM POSTS' ticker strip);
  the news ticker / glow chrome does not match the new aesthetic and the
  forum row was the explicit removal target.
- Tailwind theme + globals.css now expose the AV BEAT 2026 palette as
  semantic tokens: --brand-blue (#1D4ED8), --brand-blue-bright (#38BDF8),
  --brand-navy (#0F172A), --brand-bg (#F8FAFC), --brand-surface, --brand-border,
  --brand-text, --brand-text-muted. Legacy --color-* aliases re-point to the
  new tokens so any inline-styled component re-themes for free.
- Site-wide hex sweep migrates 2,769 hardcoded color literals across 144
  files from the old dark-broadcast palette to the new tokens (orange
  -> blue, dark-brown -> white surface / navy text, cream -> navy).
- Layout body class flipped from 'bb-neon' to 'bg-brand-bg text-brand-text'
  so the dark glow chrome no longer leaks through the new light theme.
This commit is contained in:
2026-06-03 12:07:18 +00:00
parent 39d2bf9073
commit 8042024c4a
146 changed files with 2219 additions and 2081 deletions

View File

@@ -75,7 +75,7 @@ function DomainsContent() {
load();
}
if (loading) return <div className="min-h-screen bg-[#0a0a0a] flex items-center justify-center"><div className="w-8 h-8 border-2 border-[#F0A623] border-t-transparent rounded-full animate-spin" /></div>;
if (loading) return <div className="min-h-screen bg-[#0a0a0a] flex items-center justify-center"><div className="w-8 h-8 border-2 border-[#1D4ED8] border-t-transparent rounded-full animate-spin" /></div>;
if (!user) return null;
return (
@@ -86,41 +86,41 @@ function DomainsContent() {
<h1 className="text-xl font-bold">Sending Domains</h1>
<Link href="/admin/email" className="text-xs text-[#555] hover:text-[#888]"> Email</Link>
</div>
<button onClick={() => setShowAddForm(true)} className="px-3 py-1.5 bg-[#F0A623] rounded text-xs font-medium hover:bg-blue-500">+ Add Domain</button>
<button onClick={() => setShowAddForm(true)} className="px-3 py-1.5 bg-[#1D4ED8] rounded text-xs font-medium hover:bg-blue-500">+ Add Domain</button>
</div>
<div className="flex gap-2">
<select value={filterSite} onChange={e => setFilterSite(e.target.value)} className="px-2 py-1 bg-[#111] border border-[#3a322b] rounded text-xs text-[#888] focus:outline-none">
<select value={filterSite} onChange={e => setFilterSite(e.target.value)} className="px-2 py-1 bg-[#111] border border-[#DCE6F2] rounded text-xs text-[#888] focus:outline-none">
<option value="">All Sites</option>
{SITES.map(s => <option key={s} value={s}>{s}</option>)}
</select>
</div>
{showAddForm && (
<form onSubmit={handleAddDomain} className="bg-[#111] border border-[#3a322b] rounded-lg p-4 space-y-3">
<form onSubmit={handleAddDomain} className="bg-[#111] border border-[#DCE6F2] rounded-lg p-4 space-y-3">
<h3 className="text-sm font-semibold">Add Rotation Domain</h3>
<div className="grid grid-cols-2 gap-3">
<div>
<label className="text-xs text-[#888] block mb-1">Site *</label>
<select required value={addForm.site} onChange={e => setAddForm(p => ({ ...p, site: e.target.value }))} className="w-full px-2 py-1.5 bg-[#0a0a0a] border border-[#3a322b] rounded text-xs text-white focus:outline-none">
<select required value={addForm.site} onChange={e => setAddForm(p => ({ ...p, site: e.target.value }))} className="w-full px-2 py-1.5 bg-[#0a0a0a] border border-[#DCE6F2] rounded text-xs text-white focus:outline-none">
<option value="">Select</option>
{SITES.map(s => <option key={s} value={s}>{s}</option>)}
</select>
</div>
<div>
<label className="text-xs text-[#888] block mb-1">Domain *</label>
<input required value={addForm.domain} onChange={e => setAddForm(p => ({ ...p, domain: e.target.value }))} placeholder="mail.example.com" className="w-full px-2 py-1.5 bg-[#0a0a0a] border border-[#3a322b] rounded text-xs text-white focus:outline-none focus:border-[#F0A623]" />
<input required value={addForm.domain} onChange={e => setAddForm(p => ({ ...p, domain: e.target.value }))} placeholder="mail.example.com" className="w-full px-2 py-1.5 bg-[#0a0a0a] border border-[#DCE6F2] rounded text-xs text-white focus:outline-none focus:border-[#1D4ED8]" />
</div>
<div>
<label className="text-xs text-[#888] block mb-1">Type</label>
<select value={addForm.domain_type} onChange={e => setAddForm(p => ({ ...p, domain_type: e.target.value }))} className="w-full px-2 py-1.5 bg-[#0a0a0a] border border-[#3a322b] rounded text-xs text-white focus:outline-none">
<select value={addForm.domain_type} onChange={e => setAddForm(p => ({ ...p, domain_type: e.target.value }))} className="w-full px-2 py-1.5 bg-[#0a0a0a] border border-[#DCE6F2] rounded text-xs text-white focus:outline-none">
{['subdomain','sister_domain','primary'].map(t => <option key={t} value={t}>{t}</option>)}
</select>
</div>
</div>
<div className="flex gap-2">
<button type="submit" disabled={saving} className="px-3 py-1.5 bg-[#F0A623] rounded text-xs font-medium hover:bg-blue-500 disabled:opacity-50">{saving ? 'Saving…' : 'Add Domain'}</button>
<button type="button" onClick={() => setShowAddForm(false)} className="px-3 py-1.5 bg-[#231d18] border border-[#3a322b] rounded text-xs text-[#888] hover:text-white">Cancel</button>
<button type="submit" disabled={saving} className="px-3 py-1.5 bg-[#1D4ED8] rounded text-xs font-medium hover:bg-blue-500 disabled:opacity-50">{saving ? 'Saving…' : 'Add Domain'}</button>
<button type="button" onClick={() => setShowAddForm(false)} className="px-3 py-1.5 bg-[#FFFFFF] border border-[#DCE6F2] rounded text-xs text-[#888] hover:text-white">Cancel</button>
</div>
</form>
)}
@@ -131,10 +131,10 @@ function DomainsContent() {
<div className="bg-[#111] border border-yellow-400/30 rounded-lg p-5 w-80 space-y-3">
<h3 className="text-sm font-semibold text-yellow-400"> Override DNS Verification</h3>
<p className="text-xs text-[#888]">This allows sending before DNS is verified. Use with caution.</p>
<textarea value={bypassReason} onChange={e => setBypassReason(e.target.value)} placeholder="Reason for bypass…" rows={3} className="w-full px-2 py-1.5 bg-[#0a0a0a] border border-[#3a322b] rounded text-xs text-white focus:outline-none" />
<textarea value={bypassReason} onChange={e => setBypassReason(e.target.value)} placeholder="Reason for bypass…" rows={3} className="w-full px-2 py-1.5 bg-[#0a0a0a] border border-[#DCE6F2] rounded text-xs text-white focus:outline-none" />
<div className="flex gap-2">
<button onClick={() => setBypass(showBypass)} disabled={!bypassReason} className="px-3 py-1.5 bg-yellow-600 rounded text-xs font-medium hover:bg-yellow-500 disabled:opacity-50">Set Bypass</button>
<button onClick={() => setShowBypass(null)} className="px-3 py-1.5 bg-[#231d18] border border-[#3a322b] rounded text-xs text-[#888] hover:text-white">Cancel</button>
<button onClick={() => setShowBypass(null)} className="px-3 py-1.5 bg-[#FFFFFF] border border-[#DCE6F2] rounded text-xs text-[#888] hover:text-white">Cancel</button>
</div>
</div>
</div>
@@ -142,12 +142,12 @@ function DomainsContent() {
<div className="space-y-2">
{loadingData ? (
<div className="bg-[#111] border border-[#3a322b] rounded-lg p-8 text-center text-[#555] text-xs">Loading</div>
<div className="bg-[#111] border border-[#DCE6F2] rounded-lg p-8 text-center text-[#555] text-xs">Loading</div>
) : domains.length === 0 ? (
<div className="bg-[#111] border border-[#3a322b] rounded-lg p-8 text-center text-[#555] text-xs">No domains found</div>
<div className="bg-[#111] border border-[#DCE6F2] rounded-lg p-8 text-center text-[#555] text-xs">No domains found</div>
) : domains.map((d: any) => (
<div key={d.id} className="bg-[#111] border border-[#3a322b] rounded-lg overflow-hidden">
<div className="px-4 py-3 flex items-center gap-3 cursor-pointer hover:bg-[#231d18]" onClick={() => setExpanded(expanded === d.id ? null : d.id)}>
<div key={d.id} className="bg-[#111] border border-[#DCE6F2] rounded-lg overflow-hidden">
<div className="px-4 py-3 flex items-center gap-3 cursor-pointer hover:bg-[#FFFFFF]" onClick={() => setExpanded(expanded === d.id ? null : d.id)}>
<div className="flex-1 min-w-0">
<div className="flex items-center gap-2 flex-wrap">
<span className="text-sm font-medium text-white">{d.domain}</span>
@@ -156,7 +156,7 @@ function DomainsContent() {
<span className={`px-1.5 py-0.5 rounded text-xs ${d.dns_fully_verified ? 'bg-green-400/10 text-green-400' : 'bg-yellow-400/10 text-yellow-400'}`}>{d.dns_fully_verified ? 'DNS OK' : 'DNS Pending'}</span>
{d.blacklisted && <span className="px-1.5 py-0.5 bg-red-400/10 text-red-400 rounded text-xs">Blacklisted</span>}
{d.bypass_verification && <span className="px-1.5 py-0.5 bg-yellow-400/10 text-yellow-400 rounded text-xs">Bypass Active</span>}
<span className={`px-1.5 py-0.5 rounded text-xs ${d.is_active ? 'bg-green-400/10 text-green-400' : 'bg-[#231d18] text-[#555]'}`}>{d.is_active ? 'Active' : 'Inactive'}</span>
<span className={`px-1.5 py-0.5 rounded text-xs ${d.is_active ? 'bg-green-400/10 text-green-400' : 'bg-[#FFFFFF] text-[#555]'}`}>{d.is_active ? 'Active' : 'Inactive'}</span>
</div>
<div className="flex gap-3 mt-1 text-xs text-[#555]">
<span>Health: {d.health_score}/100</span>
@@ -167,7 +167,7 @@ function DomainsContent() {
</div>
{expanded === d.id && (
<div className="border-t border-[#231d18] px-4 py-3 space-y-3">
<div className="border-t border-[#FFFFFF] px-4 py-3 space-y-3">
{/* DNS checks */}
<div className="grid grid-cols-2 gap-x-6">
<DnsRow label="SPF" valid={d.spf_valid} checkedAt={d.spf_checked_at} />
@@ -178,7 +178,7 @@ function DomainsContent() {
</div>
{/* DNS helper panel */}
<div className="bg-[#0a0a0a] border border-[#231d18] rounded p-3 space-y-2">
<div className="bg-[#0a0a0a] border border-[#FFFFFF] rounded p-3 space-y-2">
<p className="text-xs font-semibold text-[#888]">DNS Record Helper (GoDaddy)</p>
<div className="space-y-1 text-xs text-[#555] font-mono">
<p>SPF: <span className="text-[#888]">v=spf1 include:sendgrid.net ~all</span></p>
@@ -197,10 +197,10 @@ function DomainsContent() {
{/* Actions */}
<div className="flex gap-2 flex-wrap">
<button onClick={() => runVerify(d.id)} disabled={verifying === d.id} className="px-3 py-1.5 bg-[#231d18] border border-[#2a3a50] rounded text-xs text-[#F0A623] hover:bg-[#0d1a2d] disabled:opacity-50">
<button onClick={() => runVerify(d.id)} disabled={verifying === d.id} className="px-3 py-1.5 bg-[#FFFFFF] border border-[#2a3a50] rounded text-xs text-[#1D4ED8] hover:bg-[#0d1a2d] disabled:opacity-50">
{verifying === d.id ? 'Verifying…' : 'Run Full Verification'}
</button>
<button onClick={() => toggleActive(d.id, d.is_active)} disabled={!d.dns_fully_verified && !d.bypass_verification && !d.is_active} className="px-3 py-1.5 bg-[#231d18] border border-[#3a322b] rounded text-xs text-[#888] hover:text-white disabled:opacity-30">
<button onClick={() => toggleActive(d.id, d.is_active)} disabled={!d.dns_fully_verified && !d.bypass_verification && !d.is_active} className="px-3 py-1.5 bg-[#FFFFFF] border border-[#DCE6F2] rounded text-xs text-[#888] hover:text-white disabled:opacity-30">
{d.is_active ? 'Deactivate' : 'Activate'}
</button>
<button onClick={() => setShowBypass(d.id)} className="px-3 py-1.5 bg-yellow-900/30 border border-yellow-400/20 rounded text-xs text-yellow-400 hover:bg-yellow-900/50">
@@ -219,7 +219,7 @@ function DomainsContent() {
export default function EmailDomainsPage() {
return (
<Suspense fallback={<div className="min-h-screen bg-[#0a0a0a] flex items-center justify-center"><div className="w-8 h-8 border-2 border-[#F0A623] border-t-transparent rounded-full animate-spin" /></div>}>
<Suspense fallback={<div className="min-h-screen bg-[#0a0a0a] flex items-center justify-center"><div className="w-8 h-8 border-2 border-[#1D4ED8] border-t-transparent rounded-full animate-spin" /></div>}>
<DomainsContent />
</Suspense>
);