mirror of
https://github.com/hanzoai/bootnode.git
synced 2026-09-30 20:46:32 +00:00
Names the two halves for what they are. The repo already holds both (12407e9 merged bootnode/bootnode into this history); this makes the frontend directory say so, so the layout reads the way the owner describes the system: backend and frontend separate, one repo. git mv throughout — 187 renames, history preserved. Every path reference follows: hanzo.yml build context and dockerfile, compose.yml, compose.prod.yml, start.sh, LLM.md, infra/k8s/web-deployments.yaml, infra/cloud/deploy.sh, and the Dockerfile's own COPY paths. Image and container names (bootnode-web, the -web tag suffix) are deliberately NOT renamed here: those are a deploy contract the App CR and ingress bind to on port 3001, and breaking them is a separate, staged change. Console builds green after the move; the Go tree builds. Co-authored-by: Hanzo Dev <[email protected]>
100 lines
3.2 KiB
TypeScript
100 lines
3.2 KiB
TypeScript
"use client"
|
|
|
|
import Image from "next/image"
|
|
import { useEffect, useState } from "react"
|
|
import { useBrand } from "@/components/brand-provider"
|
|
import { cn } from "@/lib/utils"
|
|
|
|
// Re-exported so existing importers of `@/components/brand-logo` keep working;
|
|
// the hook itself lives in brand-provider.tsx.
|
|
export { useBrand }
|
|
|
|
const MARK = { small: 18, default: 22, large: 30 } as const
|
|
const WORD = { small: "text-base", default: "text-lg", large: "text-2xl" } as const
|
|
|
|
/**
|
|
* The brand lockup: mark plus wordmark, white-labelled by hostname.
|
|
*
|
|
* lux.cloud's signature move is here — the wordmark retracts a couple of
|
|
* seconds after load and returns on hover, so the mark holds the corner and
|
|
* the nav gets the width back. It is a width transition on an overflow-hidden
|
|
* span, not a mount/unmount, so nothing reflows abruptly and the accessible
|
|
* name never disappears.
|
|
*
|
|
* The mark is the brand's own asset (public/logo/<brand>-icon.svg), not a
|
|
* shared placeholder, so bootno.de, lux.cloud and zoo.cloud each render their
|
|
* own mark from the one build.
|
|
*/
|
|
export function BrandLogo({
|
|
showText = true,
|
|
size = "default",
|
|
collapsible = false,
|
|
className = "",
|
|
}: {
|
|
showText?: boolean
|
|
size?: "small" | "default" | "large"
|
|
/** Retract the wordmark after load, revealing it on hover (header use). */
|
|
collapsible?: boolean
|
|
className?: string
|
|
}) {
|
|
const brand = useBrand()
|
|
const [collapsed, setCollapsed] = useState(false)
|
|
|
|
useEffect(() => {
|
|
if (!collapsible) return
|
|
const t = setTimeout(() => setCollapsed(true), 2500)
|
|
return () => clearTimeout(t)
|
|
}, [collapsible])
|
|
|
|
const px = MARK[size]
|
|
|
|
return (
|
|
<span className={cn("group inline-flex items-center gap-2", className)}>
|
|
{brand.monoMark ? (
|
|
// A single-colour mark is painted in the CURRENT TEXT COLOUR, so it is
|
|
// legible in both themes and always matches the wordmark beside it —
|
|
// the same thing lux.cloud does with its pyramid. An <img> cannot do
|
|
// this: it is an isolated document, so a `fill="currentColor"` mark
|
|
// resolves to black and disappears on a black page.
|
|
<span
|
|
role="img"
|
|
aria-label={brand.name}
|
|
style={{
|
|
width: px,
|
|
height: px,
|
|
maskImage: `url(${brand.logoIcon})`,
|
|
WebkitMaskImage: `url(${brand.logoIcon})`,
|
|
maskSize: "contain",
|
|
WebkitMaskSize: "contain",
|
|
maskRepeat: "no-repeat",
|
|
WebkitMaskRepeat: "no-repeat",
|
|
maskPosition: "center",
|
|
WebkitMaskPosition: "center",
|
|
}}
|
|
className="shrink-0 bg-current"
|
|
/>
|
|
) : (
|
|
<Image
|
|
src={brand.logoIcon}
|
|
alt={brand.name}
|
|
width={px}
|
|
height={px}
|
|
style={{ width: px, height: px }}
|
|
className="shrink-0"
|
|
/>
|
|
)}
|
|
{showText && (
|
|
<span
|
|
className={cn(
|
|
"inline-block overflow-hidden whitespace-nowrap font-medium tracking-tight transition-[max-width,opacity] duration-300 ease-out group-hover:max-w-40 group-hover:opacity-100",
|
|
WORD[size],
|
|
collapsed ? "max-w-0 opacity-0" : "max-w-40 opacity-100"
|
|
)}
|
|
>
|
|
{brand.name}
|
|
</span>
|
|
)}
|
|
</span>
|
|
)
|
|
}
|