From 5589d95d1faac6ddab869301486c4c05b257cad8 Mon Sep 17 00:00:00 2001 From: Jeff Emmett Date: Tue, 24 Feb 2026 19:15:56 -0800 Subject: [PATCH] feat: add rStack AppSwitcher dropdown to header Adds the unified rStack app switcher as pure HTML/CSS/JS with pastel badges, emoji icons, and categorized navigation across all 17 rStack apps. Co-Authored-By: Claude Opus 4.6 --- backlog/config.yml | 1 + ...cy-scaling-and-waterfall-flow-direction.md | 44 ++ index.html | 456 +++++++++++++++++- 3 files changed, 498 insertions(+), 3 deletions(-) create mode 100644 backlog/tasks/task-6 - Fix-balance-river-accuracy-scaling-and-waterfall-flow-direction.md diff --git a/backlog/config.yml b/backlog/config.yml index 20df00f..23a2e19 100644 --- a/backlog/config.yml +++ b/backlog/config.yml @@ -13,3 +13,4 @@ auto_commit: false bypass_git_hooks: false check_active_branches: true active_branch_days: 30 +task_prefix: "task" diff --git a/backlog/tasks/task-6 - Fix-balance-river-accuracy-scaling-and-waterfall-flow-direction.md b/backlog/tasks/task-6 - Fix-balance-river-accuracy-scaling-and-waterfall-flow-direction.md new file mode 100644 index 0000000..08424d6 --- /dev/null +++ b/backlog/tasks/task-6 - Fix-balance-river-accuracy-scaling-and-waterfall-flow-direction.md @@ -0,0 +1,44 @@ +--- +id: TASK-6 +title: 'Fix balance river accuracy, scaling, and waterfall flow direction' +status: Done +assignee: + - '@claude' +created_date: '2026-02-18 19:54' +labels: + - fix + - visualization + - blockchain +dependencies: [] +references: + - js/safe-api.js + - wallet-timeline-visualization.html + - js/data-transform.js +priority: high +--- + +## Description + + +Fixed three issues with the wallet balance river visualization: + +1. **Transaction accuracy** — Switched `fetchChainData` from separate `getAllMultisigTransactions` + `getAllIncomingTransfers` endpoints to the unified `getAllTransactions` endpoint. This returns enriched `transfers[]` arrays with proper `tokenInfo` including correct decimals (e.g., USDC=6 decimals, not hardcoded 18). Eliminates the inaccurate `dataDecoded` fallback parsing. + +2. **Flow scaling** — Flow widths are now sankey-proportional: each waterfall's width at the river is proportional to `tx.usd / balance`, so flows visually represent their share of the river. Far ends taper to 30% for dramatic effect. + +3. **Waterfall direction** — Inflows now flow diagonally from upper-left down-right into the river (like a tributary waterfall). Outflows flow diagonally from the river down-right away (like water cascading off). Gradients updated to diagonal to follow flow direction. + + +## Acceptance Criteria + +- [ ] #1 ERC20 token amounts use correct decimals from tokenInfo +- [ ] #2 Flow widths are proportional to their share of the river balance +- [ ] #3 Inflows flow diagonally down-right into the river from above-left +- [ ] #4 Outflows flow diagonally down-right away from the river below + + +## Final Summary + + +Committed and pushed to main as `f197a20`. Changes span `js/safe-api.js` (all-transactions endpoint, sequential rate-limited fetching) and `wallet-timeline-visualization.html` (diagonal bezier waterfall paths, proportional widths, diagonal gradients). Resolved merge conflict with upstream `eb5f93e` that had introduced sankey-proportional widths and sequential API calls — merged both improvements together. + diff --git a/index.html b/index.html index 246b347..4a61811 100644 --- a/index.html +++ b/index.html @@ -507,6 +507,230 @@ color: var(--border); } + /* ─── AppSwitcher ─────────────────────────────────── */ + + .app-switcher { + position: relative; + } + + .app-switcher-trigger { + display: flex; + align-items: center; + gap: 0.5rem; + padding: 0.375rem 0.625rem; + border-radius: 0.5rem; + font-size: 0.875rem; + font-weight: 600; + background: rgba(255, 255, 255, 0.08); + color: #cbd5e1; + border: none; + cursor: pointer; + transition: background 0.15s; + white-space: nowrap; + } + .app-switcher-trigger:hover { + background: rgba(255, 255, 255, 0.12); + } + + .app-switcher-badge { + width: 1.5rem; + height: 1.5rem; + border-radius: 0.375rem; + display: flex; + align-items: center; + justify-content: center; + font-size: 10px; + font-weight: 900; + color: #0f172a; + line-height: 1; + flex-shrink: 0; + } + + .app-switcher-arrow { + font-size: 0.7em; + opacity: 0.6; + } + + .app-switcher-dropdown { + display: none; + position: absolute; + top: 100%; + left: 0; + margin-top: 0.375rem; + width: 300px; + max-height: 70vh; + overflow-y: auto; + border-radius: 0.75rem; + background: #1e293b; + border: 1px solid rgba(255, 255, 255, 0.1); + box-shadow: 0 25px 50px rgba(0, 0, 0, 0.3); + z-index: 9999; + } + .app-switcher-dropdown.open { + display: block; + } + + .app-switcher-dropdown::-webkit-scrollbar { + width: 6px; + } + .app-switcher-dropdown::-webkit-scrollbar-track { + background: transparent; + } + .app-switcher-dropdown::-webkit-scrollbar-thumb { + background: rgba(255, 255, 255, 0.1); + border-radius: 3px; + } + + .app-switcher-header { + display: flex; + align-items: center; + gap: 0.625rem; + padding: 0.75rem 0.875rem; + border-bottom: 1px solid rgba(255, 255, 255, 0.08); + } + + .app-switcher-header-badge { + width: 1.75rem; + height: 1.75rem; + border-radius: 0.5rem; + background: linear-gradient(135deg, #67e8f9, #c4b5fd, #fda4af); + display: flex; + align-items: center; + justify-content: center; + font-size: 11px; + font-weight: 900; + color: #0f172a; + line-height: 1; + flex-shrink: 0; + } + + .app-switcher-header-text { + display: flex; + flex-direction: column; + } + .app-switcher-header-title { + font-size: 0.875rem; + font-weight: 700; + color: #fff; + } + .app-switcher-header-sub { + font-size: 10px; + color: #94a3b8; + } + + .app-switcher-category { + padding: 0.75rem 0.875rem 0.25rem; + font-size: 0.6rem; + font-weight: 700; + text-transform: uppercase; + letter-spacing: 0.1em; + color: #64748b; + user-select: none; + } + + .app-switcher-item { + display: flex; + align-items: center; + transition: background 0.15s; + } + .app-switcher-item:hover { + background: rgba(255, 255, 255, 0.04); + } + .app-switcher-item.current { + background: rgba(255, 255, 255, 0.07); + } + + .app-switcher-item a { + display: flex; + align-items: center; + gap: 0.625rem; + flex: 1; + padding: 0.5rem 0.875rem; + color: #cbd5e1; + text-decoration: none; + min-width: 0; + } + + .app-switcher-item-info { + display: flex; + flex-direction: column; + min-width: 0; + flex: 1; + } + .app-switcher-item-name { + display: flex; + align-items: center; + gap: 0.375rem; + } + .app-switcher-item-name span:first-child { + font-size: 0.875rem; + font-weight: 600; + } + .app-switcher-item-name span:last-child { + font-size: 0.875rem; + flex-shrink: 0; + } + .app-switcher-item-desc { + font-size: 11px; + color: #94a3b8; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + } + + .app-switcher-item .app-switcher-ext { + width: 2rem; + display: flex; + align-items: center; + justify-content: center; + font-size: 0.75rem; + color: #22d3ee; + opacity: 0; + transition: opacity 0.15s; + flex-shrink: 0; + text-decoration: none; + } + .app-switcher-item:hover .app-switcher-ext { + opacity: 0.5; + } + .app-switcher-item .app-switcher-ext:hover { + opacity: 1 !important; + } + + .app-switcher-footer { + padding: 0.625rem 0.875rem; + border-top: 1px solid rgba(255, 255, 255, 0.08); + text-align: center; + } + .app-switcher-footer a { + font-size: 11px; + color: #64748b; + text-decoration: none; + transition: color 0.15s; + } + .app-switcher-footer a:hover { + color: #22d3ee; + } + + /* badge colors */ + .badge-teal { background: #5eead4; } + .badge-amber { background: #fcd34d; } + .badge-rose { background: #fda4af; } + .badge-sky { background: #7dd3fc; } + .badge-emerald { background: #6ee7b7; } + .badge-green { background: #86efac; } + .badge-indigo { background: #a5b4fc; } + .badge-fuchsia { background: #f0abfc; } + .badge-violet { background: #c4b5fd; } + .badge-lime { background: #bef264; } + .badge-yellow { background: #fde047; } + .badge-orange { background: #fdba74; } + .badge-red { background: #fca5a5; } + .badge-blue { background: #93c5fd; } + .badge-cyan { background: #67e8f9; } + .badge-pink { background: #f9a8d4; } + .badge-purple { background: #d8b4fe; } + /* ─── Responsive ──────────────────────────────────── */ @media (max-width: 640px) { @@ -516,6 +740,8 @@ .wallet-input-group button { padding: 14px; } .demo-section { padding: 40px 20px; } .btn-row { flex-direction: column; align-items: center; } + .app-switcher-trigger .app-switcher-label { display: none; } + .app-switcher-dropdown { width: 280px; } } @@ -525,9 +751,208 @@