feat(aegis): 0.16.0 — Address & QR and Assets are peer chips, and the coin row loses its dropdown
Two changes to the same idea: one way to do each thing, and the same shape for every coin. **Assets is no longer buried under the QR.** The Receive body stacked address → QR → assets in one column, so in a 380px panel the token list sat permanently below the fold behind 200px of QR — and a coin holding no tokens simply lost a section, which made every coin look structurally different. Address & QR and Assets are now peers behind a persistent chip row. The count rides on the chip, and a wallet with nothing says "No assets held by this wallet" instead of the section vanishing. That mattered more than it sounds: a chipnet wallet with 46 CashToken categories was indistinguishable from an empty one until 0.15.0, because the only signal was an absent card. The choice persists across re-renders and wallet switches — comparing token balances between wallets should not throw you back to the QR on every click. Switching back to Address redraws the QR, since a canvas sized while hidden comes out blank and renderReceive only repaints when the address changes. **The coin row's ▾ network dropdown is gone.** The coin view already carries real network chips (data-browse-net: they filter the wallet list and show a per-network count), so the popover was a second control for one job — and the only one that hid its options behind a click. Chips are the single network control now and the ticker is plain text again. Verified in the panel: chips switch panes and track their own state, the count shows, the empty state reads correctly, the QR survives the round trip, and no .wchev / .wcname.wswitchable remain in the DOM.
This commit is contained in:
parent
74224cd7dd
commit
b42f304ce8
3 changed files with 84 additions and 22 deletions
|
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"id": "aegis",
|
"id": "aegis",
|
||||||
"name": "Aegis Wallet",
|
"name": "Aegis Wallet",
|
||||||
"version": "0.15.0",
|
"version": "0.16.0",
|
||||||
"category": "plugin",
|
"category": "plugin",
|
||||||
"description": "Multi-chain wallet (BCH, BTC, TRX, ETH, SOL, SC, DGB) derived from your Theseus vault. Dapps get window.bitcoincash on .x sites; window.tronWeb / window.tronLink / window.ethereum / window.solana on any https page.",
|
"description": "Multi-chain wallet (BCH, BTC, TRX, ETH, SOL, SC, DGB) derived from your Theseus vault. Dapps get window.bitcoincash on .x sites; window.tronWeb / window.tronLink / window.ethereum / window.solana on any https page.",
|
||||||
"author": "Silent Mode",
|
"author": "Silent Mode",
|
||||||
|
|
|
||||||
|
|
@ -768,10 +768,19 @@
|
||||||
<button data-rcv-mode="consolidate" type="button">Consolidate <span id="rcvConsolidateCount" class="hint"></span></button>
|
<button data-rcv-mode="consolidate" type="button">Consolidate <span id="rcvConsolidateCount" class="hint"></span></button>
|
||||||
</div>
|
</div>
|
||||||
<div id="rcvNormal">
|
<div id="rcvNormal">
|
||||||
<!-- 0.9.2: address first, assets next, QR last and collapsed.
|
<!-- 0.16.0: Address-and-QR and Assets are PEERS, switched by a
|
||||||
The QR was 200px of always-on vertical space above the thing
|
persistent chip row, instead of one stacked column. Stacking meant
|
||||||
people actually came for, and it pushed the token list below
|
the QR sat between the address and the token list, so assets were
|
||||||
the fold. Explorer / Faucet moved to the header. -->
|
permanently below the fold in a 380px panel; and it made every coin
|
||||||
|
look different, since a coin with no tokens simply lost a section.
|
||||||
|
Chips give one shape for every coin and a visible answer either
|
||||||
|
way. (0.9.2 had already reordered the stack for the same reason —
|
||||||
|
this replaces that workaround.) -->
|
||||||
|
<div id="rcvViewToggle" class="modetoggle">
|
||||||
|
<button data-rcv-view="address" class="on" type="button">Address & QR</button>
|
||||||
|
<button data-rcv-view="assets" type="button">Assets <span id="rcvAssetsCount" class="hint"></span></button>
|
||||||
|
</div>
|
||||||
|
<div id="rcvAddressPane">
|
||||||
<div class="card">
|
<div class="card">
|
||||||
<div class="lbl">Receiving address <span id="addrMeta"></span></div>
|
<div class="lbl">Receiving address <span id="addrMeta"></span></div>
|
||||||
<!-- 0.9.8: address and its copy button share one row, so the
|
<!-- 0.9.8: address and its copy button share one row, so the
|
||||||
|
|
@ -790,11 +799,14 @@
|
||||||
<div class="qrwrap" id="qrWrap"><canvas id="qr" width="200" height="200"></canvas></div>
|
<div class="qrwrap" id="qrWrap"><canvas id="qr" width="200" height="200"></canvas></div>
|
||||||
<div class="qrgrip" id="qrGrip" title="Drag to resize the QR code"><span></span></div>
|
<div class="qrgrip" id="qrGrip" title="Drag to resize the QR code"><span></span></div>
|
||||||
</div>
|
</div>
|
||||||
<div class="card" id="tokensCard" hidden style="margin-top:12px">
|
</div><!-- /rcvAddressPane -->
|
||||||
|
<div id="rcvAssetsPane" hidden>
|
||||||
|
<div class="card" id="tokensCard">
|
||||||
<div class="lbl">Assets <span class="hint" id="tokensCount"></span></div>
|
<div class="lbl">Assets <span class="hint" id="tokensCount"></span></div>
|
||||||
<div id="tokensList" class="kv"></div>
|
<div id="tokensList" class="kv"></div>
|
||||||
<div class="hint" id="tokensHint">Tokens held by this wallet.</div>
|
<div class="hint" id="tokensHint">Tokens held by this wallet.</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
</div><!-- /rcvNormal -->
|
</div><!-- /rcvNormal -->
|
||||||
<!-- Consolidate view (inline, replaces Receive body when active). -->
|
<!-- Consolidate view (inline, replaces Receive body when active). -->
|
||||||
<div id="rcvConsolidate" hidden>
|
<div id="rcvConsolidate" hidden>
|
||||||
|
|
|
||||||
|
|
@ -2136,6 +2136,29 @@ function paintSendMode() {
|
||||||
if (host && consolidateInlineHost !== host) { consolidateInlineHost = host; renderConsolidateInline(host); }
|
if (host && consolidateInlineHost !== host) { consolidateInlineHost = host; renderConsolidateInline(host); }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Which half of the Receive pane is showing. Persistent: the choice sticks
|
||||||
|
// across re-renders and across wallet switches, because someone comparing
|
||||||
|
// token balances between wallets should not be knocked back to the QR on
|
||||||
|
// every click.
|
||||||
|
let rcvView = "address";
|
||||||
|
try { rcvView = localStorage.getItem("aegis/rcvView") === "assets" ? "assets" : "address"; } catch (_e) {}
|
||||||
|
function paintRcvView() {
|
||||||
|
const addr = $("rcvAddressPane"), assets = $("rcvAssetsPane");
|
||||||
|
if (!addr || !assets) return;
|
||||||
|
document.querySelectorAll("[data-rcv-view]").forEach((b) =>
|
||||||
|
b.classList.toggle("on", b.dataset.rcvView === rcvView));
|
||||||
|
addr.hidden = rcvView !== "address";
|
||||||
|
assets.hidden = rcvView !== "assets";
|
||||||
|
// The QR's backing store is sized from its rendered box, so one drawn
|
||||||
|
// while its pane was hidden comes out blank. Redraw on reveal — and note
|
||||||
|
// renderReceive only redraws when the address CHANGES, so switching back
|
||||||
|
// to an unchanged address would otherwise never repaint it.
|
||||||
|
if (rcvView === "address") {
|
||||||
|
const a = sel()?.address || "";
|
||||||
|
if (a) { try { drawQr(qrPayload(chain(), a, sel()?.network)); } catch (_e) {} }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function paintRcvMode() {
|
function paintRcvMode() {
|
||||||
const normal = $("rcvNormal"); const cons = $("rcvConsolidate");
|
const normal = $("rcvNormal"); const cons = $("rcvConsolidate");
|
||||||
if (!normal || !cons) return;
|
if (!normal || !cons) return;
|
||||||
|
|
@ -2522,15 +2545,16 @@ function renderWalletStrip() {
|
||||||
pill = `<span class="wnetpill ${cls}" title="${esc(tip)}">${esc(meta.networkLabel)}</span>`;
|
pill = `<span class="wnetpill ${cls}" title="${esc(tip)}">${esc(meta.networkLabel)}</span>`;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ▾ chevron shown only when the chain has more than one network —
|
// 0.16.0: no ▾ network dropdown on the coin row. The coin view already
|
||||||
// otherwise the click affordance would be a lie and the ticker acts
|
// carries real network chips (data-browse-net — they filter the list and
|
||||||
// like plain text.
|
// show a per-network count), so a popover menu doing the same job was a
|
||||||
const multiNet = nets.length > 1;
|
// second way to do one thing, and the only one that hid its options
|
||||||
const chevron = multiNet ? `<span class="wchev" aria-hidden="true">▾</span>` : "";
|
// behind a click. Chips are the single network control now; the ticker
|
||||||
const nameCls = multiNet ? "wcname wswitchable" : "wcname";
|
// is plain text again.
|
||||||
const nameTitle = multiNet
|
const multiNet = false;
|
||||||
? `Switch network — ${nets.map((n) => networkLabelFor(chain, n, n)).join(" / ")}`
|
const chevron = "";
|
||||||
: meta.coinName;
|
const nameCls = "wcname";
|
||||||
|
const nameTitle = meta.coinName;
|
||||||
|
|
||||||
// Single wallet under the active network → click selects it. Multi-
|
// Single wallet under the active network → click selects it. Multi-
|
||||||
// wallet: click selects the "active" wallet for this bucket (defaults
|
// wallet: click selects the "active" wallet for this bucket (defaults
|
||||||
|
|
@ -3323,6 +3347,7 @@ function render() {
|
||||||
if (!showToggle) { sendMode = "send"; rcvMode = "receive"; }
|
if (!showToggle) { sendMode = "send"; rcvMode = "receive"; }
|
||||||
paintSendMode();
|
paintSendMode();
|
||||||
paintRcvMode();
|
paintRcvMode();
|
||||||
|
paintRcvView();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sum every wallet's confirmed+unconfirmed × price and show "≈ $X across N
|
// Sum every wallet's confirmed+unconfirmed × price and show "≈ $X across N
|
||||||
|
|
@ -3355,6 +3380,24 @@ function renderPortfolio() {
|
||||||
el.innerHTML = `Portfolio: <b>${esc(fmtFiat(total))}</b> across ${wallets.length} ${noun}`;
|
el.innerHTML = `Portfolio: <b>${esc(fmtFiat(total))}</b> across ${wallets.length} ${noun}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Assets is a chip now, not a card that disappears when the count is zero.
|
||||||
|
// The count rides on the chip and an empty wallet says so in the pane, so
|
||||||
|
// "this wallet holds nothing" is a visible answer rather than a missing
|
||||||
|
// section the user has to infer — which is exactly how 46 CashTokens managed
|
||||||
|
// to look like a working, empty wallet before 0.15.0.
|
||||||
|
function setAssetsCount(n) {
|
||||||
|
const chip = $("rcvAssetsCount");
|
||||||
|
if (chip) chip.textContent = n ? String(n) : "";
|
||||||
|
const card = $("tokensCard");
|
||||||
|
if (card) card.hidden = false;
|
||||||
|
if (!n) {
|
||||||
|
const el = $("tokensList");
|
||||||
|
if (el) el.innerHTML = `<div class="hint" style="padding:4px 2px">No assets held by this wallet.</div>`;
|
||||||
|
const cnt = $("tokensCount");
|
||||||
|
if (cnt) cnt.textContent = "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function renderTokens() {
|
function renderTokens() {
|
||||||
const s = sel();
|
const s = sel();
|
||||||
const card = $("tokensCard");
|
const card = $("tokensCard");
|
||||||
|
|
@ -3362,7 +3405,7 @@ function renderTokens() {
|
||||||
// SOL wallets: SPL tokens with a Send button (existing flow).
|
// SOL wallets: SPL tokens with a Send button (existing flow).
|
||||||
if (chain() === "sol") {
|
if (chain() === "sol") {
|
||||||
const tokens = s?.tokens || [];
|
const tokens = s?.tokens || [];
|
||||||
card.hidden = tokens.length === 0;
|
setAssetsCount(tokens.length);
|
||||||
const hintEl = $("tokensHint");
|
const hintEl = $("tokensHint");
|
||||||
if (hintEl) hintEl.textContent = "SPL tokens held by this wallet. Send by picking one under the Send tab's Asset dropdown.";
|
if (hintEl) hintEl.textContent = "SPL tokens held by this wallet. Send by picking one under the Send tab's Asset dropdown.";
|
||||||
if (!tokens.length) return;
|
if (!tokens.length) return;
|
||||||
|
|
@ -3388,7 +3431,7 @@ function renderTokens() {
|
||||||
if (chain() === "bch") {
|
if (chain() === "bch") {
|
||||||
const balances = s?.tokenBalances || {};
|
const balances = s?.tokenBalances || {};
|
||||||
const cats = Object.keys(balances);
|
const cats = Object.keys(balances);
|
||||||
card.hidden = cats.length === 0;
|
setAssetsCount(cats.length);
|
||||||
const hintEl = $("tokensHint");
|
const hintEl = $("tokensHint");
|
||||||
if (hintEl) hintEl.textContent = "CashTokens held by this wallet. Names come from BCMR — configure custom registries in Settings.";
|
if (hintEl) hintEl.textContent = "CashTokens held by this wallet. Names come from BCMR — configure custom registries in Settings.";
|
||||||
if (!cats.length) return;
|
if (!cats.length) return;
|
||||||
|
|
@ -3432,8 +3475,8 @@ function renderTokens() {
|
||||||
// through to a hidden card the way ETH did until 0.9.3.
|
// through to a hidden card the way ETH did until 0.9.3.
|
||||||
{
|
{
|
||||||
const tokens = s?.tokens || [];
|
const tokens = s?.tokens || [];
|
||||||
if (!tokens.length) { card.hidden = true; return; }
|
if (!tokens.length) { setAssetsCount(0); return; }
|
||||||
card.hidden = false;
|
setAssetsCount(tokens.length);
|
||||||
const hintEl = $("tokensHint");
|
const hintEl = $("tokensHint");
|
||||||
const kindLabel = chain() === "trx" ? "TRC20" : chain() === "eth" ? "ERC20" : "Tokens";
|
const kindLabel = chain() === "trx" ? "TRC20" : chain() === "eth" ? "ERC20" : "Tokens";
|
||||||
if (hintEl) hintEl.textContent = `${kindLabel} tokens held by this wallet. Read-only in this build — open the explorer from the header to move them.`;
|
if (hintEl) hintEl.textContent = `${kindLabel} tokens held by this wallet. Read-only in this build — open the explorer from the header to move them.`;
|
||||||
|
|
@ -3830,10 +3873,17 @@ document.querySelectorAll("[data-send-mode]").forEach((b) => b.addEventListener(
|
||||||
consolidateInlineHost = null; // force re-render on next switch
|
consolidateInlineHost = null; // force re-render on next switch
|
||||||
paintSendMode();
|
paintSendMode();
|
||||||
}));
|
}));
|
||||||
|
// Address & QR / Assets — the persistent pair inside the Receive body.
|
||||||
|
document.querySelectorAll("[data-rcv-view]").forEach((b) => b.addEventListener("click", () => {
|
||||||
|
rcvView = b.dataset.rcvView === "assets" ? "assets" : "address";
|
||||||
|
try { localStorage.setItem("aegis/rcvView", rcvView); } catch (_e) {}
|
||||||
|
paintRcvView();
|
||||||
|
}));
|
||||||
document.querySelectorAll("[data-rcv-mode]").forEach((b) => b.addEventListener("click", () => {
|
document.querySelectorAll("[data-rcv-mode]").forEach((b) => b.addEventListener("click", () => {
|
||||||
rcvMode = b.dataset.rcvMode;
|
rcvMode = b.dataset.rcvMode;
|
||||||
consolidateInlineHost = null;
|
consolidateInlineHost = null;
|
||||||
paintRcvMode();
|
paintRcvMode();
|
||||||
|
paintRcvView();
|
||||||
}));
|
}));
|
||||||
["sendTo", "sendAmt"].forEach((id) => $(id).addEventListener("input", () => {
|
["sendTo", "sendAmt"].forEach((id) => $(id).addEventListener("input", () => {
|
||||||
if (id === "sendAmt" && sendMax) return;
|
if (id === "sendAmt" && sendMax) return;
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue