Skip to content

Commit

Permalink
repaced bigaddress component with multilinecard
Browse files Browse the repository at this point in the history
  • Loading branch information
jubalm committed Nov 5, 2024
1 parent 44becb1 commit 5eff891
Show file tree
Hide file tree
Showing 5 changed files with 245 additions and 61 deletions.
124 changes: 124 additions & 0 deletions app/css/interceptor.css
Original file line number Diff line number Diff line change
Expand Up @@ -1736,6 +1736,130 @@ header:has(form[role='search']) h1 {
}
}

.multiline-card {
--bg-color: #484848;
--button-color: #77738ccc;
--image-size: 2.25rem;
--min-text-width: 3ch;
--pad-x: 0;
--pad-y: 0;
--gap-x: 0.5rem;
---space: 0.425rem;
--edge-roundness: 3px;
--status-backdrop-color: #303030ed;
--status-success-color: #4fb64f;

font: inherit;
display: inline-grid;
grid-template-columns: [left] minmax(0, min-content) [data] minmax(0, max-content) [right];
grid-template-rows: [top] min-content [sub] min-content [bottom];
column-gap: var(--gap-x);
row-gap: 2px;
padding-block: var(--pad-y);
padding-inline: var(--pad-x);
background-color: var(--bg-color);
border-radius: var(--edge-roundness);
min-width: calc(var(--min-text-width) + var(--image-size) + (var(-pad-x) * 2) + var(--gap-x));

data {
line-height: 1em;
color: var(--text-color);
text-align: left;
min-width: var(--min-text-width);
}

button {
font: inherit;
background: var(--bg-color);
border: 0 none;
padding: 0;
cursor: pointer;

&:hover, &:focus { background: var(--bg-color) }
}

> [role=img] {
grid-area: top / left / bottom / data;
align-self: center;
font-size: var(--image-size);
line-height: 1;

& svg, img {
display: inline-block;
vertical-align: -0.15em;
}
}

> :has(data ~ button) {
display: inline-grid;
align-items: baseline;
grid-template-columns: [left] minmax(0, min-content) [right];
grid-template-rows: [top] min-content [bottom];

/* title */
&:nth-of-type(2) {
grid-area: top / data / sub / right;
data {
font-weight: 600;
}
}

/* subtitle */
&:nth-of-type(3) {
grid-area: sub / data / bottom / right;
data {
font-size: 0.825em;
color: var(--disabled-text-color);
}
}

> data { grid-area: top / left / bottom / right }

> button {
grid-area: top / left / bottom / right;
display: inline-grid;
align-items: baseline;
grid-template-columns: minmax(0, 1fr) min-content;
background-color: var(--bg-color);
opacity: 0;
outline: none;

&:is(.multiline-card:hover *, .multiline-card:focus-within *) { opacity: 1 }

&:hover, &:focus {
> span {
background: white;
color: black;

span { display: inline }
svg { display: none }
}
}

> span {
background: var(--button-color);
color: white;
font-size: 0.8em;
font-weight: 600;
padding-inline: 0.25em;
border-radius: 2px;
text-transform: uppercase;
line-height: 1.4;

span {
display: none;
font-size: 0.8em;
}

svg {
display: inline-block;
vertical-align: -0.125em;
}
}
}
}
}

.tooltip {
background: #222222;
color: #ffffff;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -351,6 +351,7 @@ function SummarizeAddress(param: SummarizeAddressParams) {
<BigAddress
addressBookEntry = { param.balanceSummary.summaryFor }
renameAddressCallBack = { param.renameAddressCallBack }
style = { { '--bg-color': '#6d6d6d' } }
/> :
<SmallAddress
textColor = { positiveNegativeColors.textColor }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ type TransferAddressParams = BeforeAfterAddress & {

export function AddressBeforeAfter({ address, beforeAndAfter, renameAddressCallBack, tokenOrEtherDefinition }: TransferAddressParams) {
return <>
<BigAddress addressBookEntry = { address } renameAddressCallBack = { renameAddressCallBack } />
<BigAddress addressBookEntry = { address } renameAddressCallBack = { renameAddressCallBack } style = { { '--bg-color' : '#757575' } } />
{ beforeAndAfter === undefined
? <></>
: <span style = 'grid-template-columns: auto auto; display: grid; justify-content: space-between; margin-top: 10px'>
Expand Down
93 changes: 93 additions & 0 deletions app/ts/components/subcomponents/MultilineCard.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
import { JSX } from 'preact/jsx-runtime'
import { useSignal } from '@preact/signals'
import { Tooltip, TooltipConfig } from './Tooltip.js'
import { clipboardCopy } from './clipboardcopy.js'
import { CopyIcon } from './icons.js'

export type CardIcon = {
component: () => JSX.Element
onClick?: () => void
tooltipText?: string
}

export type MultilineCardProps = {
icon: CardIcon
label: ActionableTextProps
note: ActionableTextProps
style?: JSX.CSSProperties
}

export const MultilineCard = ({ icon, label, note, style }: MultilineCardProps) => {
const tooltipConfig = useSignal<TooltipConfig | undefined>(undefined)

const copyTextToClipboard = async (event: JSX.TargetedMouseEvent<HTMLButtonElement>) => {
event.currentTarget.blur()
await clipboardCopy(event.currentTarget.value)
tooltipConfig.value = { message: 'Copied!', x: event.clientX, y: event.clientY }
}

const CardIcon = icon.component
const defaultAction:TextAction = { label: 'Copy', icon: () => <CopyIcon />, onClick: copyTextToClipboard }

return (
<>
<figure class = 'multiline-card' role = 'figure' style = { style }>
<span role = 'img'>
<button type = 'button' onClick = { icon.onClick || copyTextToClipboard } tabIndex = { -1 } title = { icon.tooltipText || label.displayText }><CardIcon /></button>
</span>
<ActionableText { ...label } action = { !label.action ? defaultAction : label.action } />
<ActionableText { ...note } action = { !note.action ? defaultAction : note.action } />
</figure>
<Tooltip config = { tooltipConfig } />
</>
)
}

export type TextAction = {
label: string
icon: () => JSX.Element
onClick?: JSX.MouseEventHandler<HTMLButtonElement>
}

export type ActionableTextProps = {
displayText: string
value?: string
action: TextAction | 'noaction' | undefined
}

type TextNodeProps = {
displayText: string,
value: string
}

const TextNode = ({ displayText, value }: TextNodeProps) => <data class = 'truncate text-legible' value = { value || displayText }>{ displayText }</data>

const ActionableText = ({ displayText, value, action }: ActionableTextProps) => {
const DisplayText = () => <TextNode displayText = { displayText } value = { value || displayText } />
return (
<span>
<DisplayText />
{ action !== undefined && action !== 'noaction' ? <TextAction { ...action } textNode = { DisplayText } /> : <></> }
</span>
)
}

type TextActionProps = {
icon: () => JSX.Element
textNode: () => JSX.Element
label: string
onClick?: JSX.MouseEventHandler<HTMLButtonElement>
}

const TextAction = ({ textNode: DisplayText, icon: ActionIcon, label, onClick }: TextActionProps) => {
return (
<button type = 'button' onClick = { onClick } value = { '' } tabIndex = { 1 }>
<DisplayText />
<span>
<ActionIcon />
<span>{ label }</span>
</span>
</button>
)
}

86 changes: 26 additions & 60 deletions app/ts/components/subcomponents/address.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,10 @@ import { checksummedAddress } from '../../utils/bigint.js'
import { RenameAddressCallBack } from '../../types/user-interface-types.js'
import { AddressBookEntries, AddressBookEntry } from '../../types/addressBookTypes.js'
import { Website } from '../../types/websiteAccessTypes.js'
import { CopyToClipboard } from './CopyToClipboard.js'
import { Blockie } from './SVGBlockie.js'
import { InlineCard } from './InlineCard.js'
import { EditIcon } from './icons.js'
import { ActionableTextProps, MultilineCard, TextAction } from './MultilineCard.js'

export function getActiveAddressEntry(addressToFind: bigint, activeAddresses: AddressBookEntries): AddressBookEntry {
for (const info of activeAddresses) {
Expand Down Expand Up @@ -53,73 +54,38 @@ type BigAddressParams = {
readonly noCopying?: boolean
readonly noEditAddress?: boolean
readonly renameAddressCallBack: RenameAddressCallBack
readonly style?: JSX.CSSProperties
}

export function BigAddress(params: BigAddressParams) {
const addrString = params.addressBookEntry && checksummedAddress(params.addressBookEntry.address)
const title = params.addressBookEntry === undefined ? 'No address found' : params.addressBookEntry.name
const subTitle = title !== addrString ? addrString : ''

return <div class = 'media'>
<div class = 'media-left'>
{ !params.noCopying && addrString !== undefined ?
<CopyToClipboard content = { addrString } copyMessage = 'Address copied!'>
<AddressIcon
address = { params.addressBookEntry?.address }
logoUri = { params.addressBookEntry !== undefined && 'logoUri' in params.addressBookEntry ? params.addressBookEntry.logoUri : undefined }
isBig = { true }
backgroundColor = { 'var(--text-color)' }
/>
</CopyToClipboard>
:
<AddressIcon
address = { params.addressBookEntry?.address }
logoUri = { params.addressBookEntry !== undefined && 'logoUri' in params.addressBookEntry ? params.addressBookEntry.logoUri : undefined }
isBig = { true }
backgroundColor = { 'var(--text-color)' }
/>
}
</div>
const subTitle = addrString && title !== addrString ? addrString : '(Not in addressbook)'

<div class = { `media-content ${ params.noEditAddress ? 'noselect nopointer' : '' }` } style = 'overflow-y: hidden; overflow-x: clip; display: block;'>
<span className = 'big-address-container' data-value = { title }>
<span class = 'address-text-holder'>
{ !params.noCopying && addrString !== undefined ?
<CopyToClipboard content = { addrString } copyMessage = 'Address copied!' style = { { 'text-overflow': 'ellipsis', overflow: 'hidden' } }>
<AddressTitle content = { title } useLegibleFont = { title === addrString } />
</CopyToClipboard>
: <AddressTitle content = { title } useLegibleFont = { title === addrString } />
}
<button
type = 'button'
className = 'button is-primary is-small rename-address-button'
onClick = { () => params.addressBookEntry && params.renameAddressCallBack(params.addressBookEntry) }
disabled = { params.addressBookEntry === undefined }
>
<span class = 'icon'>
<img src = '../img/rename.svg'/>
</span>
</button>
</span>
</span>
{ !params.noCopying && addrString !== undefined && subTitle !== undefined ?
<CopyToClipboard content = { addrString } copyMessage = 'Address copied!'>
<AddressSubTitle content = { subTitle } />
</CopyToClipboard>
: <AddressSubTitle content = { subTitle } />

}
</div>
</div>
}
const renameAddressAction:TextAction = {
label: 'Edit',
icon: () => <EditIcon />,
onClick: () => params.addressBookEntry && params.renameAddressCallBack(params.addressBookEntry)
}

const AddressTitle = ({ content, useLegibleFont }: { content: string, useLegibleFont?: boolean }) => {
return <p class = { `title is-5 is-spaced address-text noselect nopointer${ useLegibleFont ? ' text-legible' : '' }` }>{ content }</p>
}
const labelConfig:ActionableTextProps = {
displayText: title,
action: !params.noEditAddress && title !== addrString ? renameAddressAction : undefined
}

const noteConfig:ActionableTextProps = {
displayText: subTitle,
action: addrString && subTitle !== addrString ? renameAddressAction : undefined
}

const AddressSubTitle = ({ content }: { content?: string }) => {
if (!content) return <></>
return <p class = 'subtitle is-7 noselect nopointer text-legible' style = { { textOverflow: 'ellipsis', whiteSpace: 'nowrap' } }>{ content }</p>
return (
<MultilineCard
label = { labelConfig }
note = { noteConfig }
icon = { { component: () => params.addressBookEntry ? <Blockie address = { params.addressBookEntry.address } /> : <></> } }
style = { params.style }
/>
)
}

type ActiveAddressParams = {
Expand Down

0 comments on commit 5eff891

Please sign in to comment.