Files
zeekayandHanzo Dev 43afc1a6c9 The wallet wears the Lux wordmark, from the package that draws it
The header drew /brands/lux.svg — a purple diamond that appears in no Lux
brand, committed here and nowhere else. It is now generated from
@luxfi/logo at build time, alongside a squared lockup for the tab, so the
wallet has no drawing of its own to drift from.

The mark was sized into a 24x24 box. A square box suits a square mark and
letterboxes a wordmark down to about six pixels of letter, so height is
the given dimension now and width follows. One rule covers both shapes,
which matters because hanzo and zoo still ship square marks.

brand.json and the marks are all files the SPA serves but nobody authors,
so they are written by one plugin from one list instead of a plugin each.

Co-authored-by: Hanzo Dev <[email protected]>
2026-08-13 15:03:03 -07:00

76 lines
2.5 KiB
TypeScript

import { defineConfig, type Plugin } from "vite"
import react from "@vitejs/plugin-react"
import { getWordmarkAdaptiveSVG, getWordmarkSquareSVG } from "@luxfi/logo"
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs"
import { dirname, resolve } from "node:path"
/**
* The files the SPA serves but nobody authors here.
*
* `brand.json` is the canonical one from `@luxfi/wallet-brand`; white-label
* deployments overlay it via a K8s ConfigMap mount — no code change required.
*
* The Lux marks come from `@luxfi/logo`, which is where the geometry lives.
* They used to be committed SVGs, and the one the header drew was a purple
* diamond that appears in no Lux brand. Generating them means the wallet
* cannot drift from the mark: a new version of the package is the only way
* they change. Written to `public/` for the dev server and `dist/` for the
* build, both from the same list.
*/
function served(): Plugin {
const brandJson = resolve(__dirname, "../../pkgs/brand/brand.json")
const files = (): Record<string, string | null> => ({
"brand.json": existsSync(brandJson) ? readFileSync(brandJson, "utf8") : null,
// Horizontal for the header, squared for the tab and the home screen.
"brands/lux.svg": getWordmarkAdaptiveSVG(),
"brands/lux-square.svg": getWordmarkSquareSVG(),
})
const writeInto = (root: string) => {
for (const [name, body] of Object.entries(files())) {
if (body == null) continue
const dest = resolve(__dirname, root, name)
mkdirSync(dirname(dest), { recursive: true })
writeFileSync(dest, body)
}
}
return {
name: "luxfi-wallet-served",
buildStart() {
writeInto("public")
},
closeBundle() {
writeInto("dist")
},
}
}
export default defineConfig({
plugins: [
react({
// `@hanzo/gui` ships React-only on web; default automatic JSX runtime.
jsxRuntime: "automatic",
}),
served(),
],
resolve: {
alias: {
"@": resolve(__dirname, "src"),
// @hanzo/gui v7 npm publish ships without dist/ (its package.json
// exports point at ./dist/esm/index.mjs which doesn't exist). Until
// upstream republishes a fixed v7, alias to a local stub with
// minimal primitives. Tokenized props map to CSS vars set by
// loadBrandConfig() at boot.
"@hanzo/gui": resolve(__dirname, "src/lib/gui-stub.tsx"),
},
},
build: {
outDir: "dist",
target: "es2022",
sourcemap: true,
},
server: {
port: 3000,
strictPort: false,
},
})