feat(cards): show operation icons on hover
This commit is contained in:
@@ -1,4 +1,5 @@
|
|||||||
import {
|
import {
|
||||||
|
ActionIcon,
|
||||||
Anchor,
|
Anchor,
|
||||||
Badge,
|
Badge,
|
||||||
Button,
|
Button,
|
||||||
@@ -161,24 +162,56 @@ const CardPageView: FC<CardPageViewProps> = (props) => {
|
|||||||
</Anchor>
|
</Anchor>
|
||||||
) : null
|
) : null
|
||||||
}
|
}
|
||||||
|
actions={
|
||||||
|
<Group gap={4} wrap="nowrap">
|
||||||
|
<ActionIcon
|
||||||
|
variant="subtle"
|
||||||
|
disabled={!row.editable || Boolean(card.archivedAt)}
|
||||||
|
size="sm"
|
||||||
|
aria-label={t("bank.edit")}
|
||||||
|
title={t("bank.edit")}
|
||||||
|
onClick={() => vm.setOperation(row.item)}
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
width="18"
|
||||||
|
height="18"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
fill="none"
|
||||||
|
stroke="currentColor"
|
||||||
|
strokeWidth="1.5"
|
||||||
|
strokeLinecap="round"
|
||||||
|
strokeLinejoin="round"
|
||||||
|
aria-hidden="true"
|
||||||
|
>
|
||||||
|
<path d="m16 3 5 5-12 12-6 1 1-6L16 3Z M13 6l5 5" />
|
||||||
|
</svg>
|
||||||
|
</ActionIcon>
|
||||||
|
<ActionIcon
|
||||||
|
variant="subtle"
|
||||||
|
color="red"
|
||||||
|
disabled={!row.editable || Boolean(card.archivedAt)}
|
||||||
|
size="sm"
|
||||||
|
aria-label={t("bank.delete")}
|
||||||
|
title={t("bank.delete")}
|
||||||
|
onClick={() => vm.setDeleting(row.item)}
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
width="18"
|
||||||
|
height="18"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
fill="none"
|
||||||
|
stroke="currentColor"
|
||||||
|
strokeWidth="1.5"
|
||||||
|
strokeLinecap="round"
|
||||||
|
strokeLinejoin="round"
|
||||||
|
aria-hidden="true"
|
||||||
|
>
|
||||||
|
<path d="M3 6h18 M9 6V3h6v3 M5 6l1 15h12l1-15 M10 10v7 M14 10v7" />
|
||||||
|
</svg>
|
||||||
|
</ActionIcon>
|
||||||
|
</Group>
|
||||||
|
}
|
||||||
/>
|
/>
|
||||||
<Group mt="xs">
|
|
||||||
<Button
|
|
||||||
variant="subtle"
|
|
||||||
disabled={!row.editable || Boolean(card.archivedAt)}
|
|
||||||
onClick={() => vm.setOperation(row.item)}
|
|
||||||
>
|
|
||||||
{t("bank.edit")}
|
|
||||||
</Button>
|
|
||||||
<Button
|
|
||||||
variant="subtle"
|
|
||||||
color="red"
|
|
||||||
disabled={!row.editable || Boolean(card.archivedAt)}
|
|
||||||
onClick={() => vm.setDeleting(row.item)}
|
|
||||||
>
|
|
||||||
{t("bank.delete")}
|
|
||||||
</Button>
|
|
||||||
</Group>
|
|
||||||
</section>
|
</section>
|
||||||
))
|
))
|
||||||
) : (
|
) : (
|
||||||
|
|||||||
@@ -40,3 +40,56 @@
|
|||||||
text-align: left;
|
text-align: left;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.valueFooter {
|
||||||
|
display: grid;
|
||||||
|
align-items: center;
|
||||||
|
justify-items: end;
|
||||||
|
min-height: 28px;
|
||||||
|
}
|
||||||
|
.valueLabel,
|
||||||
|
.actions {
|
||||||
|
grid-area: 1 / 1;
|
||||||
|
transition: opacity 180ms ease;
|
||||||
|
}
|
||||||
|
.valueLabel {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
.actions {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
@media (hover: hover) and (pointer: fine) {
|
||||||
|
.valueLabel {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
.actions {
|
||||||
|
opacity: 0;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
.row:hover .actions,
|
||||||
|
.row:focus-within .actions {
|
||||||
|
opacity: 1;
|
||||||
|
pointer-events: auto;
|
||||||
|
}
|
||||||
|
.row:hover .valueLabel,
|
||||||
|
.row:focus-within .valueLabel {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@media (max-width: 36em) {
|
||||||
|
.valueFooter {
|
||||||
|
justify-items: start;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@media (pointer: coarse) {
|
||||||
|
.actions button {
|
||||||
|
min-width: 36px;
|
||||||
|
min-height: 36px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@media (prefers-reduced-motion: reduce) {
|
||||||
|
.valueLabel,
|
||||||
|
.actions {
|
||||||
|
transition: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ type EntryCardProps = {
|
|||||||
title: string;
|
title: string;
|
||||||
metadata: string;
|
metadata: string;
|
||||||
details?: ReactNode;
|
details?: ReactNode;
|
||||||
|
actions?: ReactNode;
|
||||||
initial: string;
|
initial: string;
|
||||||
imageSrc?: string | null;
|
imageSrc?: string | null;
|
||||||
value: string;
|
value: string;
|
||||||
@@ -40,9 +41,17 @@ const EntryCard: FC<EntryCardProps> = (props) => {
|
|||||||
<Text className={classes[props.tone]} fw={700}>
|
<Text className={classes[props.tone]} fw={700}>
|
||||||
{props.value}
|
{props.value}
|
||||||
</Text>
|
</Text>
|
||||||
<Text className={classes[props.tone]} size="sm">
|
<div className={props.actions ? classes.valueFooter : undefined}>
|
||||||
{props.valueLabel}
|
<Text
|
||||||
</Text>
|
className={`${classes[props.tone]} ${props.actions ? classes.valueLabel : ""}`}
|
||||||
|
size="sm"
|
||||||
|
>
|
||||||
|
{props.valueLabel}
|
||||||
|
</Text>
|
||||||
|
{props.actions && (
|
||||||
|
<div className={classes.actions}>{props.actions}</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
</Stack>
|
</Stack>
|
||||||
</Paper>
|
</Paper>
|
||||||
);
|
);
|
||||||
|
|||||||
Reference in New Issue
Block a user