Files
base/ui-react
zeekayandHanzo Dev ad7e7c1c2f ui-react: drop image-size from metro's install
No image-size release fixes GHSA-5p2g-fcmc-qvqq or GHSA-w3rx-r6r6-pgpr
(every version through 2.0.2 is affected). Its one dependent is metro,
React Native's bundler, which arrives with the react-native peer; metro
0.87.0 still depends on it. Vite aliases react-native to react-native-web,
so metro never runs here, and the bundle built from this lockfile is
byte-identical to the committed dist.

Co-authored-by: Hanzo Dev <[email protected]>
2026-09-11 10:27:31 -07:00
..
2026-09-10 21:55:06 -07:00

Base Admin UI

The Base admin SPA. Source is ./src; pnpm build writes ./dist, and embed.go compiles that into the Base binary with //go:embed all:dist, which the server mounts at /_/ when BASE_ENABLE_ADMIN_UI=1.

dist/ is committed so go build is hermetic — CI compiles the binary without a Node toolchain. Rebuild it in the same commit as any src/ change.

Build

pnpm install
pnpm build      # tsc --noEmit && vite build  ->  ./dist
pnpm dev        # vite, proxying /v1 to a local Base on :8090

Two env knobs, both set at build time and both mirrored by the Go server:

Env Default Read by
BASE_ADMIN_UI_PATH /_/ Vite base + the Go static mount
VITE_IAM_URL / VITE_IAM_CLIENT_ID https://hanzo.id / hanzo-base src/lib/iam.ts

Stack

One framework, all platforms. No Tailwind, no Radix, no shadcn.

Layer What
Framework React 19 + TanStack Router (file-based, src/routes/**) + TanStack Query
Bundler Vite 8 (rolldown)
Components @hanzo/ui on @hanzo/gui — the cross-platform primitives, same import on web/native/desktop
Icons @hanzogui/lucide-icons-2
Styling src/index.css: @hanzo/design tokens (plain CSS custom properties) + ~30 class names for the things this admin has
Data One /v1 fetch layer (src/lib/api.ts) behind a base.collection(x).method() facade (src/lib/base-client.ts); realtime is /v1/realtime SSE
Auth Hanzo IAM, OAuth2 PKCE via @hanzo/iam (src/lib/iam.ts). No local password — the fork retired _superusers password auth and the server 404s auth-with-password for every collection

Where the line falls: overlays (dialog, dropdown) are @hanzo/ui components, because they carry a11y, focus management and placement that CSS cannot. Every other surface is a class in index.css. A route says what a thing IS.

Verifying a change

pnpm build going green does not prove a visual change worked. @hanzo/gui drops a prop it does not recognise in silence — no error, no type failure, just an unstyled element — and CSS resolves an undefined var(--x) to nothing. Both layers fail quietly, so run the browser check:

pnpm smoke      # needs playwright; PLAYWRIGHT=/path/to/playwright/index.mjs

It serves the committed dist/ under /_/ exactly as the Go server does, stubs /v1, and gates on: every route paints, every var(--token) resolves, zero utility-class residue, every control computes real colours and radii, the overlays open, and the confirm dialog measures the width DialogContent maxW asks for. That last one is the shape of the silent-drop bug, so it is asserted, not just printed.