create-awarizon-app 1.0.9 → 1.0.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (33) hide show
  1. package/dist/index.js +0 -0
  2. package/package.json +8 -8
  3. package/templates/expo/app/(tabs)/_layout.tsx +4 -3
  4. package/templates/expo/app/(tabs)/index.tsx +40 -64
  5. package/templates/expo/app/(tabs)/nft.tsx +142 -0
  6. package/templates/expo/app/(tabs)/wallet.tsx +127 -0
  7. package/templates/expo/babel.config.js +6 -0
  8. package/templates/expo/package.json +22 -23
  9. package/templates/expo-js/app/(tabs)/_layout.jsx +4 -3
  10. package/templates/expo-js/app/(tabs)/index.jsx +40 -66
  11. package/templates/expo-js/app/(tabs)/nft.jsx +141 -0
  12. package/templates/expo-js/app/(tabs)/wallet.jsx +128 -0
  13. package/templates/expo-js/package.json +19 -20
  14. package/templates/nextjs/app/layout.tsx +5 -1
  15. package/templates/nextjs/app/nft/page.tsx +140 -0
  16. package/templates/nextjs/app/page.tsx +37 -155
  17. package/templates/nextjs/app/wallet/page.tsx +116 -0
  18. package/templates/nextjs/components/Header.tsx +56 -0
  19. package/templates/nextjs/package.json +15 -16
  20. package/templates/nextjs-js/app/layout.jsx +5 -1
  21. package/templates/nextjs-js/app/nft/page.jsx +139 -0
  22. package/templates/nextjs-js/app/page.jsx +37 -128
  23. package/templates/nextjs-js/app/wallet/page.jsx +116 -0
  24. package/templates/nextjs-js/components/Header.jsx +56 -0
  25. package/templates/nextjs-js/package.json +11 -12
  26. package/templates/react/package.json +14 -15
  27. package/templates/react/src/App.tsx +88 -145
  28. package/templates/react/src/pages/NftPage.tsx +138 -0
  29. package/templates/react/src/pages/WalletPage.tsx +114 -0
  30. package/templates/react-js/package.json +11 -12
  31. package/templates/react-js/src/App.jsx +86 -118
  32. package/templates/react-js/src/pages/NftPage.jsx +137 -0
  33. package/templates/react-js/src/pages/WalletPage.jsx +114 -0
@@ -1,166 +1,109 @@
1
- import { useReadContract, ConnectButton } from '@awarizon/react'
2
- import { ERC20_ABI } from '@awarizon/web3'
3
- import { Badge } from './components/ui/Badge'
4
- import { Button } from './components/ui/Button'
5
- import { Card } from './components/ui/Card'
6
- import { Skeleton } from './components/ui/Skeleton'
7
- import { StatCard } from './components/ui/StatCard'
1
+ import { useState } from 'react'
2
+ import { usePrices, ConnectButton } from '@awarizon/react'
3
+ import { Skeleton } from './components/ui/Skeleton'
4
+ import { NftPage } from './pages/NftPage'
5
+ import { WalletPage } from './pages/WalletPage'
8
6
 
9
- const USDC_BASE = '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913'
7
+ type Page = 'home' | 'nft' | 'wallet'
8
+
9
+ const NAV: { id: Page; label: string }[] = [
10
+ { id: 'home', label: 'Markets' },
11
+ { id: 'nft', label: 'NFT' },
12
+ { id: 'wallet', label: 'Wallet' },
13
+ ]
14
+
15
+ const TOKENS = [
16
+ { symbol: 'ETH', name: 'Ethereum', color: '#627EEA' },
17
+ { symbol: 'BTC', name: 'Bitcoin', color: '#F7931A' },
18
+ { symbol: 'USDC', name: 'USD Coin', color: '#2775CA' },
19
+ { symbol: 'BNB', name: 'BNB', color: '#F3BA2F' },
20
+ { symbol: 'SOL', name: 'Solana', color: '#9945FF' },
21
+ ]
22
+
23
+ function HomePage() {
24
+ const { prices, isLoading } = usePrices(TOKENS.map(t => t.symbol))
10
25
 
11
- function DataRow({ label, value, loading }: { label: string; value?: string; loading: boolean }) {
12
26
  return (
13
- <div className="flex items-center justify-between py-3 border-b border-zinc-800/50 last:border-0">
14
- <code className="text-[11px] text-yellow-400/70 font-mono">{label}</code>
15
- {loading
16
- ? <Skeleton className="h-3.5 w-28" />
17
- : <span className="font-mono text-xs text-zinc-300">{value ?? '—'}</span>}
18
- </div>
27
+ <main className="max-w-5xl mx-auto px-6 py-10">
28
+ <div className="grid grid-cols-2 sm:grid-cols-3 lg:grid-cols-5 gap-4">
29
+ {TOKENS.map(({ symbol, name, color }) => {
30
+ const price = prices[symbol]?.price
31
+ return (
32
+ <div
33
+ key={symbol}
34
+ className="bg-zinc-900/40 border border-zinc-800/40 rounded-2xl p-5 hover:bg-zinc-900/60 hover:border-zinc-700/50 transition-all cursor-default"
35
+ >
36
+ <div className="mb-4">
37
+ <div
38
+ className="w-10 h-10 rounded-full flex items-center justify-center text-[10px] font-bold tracking-wider mb-3"
39
+ style={{ backgroundColor: `${color}18`, border: `1px solid ${color}25`, color }}
40
+ >
41
+ {symbol.slice(0, 3)}
42
+ </div>
43
+ <p className="text-[11px] text-zinc-500 font-medium mb-0.5">{symbol}</p>
44
+ <p className="text-xs text-zinc-600">{name}</p>
45
+ </div>
46
+ <div className="text-lg font-semibold text-white tracking-tight">
47
+ {isLoading
48
+ ? <Skeleton className="h-5 w-20" />
49
+ : price != null
50
+ ? `$${price.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}`
51
+ : '—'}
52
+ </div>
53
+ </div>
54
+ )
55
+ })}
56
+ </div>
57
+ </main>
19
58
  )
20
59
  }
21
60
 
22
61
  export default function App() {
23
- const { data: name, isLoading: l1 } = useReadContract({ address: USDC_BASE, abi: ERC20_ABI, method: 'name' })
24
- const { data: symbol, isLoading: l2 } = useReadContract({ address: USDC_BASE, abi: ERC20_ABI, method: 'symbol' })
25
- const { data: decimals, isLoading: l3 } = useReadContract({ address: USDC_BASE, abi: ERC20_ABI, method: 'decimals' })
26
- const { data: totalSupply, isLoading: l4 } = useReadContract({ address: USDC_BASE, abi: ERC20_ABI, method: 'totalSupply' })
27
-
28
- const formatted =
29
- totalSupply !== undefined && decimals !== undefined
30
- ? (Number(totalSupply as bigint) / 10 ** Number(decimals as bigint))
31
- .toLocaleString(undefined, { maximumFractionDigits: 2 })
32
- : undefined
33
-
34
- const synced = !l1 && !l2 && !l3 && !l4
62
+ const [page, setPage] = useState<Page>('home')
35
63
 
36
64
  return (
37
- <div className="min-h-screen bg-zinc-950 text-zinc-100">
65
+ <div className="min-h-screen">
38
66
 
39
- {/* ── Header ─────────────────────────────────────── */}
40
- <header className="sticky top-0 z-10 border-b border-zinc-800/60 bg-zinc-950/80 backdrop-blur-sm px-6 py-4">
41
- <div className="max-w-4xl mx-auto flex items-center justify-between">
42
- <div className="flex items-center gap-2.5">
43
- <div className="w-5 h-5 rounded-[4px] bg-yellow-400" />
44
- <span className="font-mono text-[11px] tracking-[0.2em] text-zinc-400 uppercase">
45
- {{project-name}}
46
- </span>
47
- </div>
48
- <div className="flex items-center gap-3">
49
- <Badge variant="outline">Base</Badge>
50
- <Badge variant={synced ? 'success' : 'loading'}>
51
- {synced ? '● Live' : '○ Loading'}
52
- </Badge>
53
- {import.meta.env.VITE_WALLETCONNECT_PROJECT_ID && <ConnectButton />}
54
- </div>
55
- </div>
56
- </header>
67
+ <header className="sticky top-0 z-50 border-b border-white/[0.06] bg-zinc-950/70 backdrop-blur-2xl">
68
+ <div className="max-w-5xl mx-auto px-6 h-16 flex items-center justify-between gap-8">
57
69
 
58
- <main className="max-w-4xl mx-auto px-6 py-12">
59
-
60
- {/* ── Hero ───────────────────────────────────────── */}
61
- <div className="mb-10">
62
- <Badge variant="outline" className="mb-5">Awarizon Web3 SDK · React + Vite</Badge>
63
- <h1 className="text-4xl font-bold tracking-tight text-white mb-3">{{ProjectName}}</h1>
64
- <p className="text-zinc-400 text-base max-w-lg leading-relaxed">
65
- Live on-chain reads from Base — no backend required. Built with{' '}
66
- <code className="font-mono text-[11px] text-yellow-400/80">@awarizon/react</code>.
67
- </p>
68
- </div>
70
+ <div className="flex items-center gap-2.5 shrink-0">
71
+ <div className="w-7 h-7 rounded-lg bg-yellow-400" />
72
+ <span className="text-sm font-semibold text-white">{'{{project-name}}'}</span>
73
+ </div>
69
74
 
70
- {/* ── Data grid ──────────────────────────────────── */}
71
- <div className="grid md:grid-cols-3 gap-4 mb-4">
75
+ <nav className="flex items-center">
76
+ {NAV.map(({ id, label }) => (
77
+ <button
78
+ key={id}
79
+ onClick={() => setPage(id)}
80
+ className={[
81
+ 'relative px-4 py-2 text-sm font-medium transition-colors',
82
+ page === id ? 'text-white' : 'text-zinc-500 hover:text-zinc-300',
83
+ ].join(' ')}
84
+ >
85
+ {label}
86
+ {page === id && (
87
+ <span className="absolute bottom-0 left-4 right-4 h-px bg-yellow-400" />
88
+ )}
89
+ </button>
90
+ ))}
91
+ </nav>
72
92
 
73
- {/* Contract reader spans 2 cols */}
74
- <Card className="md:col-span-2">
75
- <div className="flex items-start justify-between mb-4">
76
- <div>
77
- <p className="font-mono text-[9px] tracking-widest text-zinc-600 uppercase mb-1.5">
78
- Contract · Live Read
79
- </p>
80
- <code className="font-mono text-xs text-zinc-500">
81
- 0x8335…2913 · Base
82
- </code>
83
- </div>
84
- <Badge variant={synced ? 'success' : 'loading'}>
85
- {synced ? 'Synced' : 'Fetching…'}
86
- </Badge>
93
+ <div className="flex items-center gap-3 shrink-0">
94
+ <div className="hidden sm:flex items-center gap-1.5 px-3 py-1.5 rounded-full border border-zinc-800 bg-zinc-900/60 text-xs text-zinc-400 font-medium">
95
+ <span className="w-1.5 h-1.5 rounded-full bg-green-400 inline-block" />
96
+ Base
87
97
  </div>
88
- <DataRow label="name()" value={name as string} loading={l1} />
89
- <DataRow label="symbol()" value={symbol as string} loading={l2} />
90
- <DataRow label="decimals()" value={String(decimals ?? '')} loading={l3} />
91
- <DataRow label="totalSupply()" value={formatted} loading={l4} />
92
- </Card>
93
-
94
- {/* Stat column */}
95
- <div className="flex flex-col gap-4">
96
- <StatCard
97
- label="Total Supply"
98
- value={formatted}
99
- loading={l4}
100
- sub="USDC · formatted"
101
- className="flex-1"
102
- />
103
- <StatCard
104
- label="Token"
105
- value={symbol as string}
106
- loading={l2}
107
- sub="Base mainnet"
108
- className="flex-1"
109
- />
98
+ {import.meta.env.VITE_WALLETCONNECT_PROJECT_ID && <ConnectButton />}
110
99
  </div>
111
- </div>
112
100
 
113
- {/* ── Network info ────────────────────────────────── */}
114
- <div className="grid sm:grid-cols-3 gap-4 mb-4">
115
- {[
116
- { label: 'Network', value: 'Base Mainnet' },
117
- { label: 'Chain ID', value: '8453' },
118
- { label: 'SDK', value: '@awarizon/react' },
119
- ].map(({ label, value }) => (
120
- <div
121
- key={label}
122
- className="bg-zinc-900/50 border border-zinc-800/40 rounded-xl px-5 py-4 flex items-center justify-between"
123
- >
124
- <span className="font-mono text-[10px] text-zinc-600 uppercase tracking-widest">{label}</span>
125
- <code className="font-mono text-xs text-zinc-400">{value}</code>
126
- </div>
127
- ))}
128
101
  </div>
102
+ </header>
129
103
 
130
- {/* ── Next steps ──────────────────────────────────── */}
131
- <Card>
132
- <p className="font-mono text-[9px] tracking-widest text-zinc-600 uppercase mb-4">
133
- Next Steps
134
- </p>
135
- <ul className="space-y-3 mb-6">
136
- {[
137
- ['01', 'Replace USDC_BASE with your contract address'],
138
- ['02', 'Swap ERC20_ABI for your contract ABI'],
139
- ['03', 'Change chain="base" in src/main.tsx to your target network'],
140
- ['04', 'Use useWriteContract() for send transactions'],
141
- ['05', 'Add walletConnectProjectId to AwarizonProvider for mobile wallet support'],
142
- ].map(([n, s]) => (
143
- <li key={n} className="flex items-start gap-3">
144
- <span className="font-mono text-[10px] text-yellow-400/50 mt-0.5 shrink-0 select-none">{n}</span>
145
- <span className="text-sm text-zinc-400 leading-relaxed">{s}</span>
146
- </li>
147
- ))}
148
- </ul>
149
- <div className="flex flex-wrap gap-2">
150
- <Button href="https://awarizon.com/docs" target="_blank" rel="noreferrer">
151
- Read the docs →
152
- </Button>
153
- <Button
154
- href="https://awarizon.com/dashboard"
155
- target="_blank"
156
- rel="noreferrer"
157
- variant="secondary"
158
- >
159
- Dashboard
160
- </Button>
161
- </div>
162
- </Card>
163
- </main>
104
+ {page === 'home' && <HomePage />}
105
+ {page === 'nft' && <NftPage />}
106
+ {page === 'wallet' && <WalletPage />}
164
107
  </div>
165
108
  )
166
109
  }
@@ -0,0 +1,138 @@
1
+ import { useState } from 'react'
2
+ import { useNFT } from '@awarizon/react'
3
+ import type { Address } from '@awarizon/web3'
4
+ import { Badge } from '../components/ui/Badge'
5
+ import { Button } from '../components/ui/Button'
6
+ import { Card } from '../components/ui/Card'
7
+ import { Skeleton } from '../components/ui/Skeleton'
8
+
9
+ // Replace with your ERC-721 contract address on your configured chain.
10
+ const NFT_ADDRESS = '0x0000000000000000000000000000000000000000' as Address
11
+
12
+ function DataRow({ label, value, loading }: { label: string; value?: string; loading: boolean }) {
13
+ return (
14
+ <div className="flex items-center justify-between py-3 border-b border-zinc-800/50 last:border-0">
15
+ <code className="text-[11px] text-yellow-400/70 font-mono">{label}</code>
16
+ {loading
17
+ ? <Skeleton className="h-3.5 w-28" />
18
+ : <span className="font-mono text-xs text-zinc-300">{value ?? '—'}</span>}
19
+ </div>
20
+ )
21
+ }
22
+
23
+ export function NftPage() {
24
+ const { name, symbol, isLoading, error, ownerOf, tokenURI } = useNFT(NFT_ADDRESS)
25
+
26
+ const [tokenId, setTokenId] = useState('')
27
+ const [owner, setOwner] = useState<string | null>(null)
28
+ const [uri, setUri] = useState<string | null>(null)
29
+ const [lookupLoading, setLookupLoading] = useState(false)
30
+ const [lookupError, setLookupError] = useState<string | null>(null)
31
+
32
+ async function handleLookup() {
33
+ if (!tokenId) return
34
+ setLookupLoading(true)
35
+ setLookupError(null)
36
+ setOwner(null)
37
+ setUri(null)
38
+ try {
39
+ const id = BigInt(tokenId)
40
+ const [o, u] = await Promise.all([ownerOf(id), tokenURI(id)])
41
+ setOwner(o)
42
+ setUri(u)
43
+ } catch (e) {
44
+ setLookupError(e instanceof Error ? e.message : 'Lookup failed')
45
+ } finally {
46
+ setLookupLoading(false)
47
+ }
48
+ }
49
+
50
+ return (
51
+ <main className="max-w-4xl mx-auto px-6 py-12">
52
+
53
+ {/* ── Hero ───────────────────────────────────────── */}
54
+ <div className="mb-10">
55
+ <Badge variant="outline" className="mb-5">ERC-721</Badge>
56
+ <h1 className="text-4xl font-bold tracking-tight text-white mb-3">NFT Collection</h1>
57
+ <p className="text-zinc-400 text-base max-w-lg leading-relaxed">
58
+ Zero-ABI reads from any ERC-721 contract using{' '}
59
+ <code className="font-mono text-[11px] text-yellow-400/80">useNFT</code>.
60
+ Replace <code className="font-mono text-[11px] text-yellow-400/80">NFT_ADDRESS</code> at the top of this file.
61
+ </p>
62
+ </div>
63
+
64
+ {error && (
65
+ <div className="mb-4 px-4 py-3 bg-red-500/10 border border-red-500/20 rounded-xl">
66
+ <code className="font-mono text-xs text-red-400">{error.message}</code>
67
+ </div>
68
+ )}
69
+
70
+ {/* ── Cards ──────────────────────────────────────── */}
71
+ <div className="grid md:grid-cols-2 gap-4 mb-4">
72
+
73
+ <Card>
74
+ <div className="mb-4">
75
+ <p className="font-mono text-[9px] tracking-widest text-zinc-600 uppercase mb-1.5">Collection Info</p>
76
+ <code className="font-mono text-xs text-zinc-500">
77
+ {NFT_ADDRESS.slice(0, 6)}…{NFT_ADDRESS.slice(-4)}
78
+ </code>
79
+ </div>
80
+ <DataRow label="name()" value={name ?? undefined} loading={isLoading} />
81
+ <DataRow label="symbol()" value={symbol ?? undefined} loading={isLoading} />
82
+ </Card>
83
+
84
+ <Card>
85
+ <p className="font-mono text-[9px] tracking-widest text-zinc-600 uppercase mb-4">Token Lookup</p>
86
+ <div className="flex gap-2 mb-4">
87
+ <input
88
+ type="number"
89
+ min="0"
90
+ value={tokenId}
91
+ onChange={e => setTokenId(e.target.value)}
92
+ placeholder="Token ID"
93
+ className="flex-1 bg-zinc-800 border border-zinc-700 rounded-lg px-3 py-2 font-mono text-xs text-zinc-200 placeholder-zinc-600 outline-none focus:border-yellow-400/40"
94
+ />
95
+ <Button onClick={handleLookup} disabled={!tokenId || lookupLoading}>
96
+ {lookupLoading ? 'Loading…' : 'Look up'}
97
+ </Button>
98
+ </div>
99
+ {lookupError && (
100
+ <p className="font-mono text-[11px] text-red-400 mb-3">{lookupError}</p>
101
+ )}
102
+ {owner !== null && (
103
+ <DataRow
104
+ label="ownerOf()"
105
+ value={`${owner.slice(0, 6)}…${owner.slice(-4)}`}
106
+ loading={false}
107
+ />
108
+ )}
109
+ {uri !== null && (
110
+ <div className="pt-3">
111
+ <p className="font-mono text-[9px] tracking-widest text-zinc-600 uppercase mb-1.5">tokenURI()</p>
112
+ <p className="font-mono text-xs text-zinc-300 break-all">{uri}</p>
113
+ </div>
114
+ )}
115
+ </Card>
116
+ </div>
117
+
118
+ {/* ── Notes ──────────────────────────────────────── */}
119
+ <Card>
120
+ <p className="font-mono text-[9px] tracking-widest text-zinc-600 uppercase mb-4">Usage Notes</p>
121
+ <ul className="space-y-3">
122
+ {[
123
+ ['01', 'Replace NFT_ADDRESS with any ERC-721 contract on your configured chain'],
124
+ ['02', 'useNFT requires no ABI — the SDK uses the built-in ERC-721 interface'],
125
+ ['03', 'ownerOf(tokenId) returns the owner address of a specific token'],
126
+ ['04', 'tokenURI(tokenId) returns the metadata URI (IPFS, Arweave, HTTP, etc.)'],
127
+ ['05', 'balanceOf(address) counts how many tokens a given address holds'],
128
+ ].map(([n, s]) => (
129
+ <li key={n} className="flex items-start gap-3">
130
+ <span className="font-mono text-[10px] text-yellow-400/50 mt-0.5 shrink-0 select-none">{n}</span>
131
+ <span className="text-sm text-zinc-400 leading-relaxed">{s}</span>
132
+ </li>
133
+ ))}
134
+ </ul>
135
+ </Card>
136
+ </main>
137
+ )
138
+ }
@@ -0,0 +1,114 @@
1
+ import { useWallet, useNativeBalance, usePrices, ConnectButton } from '@awarizon/react'
2
+ import { Badge } from '../components/ui/Badge'
3
+ import { Card } from '../components/ui/Card'
4
+ import { Skeleton } from '../components/ui/Skeleton'
5
+ import { StatCard } from '../components/ui/StatCard'
6
+
7
+ const SYMBOLS = ['ETH', 'BTC', 'USDC']
8
+
9
+ function DataRow({ label, value, loading }: { label: string; value?: string; loading: boolean }) {
10
+ return (
11
+ <div className="flex items-center justify-between py-3 border-b border-zinc-800/50 last:border-0">
12
+ <span className="font-mono text-[10px] text-zinc-600 uppercase tracking-widest">{label}</span>
13
+ {loading
14
+ ? <Skeleton className="h-3.5 w-32" />
15
+ : <span className="font-mono text-xs text-zinc-300">{value ?? '—'}</span>}
16
+ </div>
17
+ )
18
+ }
19
+
20
+ export function WalletPage() {
21
+ const { address, isConnected, isChainMismatch, chainId, connectorInfo } = useWallet()
22
+ const { formatted: nativeBalance, isLoading: balanceLoading } = useNativeBalance(
23
+ address ?? undefined,
24
+ 12_000,
25
+ )
26
+ const { prices, isLoading: pricesLoading } = usePrices(SYMBOLS)
27
+
28
+ const fmtPrice = (sym: string) =>
29
+ prices[sym]?.price != null
30
+ ? `$${prices[sym].price.toLocaleString(undefined, { maximumFractionDigits: 2 })}`
31
+ : undefined
32
+
33
+ const ethFiatValue =
34
+ nativeBalance != null && prices['ETH']?.price != null
35
+ ? `$${(parseFloat(nativeBalance) * prices['ETH'].price).toLocaleString(undefined, { maximumFractionDigits: 2 })}`
36
+ : undefined
37
+
38
+ return (
39
+ <main className="max-w-4xl mx-auto px-6 py-12">
40
+
41
+ {/* ── Hero ───────────────────────────────────────── */}
42
+ <div className="mb-10">
43
+ <Badge variant="outline" className="mb-5">Portfolio</Badge>
44
+ <h1 className="text-4xl font-bold tracking-tight text-white mb-3">Wallet</h1>
45
+ <p className="text-zinc-400 text-base max-w-lg leading-relaxed">
46
+ Live balance and portfolio data via{' '}
47
+ <code className="font-mono text-[11px] text-yellow-400/80">useWallet</code>,{' '}
48
+ <code className="font-mono text-[11px] text-yellow-400/80">useNativeBalance</code>, and{' '}
49
+ <code className="font-mono text-[11px] text-yellow-400/80">usePrices</code>.
50
+ </p>
51
+ </div>
52
+
53
+ {!isConnected ? (
54
+ <Card className="py-12 flex flex-col items-center text-center">
55
+ <p className="font-mono text-[10px] tracking-widest text-zinc-600 uppercase mb-3">
56
+ No Wallet Connected
57
+ </p>
58
+ <p className="text-zinc-400 text-sm mb-6 max-w-sm leading-relaxed">
59
+ Connect a wallet to view your address, native balance, and real-time portfolio value.
60
+ </p>
61
+ <ConnectButton />
62
+ </Card>
63
+ ) : (
64
+ <>
65
+ {isChainMismatch && (
66
+ <div className="mb-4 px-4 py-3 bg-amber-500/10 border border-amber-500/20 rounded-xl">
67
+ <span className="font-mono text-xs text-amber-400">
68
+ Wrong network — switch to the chain configured in src/main.tsx
69
+ </span>
70
+ </div>
71
+ )}
72
+
73
+ {/* ── Account ──────────────────────────────────── */}
74
+ <Card className="mb-4">
75
+ <p className="font-mono text-[9px] tracking-widest text-zinc-600 uppercase mb-4">Account</p>
76
+ <DataRow label="Address" value={address ?? undefined} loading={false} />
77
+ <DataRow label="Chain ID" value={chainId != null ? String(chainId) : undefined} loading={false} />
78
+ <DataRow label="Connector" value={connectorInfo?.name ?? connectorInfo?.type} loading={false} />
79
+ </Card>
80
+
81
+ {/* ── Balance ──────────────────────────────────── */}
82
+ <div className="grid sm:grid-cols-3 gap-4 mb-4">
83
+ <StatCard
84
+ label="Native Balance"
85
+ value={nativeBalance != null ? `${parseFloat(nativeBalance).toFixed(6)} ETH` : undefined}
86
+ loading={balanceLoading}
87
+ sub="useNativeBalance · 12 s poll"
88
+ className="sm:col-span-2"
89
+ />
90
+ <StatCard
91
+ label="Est. Value"
92
+ value={ethFiatValue}
93
+ loading={balanceLoading || pricesLoading}
94
+ sub="ETH × market price"
95
+ />
96
+ </div>
97
+
98
+ {/* ── Prices ───────────────────────────────────── */}
99
+ <div className="grid sm:grid-cols-3 gap-4">
100
+ {SYMBOLS.map(sym => (
101
+ <StatCard
102
+ key={sym}
103
+ label={sym}
104
+ value={fmtPrice(sym)}
105
+ loading={pricesLoading}
106
+ sub="USD · usePrices"
107
+ />
108
+ ))}
109
+ </div>
110
+ </>
111
+ )}
112
+ </main>
113
+ )
114
+ }
@@ -4,23 +4,22 @@
4
4
  "private": true,
5
5
  "type": "module",
6
6
  "scripts": {
7
- "dev": "vite",
8
- "build": "vite build",
7
+ "dev": "vite",
8
+ "build": "vite build",
9
9
  "preview": "vite preview",
10
- "lint": "eslint ."
10
+ "lint": "eslint ."
11
11
  },
12
12
  "dependencies": {
13
- "@awarizon/react": "^1.6.1",
14
- "@awarizon/web3": "^1.3.4",
15
- "react": "^18.3.1",
16
- "react-dom": "^18.3.1"
13
+ "@awarizon/react": "^1.6.2",
14
+ "@awarizon/web3": "^1.3.5",
15
+ "react": "^18.3.1",
16
+ "react-dom": "^18.3.1"
17
17
  },
18
18
  "devDependencies": {
19
19
  "@vitejs/plugin-react": "^4.3.1",
20
- "vite": "^5.4.1",
21
- "autoprefixer": "^10.4.19",
22
- "postcss": "^8.4.38",
23
- "tailwindcss": "^3.4.4"
20
+ "vite": "^5.4.1",
21
+ "autoprefixer": "^10.4.19",
22
+ "postcss": "^8.4.38",
23
+ "tailwindcss": "^3.4.4"
24
24
  }
25
25
  }
26
-