mirror of
https://github.com/hanzoai/bootnode.git
synced 2026-09-30 20:46:32 +00:00
The shell and design system half of the console merge. lux.cloud's look and feel comes across as tokens and shell geometry, so all 67 existing routes inherit it without one page being edited, and the per-deployment brand is replaced by a hostname resolve. DESIGN SYSTEM — lux.cloud's palette becomes the token layer app/globals.css now states lux.cloud's scheme in the variables Tailwind already reads: #000 ground, #f5f5f5 ink, 55% muted, 8% hairline / 18% strong border, #1a1a1a active fill, its status greens/ambers/reds, 10px/16px radii, clamp() display type, -0.01em tracking. Light is a faithful inversion, kept because the app ships a theme toggle. Because these are the same variables `bg-background` / `border-border` / `text-muted-foreground` always resolved to, every page changed appearance without changing. The shared primitives then say it in their own geometry: Card is lux's `.panel` (16px, hairline, no shadow — a shadow is invisible on black and grime on white), Table is `.vtable` (12px uppercase heads, border on the TOP of each row so the header needs no rule and the table ends flush), Badge is `.pill` with the status dot, Button and Input are `.btn` and `.stake-input`. SHELL One header for marketing and console, as on lux.cloud — 57px, blurred, one hairline, brand lockup with the retracting wordmark, actions hard right, collapsing behind a single hamburger below `lg` into an OPAQUE sheet (a nested backdrop-filter re-roots the backdrop, the bug lux.cloud documents). ConsoleLayout adds the one thing the console needs: a 236px sticky rail that becomes a horizontally-scrolling strip on a phone — 7% of a 390x844 screen measured, against the 27% a wrapped grid of pills costs. Deleted: unified-navigation.tsx, a second console-only top bar with its own logo, an org switcher whose options changed nothing, and a bell wired to no notification source. The hard-coded `pl-64 pt-16` offsets are now the --header-h / --sidebar-w tokens, so the header and rail cannot disagree. Loading, empty and error are three components in one file instead of nine hand-rolled spinners at four sizes, and the callback page's `bg-green-100` / `text-red-600` — the only two colours in the app that ignored the tokens and so stayed light-mode on a black page — are gone. WHITE-LABEL BY HOSTNAME — one image, five hosts lib/brand.ts resolves brand, theme, API origin, IAM issuer and OIDC client from window.location.hostname. Every triple was verified against the live /v1/iam/oauth/authorize (302 = registered, 400 = not): id.bootno.de bootnode-platform bootno.de/auth/callback 302 hanzo.id hanzo-web3 web3.hanzo.ai/auth/callback 302 lux.id lux-cloud lux.cloud/auth/callback 302 zoolabs.id zoo-cloud zoo.cloud/auth/callback 302 zoolabs.id zoo-cloud cloud.zoo.network/auth/callback 302 zoolabs.id zoo-web3 cloud.zoo.network/auth/callback 400 ← was shipping Deleted, because all three were the same defect — a value picked at deploy time while ONE deployment serves five hosts: • public/config.json + config.example.json (the shipped catalog had the 400 client above, and named apiUrls whose hosts do not resolve) • the Dockerfile's NEXT_PUBLIC_BRAND / _API_URL / _WS_URL, which were also inert — the runtime is the Go static binary, which never reads env • four near-identical Deployments differing only in those variables, now one, with the nine ingress rules pointing at the single service • NEXT_PUBLIC_AUTH_MODE and four NEXT_PUBLIC_* docs URLs Matching is exact-or-dot-suffix, never substring: `includes("lux.cloud")` hands lux.cloud's OIDC client to lux.cloud.attacker.example. Each brand also gets its own mark. public/logo/{brand}-icon.svg existed for all five and nothing used them — every brand pointed at one shared /logo.svg. bootnode's is fill="currentColor" and lux's is fill="white", which as an <img> (an isolated document) render invisible on black and on white respectively, so those two are painted in the current text colour via a CSS mask — which is what lux.cloud does with its own pyramid. FIXED ALONG THE WAY • AuthProvider's local getApiUrl() shadowed the import at the top of the file and its last line called itself — infinite recursion on localhost, 127.0.0.1, 192.168.* and 10.*. Every checkAuth/login/register in local development overflowed the stack. Deleted; lib/api's resolver is the one. • The console nav could not reach eight of its own pages — /dashboard/settings, assets/{tokens,nfts}, infrastructure/{lux,services, observability}, /chains, /agents rendered and were linked from nowhere. • No row was ever marked current: the image serves clean URLs as directory indexes, so the pathname is `/dashboard/` and an equality test never matched. Nested routes also lit two rows at once. Both are one selection rule now — longest matching href wins. • Two dead links in the chrome: /products (a directory of pages with no index — the static server answers it with the home page) and /docs/tutorials (a plain 404). TESTS — 26, node:test with native TS stripping, no new dependency The five-host contract including the substring-matching attack; the nav reaching every built route; the trailing-slash and most-specific-row rules; and a whole-source dead-link check that derives routes by walking app/ so it cannot go stale. That check holds the shell at ZERO dead links and ratchets the 36 that predate this work in the docs and product pages — a test that fails on the day it is written gets deleted, one that stops the bleeding gets kept. VERIFIED pnpm build exit 0, 77/77 pages, route set byte-identical to the baseline taken before any change. In a real browser against the built static export: body #000 / #f5f5f5, --border rgba(255,255,255,.08), header 57px sticky blur(24px), sidebar 236px sticky at top:57px, exactly one active row with #1a1a1a fill and aria-current, the phone strip 7% of the viewport scrolling inside itself with the body never scrolling sideways, the sheet opaque with no nested backdrop-filter, and the favicon, mark and "Sign in with Bootnode ID" all coming from the resolved brand. Not deployed. No page bodies touched.
75 lines
2.1 KiB
JSON
75 lines
2.1 KiB
JSON
{
|
|
"name": "@bootnode/web",
|
|
"version": "2.0.0",
|
|
"packageManager": "[email protected]",
|
|
"private": true,
|
|
"type": "module",
|
|
"scripts": {
|
|
"dev": "next dev -p 3001",
|
|
"build": "next build",
|
|
"start": "next start -p 3001",
|
|
"lint": "next lint",
|
|
"typecheck": "tsc --noEmit",
|
|
"test": "node --test --experimental-strip-types \"lib/**/*.test.ts\""
|
|
},
|
|
"dependencies": {
|
|
"@hanzo/iam": "^0.13.8",
|
|
"@luxfi/logo": "^1.0.7",
|
|
"@radix-ui/react-accordion": "^1.2.20",
|
|
"@radix-ui/react-alert-dialog": "^1.1.23",
|
|
"@radix-ui/react-avatar": "^1.2.6",
|
|
"@radix-ui/react-checkbox": "^1.3.11",
|
|
"@radix-ui/react-collapsible": "^1.1.20",
|
|
"@radix-ui/react-dialog": "^1.1.23",
|
|
"@radix-ui/react-dropdown-menu": "^2.1.24",
|
|
"@radix-ui/react-label": "^2.1.15",
|
|
"@radix-ui/react-navigation-menu": "^1.2.22",
|
|
"@radix-ui/react-popover": "^1.1.23",
|
|
"@radix-ui/react-progress": "^1.1.16",
|
|
"@radix-ui/react-scroll-area": "^1.2.18",
|
|
"@radix-ui/react-select": "^2.3.7",
|
|
"@radix-ui/react-separator": "^1.1.15",
|
|
"@radix-ui/react-slot": "^1.3.3",
|
|
"@radix-ui/react-switch": "^1.3.7",
|
|
"@radix-ui/react-tabs": "^1.1.21",
|
|
"@radix-ui/react-toast": "^1.2.23",
|
|
"@radix-ui/react-tooltip": "^1.2.16",
|
|
"@tanstack/react-query": "^5.101.4",
|
|
"@tanstack/react-table": "^8.21.3",
|
|
"@types/d3": "^7.4.3",
|
|
"class-variance-authority": "^0.7.1",
|
|
"clsx": "^2.1.1",
|
|
"cmdk": "^1.1.1",
|
|
"d3": "^7.9.0",
|
|
"date-fns": "^4.4.0",
|
|
"geist": "^1.7.2",
|
|
"lucide-react": "^1.26.0",
|
|
"next": "^16.2.11",
|
|
"next-themes": "^0.4.6",
|
|
"nuqs": "^2.9.2",
|
|
"react": "^19.2.8",
|
|
"react-dom": "^19.2.8",
|
|
"recharts": "^3.10.1",
|
|
"sonner": "^2.0.7",
|
|
"tailwind-merge": "^3.6.0",
|
|
"tailwindcss-animate": "^1.0.7",
|
|
"zod": "^4.4.3"
|
|
},
|
|
"devDependencies": {
|
|
"@tailwindcss/postcss": "^4.3.3",
|
|
"@types/node": "^24.13.3",
|
|
"@types/react": "^19.2.17",
|
|
"@types/react-dom": "^19.2.3",
|
|
"postcss": "^8.5.23",
|
|
"tailwindcss": "^4.3.3",
|
|
"typescript": "^5.9.3"
|
|
},
|
|
"pnpm": {
|
|
"onlyBuiltDependencies": [
|
|
"@tailwindcss/oxide",
|
|
"esbuild",
|
|
"sharp"
|
|
]
|
|
}
|
|
}
|