From 75ec67617b017391e595657a79c58b3201809b6f Mon Sep 17 00:00:00 2001 From: sneak Date: Thu, 26 Feb 2026 03:12:33 +0700 Subject: [PATCH] Rewrite tx list with innerHTML, fix scrollbar overlay and overflow - Rebuilt tx list rendering using innerHTML instead of createElement - scrollbar-gutter: stable on body to prevent content shift - max-width:42ch instead of width:42ch to prevent horizontal overflow - overflow-x:hidden on body and #app --- src/popup/index.html | 2 +- src/popup/styles/main.css | 2 + src/popup/views/addressDetail.js | 65 ++++++++++---------------------- src/popup/views/helpers.js | 2 +- src/popup/views/home.js | 2 +- 5 files changed, 24 insertions(+), 49 deletions(-) diff --git a/src/popup/index.html b/src/popup/index.html index 4071d16..2a72bd4 100644 --- a/src/popup/index.html +++ b/src/popup/index.html @@ -201,7 +201,7 @@ class="flex text-xs mb-3 cursor-pointer" title="Click to copy" > - + No transactions found.'; return; } - list.innerHTML = ""; - txs.forEach((tx, i) => { + let html = ""; + let i = 0; + for (const tx of txs) { const counterparty = tx.direction === "sent" ? tx.to : tx.from; const dirLabel = tx.direction === "sent" ? "Sent" : "Received"; - const errorStyle = tx.isError ? " opacity:0.5" : ""; - - const row = document.createElement("div"); - row.style.cssText = - "padding:0.5rem 0;border-bottom:1px solid #ccc;font-size:12px;cursor:pointer;overflow:hidden;" + - errorStyle; - - const line1 = document.createElement("div"); - line1.style.cssText = - "display:flex;justify-content:space-between;overflow:hidden;"; - const age = document.createElement("span"); - age.style.cssText = - "color:#666;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;min-width:0;"; - age.textContent = timeAgo(tx.timestamp); - age.title = isoDate(tx.timestamp); - const dir = document.createElement("span"); - dir.style.cssText = - "flex-shrink:0;padding-left:0.5rem;white-space:nowrap;" + - (tx.isError ? "color:#666;" : ""); - dir.textContent = dirLabel + (tx.isError ? " (failed)" : ""); - line1.appendChild(age); - line1.appendChild(dir); - - const amountStr = tx.value + " " + tx.symbol; - const line2 = document.createElement("div"); - line2.style.cssText = - "display:flex;justify-content:space-between;overflow:hidden;"; - const addr = document.createElement("span"); - addr.style.cssText = - "overflow:hidden;text-overflow:ellipsis;white-space:nowrap;min-width:0;"; + const amountStr = escapeHtml(tx.value + " " + tx.symbol); const maxAddr = Math.max(10, 38 - Math.max(0, amountStr.length - 10)); - addr.textContent = truncateMiddle(counterparty, maxAddr); - addr.title = counterparty; - const amount = document.createElement("span"); - amount.style.cssText = - "flex-shrink:0;padding-left:0.5rem;white-space:nowrap;"; - amount.textContent = amountStr; - line2.appendChild(addr); - line2.appendChild(amount); - - row.appendChild(line1); - row.appendChild(line2); + const addrStr = escapeHtml(truncateMiddle(counterparty, maxAddr)); + const err = tx.isError ? " (failed)" : ""; + const opacity = tx.isError ? " opacity:0.5;" : ""; + const ago = escapeHtml(timeAgo(tx.timestamp)); + const iso = escapeHtml(isoDate(tx.timestamp)); + html += `
`; + html += `
${ago}${dirLabel}${err}
`; + html += `
${addrStr}${amountStr}
`; + html += `
`; + i++; + } + list.innerHTML = html; + list.querySelectorAll(".tx-row").forEach((row) => { row.addEventListener("click", () => { - state.selectedTx = i; - showTxDetail(tx); + const idx = parseInt(row.dataset.tx, 10); + showTxDetail(loadedTxs[idx]); }); - list.appendChild(row); }); } diff --git a/src/popup/views/helpers.js b/src/popup/views/helpers.js index a11d2f4..28d0462 100644 --- a/src/popup/views/helpers.js +++ b/src/popup/views/helpers.js @@ -76,7 +76,7 @@ function balanceLine(symbol, amount, price) { const usd = price ? formatUsd(amount * price) : ""; return ( `
` + - `` + + `` + `${symbol}` + `${qty}` + `` + diff --git a/src/popup/views/home.js b/src/popup/views/home.js index 0ff1403..0c12c96 100644 --- a/src/popup/views/home.js +++ b/src/popup/views/home.js @@ -40,7 +40,7 @@ function render(ctx) { } const addrUsd = formatUsd(getAddressValueUsd(addr)); html += `
`; - html += `${addr.address}`; + html += `${addr.address}`; html += `${addrUsd}`; html += `
`; html += balanceLinesForAddress(addr);