feat: add neon color picker for wallet management

- Replace muted Tailwind palette with 16-color neon palette
- Add clickable color dot in sidebar that opens a popup swatch grid
- Allow color override for all wallets (including embedded)
- Fix getColorForWallet to respect localStorage override
- Fix duplicate renameWallet in wallets.js
- Update Dockerfile to serve ESM modules via nginx
This commit is contained in:
Dione
2026-06-10 07:10:24 +00:00
parent 5716f34967
commit c573e58e0f
4 changed files with 173 additions and 7 deletions

View File

@ -10,11 +10,24 @@ docker build -t cbBTC-dashboard . && docker run -p 8080:80 cbBTC-dashboard
Or just open `index.html` in a browser (without the `/api/` proxy, only the Kraken BTC price chart will work).
## Architecture
The codebase is split into three vanilla ESM modules plus the single-page dashboard:
| Module | Purpose |
|---|---|
| `wallets.js` | **`WalletManager`** — localStorage state, chain-specific address validation, verification lifecycle |
| `verifier.js` | **`WalletVerifier`** — EIP-712 typed-data signing via `window.ethereum`, user rejection handling |
| `stream.js` | **`WalletStreamManager`** — single WebSocket with BroadcastChannel leader election, exponential backoff + jitter |
## File layout
| File | Purpose |
|---|---|
| `index.html` | Everything. Frontend, embedded chart data, inline JS logic. Edit here. |
| `index.html` | Dashboard UI. Embedded chart data, ApexCharts, TailwindCSS. Loads modules via `<script type="module">`. |
| `wallets.js` | `WalletManager` — anonymous localStorage wallet state, add/remove/verify/revoke |
| `verifier.js` | `WalletVerifier``window.ethereum` connection + EIP-712 signature flow |
| `stream.js` | `WalletStreamManager` — single WS, cross-tab leader election, event routing |
| `Dockerfile` | 4 lines. Copies `index.html` and `default.conf` into `nginx:alpine`. |
| `default.conf` | Reverse proxy: `/api/``http://192.168.1.102:8000/api/`. |
| `aave_portfolio.md` / `wallet_portfolio.md` | Reference data dumps. NOT consumed by the app. |
@ -34,11 +47,62 @@ Or just open `index.html` in a browser (without the `/api/` proxy, only the Krak
- **Tracked wallet:** `0x0c1a4a060e119f981412e323104d1c134d413dba` ("penguin", Base)
- **Token decimals:** cbBTC=8, WETH=18, USDC=6
## Module API
Each module is loaded via `<script type="module">` in `index.html`:
```js
import { WalletManager } from './wallets.js';
import { WalletVerifier } from './verifier.js';
import { WalletStreamManager } from './stream.js';
const wm = new WalletManager();
wm.loadWallets();
const verifier = new WalletVerifier(wm);
const stream = new WalletStreamManager(wm);
stream.connect();
```
### WalletManager
| Method | Description |
|---|---|
| `loadWallets()` | Reads from localStorage, sanitizes (always `isVerified: false`) |
| `addWallet(address, chain, nickname)` | Validates format, appends, persists |
| `removeWallet(address, chain)` | Drops from state, persists |
| `verifyWallet(address, chain, signature, messageData)` | Sets `isVerified: true` |
| `revokeVerification(address, chain)` | Resets to unverified |
| `findWallet(address, chain)` | Lookup helper |
| `getWallets()` | Returns deep copy of state |
### WalletVerifier
| Method | Description |
|---|---|
| `triggerWalletVerification(chain, nickname)` | Full flow: eth_requestAccounts → EIP-712 sign → add + verify |
| `connect()` | Quick connect check (no signature) |
EIP-712 domain: `{ name: "Anonymous Wallet Tracker", version: "1", chainId: 1 }`
### WalletStreamManager
| Method | Description |
|---|---|
| `connect()` | Triggers BroadcastChannel leader election → opens single WS |
| `disconnect()` | Closes WS + BC, cancels timers |
| `on(event, callback)` | Register callback per event type |
| `subscribeToNewWallet(wallet)` | Dynamic subscribe (leader → WS, follower → BC) |
| `unsubscribeFromWallet(address, chain)` | Dynamic unsubscribe |
Cross-tab leader election uses `BroadcastChannel("dione_shared_stream")` with a 200ms timeout. Leader-death broadcast triggers failover election. Reconnect uses exponential backoff (1s → 30s) with ±25% jitter.
## Gotchas
- `apiBase = window.location.origin` — the dashboard relies on nginx proxy to reach the backend at `192.168.1.102:8000`. Running without Docker/proxy means the Aave table and price charts fail silently.
- No linting, no type-checking, no CI. Validate changes by opening the HTML in a browser.
- Adding chart data? Update the embedded arrays (`walletCumulData`, etc.) — they are plain JS arrays of `[timestampMs, value]` pairs.
- `wallets.js` always forces `isVerified: false` on `loadWallets()` — persisted signatures are discarded. Verification must go through `WalletVerifier`.
## Coding Guidelines