From 1148f7a72f146a449cfe756deb57a7ea6950c662 Mon Sep 17 00:00:00 2001 From: muken Date: Sat, 27 Jun 2026 16:44:17 -0500 Subject: [PATCH] Switch navbar to #001321, admin can update logo/favicon, logo links home --- src/app/admin/page.tsx | 121 ++++++++++++++++++++++++++++++- src/app/api/site-assets/route.ts | 35 +++++++++ src/components/Navbar.tsx | 43 +++++++++-- 3 files changed, 192 insertions(+), 7 deletions(-) create mode 100644 src/app/api/site-assets/route.ts diff --git a/src/app/admin/page.tsx b/src/app/admin/page.tsx index e37bdb7..4f002d1 100644 --- a/src/app/admin/page.tsx +++ b/src/app/admin/page.tsx @@ -11,7 +11,7 @@ interface ImageRecord { } const gold = '#E8A849'; -const navy = '#010D1E'; +const navy = '#001321'; const warm = '#a6683c'; export default function AdminPage() { @@ -20,6 +20,9 @@ export default function AdminPage() { const [count, setCount] = useState(0); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); + const [logoUrl, setLogoUrl] = useState(''); + const [faviconUrl, setFaviconUrl] = useState(''); + const [message, setMessage] = useState(null); useEffect(() => { fetch('/api/admin/images', { credentials: 'same-origin' }) @@ -37,8 +40,50 @@ export default function AdminPage() { }) .catch((err) => setError(err.message)) .finally(() => setLoading(false)); + + fetch('/api/site-assets?key=logo') + .then(async (res) => { + if (!res.ok) return; + const data = await res.json(); + if (data.data) setLogoUrl(data.data); + }) + .catch(() => {}); + + fetch('/api/site-assets?key=favicon') + .then(async (res) => { + if (!res.ok) return; + const data = await res.json(); + if (data.data) setFaviconUrl(data.data); + }) + .catch(() => {}); }, [router]); + useEffect(() => { + if (!faviconUrl) return; + let link = document.querySelector("link[rel~='icon']") as HTMLLinkElement | null; + if (!link) { + link = document.createElement('link'); + link.rel = 'icon'; + document.head.appendChild(link); + } + link.href = faviconUrl; + }, [faviconUrl]); + + const updateAsset = async (key: string, value: string) => { + const res = await fetch('/api/site-assets', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ key, value }), + credentials: 'same-origin', + }); + if (!res.ok) { + setError('Failed to save ' + key); + return; + } + setMessage(`${key} updated. Refresh the page to see the change.`); + setTimeout(() => setMessage(null), 4000); + }; + const handleUpload = (e: React.ChangeEvent) => { const files = e.target.files; if (!files) return; @@ -94,6 +139,80 @@ export default function AdminPage() { Total uploaded images: {count}

{error &&

{error}

} + {message &&

{message}

} + +
+

Brand Assets

+
+ + + + + +
+

+ Tip: click an uploaded gallery image to preview, copy its data URL, and paste it above. +

+
+