mirror of
https://github.com/hanzoai/bootnode.git
synced 2026-09-30 20:46:32 +00:00
74 files imported `lucide-react` directly, pinned ^1.26.0, while @luxfi/ui — which this console renders alongside — resolves 1.27. Two Lucide copies from two resolutions in one bundle is how a set stops being one set. Two more glyphs were not from any icon library at all: the node list drew its network in/out arrows as the literal characters "↓" and "↑", and the chain onboarding selector drew its tick as "✓". Those are font glyphs — they take the text metrics, not the icon box, so they sit on a different baseline and scale with the font, not `size-*`. One source now: `@luxfi/ui/icons`, Lucide as @hanzo/gui standardises on it and @luxfi/ui themes it. `lucide-react` is out of package.json, so per-surface drift is no longer expressible; @luxfi/ui comes in at 7.4.3, which is where `./icons` lives. The three text glyphs are ArrowDown / ArrowUp / Check. All 121 distinct icon names this console uses were checked against the 6014 symbols @luxfi/ui/icons exports before the rewrite — zero missing, with a negative control. `next build` is clean: 78 routes, Next 16.2.11 + Turbopack. The d3 chart roots (node-globe, node-map, globe-view, donut-chart, fleet-map) keep their <svg>: those are plots, not glyphs. The command menu's "↑↓" stays — it is a keyboard legend inside <kbd>, and it means the keys. Co-authored-by: Hanzo Dev <[email protected]>
140 lines
4.9 KiB
TypeScript
140 lines
4.9 KiB
TypeScript
"use client"
|
|
|
|
import Link from "next/link"
|
|
import { BrandLogo, useBrand } from "@/components/brand-logo"
|
|
import { ExternalLink } from "@luxfi/ui/icons"
|
|
|
|
// Footer, in lux.cloud's chrome: no tinted slab, just a hairline rule over the
|
|
// page ground with 13px muted type. The four sitemap columns stay — dropping
|
|
// them to match lux.cloud's single row would delete real navigation — but the
|
|
// brand row underneath is lux.cloud's, and every brand string in it now comes
|
|
// from the hostname-resolved catalog rather than a constant.
|
|
|
|
const footerLinks = {
|
|
products: [
|
|
{ name: "Node (RPC)", href: "/products/node" },
|
|
{ name: "Token API", href: "/products/data" },
|
|
{ name: "NFT API", href: "/products/data" },
|
|
{ name: "Smart Wallets", href: "/products/wallets" },
|
|
{ name: "Webhooks", href: "/products/webhooks" },
|
|
{ name: "Rollups", href: "/products/rollups" },
|
|
],
|
|
chains: [
|
|
{ name: "Ethereum", href: "/chains/ethereum" },
|
|
{ name: "Solana", href: "/chains/solana" },
|
|
{ name: "Base", href: "/chains/base" },
|
|
{ name: "Arbitrum", href: "/chains/arbitrum" },
|
|
{ name: "Polygon", href: "/chains/polygon" },
|
|
{ name: "View All", href: "/chains" },
|
|
],
|
|
developers: [
|
|
{ name: "Documentation", href: "/docs" },
|
|
{ name: "API Reference", href: "/docs/api" },
|
|
{ name: "Quickstart", href: "/docs/quickstart" },
|
|
{ name: "SDKs", href: "/docs/sdks" },
|
|
{ name: "Changelog", href: "/docs/changelog" },
|
|
{ name: "llms.txt", href: "/llms.txt" },
|
|
],
|
|
}
|
|
|
|
// One rule for every footer link. `min-h-8` is not decoration: on a phone these
|
|
// were 20px tap targets in a 44px world.
|
|
const linkClass =
|
|
"inline-flex min-h-8 items-center gap-1 text-[13px] text-muted-foreground transition-colors hover:text-foreground"
|
|
|
|
function Column({ title, links }: { title: string; links: { name: string; href: string }[] }) {
|
|
return (
|
|
<div>
|
|
<h3 className="text-[11px] font-medium uppercase tracking-[0.08em] text-muted-foreground">{title}</h3>
|
|
<ul className="mt-3 space-y-0.5">
|
|
{links.map((link) => (
|
|
<li key={link.name}>
|
|
<Link href={link.href} className={linkClass}>
|
|
{link.name}
|
|
</Link>
|
|
</li>
|
|
))}
|
|
</ul>
|
|
</div>
|
|
)
|
|
}
|
|
|
|
export function Footer() {
|
|
const brand = useBrand()
|
|
|
|
return (
|
|
<footer className="mt-24 border-t border-border">
|
|
<div className="mx-auto max-w-[1440px] px-6 py-12 max-sm:px-4">
|
|
<div className="grid gap-8 sm:grid-cols-2 md:grid-cols-5">
|
|
<div className="md:col-span-1">
|
|
<Link href="/">
|
|
<BrandLogo />
|
|
</Link>
|
|
<p className="mt-3 max-w-56 text-[13px] leading-relaxed text-muted-foreground">{brand.tagline}</p>
|
|
</div>
|
|
|
|
<Column title="Products" links={footerLinks.products} />
|
|
<Column title="Chains" links={footerLinks.chains} />
|
|
<Column title="Developers" links={footerLinks.developers} />
|
|
|
|
<div>
|
|
<h3 className="text-[11px] font-medium uppercase tracking-[0.08em] text-muted-foreground">Network</h3>
|
|
<ul className="mt-3 space-y-0.5">
|
|
<li>
|
|
<a href={brand.networkUrl} className={linkClass}>
|
|
{brand.networkName}
|
|
<ExternalLink className="h-3 w-3" />
|
|
</a>
|
|
</li>
|
|
<li>
|
|
<a href={brand.statusUrl} className={linkClass}>
|
|
Status
|
|
<ExternalLink className="h-3 w-3" />
|
|
</a>
|
|
</li>
|
|
{brand.social.github && (
|
|
<li>
|
|
<a href={brand.social.github} className={linkClass}>
|
|
GitHub
|
|
<ExternalLink className="h-3 w-3" />
|
|
</a>
|
|
</li>
|
|
)}
|
|
{brand.footerLinks.map((link) => (
|
|
<li key={link.name}>
|
|
<a
|
|
href={link.href}
|
|
target={link.external ? "_blank" : undefined}
|
|
rel={link.external ? "noopener noreferrer" : undefined}
|
|
className={linkClass}
|
|
>
|
|
{link.name}
|
|
{link.external && <ExternalLink className="h-3 w-3" />}
|
|
</a>
|
|
</li>
|
|
))}
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
|
|
<div className="mt-10 flex flex-col items-center justify-between gap-3 border-t border-border pt-6 sm:flex-row">
|
|
<p className="text-[13px] text-muted-foreground">
|
|
© {new Date().getFullYear()} {brand.name}
|
|
</p>
|
|
<div className="flex gap-5">
|
|
<Link href="/privacy" className={linkClass}>
|
|
Privacy
|
|
</Link>
|
|
<Link href="/terms" className={linkClass}>
|
|
Terms
|
|
</Link>
|
|
<Link href="/security" className={linkClass}>
|
|
Security
|
|
</Link>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</footer>
|
|
)
|
|
}
|