mirror of
https://github.com/docmost/docmost.git
synced 2026-05-07 06:23:06 +08:00
fix(base): pin selection bar to viewport with Confluence-style dark pill
This commit is contained in:
@@ -1,5 +1,5 @@
|
|||||||
import { memo } from "react";
|
import { memo } from "react";
|
||||||
import { ActionIcon, Button, Transition } from "@mantine/core";
|
import { Transition } from "@mantine/core";
|
||||||
import { IconTrash, IconX } from "@tabler/icons-react";
|
import { IconTrash, IconX } from "@tabler/icons-react";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { useRowSelection } from "@/features/base/hooks/use-row-selection";
|
import { useRowSelection } from "@/features/base/hooks/use-row-selection";
|
||||||
@@ -23,28 +23,27 @@ export const SelectionActionBar = memo(function SelectionActionBar({
|
|||||||
<Transition mounted={isOpen} transition="slide-up" duration={150}>
|
<Transition mounted={isOpen} transition="slide-up" duration={150}>
|
||||||
{(styles) => (
|
{(styles) => (
|
||||||
<div className={classes.selectionActionBarWrapper} style={styles}>
|
<div className={classes.selectionActionBarWrapper} style={styles}>
|
||||||
<div className={classes.selectionActionBar}>
|
<div className={classes.selectionActionBar} role="toolbar">
|
||||||
<span className={classes.selectionActionBarCount}>
|
<span className={classes.selectionActionBarCount}>
|
||||||
{t("{{count}} selected", { count: selectionCount })}
|
{t("{{count}} selected", { count: selectionCount })}
|
||||||
</span>
|
</span>
|
||||||
<Button
|
<button
|
||||||
size="xs"
|
type="button"
|
||||||
color="red"
|
className={classes.selectionActionBarDelete}
|
||||||
variant="light"
|
disabled={isPending}
|
||||||
leftSection={<IconTrash size={14} />}
|
|
||||||
loading={isPending}
|
|
||||||
onClick={() => void deleteSelected()}
|
onClick={() => void deleteSelected()}
|
||||||
>
|
>
|
||||||
|
<IconTrash size={14} />
|
||||||
{t("Delete")}
|
{t("Delete")}
|
||||||
</Button>
|
</button>
|
||||||
<ActionIcon
|
<button
|
||||||
size="sm"
|
type="button"
|
||||||
variant="subtle"
|
className={classes.selectionActionBarClose}
|
||||||
onClick={clear}
|
onClick={clear}
|
||||||
aria-label={t("Clear selection")}
|
aria-label={t("Clear selection")}
|
||||||
>
|
>
|
||||||
<IconX size={14} />
|
<IconX size={14} />
|
||||||
</ActionIcon>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -376,28 +376,85 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.selectionActionBarWrapper {
|
.selectionActionBarWrapper {
|
||||||
position: sticky;
|
position: fixed;
|
||||||
bottom: 16px;
|
left: 50%;
|
||||||
|
bottom: 24px;
|
||||||
|
transform: translateX(-50%);
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
z-index: 5;
|
z-index: 200;
|
||||||
grid-column: 1 / -1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.selectionActionBar {
|
.selectionActionBar {
|
||||||
pointer-events: auto;
|
pointer-events: auto;
|
||||||
display: inline-flex;
|
display: inline-flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 8px;
|
gap: 4px;
|
||||||
padding: 6px 10px;
|
padding: 6px 6px 6px 14px;
|
||||||
border-radius: var(--mantine-radius-md);
|
border-radius: 999px;
|
||||||
box-shadow: var(--mantine-shadow-lg);
|
box-shadow:
|
||||||
background: light-dark(var(--mantine-color-white), var(--mantine-color-dark-6));
|
0 10px 30px rgba(0, 0, 0, 0.25),
|
||||||
border: 1px solid light-dark(var(--mantine-color-gray-3), var(--mantine-color-dark-4));
|
0 2px 8px rgba(0, 0, 0, 0.18);
|
||||||
|
background: light-dark(
|
||||||
|
var(--mantine-color-dark-8),
|
||||||
|
var(--mantine-color-dark-5)
|
||||||
|
);
|
||||||
|
color: var(--mantine-color-white);
|
||||||
|
border: 1px solid light-dark(
|
||||||
|
var(--mantine-color-dark-9),
|
||||||
|
var(--mantine-color-dark-4)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
.selectionActionBarCount {
|
.selectionActionBarCount {
|
||||||
font-size: var(--mantine-font-size-sm);
|
font-size: var(--mantine-font-size-sm);
|
||||||
color: light-dark(var(--mantine-color-gray-7), var(--mantine-color-dark-0));
|
font-weight: 500;
|
||||||
|
color: var(--mantine-color-white);
|
||||||
|
padding-right: 10px;
|
||||||
|
margin-right: 2px;
|
||||||
|
border-right: 1px solid rgba(255, 255, 255, 0.15);
|
||||||
|
}
|
||||||
|
|
||||||
|
.selectionActionBarDelete {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 6px;
|
||||||
|
padding: 4px 10px;
|
||||||
|
border: none;
|
||||||
|
background: transparent;
|
||||||
|
color: var(--mantine-color-red-4);
|
||||||
|
font-size: var(--mantine-font-size-sm);
|
||||||
|
font-weight: 500;
|
||||||
|
border-radius: 999px;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: background 120ms ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.selectionActionBarDelete:hover:not(:disabled) {
|
||||||
|
background: rgba(255, 255, 255, 0.08);
|
||||||
|
}
|
||||||
|
|
||||||
|
.selectionActionBarDelete:disabled {
|
||||||
|
opacity: 0.6;
|
||||||
|
cursor: default;
|
||||||
|
}
|
||||||
|
|
||||||
|
.selectionActionBarClose {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
width: 26px;
|
||||||
|
height: 26px;
|
||||||
|
border: none;
|
||||||
|
background: transparent;
|
||||||
|
color: var(--mantine-color-gray-3);
|
||||||
|
border-radius: 999px;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: background 120ms ease, color 120ms ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.selectionActionBarClose:hover {
|
||||||
|
background: rgba(255, 255, 255, 0.08);
|
||||||
|
color: var(--mantine-color-white);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user