mirror of
https://github.com/hanzoai/bootnode.git
synced 2026-10-25 02:31:30 +00:00
Hanzo CI/CD / cicd (push) Failing after 1h10m29s
CI/CD / cicd (push) Failing after 2h37m43s
A static export has no host when it prerenders, so BrandProvider renders the
tree only once the browser has resolved the host, pages that show the brand
are client components, the static head names no brand, and the title and
favicon come from the host. The chain page keeps its static params and
metadata on the server and renders its body on the client, with RPC endpoints
on the brand's API origin at /v1/rpc/{chain}/{network}.
Hanzo's API origin is web3.hanzo.ai itself. The node fleet view, its landing
strip and its nav link belong to the brand that operates a fleet, which is
Lux alone. llms.txt, one file for every host, names no brand and points at
each host's own /docs/api.
Marketing copy states no certification the company does not hold and no
unmeasured uptime, latency, volume or response-time figure. Every internal
link points at a page that exists, every catalog chain is prerendered, and
the routes test holds page bodies to zero dead links.
Co-authored-by: Hanzo Dev <[email protected]>
515 lines
22 KiB
TypeScript
515 lines
22 KiB
TypeScript
"use client"
|
|
|
|
import { useEffect, useRef, useState } from "react"
|
|
import Link from "next/link"
|
|
import { cn } from "@/lib/utils"
|
|
import { Button } from "@/components/ui/button"
|
|
import {
|
|
ArrowRight,
|
|
Database,
|
|
Globe,
|
|
KeyRound,
|
|
Layers,
|
|
Menu,
|
|
Search,
|
|
Wallet,
|
|
Webhook,
|
|
X,
|
|
Shield,
|
|
Building2,
|
|
Zap,
|
|
Code2,
|
|
Blocks,
|
|
BarChart3,
|
|
Server,
|
|
Bot,
|
|
Lock,
|
|
Cpu,
|
|
Network,
|
|
Coins,
|
|
FileText,
|
|
BookOpen,
|
|
GraduationCap,
|
|
GitBranch,
|
|
MessageCircle,
|
|
LifeBuoy,
|
|
Activity,
|
|
} from "@luxfi/ui/icons"
|
|
import { OrgSwitcher, UserMenu } from "@luxfi/ui"
|
|
|
|
import { BrandLogo } from "@/components/brand-logo"
|
|
import { useBrand } from "@/components/brand-provider"
|
|
import { CommandMenu } from "@/components/command-menu"
|
|
import { NavMenu } from "@/components/nav-menu"
|
|
import { useAuth } from "@/lib/auth"
|
|
import { getSdkPackage } from "@/lib/sdk-package"
|
|
|
|
// Reusable icon link for mega-menu items
|
|
function IconLink({
|
|
href,
|
|
icon: Icon,
|
|
label,
|
|
description,
|
|
closeMenu,
|
|
}: {
|
|
href: string
|
|
icon: React.ElementType
|
|
label: string
|
|
description?: string
|
|
closeMenu: () => void
|
|
}) {
|
|
return (
|
|
<Link href={href} onClick={closeMenu} className="block">
|
|
<div className="group flex items-start gap-2 py-1">
|
|
<Icon className="h-3.5 w-3.5 mt-0.5 text-muted-foreground group-hover:text-foreground transition-colors flex-shrink-0" />
|
|
<div>
|
|
<span className="text-sm text-foreground/80 group-hover:text-foreground transition-colors">
|
|
{label}
|
|
</span>
|
|
{description && (
|
|
<p className="text-xs text-muted-foreground">{description}</p>
|
|
)}
|
|
</div>
|
|
</div>
|
|
</Link>
|
|
)
|
|
}
|
|
|
|
// Products mega-menu content
|
|
function ProductsContent({ closeMenu }: { closeMenu: () => void }) {
|
|
const brand = useBrand()
|
|
const { pkg: sdkPackage } = getSdkPackage()
|
|
return (
|
|
<div className="w-full">
|
|
{/* Featured hero cards */}
|
|
<div className="mb-4 pb-4 border-b border-border">
|
|
<div className="grid grid-cols-3 gap-3">
|
|
<Link
|
|
href="/products/node"
|
|
onClick={closeMenu}
|
|
className="group flex items-start gap-3 p-3 rounded-xl bg-gradient-to-br from-blue-500/5 to-cyan-500/5 border border-border hover:border-blue-500/30 transition-all"
|
|
>
|
|
<div className="w-9 h-9 rounded-lg bg-blue-500/10 flex items-center justify-center flex-shrink-0">
|
|
<Globe className="h-5 w-5 text-blue-500" />
|
|
</div>
|
|
<div className="flex-1 min-w-0">
|
|
<div className="flex items-center justify-between">
|
|
<span className="text-sm font-semibold text-foreground">
|
|
Node (RPC)
|
|
</span>
|
|
<ArrowRight className="h-3.5 w-3.5 text-muted-foreground/40 group-hover:text-muted-foreground transition-colors" />
|
|
</div>
|
|
<p className="text-xs text-muted-foreground leading-snug mt-0.5">
|
|
Multi-chain JSON-RPC behind one API key
|
|
</p>
|
|
</div>
|
|
</Link>
|
|
<Link
|
|
href="/products/explorer"
|
|
onClick={closeMenu}
|
|
className="group flex items-start gap-3 p-3 rounded-xl bg-gradient-to-br from-emerald-500/5 to-teal-500/5 border border-border hover:border-emerald-500/30 transition-all"
|
|
>
|
|
<div className="w-9 h-9 rounded-lg bg-emerald-500/10 flex items-center justify-center flex-shrink-0">
|
|
<Search className="h-5 w-5 text-emerald-500" />
|
|
</div>
|
|
<div className="flex-1 min-w-0">
|
|
<div className="flex items-center justify-between">
|
|
<span className="text-sm font-semibold text-foreground">
|
|
Explorer
|
|
</span>
|
|
<ArrowRight className="h-3.5 w-3.5 text-muted-foreground/40 group-hover:text-muted-foreground transition-colors" />
|
|
</div>
|
|
<p className="text-xs text-muted-foreground leading-snug mt-0.5">
|
|
Deploy your own branded block explorer
|
|
</p>
|
|
</div>
|
|
</Link>
|
|
<Link
|
|
href="/products/mpc"
|
|
onClick={closeMenu}
|
|
className="group flex items-start gap-3 p-3 rounded-xl bg-gradient-to-br from-violet-500/5 to-purple-500/5 border border-border hover:border-violet-500/30 transition-all"
|
|
>
|
|
<div className="w-9 h-9 rounded-lg bg-violet-500/10 flex items-center justify-center flex-shrink-0">
|
|
<KeyRound className="h-5 w-5 text-violet-500" />
|
|
</div>
|
|
<div className="flex-1 min-w-0">
|
|
<div className="flex items-center justify-between">
|
|
<span className="text-sm font-semibold text-foreground">
|
|
MPC
|
|
</span>
|
|
<ArrowRight className="h-3.5 w-3.5 text-muted-foreground/40 group-hover:text-muted-foreground transition-colors" />
|
|
</div>
|
|
<p className="text-xs text-muted-foreground leading-snug mt-0.5">
|
|
Threshold key management, 15+ chains
|
|
</p>
|
|
</div>
|
|
</Link>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Category grid */}
|
|
<div className="grid grid-cols-2 sm:grid-cols-3 lg:grid-cols-5 gap-x-6 gap-y-4">
|
|
{/* RPC & Nodes */}
|
|
<div className="space-y-1.5">
|
|
<h3 className="text-[10px] font-semibold uppercase tracking-wider mb-2 text-muted-foreground">
|
|
RPC & Nodes
|
|
</h3>
|
|
<div className="space-y-0.5">
|
|
<IconLink href="/products/node" icon={Globe} label="Multi-Chain RPC" closeMenu={closeMenu} />
|
|
<IconLink href="/chains/ethereum" icon={Cpu} label="Ethereum" closeMenu={closeMenu} />
|
|
<IconLink href="/chains/solana" icon={Cpu} label="Solana" closeMenu={closeMenu} />
|
|
<IconLink href="/chains/base" icon={Cpu} label="Base" closeMenu={closeMenu} />
|
|
<IconLink href="/chains" icon={ArrowRight} label="All 100+ Chains" closeMenu={closeMenu} />
|
|
</div>
|
|
</div>
|
|
|
|
{/* Data APIs */}
|
|
<div className="space-y-1.5">
|
|
<h3 className="text-[10px] font-semibold uppercase tracking-wider mb-2 text-muted-foreground">
|
|
Data APIs
|
|
</h3>
|
|
<div className="space-y-0.5">
|
|
<IconLink href="/products/data" icon={Database} label="Token API" closeMenu={closeMenu} />
|
|
<IconLink href="/products/data" icon={Blocks} label="NFT API" closeMenu={closeMenu} />
|
|
<IconLink href="/products/data" icon={Code2} label="Transfers API" closeMenu={closeMenu} />
|
|
<IconLink href="/products/webhooks" icon={Webhook} label="Webhooks" closeMenu={closeMenu} />
|
|
</div>
|
|
</div>
|
|
|
|
{/* Wallets & AA */}
|
|
<div className="space-y-1.5">
|
|
<h3 className="text-[10px] font-semibold uppercase tracking-wider mb-2 text-muted-foreground">
|
|
Wallets & AA
|
|
</h3>
|
|
<div className="space-y-0.5">
|
|
<IconLink href="/products/wallets" icon={Wallet} label="Smart Wallets" closeMenu={closeMenu} />
|
|
<IconLink href="/products/wallets" icon={Zap} label="Gas Sponsorship" closeMenu={closeMenu} />
|
|
<IconLink href="/products/wallets" icon={Lock} label="Session Keys" closeMenu={closeMenu} />
|
|
</div>
|
|
</div>
|
|
|
|
{/* Infrastructure */}
|
|
<div className="space-y-1.5">
|
|
<h3 className="text-[10px] font-semibold uppercase tracking-wider mb-2 text-muted-foreground">
|
|
Infrastructure
|
|
</h3>
|
|
<div className="space-y-0.5">
|
|
<IconLink href="/products/rollups" icon={Layers} label="Custom Rollups" closeMenu={closeMenu} />
|
|
<IconLink href="/products/explorer" icon={Search} label="Block Explorer" closeMenu={closeMenu} />
|
|
<IconLink href="/products/mpc" icon={KeyRound} label="MPC Network" closeMenu={closeMenu} />
|
|
<IconLink href="/products/node" icon={Server} label="Archive Nodes" closeMenu={closeMenu} />
|
|
</div>
|
|
</div>
|
|
|
|
{/* Security & Keys */}
|
|
<div className="space-y-1.5">
|
|
<h3 className="text-[10px] font-semibold uppercase tracking-wider mb-2 text-muted-foreground">
|
|
Security
|
|
</h3>
|
|
<div className="space-y-0.5">
|
|
<IconLink href="/products/mpc" icon={Shield} label="CGGMP21 (ECDSA)" closeMenu={closeMenu} />
|
|
<IconLink href="/products/mpc" icon={Shield} label="FROST (EdDSA)" closeMenu={closeMenu} />
|
|
<IconLink href="/products/mpc" icon={KeyRound} label="Key Resharing" closeMenu={closeMenu} />
|
|
<IconLink href="/products/mpc" icon={Network} label="Threshold Signing" closeMenu={closeMenu} />
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Footer */}
|
|
<div className="mt-4 pt-4 border-t border-border flex items-center justify-between">
|
|
<div className="flex items-center gap-3">
|
|
<div className="rounded-md px-2.5 py-1 font-mono text-[10px] bg-secondary text-foreground">
|
|
{`npm i ${sdkPackage}`}
|
|
</div>
|
|
<span className="text-[10px] text-muted-foreground">
|
|
Install {brand.name} SDK
|
|
</span>
|
|
</div>
|
|
<div className="flex gap-2">
|
|
<Button
|
|
size="sm"
|
|
variant="outline"
|
|
className="h-7 text-xs px-3 bg-transparent border-border text-foreground/80 hover:bg-accent hover:text-foreground"
|
|
asChild
|
|
>
|
|
<Link href="/docs" onClick={closeMenu}>
|
|
Docs
|
|
</Link>
|
|
</Button>
|
|
<Button
|
|
size="sm"
|
|
className="bg-primary text-primary-foreground hover:bg-primary/90 h-7 text-xs px-3"
|
|
asChild
|
|
>
|
|
<Link href="/dashboard" onClick={closeMenu}>
|
|
All Products
|
|
<ArrowRight className="ml-1 h-3 w-3" />
|
|
</Link>
|
|
</Button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
)
|
|
}
|
|
|
|
// Solutions mega-menu content
|
|
function SolutionsContent({ closeMenu }: { closeMenu: () => void }) {
|
|
return (
|
|
<div className="w-full flex gap-6">
|
|
{/* Left: featured panels */}
|
|
<div className="w-64 flex-shrink-0 space-y-3">
|
|
<Link
|
|
href="/contact"
|
|
onClick={closeMenu}
|
|
className="block p-4 rounded-xl bg-gradient-to-br from-blue-500/5 to-cyan-500/5 border border-border/50 hover:border-border transition-all group"
|
|
>
|
|
<div className="flex items-center gap-3 mb-2">
|
|
<div className="w-8 h-8 rounded-lg bg-foreground/10 flex items-center justify-center">
|
|
<Building2 className="h-4 w-4 text-foreground" />
|
|
</div>
|
|
<h3 className="text-foreground font-semibold text-sm">Enterprise</h3>
|
|
</div>
|
|
<p className="text-muted-foreground text-xs leading-relaxed mb-2">
|
|
Dedicated RPC, custom rollups, managed MPC clusters, and SLAs for
|
|
scale.
|
|
</p>
|
|
<span className="text-xs font-medium text-foreground/70 group-hover:text-foreground transition-colors inline-flex items-center gap-1">
|
|
Contact sales <ArrowRight className="h-3 w-3" />
|
|
</span>
|
|
</Link>
|
|
|
|
<Link
|
|
href="/pricing"
|
|
onClick={closeMenu}
|
|
className="block p-4 rounded-xl bg-gradient-to-br from-violet-500/5 to-purple-500/5 border border-border/50 hover:border-border transition-all group"
|
|
>
|
|
<div className="flex items-center gap-3 mb-2">
|
|
<div className="w-8 h-8 rounded-lg bg-foreground/10 flex items-center justify-center">
|
|
<Shield className="h-4 w-4 text-foreground" />
|
|
</div>
|
|
<h3 className="text-foreground font-semibold text-sm">
|
|
Startup Program
|
|
</h3>
|
|
</div>
|
|
<p className="text-muted-foreground text-xs leading-relaxed mb-2">
|
|
Free tier with 100M compute units/mo. Scale as you grow.
|
|
</p>
|
|
<span className="text-xs font-medium text-foreground/70 group-hover:text-foreground transition-colors inline-flex items-center gap-1">
|
|
Get started <ArrowRight className="h-3 w-3" />
|
|
</span>
|
|
</Link>
|
|
</div>
|
|
|
|
{/* Right: columns */}
|
|
<div className="flex-1 grid grid-cols-3 gap-x-6 gap-y-4">
|
|
{/* By Use Case */}
|
|
<div className="space-y-1.5">
|
|
<h3 className="text-[10px] font-semibold uppercase tracking-wider mb-2 text-muted-foreground">
|
|
Use Cases
|
|
</h3>
|
|
<div className="space-y-0.5">
|
|
<IconLink href="/products/node" icon={Globe} label="DApp Backend" description="RPC + Data APIs for any dApp" closeMenu={closeMenu} />
|
|
<IconLink href="/products/wallets" icon={Wallet} label="User Onboarding" description="Smart wallets, no seed phrase" closeMenu={closeMenu} />
|
|
<IconLink href="/products/rollups" icon={Layers} label="Launch a Chain" description="Custom L2 with your gas token" closeMenu={closeMenu} />
|
|
<IconLink href="/products/mpc" icon={KeyRound} label="Treasury Security" description="MPC key management for funds" closeMenu={closeMenu} />
|
|
<IconLink href="/products/explorer" icon={Search} label="Chain Transparency" description="Branded explorer for your network" closeMenu={closeMenu} />
|
|
</div>
|
|
</div>
|
|
|
|
{/* By Role */}
|
|
<div className="space-y-1.5">
|
|
<h3 className="text-[10px] font-semibold uppercase tracking-wider mb-2 text-muted-foreground">
|
|
By Role
|
|
</h3>
|
|
<div className="space-y-0.5">
|
|
<IconLink href="/docs/quickstart" icon={Code2} label="Developers" description="SDKs, APIs, quickstarts" closeMenu={closeMenu} />
|
|
<IconLink href="/products/rollups" icon={Building2} label="Foundations" description="Launch and manage L2s" closeMenu={closeMenu} />
|
|
<IconLink href="/products/mpc" icon={Shield} label="Security Teams" description="MPC, audit trails, compliance" closeMenu={closeMenu} />
|
|
<IconLink href="/products/data" icon={BarChart3} label="Data Teams" description="Indexed chain data + analytics" closeMenu={closeMenu} />
|
|
</div>
|
|
</div>
|
|
|
|
{/* By Chain */}
|
|
<div className="space-y-1.5">
|
|
<h3 className="text-[10px] font-semibold uppercase tracking-wider mb-2 text-muted-foreground">
|
|
By Chain
|
|
</h3>
|
|
<div className="space-y-0.5">
|
|
<IconLink href="/chains/ethereum" icon={Coins} label="Ethereum" closeMenu={closeMenu} />
|
|
<IconLink href="/chains/solana" icon={Coins} label="Solana" closeMenu={closeMenu} />
|
|
<IconLink href="/chains/base" icon={Coins} label="Base" closeMenu={closeMenu} />
|
|
<IconLink href="/chains/arbitrum" icon={Coins} label="Arbitrum" closeMenu={closeMenu} />
|
|
<IconLink href="/chains/polygon" icon={Coins} label="Polygon" closeMenu={closeMenu} />
|
|
<IconLink href="/chains" icon={ArrowRight} label="All 100+ Chains" closeMenu={closeMenu} />
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
)
|
|
}
|
|
|
|
// Rows that appear in BOTH the desktop bar and the phone sheet. Declared once —
|
|
// the previous header wrote them twice and the two copies had already drifted
|
|
// (Chains was in the sheet only).
|
|
const PRIMARY_LINKS = [
|
|
{ name: "Chains", href: "/chains" },
|
|
{ name: "Docs", href: "/docs" },
|
|
{ name: "Pricing", href: "/pricing" },
|
|
]
|
|
|
|
// The fleet view belongs to the brand that operates a fleet (lib/brand.ts).
|
|
const FLEET_LINK = { name: "Fleet", href: "/fleet" }
|
|
|
|
// The product pages, for the phone sheet — which has no room for the desktop
|
|
// mega-menu. Every href here is a route the build actually emits. Note there
|
|
// is deliberately no bare `/products`: it is a DIRECTORY of pages with no
|
|
// index, so linking to it serves the SPA fallback (i.e. the home page) under a
|
|
// /products URL.
|
|
const PRODUCTS = [
|
|
{ name: "Node (RPC)", href: "/products/node" },
|
|
{ name: "Data APIs", href: "/products/data" },
|
|
{ name: "Smart Wallets", href: "/products/wallets" },
|
|
{ name: "Explorer", href: "/products/explorer" },
|
|
{ name: "MPC", href: "/products/mpc" },
|
|
{ name: "Rollups", href: "/products/rollups" },
|
|
{ name: "Webhooks", href: "/products/webhooks" },
|
|
]
|
|
|
|
/**
|
|
* The site header, in lux.cloud's chrome: a 57px sticky bar over a blurred
|
|
* translucent ground, one hairline rule beneath, the brand lockup at the left
|
|
* with its retracting wordmark, and the action cluster hard right.
|
|
*
|
|
* Below `lg` the nav and the actions collapse together behind one hamburger
|
|
* into a full-width sheet, so a 390px viewport still fits the bar and every
|
|
* action — Sign In included — stays reachable. The sheet closes on outside
|
|
* click and on Escape, matching every other overlay in the app.
|
|
*/
|
|
export function Navbar() {
|
|
const [isOpen, setIsOpen] = useState(false)
|
|
const brand = useBrand()
|
|
const { user, logout } = useAuth()
|
|
const ref = useRef<HTMLElement>(null)
|
|
const close = () => setIsOpen(false)
|
|
|
|
useEffect(() => {
|
|
if (!isOpen) return
|
|
const onClick = (e: MouseEvent) => {
|
|
if (ref.current && !ref.current.contains(e.target as Node)) setIsOpen(false)
|
|
}
|
|
const onKey = (e: KeyboardEvent) => {
|
|
if (e.key === "Escape") setIsOpen(false)
|
|
}
|
|
document.addEventListener("click", onClick)
|
|
document.addEventListener("keydown", onKey)
|
|
return () => {
|
|
document.removeEventListener("click", onClick)
|
|
document.removeEventListener("keydown", onKey)
|
|
}
|
|
}, [isOpen])
|
|
|
|
return (
|
|
<header
|
|
ref={ref}
|
|
className="sticky top-0 z-50 w-full border-b border-border bg-background/80 backdrop-blur-xl"
|
|
>
|
|
<div className="mx-auto flex h-(--header-h) max-w-[1440px] items-center gap-8 px-6 max-lg:gap-0 max-sm:px-4">
|
|
<Link href="/" className="shrink-0" onClick={close}>
|
|
<BrandLogo collapsible />
|
|
</Link>
|
|
|
|
<Button
|
|
variant="outline"
|
|
size="icon"
|
|
aria-label="Toggle navigation menu"
|
|
aria-expanded={isOpen}
|
|
className="ml-auto lg:hidden"
|
|
onClick={(e) => {
|
|
e.stopPropagation()
|
|
setIsOpen((v) => !v)
|
|
}}
|
|
>
|
|
{isOpen ? <X className="h-5 w-5" /> : <Menu className="h-5 w-5" />}
|
|
</Button>
|
|
|
|
{/* Desktop: an inline row. Phone: an opaque full-width sheet under the
|
|
bar. It must NOT carry its own backdrop-filter — nesting one inside
|
|
the header's re-roots the backdrop and the page bleeds through the
|
|
menu, which is the bug lux.cloud documents in its own styles. */}
|
|
<div
|
|
className={cn(
|
|
"flex min-w-0 flex-1 items-center gap-8",
|
|
"max-lg:absolute max-lg:inset-x-0 max-lg:top-full max-lg:max-h-[calc(100dvh-var(--header-h))] max-lg:flex-col max-lg:items-stretch max-lg:gap-4 max-lg:overflow-y-auto max-lg:overscroll-contain max-lg:border-b max-lg:border-border max-lg:bg-background max-lg:px-6 max-lg:pb-6 max-lg:pt-4",
|
|
isOpen ? "max-lg:flex" : "max-lg:hidden"
|
|
)}
|
|
>
|
|
<nav className="flex flex-1 items-center gap-6 max-lg:flex-col max-lg:items-stretch max-lg:gap-0.5">
|
|
<span className="max-lg:hidden">
|
|
<NavMenu label="Products">{(closeMenu) => <ProductsContent closeMenu={closeMenu} />}</NavMenu>
|
|
</span>
|
|
<span className="max-lg:hidden">
|
|
<NavMenu label="Solutions">{(closeMenu) => <SolutionsContent closeMenu={closeMenu} />}</NavMenu>
|
|
</span>
|
|
{/* The sheet has no room for a mega-menu, so the products are
|
|
listed instead of collapsing to one link — the mega-menu is the
|
|
only route to them and losing it on a phone loses the product. */}
|
|
<span className="hidden w-full max-lg:block">
|
|
<span className="mb-1 mt-1 block text-[11px] font-medium uppercase tracking-[0.08em] text-muted-foreground">
|
|
Products
|
|
</span>
|
|
{PRODUCTS.map((p) => (
|
|
<Link
|
|
key={p.href}
|
|
href={p.href}
|
|
onClick={close}
|
|
className="flex min-h-10 w-full items-center text-sm text-muted-foreground transition-colors hover:text-foreground"
|
|
>
|
|
{p.name}
|
|
</Link>
|
|
))}
|
|
</span>
|
|
{(brand.fleet ? [FLEET_LINK, ...PRIMARY_LINKS] : PRIMARY_LINKS).map((link) => (
|
|
<Link
|
|
key={link.href}
|
|
href={link.href}
|
|
onClick={close}
|
|
className="text-sm text-muted-foreground transition-colors hover:text-foreground max-lg:flex max-lg:min-h-10 max-lg:w-full max-lg:items-center"
|
|
>
|
|
{link.name}
|
|
</Link>
|
|
))}
|
|
<a
|
|
href={brand.networkUrl}
|
|
className="text-sm text-muted-foreground transition-colors hover:text-foreground max-lg:flex max-lg:min-h-10 max-lg:w-full max-lg:items-center"
|
|
>
|
|
{brand.networkName}
|
|
</a>
|
|
</nav>
|
|
|
|
{/* In the sheet every action is a full-width 40px row, matching the
|
|
nav links above it — a 32px `sm` button is a fine desktop target
|
|
and a poor thumb target. */}
|
|
<div className="flex items-center gap-2.5 max-lg:flex-col max-lg:items-stretch max-lg:gap-2 [&_button]:max-lg:h-10 [&_a]:max-lg:h-10">
|
|
<CommandMenu />
|
|
{/* The account cluster is the SHARED chrome (@luxfi/ui), not a
|
|
third copy of it. What was here was an email in a <span> and a
|
|
Sign out button — no menu, no way to see or change which org you
|
|
were acting in, and a "sign in" that only ever named the brand.
|
|
The switchers below read IAM (get-account, get-organizations)
|
|
and are the same controls the MPC dashboard and lux.market show,
|
|
including the phone sheet, which this bar had no equivalent of.
|
|
|
|
They degrade honestly: signed out they offer sign-in rather than
|
|
rendering an empty list that reads as an account with no orgs. */}
|
|
<OrgSwitcher />
|
|
<UserMenu />
|
|
<Button size="sm" asChild onClick={close}>
|
|
<Link href="/dashboard">Dashboard</Link>
|
|
</Button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</header>
|
|
)
|
|
}
|