Split popup into one file per view
All checks were successful
check / check (push) Successful in 4s

popup/index.js reduced to ~75 lines: loads state, builds a
shared context object, initializes all views, shows first screen.

Each view in popup/views/:
  helpers.js      — $(), showError, hideError, showView
  welcome.js      — welcome screen
  addWallet.js    — unified create/import recovery phrase
  importKey.js    — private key import
  home.js         — wallet list, total value, address derivation
  addressDetail.js — address view, token list, QR, copy
  send.js         — send form, ENS resolution, tx broadcast
  receive.js      — QR + copy
  addToken.js     — token lookup, common token picker
  settings.js     — RPC endpoint
  approval.js     — dApp approval (stub)

Views communicate via a ctx object with shared callbacks
(renderWalletList, showAddressDetail, doRefreshAndRender, etc).
This commit is contained in:
2026-02-25 18:51:41 +07:00
parent f50a2a0389
commit 023d8441bc
12 changed files with 673 additions and 581 deletions

View File

@@ -0,0 +1,82 @@
const { $, showError, hideError, showView } = require("./helpers");
const { TOKENS } = require("../../shared/tokens");
const { state, saveState } = require("../../shared/state");
const {
lookupTokenInfo,
invalidateBalanceCache,
refreshBalances,
} = require("../../shared/balances");
function show() {
$("add-token-address").value = "";
$("add-token-info").classList.add("hidden");
hideError("add-token-error");
const list = $("common-token-list");
list.innerHTML = TOKENS.slice(0, 25)
.map(
(t) =>
`<button class="common-token border border-border px-1 hover:bg-fg hover:text-bg cursor-pointer text-xs" data-address="${t.address}" data-symbol="${t.symbol}" data-decimals="${t.decimals}">${t.symbol}</button>`,
)
.join("");
list.querySelectorAll(".common-token").forEach((btn) => {
btn.addEventListener("click", () => {
$("add-token-address").value = btn.dataset.address;
});
});
showView("add-token");
}
function init(ctx) {
$("btn-add-token-confirm").addEventListener("click", async () => {
const contractAddr = $("add-token-address").value.trim();
if (!contractAddr || !contractAddr.startsWith("0x")) {
showError(
"add-token-error",
"Please enter a valid contract address starting with 0x.",
);
return;
}
const already = state.trackedTokens.find(
(t) => t.address.toLowerCase() === contractAddr.toLowerCase(),
);
if (already) {
showError(
"add-token-error",
already.symbol + " is already being tracked.",
);
return;
}
hideError("add-token-error");
const infoEl = $("add-token-info");
infoEl.textContent = "Looking up token...";
infoEl.classList.remove("hidden");
try {
const info = await lookupTokenInfo(contractAddr, state.rpcUrl);
state.trackedTokens.push({
address: contractAddr,
symbol: info.symbol,
decimals: info.decimals,
name: info.name,
});
await saveState();
invalidateBalanceCache();
await refreshBalances(
state.wallets,
state.trackedTokens,
state.rpcUrl,
);
await saveState();
ctx.showAddressDetail();
} catch (e) {
showError(
"add-token-error",
"Could not read token contract. Check the address.",
);
infoEl.classList.add("hidden");
}
});
$("btn-add-token-back").addEventListener("click", ctx.showAddressDetail);
}
module.exports = { init, show };