mirror of
https://github.com/hanzoai/bootnode.git
synced 2026-10-25 02:31:30 +00:00
Two duplications, both removed. 1. The header's account cluster was an email in a <span> and a Sign out button. It is now <OrgSwitcher/> + <UserMenu/> from @luxfi/ui — the same controls the MPC dashboard and lux.market render, reading the same IAM verbs (get-account, get-organizations, get-organization-projects), with the same phone sheet, which this bar had no equivalent of at all. Signed out they offer sign-in rather than showing an empty list that reads as an account with no organizations. 2. lib/brand.ts held a SECOND host→brand table. It kept what is genuinely its own — logos, taglines, palettes, footer links, the ecosystem launcher, the API origins that answer — and now takes issuer, client id and IAM host from @luxfi/ui/white-label, which is the same resolver every Lux surface already uses. Two copies of one fact is two things to get wrong, and these two DID disagree: this table had Zoo on zoolabs.id (right) and the shared one on id.zoo.network (an alias whose own discovery document names zoolabs.id, so a client on it rejects every token). The shared table is fixed; this file no longer has an opinion to be wrong about. The bundler wiring for the gui engine comes from `withLuxUi` — the one place it lives, rather than a hand-rolled transpile list per app. `next build` passes (static export, every route emitted). `pnpm test` 26/26, including the assertion that lux.cloud + lux-cloud + https://lux.cloud/auth/callback — the one login that works today — is unchanged. Co-authored-by: Hanzo Dev <[email protected]>
513 lines
22 KiB
TypeScript
513 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 with 99.999% uptime
|
|
</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: "Fleet", href: "/fleet" },
|
|
{ name: "Chains", href: "/chains" },
|
|
{ name: "Docs", href: "/docs" },
|
|
{ name: "Pricing", href: "/pricing" },
|
|
]
|
|
|
|
// 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>
|
|
{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>
|
|
)
|
|
}
|