Skip to content

[Insight] Refactored Tx Data with Boxes and Underlines #3929

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 20 commits into from
Jul 1, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
206ce69
created outline box with label within lines for transactions details
MicahMaphet Jun 3, 2025
71ef164
made box aligns around inner text
MicahMaphet Jun 3, 2025
dfcce6f
put components inside of border labeled boxes
MicahMaphet Jun 3, 2025
093f428
redid border box with field set
MicahMaphet Jun 8, 2025
019a4f1
box taked minimum room
MicahMaphet Jun 8, 2025
a47f52f
made transaction input and output columns use all space
MicahMaphet Jun 9, 2025
68ae9cf
refactored element structure for tx details, improving spacing, paddi…
MicahMaphet Jun 9, 2025
5e0c47e
added text wrapping for tx data elements; put Tx Index and Confirmati…
MicahMaphet Jun 10, 2025
9bf501c
fixed hover for address and Unparsed address+OP_RETURN spacing
MicahMaphet Jun 10, 2025
8085f6a
Merge branch 'spent-arrow' into border-box-label
MicahMaphet Jun 10, 2025
4f6f9dd
added circle placeholder to unspendable txs
MicahMaphet Jun 10, 2025
905dbf0
added back fit content to border box
MicahMaphet Jun 10, 2025
fbe97eb
removed quotes around 0
MicahMaphet Jun 10, 2025
c43faff
added automatic margin removal to BorderBoxLabel children for more co…
MicahMaphet Jun 10, 2025
52fd794
Tx id link expands down when details are expanded
MicahMaphet Jun 16, 2025
d0f4cd4
Merge branch 'master' into border-box-label
MicahMaphet Jun 23, 2025
8c108eb
moved border box to new file and renamed it data box
MicahMaphet Jun 23, 2025
8e9e96d
changed blue arrow color and show pointer only when the tx is spent
MicahMaphet Jun 30, 2025
11ccd21
put data box label around OP RETURN
MicahMaphet Jun 30, 2025
f535c71
fixed spacing of side-by-side detail elements
MicahMaphet Jun 30, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion packages/insight/src/assets/images/arrow-blue.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions packages/insight/src/assets/images/circle.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
9 changes: 6 additions & 3 deletions packages/insight/src/assets/styles/transaction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -158,16 +158,19 @@ export const TransactionChip = styled.div<TransactionChipProps>`

interface ArrowDivProps {
margin: string;
pointer?: boolean;
}

export const ArrowDiv = styled.div<ArrowDivProps>`
width: 25px;
position: relative;
margin: ${({margin}) => margin};

img {
cursor: pointer;
}
${({pointer}) => pointer &&
`img {
cursor: pointer;
}
`}
`;

export const ScriptText = styled.p`
Expand Down
2 changes: 1 addition & 1 deletion packages/insight/src/components/block-details.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@ const BlockDetails: FC<BlockDetailsProps> = ({currency, network, block}) => {
onClick={() =>
summary.previousBlockHash ? gotoBlock(summary.previousBlockHash) : null
}>
{(summary.height > 0) ? summary.height - 1 : "None"}
{(summary.height > 0) ? summary.height - 1 : 'None'}
</span>
</TileLink>
</Tile>
Expand Down
30 changes: 30 additions & 0 deletions packages/insight/src/components/data-box.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import {Children, FC, ReactNode} from 'react';
import {useTheme} from 'styled-components';

const DataBox: FC<{children: ReactNode, label: string, style?: object}> = ({children, label, style}) => {
const theme = useTheme();
const modifiedChildren = typeof children === 'object'
? Children.map(children as JSX.Element, (child: JSX.Element) => {
return <span {...child.props} style={{margin: 0}}></span>;
})
: children;

return (
<fieldset style={{
border: `2.5px solid ${theme.dark ? '#5f5f5f' : '#ccc'}`,
borderRadius: '5px',
padding: '0.1rem 0.4rem',
wordBreak: 'break-all',
whiteSpace: 'normal',
width: 'fit-content',
height: 'fit-content',
margin: '0.7rem 0.2rem',
...style
}}>
<legend style={{fontWeight: 'bold', color: 'gray', margin: '-0.2rem 0.1rem'}}>{label}</legend>
{modifiedChildren}
</fieldset>
);
}

export default DataBox;
202 changes: 115 additions & 87 deletions packages/insight/src/components/transaction-details.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,11 @@ import {
import {Tile, TileDescription} from '../assets/styles/tile';
import ArrowSvg from '../assets/images/arrow.svg';
import BlueArrowSvg from '../assets/images/arrow-blue.svg';
import CircleSvg from '../assets/images/circle.svg';
import {useNavigate, createSearchParams} from 'react-router-dom';
import styled from 'styled-components';
import {Slate, SlateDark} from '../assets/styles/colors';
import DataBox from './data-box';

const TextElipsis = styled(ScriptText)`
overflow: hidden;
Expand All @@ -46,6 +48,17 @@ const SelectedPill = styled.div`
font-size: 16px;
`;

const TxAddressLink = styled.span`
overflow: hidden;
text-overflow: ellipsis;
text-align: left;
width: 100%;
margin-right: 7px;
&:hover {
cursor: pointer;
}
`

interface TransactionDetailsProps {
transaction: Transaction;
currency: string;
Expand Down Expand Up @@ -157,9 +170,12 @@ const TransactionDetails: FC<TransactionDetailsProps> = ({
{vi.items.map((item: any, itemIndex: number) => (
<div key={item.mintTxid + itemIndex}>
{isInputSelected(item) ? <SelectedPill>Selected</SelectedPill> : null}

<Tile invertedBorderColor={arr.length > 1 && arr.length !== i + 1}>
<ArrowDiv margin='auto .5rem auto 0'>
<div style={{
display: 'flex',
marginTop: '1rem',
...(showDetails && {borderBottom: '2px solid', paddingBottom: '0.25rem'})
}}>
<ArrowDiv margin='auto .5rem auto 0' pointer>
<img
src={BlueArrowSvg}
width={17}
Expand All @@ -168,53 +184,60 @@ const TransactionDetails: FC<TransactionDetailsProps> = ({
onClick={() => goToTx(item.mintTxid, undefined, item.mintIndex)}
/>
</ArrowDiv>

<TileDescription padding='0 1rem 0 0' value>
{getAddress(vi) !== 'Unparsed address' ? (
<SpanLink onClick={() => goToAddress(getAddress(vi))}>
{getAddress(vi)}
</SpanLink>
) : (
<span>Unparsed address</span>
)}

{showDetails && (
<>
<TextElipsis>
<b>Tx ID </b>
<SpanLink
onClick={() =>
goToTx(item.mintTxid, undefined, item.mintIndex)
}>
{item.mintTxid}
</SpanLink>
</TextElipsis>

<TextElipsis>
<b>Tx Index</b> {item.mintIndex}
</TextElipsis>

{item.uiConfirmations && confirmations > 0 ? (
<ScriptText>
<b>Confirmations</b> {item.uiConfirmations + confirmations}
</ScriptText>
) : null}
{getAddress(vi) !== 'Unparsed address' ? (
<TxAddressLink onClick={() => goToAddress(getAddress(vi))} style={{wordBreak: showDetails ? 'break-all' : 'unset'}}>
{getAddress(vi)}
</TxAddressLink>
) : (
<span style={{textAlign: 'left', width: '100%'}}>
Unparsed address
</span>
)}
<div style={{minInlineSize: 'fit-content'}}>
{getConvertedValue(item.value, currency)} {currency}
</div>
</div>

<Tile invertedBorderColor={arr.length > 1 && arr.length !== i + 1} padding={showDetails ? undefined : '0.4rem'}>
{showDetails &&
<>

<TileDescription padding='0 1rem 0 0' value>
<DataBox label='Tx ID'>
<TextElipsis>
<SpanLink
onClick={() =>
goToTx(item.mintTxid, undefined, item.mintIndex)
}>
{item.mintTxid}
</SpanLink>
</TextElipsis>
</DataBox>

<div style={{display: 'flex', gap: '0.7rem', margin: '0 0.2rem'}}>
<DataBox label='Tx Index' style={{margin: 0}}>
<TextElipsis>
{item.mintIndex}
</TextElipsis>
</DataBox>
{item.uiConfirmations && confirmations > 0 ? (
<DataBox label='Confirmations' style={{margin: 0}}>
<ScriptText>
{item.uiConfirmations + confirmations}
</ScriptText>
</DataBox>
) : null}
</div>

{item.script && (
<>
<b>Script Hex</b>
<ScriptText>{item.script}</ScriptText>
<b>Script ASM</b>
<ScriptText>{new lib.Script(item.script).toASM()}</ScriptText>
<DataBox label='Script Hex'>{item.script}</DataBox>
<DataBox label='Script ASM'>{new lib.Script(item.script).toASM()}</DataBox>
</>
)}
</>
)}
</TileDescription>

<TileDescription value textAlign='right'>
{getConvertedValue(item.value, currency)} {currency}
</TileDescription>
</TileDescription>
</>
}
</Tile>
</div>
))}
Expand All @@ -234,56 +257,61 @@ const TransactionDetails: FC<TransactionDetailsProps> = ({
return (
<div key={i}>
{isOutputSelected(i) ? <SelectedPill>Selected</SelectedPill> : null}
<Tile invertedBorderColor={outputsLength > 1 && outputsLength !== i + 1}>
<TileDescription padding='0 1rem 0 0' value>
{getAddress(vo) !== 'Unparsed address' ? (
<SpanLink onClick={() => goToAddress(getAddress(vo))}>
{getAddress(vo)}
</SpanLink>
) : (
<span>{isOpReturn(vo) ? 'OP_RETURN' : 'Unparsed address'}</span>
)}

{showDetails && (
<>
{vo.spentTxid && (
<TextElipsis>
<b>Spent By </b>
<SpanLink onClick={() => goToTx(vo.spentTxid, transaction.txid, i)}>
{vo.spentTxid}
</SpanLink>
</TextElipsis>
)}
{isOpReturn(vo) && <ScriptText>{getOpReturnText(vo)}</ScriptText>}
{vo.script && (
<>
<b>Script Hex</b>
<ScriptText>{new lib.Script(vo.script).toHex()}</ScriptText>
<b>Script ASM</b>
<ScriptText>{new lib.Script(vo.script).toASM()}</ScriptText>
</>
)}
</>
)}
</TileDescription>

<TileDescription value textAlign='right'>
<div style={{
display: 'flex',
marginTop: '1rem',
...(showDetails && {borderBottom: '2px solid', paddingBottom: '0.25rem'})
}}>
{getAddress(vo) !== 'Unparsed address' ? (
<TxAddressLink onClick={() => goToAddress(getAddress(vo))} style={{wordBreak: showDetails ? 'break-all' : 'unset'}}>
{getAddress(vo)}
</TxAddressLink>
) : (
<span style={{textAlign: 'left', width: '100%'}}>
{isOpReturn(vo) ? 'OP_RETURN' : 'Unparsed address'}
</span>
)}
<div style={{minInlineSize: 'fit-content', display: 'flex'}}>
{getConvertedValue(vo.value, currency)} {currency}{' '}
</TileDescription>
<ArrowDiv margin='auto 0 auto .5rem'>
<ArrowDiv margin='auto 0 auto .5rem' pointer={vo.spentTxid}>
<img
src={vo.spentTxid ? BlueArrowSvg : ArrowSvg}
src={vo.spentTxid ? BlueArrowSvg : (isOpReturn(vo) ? CircleSvg : ArrowSvg)}
width={17}
height={17}
alt='Spent'
title={vo.spentTxid ? 'Spent' : 'Unspent'}
style={{
visibility: (isOpReturn(vo) ? 'hidden' : 'visible'),
margin: '0px 5px'
}}
title={vo.spentTxid ? 'Spent' : (isOpReturn(vo) ? 'Unspendable' : 'Unspent')}
style={{margin: `0px ${isOpReturn(vo) ? '4px' : '5px'}`}}
onClick={() => vo.spentTxid && goToTx(vo.spentTxid, transaction.txid, i)}
/>
</ArrowDiv>
</div>
</div>
<Tile invertedBorderColor={outputsLength > 1 && outputsLength !== i + 1} padding={showDetails ? undefined : '0.4rem'}>
{showDetails &&
<>
<TileDescription padding='0 1rem 0 0' value>
{vo.spentTxid && (
<DataBox label='Spent By'>
<TextElipsis>
<SpanLink onClick={() => goToTx(vo.spentTxid, transaction.txid, i)}>
{vo.spentTxid}
</SpanLink>
</TextElipsis>
</DataBox>
)}
{isOpReturn(vo) &&
<DataBox label="Text">
<ScriptText>{getOpReturnText(vo)}</ScriptText>
</DataBox>}
{vo.script && (
<>
<DataBox label='Script Hex'>{new lib.Script(vo.script).toHex()}</DataBox>
<DataBox label='Script ASM'>{new lib.Script(vo.script).toASM()}</DataBox>
</>
)}
</TileDescription>
</>
}
</Tile>
</div>
);
Expand Down