Theseus core:
- addons-host: manifest.category ("plugin") propagates through snapshot(); new
addon API surface checkAndStageSelfUpdate() + restartApp() so a plug-in
can offer in-panel "update now → restart to apply" without pushing the
user to Settings.
- main.js: wires the two new hooks into the AddonHost constructor.
- settings.html: Extensions listing filters out category==="plugin"; those
add-ons live in Plug-ins instead, single source of truth.
Aegis 0.6.31:
- BTC picker trimmed to Signet only; testnet3 hidden (adapter kept so any
existing wallet still loads).
- Wallet strip groups by chain, not chain:network; ticker gets a ▾ chevron
and a dropdown listing every subnetwork with its own totals. Mainnet
reads as the plain ticker; testnets carry a small Chipnet/Signet/Sepolia
pill inline.
- Per-unit price sits directly under the ticker; amount + fiat mirror on
the right — one glance covers name/price/holding/value.
- + Add and ⋯ More promoted from the strip into the header's action row,
next to the new ✎ chip (was the redundant top ⋯). Duplicate "Manage
current wallet" entry removed from the More menu.
- Footer update chip is a two-step flow via the new API: stage → restart.
Falls back to opening Settings on any Theseus that lacks the hooks.
- Manifest declares "category": "plugin".
843 lines
54 KiB
HTML
843 lines
54 KiB
HTML
<!doctype html>
|
||
<html lang="en">
|
||
<head>
|
||
<meta charset="utf-8">
|
||
<title>Aegis Wallet</title>
|
||
<!-- Aegis brand mark from aegis.x/brand/favicon.svg — kept byte-close so
|
||
the sidebar-tab icon reads as the identity a user just downloaded from. -->
|
||
<link rel="icon" type="image/svg+xml" href="data:image/svg+xml;utf8,%3Csvg%20xmlns%3D'http%3A//www.w3.org/2000/svg'%20viewBox%3D'0%200%2032%2032'%20fill%3D'none'%3E%3Cpolygon%20points%3D'16%2C2%2028%2C9%2028%2C23%2016%2C30%204%2C23%204%2C9'%20fill%3D'%230a0a0d'%20stroke%3D'%23D6FF3D'%20stroke-width%3D'1.6'%20stroke-linejoin%3D'round'/%3E%3Ccircle%20cx%3D'16'%20cy%3D'16'%20r%3D'4.5'%20fill%3D'none'%20stroke%3D'%23D6FF3D'%20stroke-width%3D'1.4'/%3E%3Ccircle%20cx%3D'16'%20cy%3D'16'%20r%3D'1.6'%20fill%3D'%23D6FF3D'/%3E%3C/svg%3E">
|
||
<style>
|
||
:root { color-scheme: light dark;
|
||
--bg:#0e131c; --panel:#141a24; --card:#0f1621; --line:rgba(255,255,255,.09);
|
||
--ink:#e7eaf1; --mut:#8b98a9; --dim:#5e6678; --acid:#d6ff3d; --danger:#f6768a; --ok:#5ad38a;
|
||
--bch:#0ac18e; --trx:#ff060a; --trxNile:#4d9dff; }
|
||
@media (prefers-color-scheme: light) {
|
||
:root { --bg:#f8faff; --panel:#ffffff; --card:#f1f4fa; --line:rgba(0,0,0,.10);
|
||
--ink:#1a1f2b; --mut:#5c6577; --dim:#8a93a5;
|
||
/* Darker acid on light backgrounds — ~7:1 contrast on white. */
|
||
--acid: #0AC18E; }
|
||
}
|
||
* { box-sizing: border-box; }
|
||
html, body { margin: 0; height: 100%; }
|
||
body { background: var(--bg); color: var(--ink);
|
||
font: 13.5px/1.5 system-ui, -apple-system, Segoe UI, Roboto, sans-serif;
|
||
display: flex; flex-direction: column; position: relative; }
|
||
header { padding: 10px 14px 10px; border-bottom: 1px solid var(--line); background: var(--panel); position: relative; }
|
||
.picker { display: flex; align-items: center; justify-content: space-between; gap: 8px; cursor: pointer; user-select: none; }
|
||
.picker .t { display: flex; align-items: center; gap: 7px; font-weight: 600; min-width: 0; }
|
||
.picker .t .badge { font-size: 15px; line-height: 1; }
|
||
.picker .t .lbl { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
||
.picker .caret { color: var(--mut); font-size: 10px; }
|
||
.picker:hover { color: var(--acid); }
|
||
.net { display: flex; align-items: center; gap: 6px; color: var(--dim); font-size: 11.5px; white-space: nowrap; }
|
||
.dot { width: 7px; height: 7px; border-radius: 50%; background: var(--dim); }
|
||
.dot.on { background: var(--ok); } .dot.busy { background: #e0b341; }
|
||
.bal { margin-top: 8px; font-variant-numeric: tabular-nums; }
|
||
.bal .big { font-size: 22px; font-weight: 650; letter-spacing: .2px; }
|
||
.bal .big small { font-size: 13px; color: var(--mut); font-weight: 500; margin-left: 4px; }
|
||
.bal .sub { color: var(--dim); font-size: 11.5px; display: flex; justify-content: space-between; gap: 8px; }
|
||
.bal .sub .netlbl { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
||
/* Full-panel sheet — fills the sidebar so long wallet lists and the
|
||
import form aren't squeezed into a small popover. */
|
||
#drop { position: fixed; left: 0; right: 0; top: 60px; bottom: 0;
|
||
background: var(--panel); border-top: 1px solid var(--line);
|
||
box-shadow: 0 -6px 26px rgba(0,0,0,.35); z-index: 20;
|
||
display: flex; flex-direction: column; }
|
||
#drop[hidden] { display: none; }
|
||
#drop .droptabs { display: flex; border-bottom: 1px solid var(--line); flex: none; }
|
||
#drop .droptabs button { flex: 1; background: transparent; border: 0; color: var(--dim);
|
||
padding: 10px 8px; font: inherit; font-size: 13px; cursor: pointer; border-bottom: 2px solid transparent; }
|
||
#drop .droptabs button.on { color: var(--ink); border-bottom-color: var(--acid, #d6ff3d); font-weight: 600; }
|
||
#drop .droptabs .closex { flex: none; width: 40px; font-size: 16px; color: var(--dim); border-left: 1px solid var(--line); }
|
||
#drop .droppane { flex: 1; overflow-y: auto; padding: 6px; }
|
||
#drop .droppane[hidden] { display: none; }
|
||
#drop .row, #drop .coinrow { display: flex; align-items: center; gap: 9px; padding: 8px 10px; border-radius: 7px; cursor: pointer; }
|
||
#drop .row:hover, #drop .coinrow:hover { background: rgba(255,255,255,.05); }
|
||
#drop .row .m, #drop .coinrow .m { flex: 1; min-width: 0; }
|
||
#drop .row .m .l, #drop .coinrow .m .l { font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
||
#drop .row .m .s, #drop .coinrow .m .s { color: var(--dim); font-size: 11.5px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
||
#drop .row .v { color: var(--mut); font-size: 12px; font-variant-numeric: tabular-nums; text-align: right; white-space: nowrap; }
|
||
#drop .row .v .fs { color: var(--dim); font-size: 11px; margin-top: 2px; }
|
||
#drop .row.on { background: rgb(from var(--acid) r g b / .10); }
|
||
#drop .coinrow .caret { color: var(--dim); font-size: 11px; }
|
||
#drop hr { border: 0; border-top: 1px solid var(--line); margin: 6px 0; }
|
||
#drop .addhdr { padding: 5px 8px 3px; color: var(--dim); font-size: 11px; text-transform: uppercase; letter-spacing: .04em; }
|
||
#drop .netgroup { padding: 2px 4px 6px 40px; }
|
||
#drop .netgroup[hidden] { display: none; }
|
||
#drop .netchoice { padding: 6px 8px; border-radius: 6px; cursor: pointer; font-size: 12.5px; color: var(--mut); }
|
||
#drop .netchoice:hover { background: rgba(255,255,255,.06); color: var(--ink); }
|
||
.ttag { display: inline-block; font-size: 9.5px; letter-spacing: .06em; padding: 1px 5px; border-radius: 3px;
|
||
background: rgba(224,179,65,.18); color: #e0b341; font-weight: 700; vertical-align: middle; margin-left: 2px; }
|
||
#hNet { color: var(--dim); font-size: 11px; margin-left: 4px; font-weight: 500; }
|
||
.fiat { color: var(--dim); font-size: 12.5px; margin-left: 10px; font-weight: 500; letter-spacing: .2px; }
|
||
.portfolio { margin-top: 6px; color: var(--mut); font-size: 11.5px; }
|
||
.portfolio b { color: var(--ink); font-weight: 600; }
|
||
.portfolio[hidden] { display: none; }
|
||
.picker-actions { display: flex; align-items: center; gap: 6px; }
|
||
.chip { background: transparent; border: 1px solid var(--line); color: var(--mut); border-radius: 6px;
|
||
padding: 0 8px; height: 22px; cursor: pointer; font: inherit; font-size: 13.5px; line-height: 1;
|
||
display: inline-flex; align-items: center; justify-content: center; }
|
||
.chip:hover { border-color: var(--acid); color: var(--acid); }
|
||
nav { display: flex; border-bottom: 1px solid var(--line); background: var(--panel); }
|
||
nav button { flex: 1; padding: 9px 0 8px; border: 0; background: transparent; color: var(--mut); cursor: pointer;
|
||
font: inherit; font-size: 12.5px; border-bottom: 2px solid transparent; }
|
||
nav button.on { color: var(--acid); border-bottom-color: var(--acid); }
|
||
nav button:hover { color: var(--ink); }
|
||
main { flex: 1; overflow: auto; padding: 14px; }
|
||
/* Persistent aegis.x brand strip. Sticks to the panel's bottom edge so the
|
||
wallet always advertises its own front-door site — helps users bookmark
|
||
it, and doubles as a version marker for support triage. */
|
||
.brandfoot { flex: none; display: flex; align-items: center; justify-content: space-between;
|
||
padding: 6px 12px; border-top: 1px solid var(--line); background: var(--panel);
|
||
font-size: 11px; color: var(--dim); }
|
||
.brandlink { display: inline-flex; align-items: center; gap: 5px; color: var(--dim); text-decoration: none;
|
||
padding: 2px 4px; border-radius: 4px; }
|
||
.brandlink:hover { color: var(--acid, #d6ff3d); }
|
||
.brandlink svg { color: currentColor; }
|
||
.brandver { font-variant-numeric: tabular-nums; letter-spacing: .3px; }
|
||
.brandfoot-right { display: inline-flex; align-items: center; gap: 8px; }
|
||
.brandcheck { background: transparent; border: 0; color: var(--dim); cursor: pointer; padding: 0 2px;
|
||
font: inherit; font-size: 12px; line-height: 1; opacity: .7; transition: opacity .12s, color .12s; }
|
||
.brandcheck:hover { color: var(--acid, #d6ff3d); opacity: 1; }
|
||
.brandcheck.spin { animation: brandspin 1s linear infinite; }
|
||
@keyframes brandspin { to { transform: rotate(360deg); } }
|
||
.brandupd { display: inline-flex; align-items: center; gap: 5px; font-size: 11px; padding: 2px 8px;
|
||
border-radius: 999px; background: rgb(from var(--acid, #d6ff3d) r g b / .14); color: var(--acid, #d6ff3d);
|
||
cursor: pointer; text-decoration: none; font-weight: 600;
|
||
transition: opacity .2s; }
|
||
.brandupd[hidden] { display: none; }
|
||
.brandupd:hover { background: rgb(from var(--acid, #d6ff3d) r g b / .22); }
|
||
/* Transient states painted by paintFooterUpdate: "✓ Up to date" after a
|
||
manual check when no newer version is available, and "⚠ Check failed"
|
||
when the OTA fetch errors. Both auto-hide after ~2s; the styling reads
|
||
as ephemeral confirmation rather than a persistent chip. */
|
||
.brandupd.brandok { background: rgba(255,255,255,.06); color: var(--dim); font-weight: 500;
|
||
cursor: default; }
|
||
.brandupd.brandok:hover { background: rgba(255,255,255,.06); }
|
||
.brandupd.branderr { background: rgba(224,90,90,.18); color: #e05a5a; font-weight: 500;
|
||
cursor: default; }
|
||
.brandupd.branderr:hover { background: rgba(224,90,90,.18); }
|
||
/* In-progress state: painted while the panel is fetching / staging /
|
||
restarting. Not clickable, dimmer than the acid CTA chip so users
|
||
don't try to smash it. */
|
||
.brandupd.brandwait { background: rgba(255,255,255,.06); color: var(--mut);
|
||
font-weight: 500; cursor: default; }
|
||
.brandupd.brandwait:hover { background: rgba(255,255,255,.06); }
|
||
section[hidden] { display: none; }
|
||
.card { background: var(--card); border: 1px solid var(--line); border-radius: 10px; padding: 12px; }
|
||
.mono { font: 12.5px/1.45 ui-monospace, "Cascadia Code", Consolas, monospace; word-break: break-all; }
|
||
.lbl { color: var(--dim); font-size: 11.5px; margin-bottom: 4px; }
|
||
.btn { padding: 7px 12px; border-radius: 7px; border: 1px solid var(--line); background: var(--panel); color: var(--ink);
|
||
cursor: pointer; font: inherit; font-size: 12.5px; }
|
||
.btn:hover { border-color: rgb(from var(--acid) r g b / .4); }
|
||
.btn.primary { background: var(--acid); color: #0b0e14; border-color: transparent; font-weight: 650; }
|
||
.btn.primary:disabled { opacity: .45; cursor: default; }
|
||
.btn.danger { color: var(--danger); }
|
||
.btn.sm { padding: 4px 9px; font-size: 12px; }
|
||
.actions { display: flex; gap: 6px; flex-wrap: wrap; margin-top: 10px; }
|
||
.qrwrap { display: grid; place-items: center; padding: 12px; background: #fff; border-radius: 10px; margin-bottom: 12px; }
|
||
canvas { image-rendering: pixelated; }
|
||
input[type=text], input[type=number], input[type=password], textarea { width: 100%; padding: 7px 9px; border-radius: 7px; background: var(--panel);
|
||
border: 1px solid var(--line); color: var(--ink); font: inherit; font-size: 13px; outline: none; }
|
||
input:focus, textarea:focus { border-color: rgb(from var(--acid) r g b / .5); }
|
||
textarea { resize: vertical; min-height: 96px; font: 12px/1.45 ui-monospace, Consolas, monospace; }
|
||
.field { margin-bottom: 12px; }
|
||
.hint { color: var(--dim); font-size: 11.5px; margin-top: 4px; }
|
||
.switch { display: inline-flex; align-items: center; gap: 8px; cursor: pointer; user-select: none; font-size: 12.5px; color: var(--ink); }
|
||
.switch input { accent-color: var(--brand, #d6ff3d); width: 15px; height: 15px; margin: 0; }
|
||
.amt { display: flex; gap: 6px; }
|
||
.amt input { flex: 1; }
|
||
.unit { display: flex; border: 1px solid var(--line); border-radius: 7px; overflow: hidden; }
|
||
.unit button { border: 0; background: var(--panel); color: var(--mut); padding: 0 10px; cursor: pointer; font: inherit; font-size: 12px; }
|
||
.unit button.on { background: rgb(from var(--acid) r g b / .14); color: var(--acid); }
|
||
.fee { display: flex; align-items: center; gap: 10px; }
|
||
.fee input[type=range] { flex: 1; accent-color: var(--acid); }
|
||
.fee .v { color: var(--mut); font-size: 12px; min-width: 70px; text-align: right; font-variant-numeric: tabular-nums; }
|
||
.summary { display: grid; grid-template-columns: max-content 1fr; gap: 4px 12px; font-size: 12.5px; margin-top: 10px; }
|
||
.summary .k { color: var(--dim); } .summary .v { text-align: right; font-variant-numeric: tabular-nums; }
|
||
.msg { margin-top: 10px; font-size: 12.5px; padding: 8px 10px; border-radius: 7px; }
|
||
.msg.err { background: rgba(246,118,138,.12); color: var(--danger); }
|
||
.msg.ok { background: rgba(90,211,138,.12); color: var(--ok); }
|
||
.msg a { color: inherit; }
|
||
.tx { display: grid; grid-template-columns: 22px 1fr auto; gap: 2px 10px; padding: 9px 4px; border-bottom: 1px solid var(--line); cursor: pointer; }
|
||
.tx:hover { background: rgba(255,255,255,.03); }
|
||
.tx .ic { font-size: 15px; line-height: 1.3; }
|
||
.tx .ic.in { color: var(--ok); } .tx .ic.out { color: var(--danger); }
|
||
.tx .what { font-size: 12.5px; }
|
||
.tx .when { color: var(--dim); font-size: 11.5px; grid-column: 2; }
|
||
.tx .amt2 { text-align: right; font-variant-numeric: tabular-nums; font-weight: 600; font-size: 12.5px; }
|
||
.tx .amt2.in { color: var(--ok); }
|
||
.tx .conf { grid-column: 3; text-align: right; color: var(--dim); font-size: 11px; }
|
||
.tx .conf.pending { color: #e0b341; }
|
||
.empty { color: var(--dim); text-align: center; padding: 30px 10px; font-size: 12.5px; }
|
||
.gate { padding: 40px 18px; text-align: center; color: var(--mut); }
|
||
.gate .big { font-size: 28px; margin-bottom: 8px; }
|
||
.gate b { color: var(--ink); }
|
||
.kv { margin-top: 10px; }
|
||
.kv .lbl { margin-top: 8px; }
|
||
a.link { color: var(--acid); text-decoration: none; cursor: pointer; }
|
||
/* Preset-server checkbox list — one row per known Electrum endpoint, plus
|
||
any URL the user added via the "Add a custom server" reveal. Rows show
|
||
the host + a small hover-to-remove for user-added entries. */
|
||
.serverlist { display: flex; flex-direction: column; gap: 3px; margin-top: 4px; }
|
||
.serverlist label { display: flex; align-items: center; gap: 8px; padding: 5px 6px;
|
||
border-radius: 6px; cursor: pointer; font-size: 12.5px; color: var(--mut); }
|
||
.serverlist label:hover { background: rgba(255,255,255,.04); color: var(--ink); }
|
||
.serverlist input[type=checkbox] { accent-color: var(--acid, #d6ff3d); width: 14px; height: 14px; margin: 0; }
|
||
.serverlist .surl { flex: 1; font: 11.5px/1.4 ui-monospace, Consolas, monospace; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
||
.serverlist .sremove { flex: none; background: transparent; border: 0; color: var(--dim); cursor: pointer; padding: 0 4px; opacity: 0; }
|
||
.serverlist label:hover .sremove { opacity: 1; }
|
||
.serverlist .sremove:hover { color: var(--danger, #f6768a); }
|
||
/* Always-visible wallet list — vertical column of rows so users can scan
|
||
names + balances without dragging chips sideways. Capped at ~40vh so a
|
||
giant list still leaves the main content readable; scrolls inside. */
|
||
.wstrip { flex: none; display: flex; flex-direction: column; gap: 1px; padding: 4px 6px 5px 6px;
|
||
max-height: 44vh; overflow-y: auto; scrollbar-width: thin;
|
||
background: var(--panel); border-bottom: 1px solid var(--line); }
|
||
.wstrip::-webkit-scrollbar { width: 4px; }
|
||
.wstrip::-webkit-scrollbar-thumb { background: var(--line); border-radius: 2px; }
|
||
.wstrip .wchip { display: flex; align-items: center; gap: 4px; padding: 4px 6px 4px 4px;
|
||
background: transparent; border: 1px solid transparent; border-radius: 7px;
|
||
font: inherit; font-size: 12.5px; color: var(--mut); min-width: 0; }
|
||
.wstrip .wchip:hover { background: rgba(255,255,255,.04); color: var(--ink); }
|
||
.wstrip .wchip.on { background: rgb(from var(--acid, #d6ff3d) r g b / .10);
|
||
border-color: rgb(from var(--acid, #d6ff3d) r g b / .35);
|
||
color: var(--ink); }
|
||
.wstrip .wchip .wclick { display: flex; align-items: center; gap: 8px; flex: 1; min-width: 0;
|
||
cursor: pointer; padding: 2px 4px; border-radius: 5px; }
|
||
.wstrip .wchip .wtext { flex: 1; min-width: 0; overflow: hidden; display: inline-flex;
|
||
align-items: center; gap: 6px; flex-wrap: nowrap; }
|
||
.wstrip .wchip .wname { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
||
.wstrip .wchip .wsub { color: var(--dim); font-size: 10.5px; font-weight: 400; margin-left: 6px;
|
||
font-variant-numeric: tabular-nums; white-space: nowrap; }
|
||
/* Price chip sitting right next to the wallet label. Acid tint with a
|
||
subtle glow lifts it off the grey row so users spot movement without
|
||
hunting; the small background gives it structural presence too. */
|
||
.wstrip .wchip .wprice { color: var(--acid, #d6ff3d); font-size: 11px; font-weight: 600;
|
||
font-variant-numeric: tabular-nums; white-space: nowrap;
|
||
padding: 1px 6px; border-radius: 999px;
|
||
background: rgb(from var(--acid, #d6ff3d) r g b / .10);
|
||
text-shadow: 0 0 6px rgb(from var(--acid, #d6ff3d) r g b / .35); }
|
||
.wstrip .wchip .wact { flex: none; background: transparent; border: 0; color: var(--dim);
|
||
cursor: pointer; padding: 3px 6px; border-radius: 5px; font-size: 12px; line-height: 1; }
|
||
.wstrip .wchip .wact:hover { color: var(--acid, #d6ff3d); background: rgba(255,255,255,.06); }
|
||
/* Four-column layout: [logo][ticker+price stack][amount+fiat stack][actions].
|
||
The old separate Price and Chain columns collapsed into the ticker cell —
|
||
per-unit price sits directly under the ticker so the eye can read
|
||
"BCH · $430" as one unit before jumping to the balance on the right.
|
||
A non-mainnet row also carries a small network pill inline with the
|
||
ticker (Chipnet / Sepolia / …); mainnet rows omit it entirely. */
|
||
.wstrip { padding: 4px 6px 6px 6px; }
|
||
.wstrip .wrow { display: grid; grid-template-columns: 18px minmax(72px,auto) minmax(0,1fr) auto auto;
|
||
gap: 8px; align-items: center; padding: 5px 4px;
|
||
border-radius: 6px; border: 1px solid transparent; cursor: pointer;
|
||
min-height: 30px; }
|
||
.wstrip .wrow:hover { background: rgba(255,255,255,.04); }
|
||
.wstrip .wrow.on { background: rgb(from var(--acid, #d6ff3d) r g b / .10);
|
||
border-color: rgb(from var(--acid, #d6ff3d) r g b / .35); }
|
||
.wstrip .wrow.dragging { opacity: .45; cursor: grabbing; }
|
||
.wstrip .wrow.drop-before { box-shadow: 0 -2px 0 0 var(--acid, #d6ff3d); }
|
||
.wstrip .wrow.drop-after { box-shadow: 0 2px 0 0 var(--acid, #d6ff3d); }
|
||
.wstrip .wgrip { display: inline-block; color: var(--dim); font-size: 10px; padding: 0 2px;
|
||
cursor: grab; user-select: none; opacity: 0; transition: opacity .12s; }
|
||
.wstrip .wrow:hover .wgrip { opacity: 1; }
|
||
.wstrip .wrow[draggable="true"] { cursor: grab; }
|
||
.wstrip .wcell { min-width: 0; display: inline-flex; align-items: center; gap: 3px; }
|
||
.wstrip .wclogo { justify-self: start; align-self: start; padding-top: 2px; }
|
||
/* Ticker cell: two-line stack. Line 1 has the ticker, an optional ▾
|
||
chevron (only when the chain has more than one network to switch
|
||
between), an optional Chipnet/Testnet pill, and the wallet count.
|
||
Line 2 is the per-unit price in acid-green. The cell as a whole is
|
||
the click target for the network dropdown. */
|
||
.wstrip .wcname { flex-direction: column; align-items: flex-start; line-height: 1.15; gap: 1px; }
|
||
.wstrip .wcname .wtline { display: inline-flex; align-items: center; gap: 5px; }
|
||
.wstrip .wcname .wtck { font-weight: 700; font-size: 13px; color: var(--ink); }
|
||
.wstrip .wcname .wchev { color: var(--dim); font-size: 9px; line-height: 1; padding: 0 1px;
|
||
transition: color .12s, transform .12s; }
|
||
.wstrip .wcname.wswitchable { cursor: pointer; }
|
||
.wstrip .wcname.wswitchable:hover .wchev { color: var(--acid, #d6ff3d); }
|
||
.wstrip .wcname .wnetpill { font-size: 10px; padding: 1px 6px; border-radius: 999px;
|
||
background: rgba(255,255,255,.06); color: var(--mut);
|
||
white-space: nowrap; line-height: 1.35; }
|
||
.wstrip .wcname .wnetpill.wchipnet { background: rgb(from var(--acid, #d6ff3d) r g b / .18);
|
||
color: var(--acid, #d6ff3d); font-weight: 600; }
|
||
.wstrip .wcname .wnetpill.wtestnet { background: rgba(224,179,65,.18); color: #e0b341; font-weight: 600; }
|
||
.wstrip .wcname .wgcount { color: var(--dim); font-size: 10.5px; padding: 0 6px; border-radius: 999px;
|
||
background: rgba(255,255,255,.06); font-variant-numeric: tabular-nums; line-height: 1.4; }
|
||
.wstrip .wcname .wcprice { color: var(--acid, #d6ff3d); font-size: 11px; font-weight: 600;
|
||
font-variant-numeric: tabular-nums; white-space: nowrap;
|
||
text-shadow: 0 0 5px rgb(from var(--acid, #d6ff3d) r g b / .30); }
|
||
.wstrip .wcamt { flex-direction: column; align-items: flex-end; text-align: right;
|
||
font-variant-numeric: tabular-nums; line-height: 1.2; }
|
||
.wstrip .wcamt .wnative { font-size: 12.5px; color: var(--ink); font-weight: 500; }
|
||
.wstrip .wcamt .wfiat { font-size: 11px; color: var(--dim); }
|
||
.wstrip .wcact { display: inline-flex; gap: 2px; }
|
||
.wstrip .wcact .wact { background: transparent; border: 0; color: var(--dim); cursor: pointer;
|
||
padding: 2px 5px; border-radius: 4px; font-size: 12.5px; line-height: 1; }
|
||
.wstrip .wcact .wact:hover { color: var(--acid, #d6ff3d); background: rgba(255,255,255,.06); }
|
||
/* Network dropdown menu — anchored below the ticker cell on click. Shows
|
||
every network under the chain (mainnet + testnets) with its own totals,
|
||
so switching networks feels like flipping a segment on the same coin
|
||
row rather than jumping to a separate wallet. */
|
||
.netmenu { position: absolute; z-index: 60; min-width: 180px; background: var(--panel, #1a1a1a);
|
||
border: 1px solid var(--line); border-radius: 8px; padding: 4px;
|
||
box-shadow: 0 6px 20px rgba(0,0,0,.35); }
|
||
.netmenu .nmitem { display: flex; align-items: center; justify-content: space-between;
|
||
gap: 10px; padding: 6px 8px; border-radius: 5px; cursor: pointer;
|
||
color: var(--ink); font-size: 12.5px; }
|
||
.netmenu .nmitem:hover { background: rgba(255,255,255,.06); }
|
||
.netmenu .nmitem.on { background: rgb(from var(--acid, #d6ff3d) r g b / .12);
|
||
color: var(--acid, #d6ff3d); }
|
||
.netmenu .nmitem .nmname { display: inline-flex; align-items: center; gap: 6px; }
|
||
.netmenu .nmitem .nmnet { font-weight: 600; }
|
||
.netmenu .nmitem .nmcount { color: var(--dim); font-size: 10.5px; padding: 0 5px; border-radius: 999px;
|
||
background: rgba(255,255,255,.06); }
|
||
.netmenu .nmitem .nmamt { font-variant-numeric: tabular-nums; font-size: 11.5px; color: var(--dim); }
|
||
.netmenu .nmitem.on .nmamt { color: var(--acid, #d6ff3d); }
|
||
/* Acid-green testnet tag for the Chipnet group. Overrides the warm-amber
|
||
default so chipnet reads as "the friendly BCH testnet" instead of
|
||
borrowing the caution palette. */
|
||
.ttag.acid { background: rgb(from var(--acid, #d6ff3d) r g b / .18); color: var(--acid, #d6ff3d); }
|
||
.wstrip .waddwrap { display: flex; gap: 5px; padding: 0 0 4px 0; margin-bottom: 4px; border-bottom: 1px solid var(--line); }
|
||
.wstrip .waddwrap button { flex: 1; background: transparent; border: 1px dashed var(--line); border-radius: 6px;
|
||
padding: 5px 8px; color: var(--dim); cursor: pointer; font: inherit; font-size: 12px; line-height: 1; }
|
||
.wstrip .waddwrap button:hover { color: var(--acid, #d6ff3d); border-color: var(--acid, #d6ff3d); }
|
||
/* Inline coin-address view — takes the place of the six-column grid when
|
||
a user opens a multi-wallet group. Back-arrow row + one row per wallet
|
||
under the coin. Same container so the visual context stays put. */
|
||
.wstrip .wcoinhead { display: flex; align-items: center; gap: 6px; padding: 3px 4px 4px 4px;
|
||
border-bottom: 1px solid var(--line); }
|
||
.wstrip .wcoinhead .wback { background: transparent; border: 0; color: var(--dim); cursor: pointer;
|
||
padding: 2px 4px; border-radius: 4px; font: inherit; font-size: 12px; line-height: 1; }
|
||
.wstrip .wcoinhead .wback:hover { color: var(--acid, #d6ff3d); background: rgba(255,255,255,.06); }
|
||
.wstrip .wcoinhead .wctitle { flex: 1; min-width: 0; display: inline-flex; align-items: center; gap: 6px;
|
||
font-size: 13px; font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
||
.wstrip .wcoinhead .wcount { color: var(--dim); font-size: 11.5px; font-weight: 500; }
|
||
.wstrip .warow { display: grid; grid-template-columns: 16px minmax(60px,1fr) auto auto auto;
|
||
gap: 6px; align-items: center; padding: 5px 4px;
|
||
border-radius: 6px; border: 1px solid transparent; cursor: pointer; min-height: 30px; }
|
||
.wstrip .warow:hover { background: rgba(255,255,255,.04); }
|
||
.wstrip .warow.on { background: rgb(from var(--acid, #d6ff3d) r g b / .10);
|
||
border-color: rgb(from var(--acid, #d6ff3d) r g b / .35); }
|
||
.wstrip .warow .waname { font-size: 13px; color: var(--ink); overflow: hidden; text-overflow: ellipsis;
|
||
white-space: nowrap; font-weight: 500; }
|
||
.wstrip .warow .waaddr { font: 11px/1.15 ui-monospace, Consolas, monospace; color: var(--dim); margin-top: 2px;
|
||
overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
||
.wstrip .warow .waamt { text-align: right; font-variant-numeric: tabular-nums; font-size: 12.5px; color: var(--ink); }
|
||
.wstrip .warow .wafiat { font-size: 11px; color: var(--dim); }
|
||
.wstrip .warow .wact { background: transparent; border: 0; color: var(--dim); cursor: pointer;
|
||
padding: 2px 5px; border-radius: 4px; font-size: 12.5px; line-height: 1; }
|
||
.wstrip .warow .wact:hover { color: var(--acid, #d6ff3d); background: rgba(255,255,255,.06); }
|
||
|
||
/* Full-panel lock screen — takes over the entire panel below the aegis
|
||
footer when the vault is locked or awaiting first-time setup. Rest of
|
||
the app (header picker, tabs, wallet strip) is hidden until unlocked
|
||
so nothing sensitive shows and there is no accidental interaction
|
||
surface. */
|
||
#lockScreen[hidden] { display: none; }
|
||
#lockScreen { position: absolute; inset: 0 0 30px 0; z-index: 50; background: var(--bg);
|
||
display: flex; flex-direction: column; align-items: center; justify-content: center;
|
||
padding: 24px 18px; color: var(--ink); text-align: center; }
|
||
#lockScreen .aegisMark { width: 64px; height: 64px; margin-bottom: 14px; }
|
||
#lockScreen .aegisMark svg { width: 100%; height: 100%; color: var(--acid, #d6ff3d);
|
||
filter: drop-shadow(0 0 12px rgb(from var(--acid, #d6ff3d) r g b / .35)); }
|
||
#lockScreen h1 { font: 600 16px/1.3 inherit; margin: 0 0 4px 0; letter-spacing: .2px; }
|
||
#lockScreen .subhint { color: var(--mut); font-size: 12px; max-width: 320px; margin: 0 0 20px 0; }
|
||
#lockScreen .lockform { width: min(320px, 100%); display: flex; flex-direction: column; gap: 10px; text-align: left; }
|
||
#lockScreen .lockform input[type=password],
|
||
#lockScreen .lockform input[type=text],
|
||
#lockScreen .lockform textarea { text-align: center; }
|
||
#lockScreen .altline { color: var(--dim); font-size: 11.5px; margin-top: 12px; text-align: center; }
|
||
#lockScreen .altline a { color: var(--acid, #d6ff3d); cursor: pointer; text-decoration: none; }
|
||
#lockScreen .altline a:hover { text-decoration: underline; }
|
||
/* PIN pad — six dots + a 3x4 keypad. Used both in lock screen and in the
|
||
PIN approval modal. */
|
||
.pinpad { display: flex; flex-direction: column; align-items: center; gap: 14px; }
|
||
.pinpad .pindots { display: flex; gap: 12px; }
|
||
.pinpad .pindot { width: 12px; height: 12px; border-radius: 50%; border: 1.5px solid var(--dim);
|
||
background: transparent; transition: background .12s, border-color .12s; }
|
||
.pinpad .pindot.on { background: var(--acid, #d6ff3d); border-color: var(--acid, #d6ff3d);
|
||
box-shadow: 0 0 6px rgb(from var(--acid, #d6ff3d) r g b / .5); }
|
||
.pinpad .pinkeys { display: grid; grid-template-columns: repeat(3, 62px); gap: 8px; }
|
||
.pinpad .pinkeys button { height: 46px; border-radius: 10px; border: 1px solid var(--line);
|
||
background: var(--card); color: var(--ink); font: 500 18px inherit;
|
||
cursor: pointer; }
|
||
.pinpad .pinkeys button:hover { border-color: var(--acid, #d6ff3d); color: var(--acid, #d6ff3d); }
|
||
.pinpad .pinkeys button.util { background: transparent; font-size: 13px; color: var(--dim); }
|
||
.pinpad .pinerr { color: var(--danger); font-size: 12px; text-align: center; min-height: 16px; }
|
||
|
||
/* PIN modal overlay — used for set-PIN / change-PIN / verify-PIN flows. */
|
||
.pinmodal { position: fixed; inset: 0; background: rgba(0,0,0,.55); display: flex;
|
||
align-items: center; justify-content: center; z-index: 9999; padding: 20px; }
|
||
.pinmodal .pincard { width: min(94vw, 340px); background: var(--panel); border: 1px solid var(--line);
|
||
border-radius: 12px; padding: 18px 16px 14px; box-shadow: 0 10px 40px rgba(0,0,0,.4); }
|
||
.pinmodal h2 { margin: 0 0 6px 0; font: 600 15px inherit; }
|
||
.pinmodal .pinsub { color: var(--mut); font-size: 12px; margin-bottom: 12px; text-align: center; }
|
||
.pinmodal .pinactions { display: flex; gap: 6px; justify-content: center; margin-top: 12px; }
|
||
|
||
/* General settings cards — pinned at top of Settings tab so cross-cutting
|
||
security/policy controls stay in one place, ahead of the per-wallet
|
||
stuff below. */
|
||
.gsec { margin-bottom: 14px; }
|
||
.gsec .gtitle { font: 600 13px inherit; color: var(--ink); margin-bottom: 6px; }
|
||
.gsec .gline { display: flex; align-items: center; justify-content: space-between; gap: 10px;
|
||
padding: 6px 0; border-top: 1px solid var(--line); }
|
||
.gsec .gline:first-of-type { border-top: 0; }
|
||
.gsec .gline .glabel { min-width: 0; font-size: 12.5px; color: var(--ink); }
|
||
.gsec .gline .ghint { display: block; color: var(--dim); font-size: 11px; margin-top: 2px; }
|
||
.gsec .gline .gactions { flex: none; display: inline-flex; gap: 6px; }
|
||
.gsec .gsoon { font-size: 10px; padding: 1px 6px; border-radius: 999px; letter-spacing: .04em;
|
||
background: rgba(224,179,65,.14); color: #e0b341; text-transform: uppercase; }
|
||
</style>
|
||
</head>
|
||
<body>
|
||
<header>
|
||
<div class="picker" id="pickerBtn">
|
||
<div class="t">
|
||
<span class="badge" id="hBadge"></span>
|
||
<span class="lbl" id="hLabel">Aegis Wallet</span>
|
||
<span id="hNet"></span>
|
||
</div>
|
||
<div class="picker-actions">
|
||
<button type="button" id="hAdd" class="chip" title="Add a new wallet">+</button>
|
||
<button type="button" id="hMore" class="chip" title="Import / Connect / About">⋯</button>
|
||
<button type="button" id="hManage" class="chip" title="Edit this wallet — rename, derivation path, remove">✎</button>
|
||
</div>
|
||
</div>
|
||
<div id="drop" hidden></div>
|
||
<div class="bal">
|
||
<div class="big">
|
||
<span id="balMain">—</span><small id="balTicker">—</small>
|
||
<span id="balFiat" class="fiat" hidden></span>
|
||
</div>
|
||
<div class="sub">
|
||
<span class="netlbl" id="netlbl">connecting…</span>
|
||
<span class="net"><span class="dot" id="dot"></span></span>
|
||
</div>
|
||
<div id="portfolio" class="portfolio" hidden></div>
|
||
</div>
|
||
</header>
|
||
<nav>
|
||
<button data-tab="receive" class="on">Receive</button>
|
||
<button data-tab="send">Send</button>
|
||
<button data-tab="history">History</button>
|
||
<button data-tab="settings">Settings</button>
|
||
</nav>
|
||
<!-- Always-visible wallet list. Sits under the Receive/Send/History/Settings
|
||
tab bar so the top of the panel stays about the SELECTED wallet, and
|
||
the list of siblings/switch-targets reads as a secondary layer below.
|
||
[+ Add] opens the Add-only picker; [⋯ More] opens Import/Connect/Manage. -->
|
||
<div id="walletStrip" class="wstrip" aria-label="Your wallets"></div>
|
||
<main>
|
||
<div id="gate" class="gate" hidden></div>
|
||
<div id="tabs">
|
||
<section id="tab-receive">
|
||
<div class="qrwrap"><canvas id="qr" width="200" height="200"></canvas></div>
|
||
<div class="card">
|
||
<div class="lbl">Receiving address <span id="addrMeta"></span></div>
|
||
<div class="mono" id="addr">—</div>
|
||
<div class="actions">
|
||
<button class="btn sm" id="copyAddr">Copy</button>
|
||
<button class="btn sm" id="nextAddr" hidden>Next unused address</button>
|
||
<button class="btn sm" id="viewAddr">Explorer</button>
|
||
<button class="btn sm" id="openFaucet" hidden>Faucet</button>
|
||
</div>
|
||
</div>
|
||
<div class="card" id="tokensCard" hidden style="margin-top:12px">
|
||
<div class="lbl">Tokens</div>
|
||
<div id="tokensList" class="kv"></div>
|
||
<div class="hint">SPL tokens held by this wallet. Send by picking one under the Send tab's Asset dropdown.</div>
|
||
</div>
|
||
</section>
|
||
<section id="tab-send" hidden>
|
||
<div class="field" id="sendAssetField" hidden>
|
||
<div class="lbl">Asset</div>
|
||
<select id="sendAsset"></select>
|
||
<div class="hint">Pick the native coin or an SPL token in this wallet.</div>
|
||
</div>
|
||
<div class="field">
|
||
<div class="lbl">Recipient</div>
|
||
<input type="text" id="sendTo" spellcheck="false" autocomplete="off" placeholder="…">
|
||
<div class="hint" id="sendToHint"></div>
|
||
</div>
|
||
<div class="field">
|
||
<div class="lbl">Amount <span id="sendAmtFiat" class="fiat" style="margin-left:8px" hidden></span></div>
|
||
<div class="amt">
|
||
<input type="text" id="sendAmt" inputmode="decimal" autocomplete="off" placeholder="0.00">
|
||
<div class="unit" id="unitPicker"></div>
|
||
<button class="btn sm" id="sendMax" type="button">Max</button>
|
||
</div>
|
||
</div>
|
||
<div class="field" id="feeField">
|
||
<div class="lbl">Fee</div>
|
||
<div class="fee"><input type="range" id="feeRate" min="1" max="5" step="1" value="1"><span class="v" id="feeLbl">1 sat/B</span></div>
|
||
</div>
|
||
<div class="card">
|
||
<div class="summary">
|
||
<div class="k">Amount</div><div class="v" id="sumAmt">—</div>
|
||
<div class="k">Network fee</div><div class="v" id="sumFee">—</div>
|
||
<div class="k">Total</div><div class="v" id="sumTotal">—</div>
|
||
</div>
|
||
</div>
|
||
<div class="actions"><button class="btn primary" id="sendBtn" disabled>Send</button></div>
|
||
<div class="msg" id="sendMsg" hidden></div>
|
||
</section>
|
||
<section id="tab-history" hidden>
|
||
<div id="txlist"></div>
|
||
</section>
|
||
<section id="tab-settings" hidden>
|
||
<!-- Cross-cutting security / policy controls, ahead of anything
|
||
per-wallet or chain-specific. Present even when the vault is
|
||
still locked so users can set up a PIN or read the multi-sig
|
||
roadmap without unlocking first (they only do the ACTUAL PIN
|
||
enrollment after a fresh unlock, though). -->
|
||
<div class="card gsec" id="genSecurity" style="margin-bottom:14px">
|
||
<div class="gtitle">Security</div>
|
||
<div class="gline">
|
||
<div class="glabel">
|
||
Quick-access PIN
|
||
<span class="ghint" id="pinStatusHint">Off — Aegis asks for the master password every time.</span>
|
||
</div>
|
||
<div class="gactions">
|
||
<button class="btn sm" id="gsPinSet" hidden>Set PIN…</button>
|
||
<button class="btn sm" id="gsPinChange" hidden>Change…</button>
|
||
<button class="btn sm danger" id="gsPinRemove" hidden>Remove</button>
|
||
</div>
|
||
</div>
|
||
<div class="gline" id="gsRequirePinLine" hidden>
|
||
<div class="glabel">
|
||
Require PIN for sending
|
||
<span class="ghint">Prompts for your PIN on every panel-initiated Send. Dapp-driven approvals still use the standard approval overlay.</span>
|
||
</div>
|
||
<div class="gactions">
|
||
<label class="switch"><input type="checkbox" id="gsRequirePin"><span></span></label>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Session: stay-signed-in + idle auto-lock + manual sign-out.
|
||
Uses electron.safeStorage under the hood so the master password
|
||
is only decryptable under this OS user account. When "Lock on
|
||
Navigator close" is on (the default), Aegis stores nothing on
|
||
disk and forces a fresh unlock on every launch. -->
|
||
<div class="card gsec" id="genSession" style="margin-bottom:14px">
|
||
<div class="gtitle">Session</div>
|
||
<div class="gline">
|
||
<div class="glabel">
|
||
Lock on Navigator close
|
||
<span class="ghint" id="gsSessionHint">On — Aegis asks for the master password (or PIN) every time Theseus starts. Turn off to stay signed in across restarts via the OS keystore.</span>
|
||
</div>
|
||
<div class="gactions">
|
||
<label class="switch"><input type="checkbox" id="gsLockOnClose" checked><span></span></label>
|
||
</div>
|
||
</div>
|
||
<div class="gline">
|
||
<div class="glabel">
|
||
Auto-lock when idle
|
||
<span class="ghint">Locks the vault after this long with no panel activity. Applies inside the wallet panel; a locked panel elsewhere in the browser doesn't count as idle.</span>
|
||
</div>
|
||
<div class="gactions">
|
||
<select id="gsIdleMinutes" style="padding:5px 8px;border-radius:6px;background:var(--panel);border:1px solid var(--line);color:var(--ink);font-size:12px">
|
||
<option value="0">Never</option>
|
||
<option value="5">5 min</option>
|
||
<option value="15" selected>15 min</option>
|
||
<option value="30">30 min</option>
|
||
<option value="60">1 hour</option>
|
||
<option value="180">3 hours</option>
|
||
</select>
|
||
</div>
|
||
</div>
|
||
<div class="gline">
|
||
<div class="glabel">
|
||
Sign out now
|
||
<span class="ghint">Locks the vault immediately. Any dapp connections stay paired, but Aegis will refuse to sign until you unlock again.</span>
|
||
</div>
|
||
<div class="gactions">
|
||
<button class="btn sm danger" id="gsSignOut">Sign out</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="card gsec" id="genMasterPw" style="margin-bottom:14px">
|
||
<div class="gtitle">Master password</div>
|
||
<div class="gline">
|
||
<div class="glabel">
|
||
Change master password
|
||
<span class="ghint">Opens Theseus <span class="mono">Settings › Passwords</span>. The vault re-encrypts under the new password; every derived wallet keeps working.</span>
|
||
</div>
|
||
<div class="gactions">
|
||
<button class="btn sm" id="gsOpenPasswords">Open Passwords…</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="card gsec" id="genMultiSig" style="margin-bottom:14px">
|
||
<div class="gtitle">Second-device approval <span class="gsoon">soon</span></div>
|
||
<div class="gline">
|
||
<div class="glabel">
|
||
Co-sign sends from a second device
|
||
<span class="ghint">Aegis will pair with Ariadne on your phone so large transfers need a nod from both places before they broadcast. Not shipped yet.</span>
|
||
</div>
|
||
<div class="gactions">
|
||
<button class="btn sm" disabled title="Not shipped yet">Set up…</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="card" id="walletManage" style="margin-bottom:14px">
|
||
<div class="lbl">This wallet</div>
|
||
<div class="field" style="margin-top:6px;margin-bottom:8px">
|
||
<input type="text" id="renameLabel" placeholder="Wallet name">
|
||
</div>
|
||
<div class="actions">
|
||
<button class="btn sm" id="renameBtn">Rename</button>
|
||
<button class="btn sm danger" id="removeBtn">Remove wallet</button>
|
||
</div>
|
||
<div class="hint" id="removeHint"></div>
|
||
</div>
|
||
|
||
<div id="bchSettings" hidden>
|
||
<div class="field">
|
||
<div class="lbl">Derivation path (account)</div>
|
||
<input type="text" id="setPath" spellcheck="false" placeholder="m/44'/145'/0'">
|
||
<div class="hint">Changing this switches to a different set of addresses under the same wallet seed.</div>
|
||
</div>
|
||
<div class="field" id="bchServersRow">
|
||
<div class="lbl">Electrum servers <span class="hint" style="font-weight:normal">(BCH mainnet — shared across BCH wallets)</span></div>
|
||
<div id="setServersList" class="serverlist"></div>
|
||
<details style="margin-top:6px">
|
||
<summary style="cursor:pointer;color:var(--dim);font-size:11.5px">Add a custom server…</summary>
|
||
<div style="display:flex;gap:6px;margin-top:6px">
|
||
<input type="text" id="setServersCustom" spellcheck="false" placeholder="wss://host:port" style="flex:1">
|
||
<button class="btn sm" id="addCustomServer" type="button">Add</button>
|
||
</div>
|
||
</details>
|
||
<div class="hint" id="serverHint"></div>
|
||
</div>
|
||
<div class="actions">
|
||
<button class="btn primary" id="applySettings">Apply</button>
|
||
<button class="btn" id="resetServers">Reset servers</button>
|
||
</div>
|
||
<div class="card" style="margin-top:16px">
|
||
<div class="lbl">Recovery info</div>
|
||
<div class="hint">Keys come from your Theseus password vault under <span class="mono" id="purpose"></span>. The same vault seed on another machine recreates this wallet.</div>
|
||
<div class="kv" id="recovery"></div>
|
||
<div class="actions">
|
||
<button class="btn" id="showXpub">Show account xpub</button>
|
||
<button class="btn danger" id="showXprv">Show account private key</button>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="card" style="margin-top:16px" id="wcCard">
|
||
<div class="lbl">WizardConnect</div>
|
||
<div class="hint" style="margin-bottom:8px">
|
||
Pair this BCH wallet with a dapp that speaks the WizardConnect protocol
|
||
(Cauldron, Moria, or any site built on the SDK). Paste the <span class="mono">wiz://</span>
|
||
URI the dapp shows in its Connect dialog. Aegis signs every transaction only after you approve it.
|
||
</div>
|
||
<!-- Warning that appears when the selected wallet is imported —
|
||
WC signing needs the derive-based signer path, which imported
|
||
wallets don't have yet. Shown in place of the input so users
|
||
don't try to paste a URI and hit "wallet not ready". -->
|
||
<div class="msg err" id="wcImportedNotice" hidden style="margin-bottom:8px">
|
||
WizardConnect isn't available for imported wallets yet — pairing
|
||
uses Aegis' vault-derived signer path, and imported wallets are
|
||
read-only for now. Coming in a later release.
|
||
</div>
|
||
<div id="wcInputs">
|
||
<div class="field" style="margin-top:8px">
|
||
<input type="text" id="wcUri" spellcheck="false" placeholder="wiz://?p=…&s=…">
|
||
</div>
|
||
<div class="actions">
|
||
<button class="btn primary" id="wcConnectBtn">Connect</button>
|
||
</div>
|
||
</div>
|
||
<div class="msg" id="wcMsg" hidden></div>
|
||
<div class="kv" id="wcSites" style="margin-top:8px"></div>
|
||
</div>
|
||
</div>
|
||
|
||
<div id="trxSettings" hidden>
|
||
<div class="card">
|
||
<div class="lbl">Recovery info</div>
|
||
<div class="hint">Keys come from your Theseus password vault under <span class="mono" id="trxPurpose"></span>. Import into TronLink with the derivation path <span class="mono">m/44'/195'/0'/0/0</span> from the same vault seed.</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div id="scSettings" hidden>
|
||
<div class="field">
|
||
<div class="lbl">walletd URL</div>
|
||
<input type="text" id="setWalletdUrl" spellcheck="false" placeholder="https://your-walletd.example/api">
|
||
<div class="hint">Any public or self-hosted <span class="mono">go.sia.tech/walletd</span> in "full" index mode. The URL is per-wallet, so different Sia sub-accounts can point at different nodes. It is not shared with anyone else.</div>
|
||
</div>
|
||
<div class="actions">
|
||
<button class="btn primary" id="applyWalletdUrl">Apply</button>
|
||
</div>
|
||
<div class="card" style="margin-top:16px">
|
||
<div class="lbl">Recovery info</div>
|
||
<div class="hint">Keys come from your Theseus password vault under <span class="mono" id="scPurpose"></span>. Address scheme: walletd <span class="mono">KeyFromSeed(seed, index)</span>.</div>
|
||
<div class="kv" id="scRecovery"></div>
|
||
<div class="actions">
|
||
<button class="btn danger" id="showScSeed">Reveal wallet seed</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div id="dgbSettings" hidden>
|
||
<div class="field">
|
||
<div class="lbl">Address family</div>
|
||
<select id="setDgbFamily"></select>
|
||
<div class="hint">Picks the BIP purpose that shapes your DGB addresses. Switching rebuilds the wallet against a different set of addresses under the same seed — old funds don't move; they still live under the family they were received on.</div>
|
||
</div>
|
||
<div class="field">
|
||
<div class="lbl">Derivation path (account)</div>
|
||
<input type="text" id="setDgbPath" spellcheck="false" placeholder="m/84'/20'/0'">
|
||
<div class="hint">Auto-filled from the family above. Edit only if you need a non-default account.</div>
|
||
</div>
|
||
<div class="actions">
|
||
<button class="btn primary" id="applyDgbPath">Apply</button>
|
||
</div>
|
||
<div class="card" style="margin-top:16px">
|
||
<div class="lbl">Recovery info</div>
|
||
<div class="hint">Keys come from your Theseus password vault under <span class="mono" id="dgbPurpose"></span>. Any BIP39 tool set to <span class="mono">DGB</span> (coin type 20) at the same purpose can reproduce this wallet.</div>
|
||
<div class="kv" id="dgbRecovery"></div>
|
||
<div class="actions">
|
||
<button class="btn" id="showDgbXpub">Show account xpub</button>
|
||
<button class="btn danger" id="showDgbXprv">Show account private key</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div id="btcSettings" hidden>
|
||
<div class="field">
|
||
<div class="lbl">Address family</div>
|
||
<select id="setBtcFamily"></select>
|
||
<div class="hint">Picks the BIP purpose that shapes your Bitcoin addresses. Switching rebuilds the wallet against a different set of addresses under the same seed — old funds don't move; they still live under the family they were received on.</div>
|
||
</div>
|
||
<div class="field">
|
||
<div class="lbl">Derivation path (account)</div>
|
||
<input type="text" id="setBtcPath" spellcheck="false" placeholder="m/84'/0'/0'">
|
||
<div class="hint">Auto-filled from the family above. Edit only if you need a non-default account.</div>
|
||
</div>
|
||
<div class="actions">
|
||
<button class="btn primary" id="applyBtcPath">Apply</button>
|
||
</div>
|
||
<div class="card" style="margin-top:16px">
|
||
<div class="lbl">Recovery info</div>
|
||
<div class="hint">Keys come from your Theseus password vault under <span class="mono" id="btcPurpose"></span>. Any BIP39 tool at coin type 0 (mainnet) / 1 (testnet) and the same purpose can reproduce this wallet.</div>
|
||
<div class="kv" id="btcRecovery"></div>
|
||
<div class="actions">
|
||
<button class="btn" id="showBtcXpub">Show account xpub</button>
|
||
<button class="btn danger" id="showBtcXprv">Show account private key</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div id="ethSettings" hidden>
|
||
<div class="field">
|
||
<div class="lbl">RPC URL</div>
|
||
<input type="text" id="setEthRpcUrl" spellcheck="false" placeholder="https://cloudflare-eth.com">
|
||
<div class="hint">JSON-RPC endpoint Aegis reads balances and broadcasts from. Any provider works — public gateways (Cloudflare, PublicNode), Alchemy, Infura, or your own node. Stored per-wallet; not shared.</div>
|
||
</div>
|
||
<div class="actions">
|
||
<button class="btn primary" id="applyEthRpc">Apply</button>
|
||
</div>
|
||
<div class="card" style="margin-top:16px">
|
||
<div class="lbl">Recovery info</div>
|
||
<div class="hint">Keys come from your Theseus password vault under <span class="mono" id="ethPurpose"></span>. Import into MetaMask / any Ethereum wallet using the derivation path <span class="mono">m/44'/60'/0'/0/0</span> from the same vault seed.</div>
|
||
<div class="kv" id="ethRecovery"></div>
|
||
<div class="actions">
|
||
<button class="btn danger" id="showEthKey">Reveal private key</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div id="solSettings" hidden>
|
||
<div class="field">
|
||
<div class="lbl">RPC URL</div>
|
||
<input type="text" id="setSolRpcUrl" spellcheck="false" placeholder="https://api.mainnet-beta.solana.com">
|
||
<div class="hint">JSON-RPC endpoint. The public Solana RPCs are heavily rate-limited — for real use point Aegis at Helius / QuickNode / your own node.</div>
|
||
</div>
|
||
<div class="actions">
|
||
<button class="btn primary" id="applySolRpc">Apply</button>
|
||
</div>
|
||
<div class="card" style="margin-top:16px">
|
||
<div class="lbl">Recovery info</div>
|
||
<div class="hint">Keys come from your Theseus password vault under <span class="mono" id="solPurpose"></span>. Import into Phantom / Solflare with the derivation path <span class="mono">m/44'/501'/0'/0'</span> from the same vault seed.</div>
|
||
<div class="kv" id="solRecovery"></div>
|
||
<div class="actions">
|
||
<button class="btn danger" id="showSolKey">Reveal wallet seed</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="card" style="margin-top:16px">
|
||
<div class="lbl">Fiat prices</div>
|
||
<div class="hint" style="margin-bottom:10px">
|
||
Off by default. When enabled, Aegis polls the chosen oracle for USD prices
|
||
on each supported coin. No keys and no address data are ever sent — but the
|
||
oracle sees your IP + a User-Agent every poll, which is a signal that a
|
||
wallet is open on this machine.
|
||
</div>
|
||
<div class="field">
|
||
<div class="lbl">Oracle</div>
|
||
<select id="pricesSource" style="width:100%;padding:7px 9px;border-radius:7px;background:var(--panel);border:1px solid var(--line);color:var(--ink);font-size:13px"></select>
|
||
<div class="hint" id="pricesSourceHint"></div>
|
||
</div>
|
||
<div class="actions" style="align-items:center;gap:12px">
|
||
<label class="switch">
|
||
<input type="checkbox" id="pricesToggle">
|
||
<span>Enable USD prices</span>
|
||
</label>
|
||
<button class="btn sm" id="refreshPrices" hidden>Refresh now</button>
|
||
<span class="hint" id="pricesStatus" style="margin-left:auto"></span>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="card" style="margin-top:16px">
|
||
<div class="lbl">Connected sites</div>
|
||
<div class="hint">Sites allowed to see your address, allowances for silent BCH payments, and Tron dapps you've connected. Message signing always asks.</div>
|
||
<div id="sites" class="kv"></div>
|
||
</div>
|
||
<div class="msg err" id="settingsMsg" hidden></div>
|
||
</section>
|
||
</div>
|
||
</main>
|
||
<!-- Full-panel lock screen. Absolutely positioned so it takes over the
|
||
entire content area (everything above the aegis footer) whenever the
|
||
vault is locked or awaiting first-time setup — the header picker, nav
|
||
tabs, and wallet strip stay in the DOM but sit visually under it. The
|
||
Settings tab still hides itself; nothing here interacts with it. -->
|
||
<div id="lockScreen" hidden>
|
||
<div class="aegisMark" aria-hidden="true">
|
||
<svg viewBox="0 0 32 32" fill="none">
|
||
<polygon points="16,2 28,9 28,23 16,30 4,23 4,9" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linejoin="round"/>
|
||
<circle cx="16" cy="16" r="4.5" fill="none" stroke="currentColor" stroke-width="1.4"/>
|
||
<circle cx="16" cy="16" r="1.6" fill="currentColor"/>
|
||
</svg>
|
||
</div>
|
||
<h1 id="lockTitle">Unlock Aegis</h1>
|
||
<div class="subhint" id="lockSub">Aegis derives its keys from your Theseus vault. There's nothing separate to unlock — the vault is your wallet.</div>
|
||
<div id="lockBody"></div>
|
||
</div>
|
||
<footer class="brandfoot" id="brandFoot">
|
||
<a href="#" id="brandLink" class="brandlink" title="Open aegis.x">
|
||
<svg viewBox="0 0 32 32" width="14" height="14" aria-hidden="true"><polygon points="16,2 28,9 28,23 16,30 4,23 4,9" fill="none" stroke="currentColor" stroke-width="2" stroke-linejoin="round"/><circle cx="16" cy="16" r="4.3" fill="none" stroke="currentColor" stroke-width="1.4"/><circle cx="16" cy="16" r="1.3" fill="currentColor"/></svg>
|
||
<span>aegis.x</span>
|
||
</a>
|
||
<!-- Update controls: a subtle "check" link that polls the OTA manifest,
|
||
then swaps to an "Update to vX.Y.Z" chip when a newer version is
|
||
ready. Panel-only view since the addon can't promote itself; the
|
||
chip links to Settings > Extensions > Aegis where the Apply flow
|
||
lives. Version marker on the far right doubles as the up-to-date
|
||
affordance so a happy panel says nothing extra. -->
|
||
<span id="brandUpdate" class="brandupd" hidden></span>
|
||
<span class="brandfoot-right">
|
||
<button id="brandCheck" class="brandcheck" type="button" title="Check for updates">↻</button>
|
||
<span class="brandver" id="brandVer"></span>
|
||
</span>
|
||
</footer>
|
||
<script src="qr.js"></script>
|
||
<script src="panel.js"></script>
|
||
</body>
|
||
</html>
|