mirror of
https://github.com/luxfi/wallet.git
synced 2026-07-27 03:37:41 +00:00
fix(wallet-web): visible brand marks, centered auth card, spaced CTAs, no cross-brand chain leak
- brands/{lux,zoo,hanzo}.svg: real marks (violet Lux prism, colorful Zoo venn,
Hanzo block-H). The prior rect fill="currentColor" + black glyph collapsed to a
solid black square in the light-theme header (currentColor is the dark text color).
- gui-stub tokenize(): numeric Tamagui space/size tokens ($3/$6/$10) now resolve to
px on a 4px scale. They were mapped to undefined CSS vars (var(--3)), so every
gap/padding/fontSize was silently dropped — the source of the gap-less "button
blob" (colliding radii) and the top-anchored auth card.
- Welcome: plain inline-styled, viewport-centered card with a max-width panel, the
brand mark, and 44px CTAs separated by real gaps (matches AppShell/Callback pattern,
independent of the unresolved Tamagui token contract).
- overlays/{lux,zoo,hanzo}/brand.json: drop sibling first-party L1s from the chain
selector. Zoo no longer lists "Lux C-Chain"/"Hanzo"; each brand keeps its own
networks + neutral public EVMs (Ethereum/Arbitrum/Base/Polygon/Avalanche).
Co-authored-by: Hanzo Dev <dev@hanzo.ai>
This commit is contained in:
@@ -27,7 +27,7 @@
|
||||
"faviconUrl": "/brands/hanzo.svg",
|
||||
"primaryColor": "#FFFFFF",
|
||||
"defaultChainId": 36963,
|
||||
"supportedChainIds": [36963, 36911, 96369, 200200, 1, 42161, 8453, 137],
|
||||
"supportedChainIds": [36963, 36911, 1, 42161, 8453, 137],
|
||||
"walletConnectProjectId": "",
|
||||
"insightsHost": "",
|
||||
"insightsApiKey": "",
|
||||
@@ -46,7 +46,7 @@
|
||||
},
|
||||
"chains": {
|
||||
"defaultChainId": 36963,
|
||||
"supported": [36963, 36911, 96369, 200200, 1, 42161, 8453, 137]
|
||||
"supported": [36963, 36911, 1, 42161, 8453, 137]
|
||||
},
|
||||
"rpc": {
|
||||
"36963": "https://api.hanzo.ai/mainnet/ext/bc/C/rpc",
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
"faviconUrl": "/brands/lux.svg",
|
||||
"primaryColor": "#FFFFFF",
|
||||
"defaultChainId": 96369,
|
||||
"supportedChainIds": [96369, 96368, 200200, 36963, 36911, 494949, 1, 42161, 8453, 137, 43114],
|
||||
"supportedChainIds": [96369, 96368, 1, 42161, 8453, 137, 43114],
|
||||
"walletConnectProjectId": "",
|
||||
"insightsHost": "",
|
||||
"insightsApiKey": "",
|
||||
@@ -46,7 +46,7 @@
|
||||
},
|
||||
"chains": {
|
||||
"defaultChainId": 96369,
|
||||
"supported": [96369, 96368, 200200, 36963, 36911, 494949, 1, 42161, 8453, 137, 43114]
|
||||
"supported": [96369, 96368, 1, 42161, 8453, 137, 43114]
|
||||
},
|
||||
"rpc": {
|
||||
"96369": "https://api.lux.network/mainnet/ext/bc/C/rpc",
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
"faviconUrl": "/brands/zoo.svg",
|
||||
"primaryColor": "#FFFFFF",
|
||||
"defaultChainId": 200200,
|
||||
"supportedChainIds": [200200, 200201, 96369, 36963, 1, 42161, 8453, 137],
|
||||
"supportedChainIds": [200200, 200201, 1, 42161, 8453, 137],
|
||||
"walletConnectProjectId": "",
|
||||
"insightsHost": "",
|
||||
"insightsApiKey": "",
|
||||
@@ -46,7 +46,7 @@
|
||||
},
|
||||
"chains": {
|
||||
"defaultChainId": 200200,
|
||||
"supported": [200200, 200201, 96369, 36963, 1, 42161, 8453, 137]
|
||||
"supported": [200200, 200201, 1, 42161, 8453, 137]
|
||||
},
|
||||
"rpc": {
|
||||
"200200": "https://api.zoo.network/rpc",
|
||||
|
||||
@@ -1,4 +1,10 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64" fill="none" role="img" aria-label="Hanzo">
|
||||
<rect width="64" height="64" rx="14" fill="currentColor" />
|
||||
<path d="M20 18 L20 46 M44 18 L44 46 M20 32 L44 32" stroke="#000" stroke-width="6" stroke-linecap="round" />
|
||||
<rect width="64" height="64" rx="14" fill="#111111" />
|
||||
<g transform="translate(12 12) scale(0.6)">
|
||||
<path d="M22.21 67V44.6369H0V67H22.21Z" fill="#FFFFFF" />
|
||||
<path d="M66.7038 22.3184H22.2534L0.0878906 44.6367H44.4634L66.7038 22.3184Z" fill="#FFFFFF" />
|
||||
<path d="M22.21 0H0V22.3184H22.21V0Z" fill="#FFFFFF" />
|
||||
<path d="M66.7198 0H44.5098V22.3184H66.7198V0Z" fill="#FFFFFF" />
|
||||
<path d="M66.7198 67V44.6369H44.5098V67H66.7198Z" fill="#FFFFFF" />
|
||||
</g>
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 283 B After Width: | Height: | Size: 584 B |
@@ -1,4 +1,5 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64" fill="none" role="img" aria-label="Lux">
|
||||
<rect width="64" height="64" rx="14" fill="currentColor" />
|
||||
<path d="M16 22 L32 48 L48 22 Z" fill="#000" />
|
||||
<rect width="64" height="64" rx="14" fill="#8B5CF6" />
|
||||
<path d="M32 13 L51 32 L32 51 L13 32 Z" fill="#FFFFFF" />
|
||||
<path d="M32 24 L40 32 L32 40 L24 32 Z" fill="#8B5CF6" />
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 220 B After Width: | Height: | Size: 285 B |
@@ -1,4 +1,16 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64" fill="none" role="img" aria-label="Zoo">
|
||||
<rect width="64" height="64" rx="14" fill="currentColor" />
|
||||
<path d="M20 20 L44 20 L20 44 L44 44" stroke="#000" stroke-width="6" stroke-linecap="round" stroke-linejoin="round" fill="none" />
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="242 241 540 540" fill="none" role="img" aria-label="Zoo">
|
||||
<defs>
|
||||
<clipPath id="zooOuter"><circle cx="512" cy="511" r="270"/></clipPath>
|
||||
<clipPath id="zooGreen"><circle cx="513" cy="369" r="234"/></clipPath>
|
||||
<clipPath id="zooRed"><circle cx="365" cy="595" r="234"/></clipPath>
|
||||
</defs>
|
||||
<g clip-path="url(#zooOuter)">
|
||||
<circle cx="513" cy="369" r="234" fill="#00A652"/>
|
||||
<circle cx="365" cy="595" r="234" fill="#ED1C24"/>
|
||||
<circle cx="643" cy="595" r="234" fill="#2E3192"/>
|
||||
<g clip-path="url(#zooGreen)"><circle cx="365" cy="595" r="234" fill="#FCF006"/></g>
|
||||
<g clip-path="url(#zooGreen)"><circle cx="643" cy="595" r="234" fill="#01ACF1"/></g>
|
||||
<g clip-path="url(#zooRed)"><circle cx="643" cy="595" r="234" fill="#EA018E"/></g>
|
||||
<g clip-path="url(#zooGreen)"><g clip-path="url(#zooRed)"><circle cx="643" cy="595" r="234" fill="#FFFFFF"/></g></g>
|
||||
</g>
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 303 B After Width: | Height: | Size: 947 B |
@@ -20,7 +20,17 @@ type CSSish = React.CSSProperties & { [k: string]: any }
|
||||
function tokenize(v: any): string | undefined {
|
||||
if (v === undefined || v === null) return undefined
|
||||
if (typeof v === "number") return `${v}px`
|
||||
if (typeof v === "string" && v.startsWith("$")) return `var(--${v.slice(1)})`
|
||||
if (typeof v === "string" && v.startsWith("$")) {
|
||||
const t = v.slice(1)
|
||||
// Numeric Tamagui space/size token ($3, $6, $10, $0.5) → px on a 4px
|
||||
// scale. These are NOT CSS vars (loadBrandConfig only sets named color
|
||||
// vars like --accent1), so mapping them to `var(--3)` silently dropped
|
||||
// every gap/padding/fontSize — the source of the "button blob" (no gap)
|
||||
// and top-anchored card. Resolve them to real pixels instead.
|
||||
if (/^-?\d*\.?\d+$/.test(t)) return `${parseFloat(t) * 4}px`
|
||||
// Named theme token ($neutral2, $accent1) → CSS var set by loadBrandConfig.
|
||||
return `var(--${t})`
|
||||
}
|
||||
return String(v)
|
||||
}
|
||||
|
||||
|
||||
@@ -1,13 +1,70 @@
|
||||
/**
|
||||
* First-launch splash. Two paths: create new wallet, or import existing.
|
||||
* Foundation router mounts this at /auth.
|
||||
*
|
||||
* Styled with plain inline styles + brand CSS vars (the same pattern as
|
||||
* AppShell / Callback / Download) rather than @hanzo/gui primitives: the
|
||||
* gui-stub's Tamagui token props do not carry a working flex/centering
|
||||
* contract, which left the card top-anchored and the CTAs gap-less. This
|
||||
* screen owns its layout so it renders correctly on every brand + breakpoint.
|
||||
*/
|
||||
import { Link } from "react-router-dom"
|
||||
import { Button, Card, Text, YStack } from "@hanzo/gui"
|
||||
import { useNavigate } from "react-router-dom"
|
||||
import { brand, getIamConfig } from "@luxfi/wallet-brand"
|
||||
import { useSession } from "../../store/session"
|
||||
|
||||
const wrap: React.CSSProperties = {
|
||||
// Fill the AppShell content row (viewport minus header + main padding) and
|
||||
// center the card so there is no empty void beneath it on desktop.
|
||||
minHeight: "calc(100vh - 140px)",
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
gap: 20,
|
||||
padding: 16,
|
||||
boxSizing: "border-box",
|
||||
}
|
||||
|
||||
const card: React.CSSProperties = {
|
||||
width: "100%",
|
||||
maxWidth: 380,
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
gap: 12,
|
||||
padding: 24,
|
||||
borderRadius: 14,
|
||||
background: "var(--surface2, #f9f9f9)",
|
||||
border: "1px solid var(--surface3, #e5e5e5)",
|
||||
boxSizing: "border-box",
|
||||
}
|
||||
|
||||
const buttonBase: React.CSSProperties = {
|
||||
width: "100%",
|
||||
minHeight: 44,
|
||||
padding: "12px 16px",
|
||||
borderRadius: 10,
|
||||
fontSize: 15,
|
||||
fontWeight: 600,
|
||||
cursor: "pointer",
|
||||
fontFamily: "inherit",
|
||||
}
|
||||
|
||||
const primaryButton: React.CSSProperties = {
|
||||
...buttonBase,
|
||||
background: "var(--accent1, #000)",
|
||||
color: "var(--surface1, #fff)",
|
||||
border: "1px solid var(--accent1, #000)",
|
||||
}
|
||||
|
||||
const outlinedButton: React.CSSProperties = {
|
||||
...buttonBase,
|
||||
background: "transparent",
|
||||
color: "var(--neutral1, #111)",
|
||||
border: "1px solid var(--surface3, #d4d4d4)",
|
||||
}
|
||||
|
||||
export default function Welcome() {
|
||||
const navigate = useNavigate()
|
||||
const login = useSession((s) => s.login)
|
||||
const status = useSession((s) => s.status)
|
||||
// Account login is additive — only offered when the brand has an IdP wired.
|
||||
@@ -16,42 +73,48 @@ export default function Welcome() {
|
||||
const idpName = brand.shortName || brand.name || "Lux"
|
||||
|
||||
return (
|
||||
<YStack flex={1} ai="center" jc="center" gap="$6" p="$6">
|
||||
<Text fontSize="$10" fontWeight="700">
|
||||
{brand.walletName || "▼"}
|
||||
</Text>
|
||||
<Text fontSize="$4" col="$neutral2" ta="center" maxWidth={360}>
|
||||
<div style={wrap}>
|
||||
{brand.logoUrl ? (
|
||||
<img src={brand.logoUrl} alt="" width={56} height={56} aria-hidden="true" />
|
||||
) : null}
|
||||
<h1 style={{ margin: 0, fontSize: 28, fontWeight: 700, color: "var(--neutral1, #111)" }}>
|
||||
{brand.walletName || "Wallet"}
|
||||
</h1>
|
||||
<p
|
||||
style={{
|
||||
margin: 0,
|
||||
maxWidth: 340,
|
||||
textAlign: "center",
|
||||
fontSize: 15,
|
||||
lineHeight: 1.5,
|
||||
color: "var(--neutral2, #666)",
|
||||
}}
|
||||
>
|
||||
{brand.description || "Self-custodial wallet for the Lux ecosystem."}
|
||||
</Text>
|
||||
</p>
|
||||
|
||||
<Card p="$5" maxWidth={360} width="100%">
|
||||
<YStack gap="$3">
|
||||
<Link to="/auth/create" style={{ textDecoration: "none" }}>
|
||||
<Button width="100%" theme="active">
|
||||
Create new wallet
|
||||
</Button>
|
||||
</Link>
|
||||
<Link to="/auth/import" style={{ textDecoration: "none" }}>
|
||||
<Button width="100%" variant="outlined">
|
||||
Import existing
|
||||
</Button>
|
||||
</Link>
|
||||
{accountLoginEnabled ? (
|
||||
<Button
|
||||
width="100%"
|
||||
variant="outlined"
|
||||
disabled={status === "loading"}
|
||||
// Self-custody keys stay local; this adds a cloud account
|
||||
// (lux.id) for sync + MPC custody. Navigates to the IdP.
|
||||
onPress={() => {
|
||||
void login()
|
||||
}}
|
||||
>
|
||||
{status === "loading" ? "Connecting…" : `Sign in with ${idpName}`}
|
||||
</Button>
|
||||
) : null}
|
||||
</YStack>
|
||||
</Card>
|
||||
</YStack>
|
||||
<div style={card}>
|
||||
<button type="button" style={primaryButton} onClick={() => navigate("/auth/create")}>
|
||||
Create new wallet
|
||||
</button>
|
||||
<button type="button" style={outlinedButton} onClick={() => navigate("/auth/import")}>
|
||||
Import existing
|
||||
</button>
|
||||
{accountLoginEnabled ? (
|
||||
<button
|
||||
type="button"
|
||||
style={{ ...outlinedButton, opacity: status === "loading" ? 0.6 : 1 }}
|
||||
disabled={status === "loading"}
|
||||
// Self-custody keys stay local; this adds a cloud account (lux.id)
|
||||
// for sync + MPC custody. Navigates to the IdP.
|
||||
onClick={() => {
|
||||
void login()
|
||||
}}
|
||||
>
|
||||
{status === "loading" ? "Connecting…" : `Sign in with ${idpName}`}
|
||||
</button>
|
||||
) : null}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user