diff --git a/app/css/interceptor.css b/app/css/interceptor.css
index f2df2378..88289d4f 100644
--- a/app/css/interceptor.css
+++ b/app/css/interceptor.css
@@ -1721,13 +1721,14 @@ header:has(form[role='search']) h1 {
}
.multiline-card {
- --bg-color: #484848;
+ --bg-color: transparent;
--button-color: #77738ccc;
--image-size: 2.25rem;
- --min-text-width: 3ch;
+ --min-text-width: 0;
--pad-x: 0;
--pad-y: 0;
--gap-x: 0.5rem;
+ --gap-y: 0.0625rem;
--edge-roundness: 3px;
font: inherit;
@@ -1735,12 +1736,12 @@ header:has(form[role='search']) h1 {
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;
+ row-gap: var(--gap-y);
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));
+ min-width: calc(var(--min-text-width) + var(--image-size) + (var(--pad-x) * 2) + var(--gap-x));
data {
line-height: 1em;
@@ -1754,8 +1755,8 @@ header:has(form[role='search']) h1 {
background: var(--bg-color);
border: 0 none;
padding: 0;
- cursor: pointer;
+ &:not(:disabled) { cursor: pointer }
&:hover, &:focus { background: var(--bg-color) }
}
@@ -1794,7 +1795,13 @@ header:has(form[role='search']) h1 {
}
}
- > data { grid-area: top / left / bottom / right }
+ > data {
+ grid-area: top / left / bottom / right;
+
+ &:not(:has(+:disabled)) {
+ .multiline-card:hover &, .multiline-card:focus-within & { visibility: hidden }
+ }
+ }
> button {
grid-area: top / left / bottom / right;
@@ -1802,10 +1809,13 @@ header:has(form[role='search']) h1 {
align-items: baseline;
grid-template-columns: minmax(0, 1fr) min-content;
background-color: var(--bg-color);
- opacity: 0;
outline: none;
+ position: relative;
+ visibility: hidden;
- &:is(.multiline-card:hover *, .multiline-card:focus-within *) { opacity: 1 }
+ &:not(:disabled) {
+ .multiline-card:hover &, .multiline-card:focus-within & { visibility: visible }
+ }
&:hover, &:focus {
> span {
diff --git a/app/ts/components/subcomponents/MultilineCard.tsx b/app/ts/components/subcomponents/MultilineCard.tsx
index ca78b88f..2eff04ab 100644
--- a/app/ts/components/subcomponents/MultilineCard.tsx
+++ b/app/ts/components/subcomponents/MultilineCard.tsx
@@ -4,88 +4,135 @@ 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
+ icon: ActionableIconProps
label: ActionableTextProps
note: ActionableTextProps
style?: JSX.CSSProperties
}
export const MultilineCard = ({ icon, label, note, style }: MultilineCardProps) => {
+ return (
+
+ )
+}
+
+export type ActionableIconProps = {
+ onClick: 'clipboard-copy'
+ icon: () => JSX.Element
+ copyValue?: string
+ copySuccessMessage: string
+ hintText?: string
+} | {
+ onClick: JSX.MouseEventHandler
+ icon: () => JSX.Element
+ hintText?: string
+} | {
+ onClick: undefined
+ icon: () => JSX.Element
+}
+
+const ActionableIcon = (props: ActionableIconProps) => {
const tooltipConfig = useSignal(undefined)
const copyTextToClipboard = async (event: JSX.TargetedMouseEvent) => {
event.currentTarget.blur()
await clipboardCopy(event.currentTarget.value)
- tooltipConfig.value = { message: 'Copied!', x: event.clientX, y: event.clientY }
+ const copySuccessMessage = props.onClick === 'clipboard-copy' && props.copySuccessMessage ? props.copySuccessMessage : 'Copied!'
+ tooltipConfig.value = { message: copySuccessMessage, x: event.clientX, y: event.clientY }
}
- const CardIcon = icon.component
- const defaultAction:TextAction = { label: 'Copy', icon: () => , onClick: copyTextToClipboard }
+ const CardIcon = props.icon
+ const handleClick = props.onClick ? props.onClick === 'clipboard-copy' ? copyTextToClipboard : props.onClick : undefined
+ const copyValue = props.onClick === 'clipboard-copy' ? props.copyValue : undefined
+ const hintText = props.onClick ? props.hintText : undefined
return (
- <>
-
-
- >
+
+
+
)
}
-export type TextAction = {
- label: string
- icon: () => JSX.Element
- onClick?: JSX.MouseEventHandler
+type TextNodeProps = {
+ displayText: string,
+ value: string
}
+const TextNode = ({ displayText, value }: TextNodeProps) => { displayText }
+
export type ActionableTextProps = {
+ onClick: 'clipboard-copy'
+ displayText: string
+ copyValue?: string
+ copySuccessMessage?: string
+} | {
+ onClick: JSX.MouseEventHandler
+ displayText: string
+ buttonLabel: string
+ buttonIcon: () => JSX.Element
+} | {
+ onClick?: undefined
displayText: string
- value?: string
- action: TextAction | 'noaction' | undefined
}
-type TextNodeProps = {
- displayText: string,
- value: string
-}
+const ActionableText = (props: ActionableTextProps) => {
+ const tooltipConfig = useSignal(undefined)
-const TextNode = ({ displayText, value }: TextNodeProps) => { displayText }
+ const copyTextToClipboard = async (event: JSX.TargetedMouseEvent) => {
+ event.currentTarget.blur()
+ await clipboardCopy(event.currentTarget.value)
+ tooltipConfig.value = {
+ message: props.onClick === 'clipboard-copy' && props.copySuccessMessage ? props.copySuccessMessage : 'Copied!',
+ x: event.clientX,
+ y: event.clientY
+ }
+ }
+
+ const copyValue = props.onClick === 'clipboard-copy' && props.copyValue ? props.copyValue : props.displayText
+ const actionIcon = props.onClick ? props.onClick === 'clipboard-copy' ? () => : props.buttonIcon : () => <>>
+ const actionHandler = props.onClick ? props.onClick === 'clipboard-copy' ? copyTextToClipboard : props.onClick : undefined
+ const actionButtonLabel = props.onClick ? props.onClick === 'clipboard-copy' ? 'Copy' : props.buttonLabel : ''
+
+ const DisplayText = () =>
-const ActionableText = ({ displayText, value, action }: ActionableTextProps) => {
- const DisplayText = () =>
return (
- { action !== undefined && action !== 'noaction' ? : <>> }
+
+
)
}
type TextActionProps = {
- icon: () => JSX.Element
+ onClick: undefined
textNode: () => JSX.Element
- label: string
- onClick?: JSX.MouseEventHandler
+} | {
+ onClick: JSX.MouseEventHandler
+ textNode: () => JSX.Element
+ buttonLabel: string
+ buttonIcon: () => JSX.Element
+ copyValue?: string
}
-const TextAction = ({ textNode: DisplayText, icon: ActionIcon, label, onClick }: TextActionProps) => {
+const TextAction = (props: TextActionProps) => {
+ const DisplayText = props.textNode
+ const ActionIcon = props.onClick ? props.buttonIcon : () => <>>
+
return (
-