diff --git a/src/components/Layout.tsx b/src/components/Layout.tsx index 010e597..80f65b3 100644 --- a/src/components/Layout.tsx +++ b/src/components/Layout.tsx @@ -2,7 +2,7 @@ import { useState, useRef, lazy, Suspense } from 'react'; import { Link, useLocation } from 'react-router-dom'; import { nip19 } from 'nostr-tools'; import { cn } from '@/lib/utils'; -import { CustomizeNavSheet } from '@/components/CustomizeNavSheet'; +import { isNativePlatform } from '@/lib/platform'; import { useNavPreferences, useDesktopNavPreferences, type NavTab } from '@/hooks/useNavPreferences'; import { Button } from '@/components/ui/button'; import { Badge } from '@/components/ui/badge'; @@ -15,9 +15,7 @@ import { DropdownMenuSeparator, } from '@/components/ui/dropdown-menu'; import { LoginArea } from '@/components/auth/LoginArea'; -import { LoginDialog } from '@/components/auth/LoginDialog'; import { useSasquatchGuide } from '@/hooks/useSasquatchGuide'; -import { BackupReminder } from '@/components/BackupReminder'; import { LanguageToggle } from '@/components/LanguageToggle'; import { useCurrentUser } from '@/hooks/useCurrentUser'; import { useTranslation } from '@/contexts/LanguageContext'; @@ -54,7 +52,6 @@ import { } from 'lucide-react'; import { OfflineIndicator } from '@/components/OfflineIndicator'; import { UserStatusIndicator } from '@/components/UserStatusIndicator'; -import { SetStatusDialog } from '@/components/SetStatusDialog'; import { Avatar, AvatarImage, AvatarFallback } from '@/components/ui/avatar'; import { useAuthor } from '@/hooks/useAuthor'; import { genUserName } from '@/lib/genUserName'; @@ -76,6 +73,35 @@ const LazyCashuMenuBalance = lazy(() => const LazySasquatchGuide = lazy(() => import('@/components/SasquatchGuide').then((m) => ({ default: m.SasquatchGuide })), ); +// On-demand modals — only rendered after the user opens them, so keep them out +// of the always-loaded Layout chunk. +const LazyCustomizeNavSheet = lazy(() => + import('@/components/CustomizeNavSheet').then((m) => ({ default: m.CustomizeNavSheet })), +); +const LazySetStatusDialog = lazy(() => + import('@/components/SetStatusDialog').then((m) => ({ default: m.SetStatusDialog })), +); +const LazyLoginDialog = lazy(() => + import('@/components/auth/LoginDialog').then((m) => ({ default: m.LoginDialog })), +); +const LazyBackupReminder = lazy(() => + import('@/components/BackupReminder').then((m) => ({ default: m.BackupReminder })), +); + +/** + * Cheap synchronous hint that a Cashu wallet MIGHT exist, used to decide + * whether to even load the (large) wallet chunk. On native the seed lives in + * the OS KeyStore which we can't query synchronously, so we always load there; + * on web `useCashu` persists the mnemonic in localStorage under this key. + */ +function hasCashuWalletHint(): boolean { + if (isNativePlatform()) return true; + try { + return !!localStorage.getItem('cashu-mnemonic'); + } catch { + return false; + } +} interface LayoutProps { children: React.ReactNode; @@ -371,9 +397,11 @@ function MobileNav({ {isWallet ? ( <> - - - + {hasCashuWalletHint() && ( + + + + )} ) : ( @@ -657,9 +685,11 @@ export function Layout({ children, noPadding }: LayoutProps) { )} > - - - + {hasCashuWalletHint() && ( + + + + )} )} @@ -778,9 +808,11 @@ export function Layout({ children, noPadding }: LayoutProps) {

Ecash

- - - + {hasCashuWalletHint() && ( + + + + )} @@ -973,8 +1005,10 @@ export function Layout({ children, noPadding }: LayoutProps) { - {/* Backup Reminder */} - + {/* Backup Reminder — lazy (on-demand banner) */} + + + {/* Main Content — extra bottom padding on mobile so the fixed bottom nav never overlaps */} {/* noPadding: full-bleed pages (map) manage their own height */} @@ -1048,8 +1082,10 @@ export function Layout({ children, noPadding }: LayoutProps) { middleTabs={middleTabs} /> - {/* Bottom-nav customization sheet (mobile) */} - + {/* Bottom-nav customization sheet (mobile) — lazy (on-demand modal) */} + + + {/* Sasquatch Guide (all screens) — lazy; not needed at first paint */} @@ -1059,18 +1095,22 @@ export function Layout({ children, noPadding }: LayoutProps) { /> - {/* Set Status Dialog */} - + {/* Set Status Dialog — lazy (on-demand modal) */} + + + - {/* Add-another-account (multi-account switch on mobile) */} - setShowAddAccount(false)} - onLogin={() => setShowAddAccount(false)} - /> + {/* Add-another-account (multi-account switch on mobile) — lazy */} + + setShowAddAccount(false)} + onLogin={() => setShowAddAccount(false)} + /> + {/* Newsletter: floating pill + Monday admin reminder */}