Files
bootnode/web/components/brand-logo.tsx
zooqueenandHanzo Dev 95d9ac6fa9 web: decomplect brand into runtime white-label config
Remove the hardcoded 5-brand catalog from web/lib/brand.ts; resolve the
active brand at runtime by hostname from an external catalog
(window.__BRAND_CATALOG__ / /config.json), mirroring the @hanzo/id SPA.
Ship one neutral built-in bootnode fallback. Add BrandProvider that loads
the per-deploy catalog client-side after hydration.

Co-authored-by: Hanzo Dev <[email protected]>
2026-06-17 00:10:05 -07:00

113 lines
2.5 KiB
TypeScript

"use client"
import Image from "next/image"
import { useEffect, useState } from "react"
import { useTheme } from "next-themes"
import { getBrand } from "@/lib/brand"
import { useBrand } from "@/components/brand-provider"
// Re-export the brand hook so existing importers (`@/components/brand-logo`)
// keep working. Single source of truth lives in brand-provider.tsx.
export { useBrand }
// Brand Logo Component - theme-aware and white-label ready
export function BrandLogo({
showText = true,
size = "default",
className = ""
}: {
showText?: boolean
size?: "small" | "default" | "large"
className?: string
}) {
const brand = useBrand()
const { resolvedTheme } = useTheme()
const [mounted, setMounted] = useState(false)
useEffect(() => {
setMounted(true)
}, [])
const sizeClasses = {
small: "h-5 w-5",
default: "h-6 w-6",
large: "h-8 w-8",
}
const textSizes = {
small: "text-lg",
default: "text-xl",
large: "text-2xl",
}
const pixelSizes = {
small: 20,
default: 24,
large: 32,
}
// Use white logo for dark mode, default logo for light mode
const logoSrc = mounted && resolvedTheme === "dark" ? brand.logoWhite : brand.logo
return (
<div className={`flex items-center space-x-2 ${className}`}>
<Image
src={brand.logoIcon}
alt={brand.name}
width={pixelSizes[size]}
height={pixelSizes[size]}
className={sizeClasses[size]}
/>
{showText && (
<span className={`font-bold ${textSizes[size]}`}>{brand.name}</span>
)}
</div>
)
}
// Full logo (icon + text as image if available)
export function BrandLogoFull({
size = "default",
className = ""
}: {
size?: "small" | "default" | "large"
className?: string
}) {
const brand = useBrand()
const { resolvedTheme } = useTheme()
const [mounted, setMounted] = useState(false)
useEffect(() => {
setMounted(true)
}, [])
const heights = {
small: 24,
default: 32,
large: 40,
}
// Use white logo for dark mode
const logoSrc = mounted && resolvedTheme === "dark" ? brand.logoWhite : brand.logo
return (
<Image
src={logoSrc}
alt={brand.name}
width={heights[size] * 4}
height={heights[size]}
className={className}
/>
)
}
// Export brand name helper for SSR-safe usage
export function getBrandName(): string {
return getBrand().name
}
// Export brand tagline
export function getBrandTagline(): string {
return getBrand().tagline
}