Compare commits

..

3 Commits

Author SHA1 Message Date
clawbot
c1e48f3825 feat: add blockie identicon to Identity block in TransactionDetail
All checks were successful
check / check (push) Successful in 22s
Generate a blockie from the transaction hash and display it centered
at the top of the Identity block, matching the pattern used in
AddressDetail and AddressToken views. Updates README to document
the new element.
2026-03-01 07:44:50 -08:00
clawbot
a35f794c53 refactor: replace hr separators with light well containers in TransactionDetail
All checks were successful
check / check (push) Successful in 9s
Replace horizontal rules (<hr>) between TransactionDetail groups with
bg-well container divs matching the Settings view pattern. Each logical
group (Identity, Timing, Value, Decoded Details, Network Details, Raw
Data) is now wrapped in a bg-well p-3 mx-1 mb-3 container with an h3
heading, providing subtle background-based visual grouping instead of
line separators.

Conditional groups (Decoded, Network, Raw Data) retain their visibility
toggling with the bg-well wrapper inside the hidden container.

Update README TransactionDetail section to reflect light well containers.

Closes #131
2026-03-01 07:40:03 -08:00
user
437b904ab6 reorder transaction detail view: txid first, logical grouping with separators
All checks were successful
check / check (push) Successful in 22s
Reorganize the transaction detail view into logical blocks separated by
thin horizontal rules:

- Identity: transaction hash (first!), type, status
- Timing: time, block number
- Value: amount, native quantity, token contract, from, to
- Decoded details: action/protocol/steps (contract calls)
- Network details: nonce, gas price, gas used, fee
- Raw data: full calldata

Updates README screen map to reflect new field ordering and grouping.

closes #131
2026-03-01 07:28:15 -08:00
4 changed files with 113 additions and 90 deletions

View File

@@ -435,25 +435,36 @@ transitions.
#### TransactionDetail #### TransactionDetail
- **When**: User tapped a transaction row from AddressDetail or AddressToken. - **When**: User tapped a transaction row from AddressDetail or AddressToken.
- **Elements**: - **Elements** (grouped into logical blocks using light well containers,
matching the Settings view pattern):
- "Transaction" heading, "Back" button - "Transaction" heading, "Back" button
- Type: transaction classification — one of: Native ETH Transfer, ERC-20 - **Identity block**:
Token Transfer, Swap, Token Approval, Contract Call, Contract Creation - Blockie identicon (48px, centered, derived from transaction hash)
- Token contract: shown for ERC-20 transfers — color dot + full contract - Transaction hash: full hash (tap to copy) + etherscan link
address (tap to copy) + etherscan token link - Type: transaction classification — one of: Native ETH Transfer, ERC-20
- Status: "Success" or "Failed" Token Transfer, Swap, Token Approval, Contract Call, Contract Creation
- Time: ISO datetime + relative age in parentheses - Status: "Success" or "Failed"
- Amount: value + symbol (bold) - **Timing block**:
- From: blockie + color dot + full address (tap to copy) + etherscan link - Time: ISO datetime + relative age in parentheses
- ENS name if available - Block: block number (tap to copy) + etherscan block link
- To: blockie + color dot + full address (tap to copy) + etherscan link - **Value block**:
- ENS name if available - Amount: value + symbol (bold)
- Transaction hash: full hash (tap to copy) + etherscan link - Native quantity: raw integer + unit (shown when available)
- Block: block number (tap to copy) + etherscan block link - Token contract: shown for ERC-20 transfers — color dot + full contract
- Nonce: transaction nonce (tap to copy) address (tap to copy) + etherscan token link
- Transaction fee: ETH amount (tap to copy) - From: blockie + color dot + full address (tap to copy) + etherscan
- Gas price: value in Gwei (tap to copy) link; ENS name if available
- Gas used: integer (tap to copy) - To: blockie + color dot + full address (tap to copy) + etherscan link;
ENS name if available
- **Decoded details** (shown for contract calls):
- Action name, decoded parameters, token details, swap steps
- **Network details** (shown when on-chain data is available):
- Nonce: transaction nonce (tap to copy)
- Gas price: value in Gwei (tap to copy)
- Gas used: integer (tap to copy)
- Transaction fee: ETH amount (tap to copy)
- **Raw data** (shown when calldata is present):
- Full calldata in monospace dashed border
- **Transitions**: - **Transitions**:
- "Back" → **AddressToken** (if `selectedToken` set) or **AddressDetail** - "Back" → **AddressToken** (if `selectedToken` set) or **AddressDetail**

View File

@@ -1066,8 +1066,13 @@
</h2> </h2>
<!-- ── Identity ── --> <!-- ── Identity ── -->
<div class="tx-detail-group mb-1"> <div class="bg-well p-3 mx-1 mb-3">
<div class="mb-3"> <h3 class="font-bold mb-1">Identity</h3>
<div
id="tx-detail-blockie"
class="flex justify-center mt-1 mb-3"
></div>
<div class="mb-2">
<div class="text-xs text-muted mb-1"> <div class="text-xs text-muted mb-1">
Transaction hash Transaction hash
</div> </div>
@@ -1076,30 +1081,40 @@
class="text-xs break-all" class="text-xs break-all"
></div> ></div>
</div> </div>
<div id="tx-detail-type-section" class="mb-3 hidden"> <div id="tx-detail-type-section" class="mb-2 hidden">
<div class="text-xs text-muted mb-1">Type</div> <div class="text-xs text-muted mb-1">Type</div>
<div <div
id="tx-detail-type" id="tx-detail-type"
class="text-xs font-bold" class="text-xs font-bold"
></div> ></div>
</div> </div>
<div class="mb-3"> <div class="mb-2">
<div class="text-xs text-muted mb-1">Status</div> <div class="text-xs text-muted mb-1">Status</div>
<div id="tx-detail-status" class="text-xs"></div> <div id="tx-detail-status" class="text-xs"></div>
</div> </div>
<div class="mb-1"> </div>
<!-- ── Timing ── -->
<div class="bg-well p-3 mx-1 mb-3">
<h3 class="font-bold mb-1">Timing</h3>
<div class="mb-2">
<div class="text-xs text-muted mb-1">Time</div> <div class="text-xs text-muted mb-1">Time</div>
<div id="tx-detail-time" class="text-xs"></div> <div id="tx-detail-time" class="text-xs"></div>
</div> </div>
<div id="tx-detail-block-section" class="mb-2 hidden">
<div class="text-xs text-muted mb-1">Block</div>
<div id="tx-detail-block" class="text-xs"></div>
</div>
</div> </div>
<!-- ── Value ── --> <!-- ── Value ── -->
<div class="tx-detail-group mb-1"> <div class="bg-well p-3 mx-1 mb-3">
<div class="mb-3"> <h3 class="font-bold mb-1">Value</h3>
<div class="mb-2">
<div class="text-xs text-muted mb-1">Amount</div> <div class="text-xs text-muted mb-1">Amount</div>
<div id="tx-detail-value" class="text-xs"></div> <div id="tx-detail-value" class="text-xs"></div>
</div> </div>
<div class="mb-3 hidden"> <div class="mb-2 hidden">
<div class="text-xs text-muted mb-1"> <div class="text-xs text-muted mb-1">
Native quantity Native quantity
</div> </div>
@@ -1107,7 +1122,7 @@
</div> </div>
<div <div
id="tx-detail-token-contract-section" id="tx-detail-token-contract-section"
class="mb-1 hidden" class="mb-2 hidden"
> >
<div class="text-xs text-muted mb-1"> <div class="text-xs text-muted mb-1">
Token contract Token contract
@@ -1117,30 +1132,24 @@
class="text-xs break-all" class="text-xs break-all"
></div> ></div>
</div> </div>
</div> <div class="mb-2">
<!-- ── Parties ── -->
<div class="tx-detail-group mb-1">
<div class="mb-3">
<div class="text-xs text-muted mb-1">From</div> <div class="text-xs text-muted mb-1">From</div>
<div <div
id="tx-detail-from" id="tx-detail-from"
class="text-xs break-all" class="text-xs break-all"
></div> ></div>
</div> </div>
<div class="mb-1"> <div class="mb-2">
<div class="text-xs text-muted mb-1">To</div> <div class="text-xs text-muted mb-1">To</div>
<div id="tx-detail-to" class="text-xs break-all"></div> <div id="tx-detail-to" class="text-xs break-all"></div>
</div> </div>
</div> </div>
<!-- ── Protocol ── --> <!-- ── Decoded details ── -->
<div id="tx-detail-calldata-section" class="mb-1 hidden"> <div id="tx-detail-calldata-section" class="hidden">
<div class="tx-detail-group mb-1"> <div class="bg-well p-3 mx-1 mb-3">
<div <h3 class="font-bold mb-1">Decoded Details</h3>
id="tx-detail-calldata-well" <div id="tx-detail-calldata-well" class="mb-2">
class="border border-border border-dashed p-2"
>
<div class="text-xs text-muted mb-1">Action</div> <div class="text-xs text-muted mb-1">Action</div>
<div <div
id="tx-detail-calldata-action" id="tx-detail-calldata-action"
@@ -1154,43 +1163,45 @@
</div> </div>
</div> </div>
<!-- ── On-chain details ── --> <!-- ── Network details ── -->
<div <div id="tx-detail-network-section" class="hidden">
id="tx-detail-onchain-group" <div class="bg-well p-3 mx-1 mb-3">
class="tx-detail-group mb-1 hidden" <h3 class="font-bold mb-1">Network Details</h3>
> <div id="tx-detail-nonce-section" class="mb-2 hidden">
<div id="tx-detail-block-section" class="mb-3 hidden"> <div class="text-xs text-muted mb-1">Nonce</div>
<div class="text-xs text-muted mb-1">Block</div> <div id="tx-detail-nonce" class="text-xs"></div>
<div id="tx-detail-block" class="text-xs"></div> </div>
</div> <div
<div id="tx-detail-nonce-section" class="mb-3 hidden"> id="tx-detail-gasprice-section"
<div class="text-xs text-muted mb-1">Nonce</div> class="mb-2 hidden"
<div id="tx-detail-nonce" class="text-xs"></div> >
</div> <div class="text-xs text-muted mb-1">Gas price</div>
<div id="tx-detail-fee-section" class="mb-3 hidden"> <div id="tx-detail-gasprice" class="text-xs"></div>
<div class="text-xs text-muted mb-1"> </div>
Transaction fee <div id="tx-detail-gasused-section" class="mb-2 hidden">
<div class="text-xs text-muted mb-1">Gas used</div>
<div id="tx-detail-gasused" class="text-xs"></div>
</div>
<div id="tx-detail-fee-section" class="mb-2 hidden">
<div class="text-xs text-muted mb-1">
Transaction fee
</div>
<div id="tx-detail-fee" class="text-xs"></div>
</div> </div>
<div id="tx-detail-fee" class="text-xs"></div>
</div>
<div id="tx-detail-gasprice-section" class="mb-3 hidden">
<div class="text-xs text-muted mb-1">Gas price</div>
<div id="tx-detail-gasprice" class="text-xs"></div>
</div>
<div id="tx-detail-gasused-section" class="mb-1 hidden">
<div class="text-xs text-muted mb-1">Gas used</div>
<div id="tx-detail-gasused" class="text-xs"></div>
</div> </div>
</div> </div>
<!-- ── Raw data ── --> <!-- ── Raw data ── -->
<div id="tx-detail-rawdata-section" class="mb-4 hidden"> <div id="tx-detail-rawdata-section" class="hidden">
<div class="tx-detail-group"> <div class="bg-well p-3 mx-1 mb-3">
<div class="text-xs text-muted mb-1">Raw data</div> <h3 class="font-bold mb-1">Raw Data</h3>
<div <div class="mb-2">
id="tx-detail-rawdata" <div class="text-xs text-muted mb-1">Raw data</div>
class="text-xs break-all font-mono border border-border border-dashed p-2" <div
></div> id="tx-detail-rawdata"
class="text-xs break-all font-mono border border-border border-dashed p-2"
></div>
</div>
</div> </div>
</div> </div>
</div> </div>

View File

@@ -44,11 +44,3 @@ body {
background-color 225ms ease-out, background-color 225ms ease-out,
color 225ms ease-out; color 225ms ease-out;
} }
/* Transaction detail view — visual grouping of related fields */
.tx-detail-group {
border-bottom: 1px solid var(--color-border-light);
padding-bottom: 0.5rem;
margin-bottom: 0.5rem;
padding-top: 0.25rem;
}

View File

@@ -130,6 +130,19 @@ function render() {
if (!tx) return; if (!tx) return;
$("tx-detail-hash").innerHTML = txHashHtml(tx.hash); $("tx-detail-hash").innerHTML = txHashHtml(tx.hash);
// Blockie identicon for the transaction hash
const blockieEl = $("tx-detail-blockie");
if (blockieEl) {
blockieEl.innerHTML = "";
const img = document.createElement("img");
img.src = makeBlockie(tx.hash);
img.width = 48;
img.height = 48;
img.style.imageRendering = "pixelated";
img.style.borderRadius = "50%";
blockieEl.appendChild(img);
}
const fromTitle = addressTitle(tx.from, state.wallets); const fromTitle = addressTitle(tx.from, state.wallets);
const toTitle = addressTitle(tx.to, state.wallets); const toTitle = addressTitle(tx.to, state.wallets);
$("tx-detail-from").innerHTML = txAddressHtml( $("tx-detail-from").innerHTML = txAddressHtml(
@@ -190,15 +203,14 @@ function render() {
const rawDataSection = $("tx-detail-rawdata-section"); const rawDataSection = $("tx-detail-rawdata-section");
if (rawDataSection) rawDataSection.classList.add("hidden"); if (rawDataSection) rawDataSection.classList.add("hidden");
// Hide on-chain detail sections (and their group wrapper) until populated // Hide on-chain detail sections until populated
const onchainGroup = $("tx-detail-onchain-group");
if (onchainGroup) onchainGroup.classList.add("hidden");
for (const id of [ for (const id of [
"tx-detail-block-section", "tx-detail-block-section",
"tx-detail-nonce-section", "tx-detail-nonce-section",
"tx-detail-fee-section", "tx-detail-fee-section",
"tx-detail-gasprice-section", "tx-detail-gasprice-section",
"tx-detail-gasused-section", "tx-detail-gasused-section",
"tx-detail-network-section",
]) { ]) {
const el = $(id); const el = $(id);
if (el) el.classList.add("hidden"); if (el) el.classList.add("hidden");
@@ -287,11 +299,10 @@ function populateOnChainDetails(txData) {
); );
} }
// Show the on-chain details group if any child section is visible // Show the network details wrapper if any child section is visible
const onchainGroup = $("tx-detail-onchain-group"); const networkWrapper = $("tx-detail-network-section");
if (onchainGroup) { if (networkWrapper) {
const hasVisible = [ const hasVisible = [
"tx-detail-block-section",
"tx-detail-nonce-section", "tx-detail-nonce-section",
"tx-detail-fee-section", "tx-detail-fee-section",
"tx-detail-gasprice-section", "tx-detail-gasprice-section",
@@ -300,9 +311,7 @@ function populateOnChainDetails(txData) {
const el = $(id); const el = $(id);
return el && !el.classList.contains("hidden"); return el && !el.classList.contains("hidden");
}); });
if (hasVisible) { if (hasVisible) networkWrapper.classList.remove("hidden");
onchainGroup.classList.remove("hidden");
}
} }
// Bind copy handlers for newly added elements // Bind copy handlers for newly added elements