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:
+6
-2
@@ -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 />} />
|
||||
|
||||
@@ -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) => (
|
||||
|
||||
@@ -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. */}
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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">
|
||||
|
||||
Reference in New Issue
Block a user