wallet: tighten layout widths, flatten settings sub-routes, swap balance skeleton for a spinner

The Wallet Settings hub stretched its header across the full layout width
while the menu list was capped at max-w-md, so the title floated centered
above a much narrower card. Constrain the page (header included) to the
same max-w-md container so the back arrow, title, and list line up. Apply
the same fix to /wallet/backup and /wallet/legacy.

Also tighten /wallet itself: the settings cog used to sit in a full-width
row while the balance + send/receive controls were max-w-sm, leaving the
cog floating off to the right. Pull the cog into the same max-w-sm
container so it sits flush with the rest of the UI.

The balance-loading state used two stacked skeletons (h-10 w-40, h-4 w-24)
that didn't match the final shape of the rendered balance — replace them
with a centered RefreshCw spinner. Drop the now-unused Skeleton import.

Flatten the sub-routes from /wallet/settings/backup -> /wallet/backup and
/wallet/settings/legacy -> /wallet/legacy. The deeper paths were redundant
since these are leaf pages reached only via the settings hub. Add Navigate
redirects from the old paths so any existing links / muscle memory still
resolve.
This commit is contained in:
Alex Gleason
2026-05-24 17:26:32 -05:00
parent 72a297935c
commit 9c16b300ea
5 changed files with 28 additions and 23 deletions
+6 -2
View File
@@ -150,8 +150,12 @@ export function AppRouter() {
<Route path="/settings/network" element={<NetworkSettingsPage />} />
<Route path="/wallet" element={<WalletPage />} />
<Route path="/wallet/settings" element={<BitcoinWalletSettingsPage />} />
<Route path="/wallet/settings/backup" element={<WalletBackupPage />} />
<Route path="/wallet/settings/legacy" element={<LegacyWalletRecoveryPage />} />
<Route path="/wallet/backup" element={<WalletBackupPage />} />
<Route path="/wallet/legacy" element={<LegacyWalletRecoveryPage />} />
{/* Old nested paths kept as redirects so any existing links / muscle
memory still land on the right page. */}
<Route path="/wallet/settings/backup" element={<Navigate to="/wallet/backup" replace />} />
<Route path="/wallet/settings/legacy" element={<Navigate to="/wallet/legacy" replace />} />
<Route path="/wallet/recovery" element={<WalletRecoveryPage />} />
<Route path="/wallet/migrate-v1" element={<WalletMigrateV1Page />} />
<Route path="/bitcoin" element={<Navigate to="/wallet" replace />} />
+4 -4
View File
@@ -39,7 +39,7 @@ export function BitcoinWalletSettingsPage() {
const rows: SettingsRow[] = [
{
id: 'backup',
to: '/wallet/settings/backup',
to: '/wallet/backup',
icon: <KeyRound className="size-4 text-white" />,
iconWrapClass: 'bg-blue-500',
labelKey: 'walletSettings.backup.label',
@@ -47,7 +47,7 @@ export function BitcoinWalletSettingsPage() {
},
{
id: 'legacy',
to: '/wallet/settings/legacy',
to: '/wallet/legacy',
icon: <History className="size-4 text-white" />,
iconWrapClass: 'bg-amber-500',
labelKey: 'walletSettings.legacy.label',
@@ -56,7 +56,7 @@ export function BitcoinWalletSettingsPage() {
];
return (
<main>
<main className="max-w-md mx-auto">
<PageHeader
backTo="/wallet"
alwaysShowBack
@@ -70,7 +70,7 @@ export function BitcoinWalletSettingsPage() {
}
/>
<div className="max-w-md mx-auto px-4 pt-2 pb-12">
<div className="px-4 pt-2 pb-12">
{/* Apple-style grouped list: rounded card, hairline dividers, chevrons. */}
<ul className="rounded-xl bg-card border divide-y divide-border overflow-hidden shadow-sm">
{rows.map((row) => (
+4 -4
View File
@@ -24,7 +24,7 @@ interface LegacyOption {
}
/**
* Legacy wallet recovery hub at `/wallet/settings/legacy`.
* Legacy wallet recovery hub at `/wallet/legacy`.
*
* Surfaces two opt-in recovery flows for funds that may still be sitting in
* Agora's previous wallet generations:
@@ -58,7 +58,7 @@ export function LegacyWalletRecoveryPage() {
if (!user) {
return (
<main>
<main className="max-w-md mx-auto">
<PageHeader
backTo="/wallet/settings"
alwaysShowBack
@@ -106,7 +106,7 @@ export function LegacyWalletRecoveryPage() {
const v2HasFunds = v2.v1TotalBalance > 0;
return (
<main>
<main className="max-w-md mx-auto">
<PageHeader
backTo="/wallet/settings"
alwaysShowBack
@@ -120,7 +120,7 @@ export function LegacyWalletRecoveryPage() {
}
/>
<div className="max-w-md mx-auto px-4 pt-2 pb-12 space-y-6">
<div className="px-4 pt-2 pb-12 space-y-6">
{/* V2 beta detection result — only when funds were actually found,
so the user gets a clear "you have something here" prompt instead
of a noisy "no funds detected" empty state for the common case. */}
+6 -6
View File
@@ -10,7 +10,7 @@ import { useCurrentUser } from '@/hooks/useCurrentUser';
import { useHdWalletAccess } from '@/hooks/useHdWalletAccess';
/**
* Seed-phrase backup page for `/wallet/settings/backup`.
* Seed-phrase backup page for `/wallet/backup`.
*
* Wraps the existing `WalletBackupMnemonic` component (previously rendered as
* a dialog from `/wallet`) in a full-page layout. The component itself hides
@@ -31,7 +31,7 @@ export function WalletBackupPage() {
// Not logged in — show the login prompt rather than redirecting away.
if (!user) {
return (
<main>
<main className="max-w-md mx-auto">
<PageHeader
backTo="/wallet/settings"
alwaysShowBack
@@ -59,7 +59,7 @@ export function WalletBackupPage() {
// leave a confusing blank page; explain why instead.
if (access.status !== 'available') {
return (
<main>
<main className="max-w-md mx-auto">
<PageHeader
backTo="/wallet/settings"
alwaysShowBack
@@ -69,7 +69,7 @@ export function WalletBackupPage() {
</div>
}
/>
<div className="py-20 px-8 flex flex-col items-center gap-6 text-center max-w-md mx-auto">
<div className="py-20 px-8 flex flex-col items-center gap-6 text-center">
<p className="text-muted-foreground text-sm">
{t('walletBackupPage.unsupported')}
</p>
@@ -79,7 +79,7 @@ export function WalletBackupPage() {
}
return (
<main>
<main className="max-w-md mx-auto">
<PageHeader
backTo="/wallet/settings"
alwaysShowBack
@@ -93,7 +93,7 @@ export function WalletBackupPage() {
}
/>
<div className="max-w-md mx-auto px-4 pt-2 pb-12">
<div className="px-4 pt-2 pb-12">
<WalletBackupMnemonic />
</div>
</main>
+8 -7
View File
@@ -17,7 +17,6 @@ import {
} from 'lucide-react';
import { Button } from '@/components/ui/button';
import { Skeleton } from '@/components/ui/skeleton';
import { LoginArea } from '@/components/auth/LoginArea';
import { QRCodeCanvas } from '@/components/ui/qrcode';
import {
@@ -152,10 +151,13 @@ export function WalletPage() {
// ── Available — full HD wallet UI ────────────────────────────
return (
<main>
<main className="max-w-sm mx-auto">
{/* Top bar: settings cog only. We deliberately keep this minimal —
the wallet home doubles as a phone-style "home screen" with the
balance as the hero, so any chrome here pushes that down. */}
balance as the hero, so any chrome here pushes that down. The cog
shares the `max-w-sm` container with the rest of the wallet UI so
it sits flush with the balance + send/receive controls instead of
floating off in the far corner of a wide layout. */}
<div className="flex items-center justify-end px-4 pt-3">
<Link
to="/wallet/settings"
@@ -167,12 +169,11 @@ export function WalletPage() {
</Link>
</div>
<div className="flex flex-col items-center px-4 pt-4 pb-4 space-y-6 max-w-sm mx-auto">
<div className="flex flex-col items-center px-4 pt-4 pb-4 space-y-6">
{/* Balance */}
{isLoading ? (
<div className="flex flex-col items-center space-y-2">
<Skeleton className="h-10 w-40 rounded-lg" />
<Skeleton className="h-4 w-24 rounded" />
<div className="flex flex-col items-center justify-center py-8">
<RefreshCw className="size-6 animate-spin text-muted-foreground" />
</div>
) : error ? (
<div className="text-center space-y-3">