新增宽表自定义横向滚动条
This commit is contained in:
parent
ac18942a4b
commit
eb472ad455
43
frontend/src/components/TableControls.test.js
Normal file
43
frontend/src/components/TableControls.test.js
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
import assert from "node:assert/strict";
|
||||||
|
import { describe, it } from "node:test";
|
||||||
|
import { readFileSync } from "node:fs";
|
||||||
|
import { dirname, join } from "node:path";
|
||||||
|
import { fileURLToPath } from "node:url";
|
||||||
|
|
||||||
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
||||||
|
const source = readFileSync(join(__dirname, "TableControls.vue"), "utf8");
|
||||||
|
const styles = readFileSync(join(__dirname, "../styles/main.css"), "utf8");
|
||||||
|
|
||||||
|
describe("TableControls wide-table scroll dock", () => {
|
||||||
|
it("creates an app-level horizontal scroll dock for wide mode instead of relying on native scrollbars", () => {
|
||||||
|
assert.match(source, /function ensureWideTableScrollDock\(/);
|
||||||
|
assert.match(source, /className = "table-scroll-dock"/);
|
||||||
|
assert.match(source, /aria-label", "宽表横向滚动"/);
|
||||||
|
assert.match(source, /table-scroll-dock-track/);
|
||||||
|
assert.match(source, /table-scroll-dock-thumb/);
|
||||||
|
assert.match(source, /table-scroll-dock-arrow/);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("keeps the scroll dock synchronized with the table wrapper scroll position", () => {
|
||||||
|
assert.match(source, /function syncWideTableScrollDock\(/);
|
||||||
|
assert.match(source, /wideScrollWrap\.scrollLeft/);
|
||||||
|
assert.match(source, /wideScrollWrap\.scrollWidth - wideScrollWrap\.clientWidth/);
|
||||||
|
assert.match(source, /wideScrollThumb\.style\.transform/);
|
||||||
|
assert.match(source, /wideScrollThumb\.style\.width/);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("supports dragging the custom thumb and using left-right step arrows", () => {
|
||||||
|
assert.match(source, /pointerdown/);
|
||||||
|
assert.match(source, /setPointerCapture/);
|
||||||
|
assert.match(source, /function nudgeWideTableScrollDock\(/);
|
||||||
|
assert.match(source, /wideScrollWrap\.scrollBy/);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("styles the scroll dock as the accepted visible low-friction control", () => {
|
||||||
|
assert.match(styles, /body \.table-scroll-dock/);
|
||||||
|
assert.match(styles, /body \.table-scroll-dock-track/);
|
||||||
|
assert.match(styles, /body \.table-scroll-dock-thumb/);
|
||||||
|
assert.match(styles, /body \.table-scroll-dock-arrow/);
|
||||||
|
assert.match(styles, /body \.table-view-wide \+ \.table-scroll-dock/);
|
||||||
|
});
|
||||||
|
});
|
||||||
@ -78,6 +78,13 @@ let headerObserver = null;
|
|||||||
let enhanceFrame = 0;
|
let enhanceFrame = 0;
|
||||||
let modeFrame = 0;
|
let modeFrame = 0;
|
||||||
let isEnhancing = false;
|
let isEnhancing = false;
|
||||||
|
let wideScrollDock = null;
|
||||||
|
let wideScrollWrap = null;
|
||||||
|
let wideScrollTrack = null;
|
||||||
|
let wideScrollThumb = null;
|
||||||
|
let wideScrollResizeObserver = null;
|
||||||
|
let wideScrollCleanupHandlers = [];
|
||||||
|
let wideScrollFrame = 0;
|
||||||
|
|
||||||
function normalizeLabel(value) {
|
function normalizeLabel(value) {
|
||||||
return String(value || "")
|
return String(value || "")
|
||||||
@ -131,6 +138,212 @@ function clearTableViewClasses(table) {
|
|||||||
delete table.dataset.tableViewMode;
|
delete table.dataset.tableViewMode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function removeWideTableScrollDock() {
|
||||||
|
wideScrollCleanupHandlers.forEach((cleanup) => cleanup());
|
||||||
|
wideScrollCleanupHandlers = [];
|
||||||
|
if (wideScrollResizeObserver) {
|
||||||
|
wideScrollResizeObserver.disconnect();
|
||||||
|
wideScrollResizeObserver = null;
|
||||||
|
}
|
||||||
|
if (wideScrollFrame) {
|
||||||
|
window.cancelAnimationFrame(wideScrollFrame);
|
||||||
|
wideScrollFrame = 0;
|
||||||
|
}
|
||||||
|
wideScrollDock?.remove();
|
||||||
|
wideScrollDock = null;
|
||||||
|
wideScrollWrap = null;
|
||||||
|
wideScrollTrack = null;
|
||||||
|
wideScrollThumb = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getWideScrollMetrics() {
|
||||||
|
if (!wideScrollWrap || !wideScrollTrack) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const maxScroll = Math.max(0, wideScrollWrap.scrollWidth - wideScrollWrap.clientWidth);
|
||||||
|
const trackWidth = wideScrollTrack.clientWidth || 0;
|
||||||
|
const thumbWidth = maxScroll > 0
|
||||||
|
? Math.max(72, Math.min(trackWidth, (wideScrollWrap.clientWidth / wideScrollWrap.scrollWidth) * trackWidth))
|
||||||
|
: trackWidth;
|
||||||
|
const thumbTravel = Math.max(0, trackWidth - thumbWidth);
|
||||||
|
const progress = maxScroll > 0 ? wideScrollWrap.scrollLeft / maxScroll : 0;
|
||||||
|
|
||||||
|
return { maxScroll, trackWidth, thumbWidth, thumbTravel, progress };
|
||||||
|
}
|
||||||
|
|
||||||
|
function syncWideTableScrollDock() {
|
||||||
|
const metrics = getWideScrollMetrics();
|
||||||
|
if (!metrics || !wideScrollDock || !wideScrollThumb) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
wideScrollDock.classList.toggle("table-scroll-dock-disabled", metrics.maxScroll <= 1);
|
||||||
|
wideScrollThumb.style.width = `${metrics.thumbWidth}px`;
|
||||||
|
wideScrollThumb.style.transform = `translateX(${metrics.thumbTravel * metrics.progress}px)`;
|
||||||
|
}
|
||||||
|
|
||||||
|
function scheduleWideTableScrollDockSync() {
|
||||||
|
if (wideScrollFrame) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
wideScrollFrame = window.requestAnimationFrame(() => {
|
||||||
|
wideScrollFrame = 0;
|
||||||
|
syncWideTableScrollDock();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function nudgeWideTableScrollDock(direction) {
|
||||||
|
if (!wideScrollWrap) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
wideScrollWrap.scrollBy({
|
||||||
|
left: direction * Math.max(180, wideScrollWrap.clientWidth * 0.42),
|
||||||
|
behavior: "smooth"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function createWideTableScrollDock() {
|
||||||
|
const dock = document.createElement("div");
|
||||||
|
dock.className = "table-scroll-dock";
|
||||||
|
dock.setAttribute("aria-label", "宽表横向滚动");
|
||||||
|
|
||||||
|
const leftArrow = document.createElement("button");
|
||||||
|
leftArrow.type = "button";
|
||||||
|
leftArrow.className = "table-scroll-dock-arrow table-scroll-dock-arrow-left";
|
||||||
|
leftArrow.setAttribute("aria-label", "向左滚动宽表");
|
||||||
|
leftArrow.innerHTML = '<span aria-hidden="true">‹</span>';
|
||||||
|
|
||||||
|
const track = document.createElement("div");
|
||||||
|
track.className = "table-scroll-dock-track";
|
||||||
|
|
||||||
|
const thumb = document.createElement("button");
|
||||||
|
thumb.type = "button";
|
||||||
|
thumb.className = "table-scroll-dock-thumb";
|
||||||
|
thumb.setAttribute("aria-label", "拖动查看宽表隐藏字段");
|
||||||
|
thumb.innerHTML = '<span aria-hidden="true"></span>';
|
||||||
|
|
||||||
|
const rightArrow = document.createElement("button");
|
||||||
|
rightArrow.type = "button";
|
||||||
|
rightArrow.className = "table-scroll-dock-arrow table-scroll-dock-arrow-right";
|
||||||
|
rightArrow.setAttribute("aria-label", "向右滚动宽表");
|
||||||
|
rightArrow.innerHTML = '<span aria-hidden="true">›</span>';
|
||||||
|
|
||||||
|
track.appendChild(thumb);
|
||||||
|
dock.append(leftArrow, track, rightArrow);
|
||||||
|
|
||||||
|
wideScrollTrack = track;
|
||||||
|
wideScrollThumb = thumb;
|
||||||
|
|
||||||
|
const handleTrackPointerDown = (event) => {
|
||||||
|
if (!wideScrollWrap || event.target === thumb) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const metrics = getWideScrollMetrics();
|
||||||
|
if (!metrics?.maxScroll || !metrics.thumbTravel) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const rect = track.getBoundingClientRect();
|
||||||
|
const targetProgress = Math.min(1, Math.max(0, (event.clientX - rect.left - metrics.thumbWidth / 2) / metrics.thumbTravel));
|
||||||
|
wideScrollWrap.scrollLeft = targetProgress * metrics.maxScroll;
|
||||||
|
syncWideTableScrollDock();
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleThumbPointerDown = (event) => {
|
||||||
|
const metrics = getWideScrollMetrics();
|
||||||
|
if (!wideScrollWrap || !metrics?.maxScroll || !metrics.thumbTravel) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
event.preventDefault();
|
||||||
|
thumb.setPointerCapture?.(event.pointerId);
|
||||||
|
dock.classList.add("table-scroll-dock-dragging");
|
||||||
|
|
||||||
|
const startX = event.clientX;
|
||||||
|
const startScrollLeft = wideScrollWrap.scrollLeft;
|
||||||
|
const handlePointerMove = (moveEvent) => {
|
||||||
|
const delta = moveEvent.clientX - startX;
|
||||||
|
wideScrollWrap.scrollLeft = startScrollLeft + (delta / metrics.thumbTravel) * metrics.maxScroll;
|
||||||
|
syncWideTableScrollDock();
|
||||||
|
};
|
||||||
|
const handlePointerUp = () => {
|
||||||
|
dock.classList.remove("table-scroll-dock-dragging");
|
||||||
|
thumb.removeEventListener("pointermove", handlePointerMove);
|
||||||
|
thumb.removeEventListener("pointerup", handlePointerUp);
|
||||||
|
thumb.removeEventListener("pointercancel", handlePointerUp);
|
||||||
|
};
|
||||||
|
|
||||||
|
thumb.addEventListener("pointermove", handlePointerMove);
|
||||||
|
thumb.addEventListener("pointerup", handlePointerUp);
|
||||||
|
thumb.addEventListener("pointercancel", handlePointerUp);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleKeyDown = (event) => {
|
||||||
|
if (event.key === "ArrowLeft") {
|
||||||
|
event.preventDefault();
|
||||||
|
nudgeWideTableScrollDock(-1);
|
||||||
|
}
|
||||||
|
if (event.key === "ArrowRight") {
|
||||||
|
event.preventDefault();
|
||||||
|
nudgeWideTableScrollDock(1);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const handleLeftClick = () => nudgeWideTableScrollDock(-1);
|
||||||
|
const handleRightClick = () => nudgeWideTableScrollDock(1);
|
||||||
|
|
||||||
|
leftArrow.addEventListener("click", handleLeftClick);
|
||||||
|
rightArrow.addEventListener("click", handleRightClick);
|
||||||
|
track.addEventListener("pointerdown", handleTrackPointerDown);
|
||||||
|
thumb.addEventListener("pointerdown", handleThumbPointerDown);
|
||||||
|
thumb.addEventListener("keydown", handleKeyDown);
|
||||||
|
wideScrollCleanupHandlers.push(() => leftArrow.removeEventListener("click", handleLeftClick));
|
||||||
|
wideScrollCleanupHandlers.push(() => rightArrow.removeEventListener("click", handleRightClick));
|
||||||
|
wideScrollCleanupHandlers.push(() => track.removeEventListener("pointerdown", handleTrackPointerDown));
|
||||||
|
wideScrollCleanupHandlers.push(() => thumb.removeEventListener("pointerdown", handleThumbPointerDown));
|
||||||
|
wideScrollCleanupHandlers.push(() => thumb.removeEventListener("keydown", handleKeyDown));
|
||||||
|
|
||||||
|
return dock;
|
||||||
|
}
|
||||||
|
|
||||||
|
function ensureWideTableScrollDock(wrap) {
|
||||||
|
if (!wrap || tableMode.value !== "wide") {
|
||||||
|
removeWideTableScrollDock();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (wideScrollWrap !== wrap) {
|
||||||
|
removeWideTableScrollDock();
|
||||||
|
}
|
||||||
|
|
||||||
|
wideScrollWrap = wrap;
|
||||||
|
if (!wideScrollDock) {
|
||||||
|
wideScrollDock = createWideTableScrollDock();
|
||||||
|
wrap.insertAdjacentElement("afterend", wideScrollDock);
|
||||||
|
|
||||||
|
const handleWrapScroll = () => scheduleWideTableScrollDockSync();
|
||||||
|
wideScrollWrap.addEventListener("scroll", handleWrapScroll, { passive: true });
|
||||||
|
window.addEventListener("resize", scheduleWideTableScrollDockSync);
|
||||||
|
if (typeof ResizeObserver !== "undefined") {
|
||||||
|
wideScrollResizeObserver = new ResizeObserver(scheduleWideTableScrollDockSync);
|
||||||
|
wideScrollResizeObserver.observe(wideScrollWrap);
|
||||||
|
const table = wideScrollWrap.querySelector("table");
|
||||||
|
if (table) {
|
||||||
|
wideScrollResizeObserver.observe(table);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
wideScrollCleanupHandlers.push(() => wideScrollWrap?.removeEventListener("scroll", handleWrapScroll));
|
||||||
|
wideScrollCleanupHandlers.push(() => window.removeEventListener("resize", scheduleWideTableScrollDockSync));
|
||||||
|
} else if (wideScrollDock.previousElementSibling !== wrap) {
|
||||||
|
wrap.insertAdjacentElement("afterend", wideScrollDock);
|
||||||
|
}
|
||||||
|
|
||||||
|
scheduleWideTableScrollDockSync();
|
||||||
|
}
|
||||||
|
|
||||||
function disconnectModeObserver() {
|
function disconnectModeObserver() {
|
||||||
if (modeTableObserver) {
|
if (modeTableObserver) {
|
||||||
modeTableObserver.disconnect();
|
modeTableObserver.disconnect();
|
||||||
@ -320,6 +533,11 @@ function applyTableViewMode(table = findTableAfterControl()) {
|
|||||||
refreshCellTooltips(table);
|
refreshCellTooltips(table);
|
||||||
bindCellTooltip(table);
|
bindCellTooltip(table);
|
||||||
observeTableForViewMode(table);
|
observeTableForViewMode(table);
|
||||||
|
if (isWide) {
|
||||||
|
ensureWideTableScrollDock(wrap);
|
||||||
|
} else {
|
||||||
|
removeWideTableScrollDock();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function scheduleApplyTableViewMode() {
|
function scheduleApplyTableViewMode() {
|
||||||
@ -573,6 +791,7 @@ onBeforeUnmount(() => {
|
|||||||
modeFrame = 0;
|
modeFrame = 0;
|
||||||
}
|
}
|
||||||
clearTableViewClasses(modeTable);
|
clearTableViewClasses(modeTable);
|
||||||
|
removeWideTableScrollDock();
|
||||||
disconnectModeObserver();
|
disconnectModeObserver();
|
||||||
clearTooltipListeners();
|
clearTooltipListeners();
|
||||||
clearEnhancedHeaders();
|
clearEnhancedHeaders();
|
||||||
|
|||||||
@ -11588,12 +11588,12 @@ body .table-view-wide {
|
|||||||
overflow-x: scroll !important;
|
overflow-x: scroll !important;
|
||||||
overflow-y: hidden !important;
|
overflow-y: hidden !important;
|
||||||
scrollbar-gutter: stable both-edges;
|
scrollbar-gutter: stable both-edges;
|
||||||
scrollbar-width: thin;
|
scrollbar-width: none;
|
||||||
scrollbar-color: rgba(100, 116, 139, 0.5) rgba(226, 232, 240, 0.72);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
body .table-view-wide::-webkit-scrollbar {
|
body .table-view-wide::-webkit-scrollbar {
|
||||||
height: 12px;
|
width: 0;
|
||||||
|
height: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
body .table-view-wide::-webkit-scrollbar-track {
|
body .table-view-wide::-webkit-scrollbar-track {
|
||||||
@ -11611,6 +11611,158 @@ body .table-view-wide::-webkit-scrollbar-thumb:hover {
|
|||||||
background: rgba(71, 85, 105, 0.72);
|
background: rgba(71, 85, 105, 0.72);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
body .table-view-wide + .table-scroll-dock,
|
||||||
|
body .table-scroll-dock {
|
||||||
|
position: relative;
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 34px minmax(0, 1fr) 34px;
|
||||||
|
gap: 10px;
|
||||||
|
align-items: center;
|
||||||
|
min-height: 56px;
|
||||||
|
margin-top: -1px;
|
||||||
|
padding: 10px 16px;
|
||||||
|
border: 1px solid rgba(205, 218, 233, 0.92);
|
||||||
|
border-radius: 0 0 18px 18px;
|
||||||
|
background:
|
||||||
|
linear-gradient(180deg, #fbfdff 0%, #f4f8fd 100%);
|
||||||
|
box-shadow:
|
||||||
|
inset 0 1px 0 rgba(255, 255, 255, 0.92),
|
||||||
|
0 14px 26px rgba(15, 23, 42, 0.06);
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
body .table-view-wide + .table-scroll-dock::before,
|
||||||
|
body .table-view-wide + .table-scroll-dock::after,
|
||||||
|
body .table-scroll-dock::before,
|
||||||
|
body .table-scroll-dock::after {
|
||||||
|
position: absolute;
|
||||||
|
top: 1px;
|
||||||
|
bottom: 1px;
|
||||||
|
z-index: 1;
|
||||||
|
width: 58px;
|
||||||
|
pointer-events: none;
|
||||||
|
content: "";
|
||||||
|
}
|
||||||
|
|
||||||
|
body .table-view-wide + .table-scroll-dock::before,
|
||||||
|
body .table-scroll-dock::before {
|
||||||
|
left: 0;
|
||||||
|
background: linear-gradient(90deg, rgba(248, 251, 255, 0.98), rgba(248, 251, 255, 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
body .table-view-wide + .table-scroll-dock::after,
|
||||||
|
body .table-scroll-dock::after {
|
||||||
|
right: 0;
|
||||||
|
background: linear-gradient(270deg, rgba(248, 251, 255, 0.98), rgba(248, 251, 255, 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
body .table-scroll-dock-arrow {
|
||||||
|
position: relative;
|
||||||
|
z-index: 2;
|
||||||
|
display: grid;
|
||||||
|
place-items: center;
|
||||||
|
width: 34px;
|
||||||
|
height: 34px;
|
||||||
|
border: 1px solid rgba(191, 206, 224, 0.9);
|
||||||
|
border-radius: 12px;
|
||||||
|
background:
|
||||||
|
linear-gradient(180deg, #ffffff 0%, #eef5fc 100%);
|
||||||
|
color: #64748b;
|
||||||
|
font: inherit;
|
||||||
|
font-size: 30px;
|
||||||
|
font-weight: 500;
|
||||||
|
line-height: 1;
|
||||||
|
box-shadow:
|
||||||
|
inset 0 1px 0 rgba(255, 255, 255, 0.96),
|
||||||
|
0 6px 14px rgba(15, 23, 42, 0.06);
|
||||||
|
cursor: pointer;
|
||||||
|
transition:
|
||||||
|
border-color 0.16s ease,
|
||||||
|
color 0.16s ease,
|
||||||
|
transform 0.16s ease,
|
||||||
|
box-shadow 0.16s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
body .table-scroll-dock-arrow span {
|
||||||
|
transform: translateY(-2px);
|
||||||
|
}
|
||||||
|
|
||||||
|
body .table-scroll-dock-arrow:hover {
|
||||||
|
border-color: rgba(64, 158, 255, 0.48);
|
||||||
|
color: #1677ff;
|
||||||
|
box-shadow:
|
||||||
|
inset 0 1px 0 rgba(255, 255, 255, 0.96),
|
||||||
|
0 8px 18px rgba(22, 119, 255, 0.14);
|
||||||
|
transform: translateY(-1px);
|
||||||
|
}
|
||||||
|
|
||||||
|
body .table-scroll-dock-track {
|
||||||
|
position: relative;
|
||||||
|
z-index: 2;
|
||||||
|
height: 22px;
|
||||||
|
overflow: hidden;
|
||||||
|
border-radius: 999px;
|
||||||
|
background:
|
||||||
|
linear-gradient(180deg, rgba(226, 234, 243, 0.98), rgba(211, 222, 235, 0.98));
|
||||||
|
box-shadow:
|
||||||
|
inset 0 1px 2px rgba(15, 23, 42, 0.12),
|
||||||
|
inset 0 -1px 0 rgba(255, 255, 255, 0.82);
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
body .table-scroll-dock-thumb {
|
||||||
|
position: absolute;
|
||||||
|
top: 3px;
|
||||||
|
left: 0;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
min-width: 72px;
|
||||||
|
height: 16px;
|
||||||
|
border: 0;
|
||||||
|
border-radius: 999px;
|
||||||
|
background:
|
||||||
|
linear-gradient(90deg, #8fc4ff 0%, #409eff 35%, #1677ff 100%);
|
||||||
|
box-shadow:
|
||||||
|
0 7px 16px rgba(22, 119, 255, 0.24),
|
||||||
|
inset 0 1px 0 rgba(255, 255, 255, 0.34);
|
||||||
|
cursor: grab;
|
||||||
|
touch-action: none;
|
||||||
|
transition:
|
||||||
|
box-shadow 0.16s ease,
|
||||||
|
filter 0.16s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
body .table-scroll-dock-thumb span {
|
||||||
|
width: 28px;
|
||||||
|
height: 10px;
|
||||||
|
background:
|
||||||
|
linear-gradient(90deg, transparent 0 5px, rgba(255, 255, 255, 0.68) 5px 7px, transparent 7px 11px, rgba(255, 255, 255, 0.68) 11px 13px, transparent 13px 17px, rgba(255, 255, 255, 0.68) 17px 19px, transparent 19px);
|
||||||
|
}
|
||||||
|
|
||||||
|
body .table-scroll-dock-thumb:hover,
|
||||||
|
body .table-scroll-dock-dragging .table-scroll-dock-thumb {
|
||||||
|
box-shadow:
|
||||||
|
0 10px 24px rgba(22, 119, 255, 0.32),
|
||||||
|
inset 0 1px 0 rgba(255, 255, 255, 0.42);
|
||||||
|
filter: saturate(1.08);
|
||||||
|
}
|
||||||
|
|
||||||
|
body .table-scroll-dock-dragging .table-scroll-dock-thumb {
|
||||||
|
cursor: grabbing;
|
||||||
|
}
|
||||||
|
|
||||||
|
body .table-scroll-dock-disabled {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (prefers-reduced-motion: reduce) {
|
||||||
|
body .table-scroll-dock-arrow,
|
||||||
|
body .table-scroll-dock-thumb {
|
||||||
|
transition: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
body .table-view-wide .data-table,
|
body .table-view-wide .data-table,
|
||||||
body .table-view-wide .compact-table,
|
body .table-view-wide .compact-table,
|
||||||
body .table-view-wide .drawer-data-table,
|
body .table-view-wide .drawer-data-table,
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user