feat(dockview): add Dockview component and panel layout management

This commit is contained in:
cfngc4594 2025-04-04 14:03:05 +08:00
parent ba11f1d5ba
commit 2f1a9767f1
2 changed files with 1010 additions and 0 deletions

150
src/components/dockview.tsx Normal file
View File

@ -0,0 +1,150 @@
"use client";
import {
DockviewReact,
themeAbyssSpaced,
type DockviewReadyEvent,
type IDockviewPanelHeaderProps,
} from "dockview";
import {
CircleCheckBigIcon,
FileTextIcon,
FlaskConicalIcon,
type LucideProps,
SquareCheckIcon,
SquarePenIcon,
TerminalIcon
} from "lucide-react";
import "@/styles/dockview.css";
import { type ForwardRefExoticComponent, type RefAttributes, useMemo } from "react";
interface DockviewProps {
Description: React.ReactNode;
Solutions: React.ReactNode;
Submissions: React.ReactNode;
Code: React.ReactNode;
Testcase: React.ReactNode;
TestResult: React.ReactNode;
}
const PanelIcons: Record<string, ForwardRefExoticComponent<Omit<LucideProps, "ref"> & RefAttributes<SVGSVGElement>>> = {
Description: FileTextIcon,
Solutions: FlaskConicalIcon,
Submissions: CircleCheckBigIcon,
Code: SquarePenIcon,
Testcase: SquareCheckIcon,
TestResult: TerminalIcon,
};
const LAYOUT_STORAGE_KEY = "dockview:layout";
const DefaultTab = ({ params }: IDockviewPanelHeaderProps<{ title: string }>) => {
const { title } = params;
const Icon = PanelIcons[title];
return (
<div className="flex items-center text-sm font-medium">
{Icon && (
<Icon
className="-ms-0.5 me-1.5 opacity-60"
size={16}
aria-hidden="true"
/>
)}
<span>{title}</span>
</div>
);
};
const tabComponents = {
default: DefaultTab,
};
const DEFAULT_PANELS = [
{ id: "Description", component: "Description", position: null },
{
id: "Solutions",
component: "Solutions",
position: { referencePanel: "Description", direction: "within" },
},
{
id: "Submissions",
component: "Submissions",
position: { referencePanel: "Solutions", direction: "within" },
},
{
id: "Code",
component: "Code",
position: { referencePanel: "Submissions", direction: "right" },
},
{
id: "Testcase",
component: "Testcase",
position: { referencePanel: "Code", direction: "below" },
},
{
id: "TestResult",
component: "TestResult",
position: { referencePanel: "Testcase", direction: "within" },
},
];
export default function DockView(props: DockviewProps) {
const components = useMemo(
() => ({
Description: () => props.Description,
Solutions: () => props.Solutions,
Submissions: () => props.Submissions,
Code: () => props.Code,
Testcase: () => props.Testcase,
TestResult: () => props.TestResult,
}),
[props]
);
const handleReady = (event: DockviewReadyEvent) => {
let success = false;
try {
const layout = localStorage.getItem(LAYOUT_STORAGE_KEY);
if (layout) {
event.api.fromJSON(JSON.parse(layout));
success = true;
}
} catch (error) {
console.error("Failed to load layout:", error);
localStorage.removeItem(LAYOUT_STORAGE_KEY);
}
if (!success) {
DEFAULT_PANELS.forEach(({ id, component, position }) => {
event.api.addPanel({
id,
component,
tabComponent: "default",
params: { title: id },
position: position || undefined,
});
});
}
const saveLayout = () => {
localStorage.setItem(
LAYOUT_STORAGE_KEY,
JSON.stringify(event.api.toJSON())
);
};
const disposable = event.api.onDidLayoutChange(saveLayout);
return () => disposable.dispose();
};
return (
<DockviewReact
theme={themeAbyssSpaced}
onReady={handleReady}
components={components}
tabComponents={tabComponents}
/>
);
}

860
src/styles/dockview.css Normal file
View File

@ -0,0 +1,860 @@
.dv-scrollable {
position: relative;
overflow: hidden;
}
.dv-scrollable .dv-scrollbar-horizontal {
position: absolute;
bottom: 0px;
left: 0px;
height: 4px;
border-radius: 2px;
background-color: transparent;
transition-property: background-color;
transition-timing-function: ease-in-out;
transition-duration: 1s;
transition-delay: 0s;
}
.dv-scrollable:hover .dv-scrollbar-horizontal,
.dv-scrollable.dv-scrollable-resizing .dv-scrollbar-horizontal,
.dv-scrollable.dv-scrollable-scrolling .dv-scrollbar-horizontal {
background-color: var(--dv-scrollbar-background-color, rgba(255, 255, 255, 0.25));
}
.dv-svg {
display: inline-block;
fill: currentcolor;
line-height: 1;
stroke: currentcolor;
stroke-width: 0;
}
.dockview-theme-abyss-spaced {
--dv-paneview-active-outline-color: dodgerblue;
--dv-tabs-and-actions-container-font-size: 13px;
--dv-tabs-and-actions-container-height: 35px;
--dv-drag-over-background-color: hsl(var(--accent) / 50%);
--dv-drag-over-border-color: transparent;
--dv-tabs-container-scrollbar-color: #888;
--dv-icon-hover-background-color: rgba(90, 93, 94, 0.31);
--dv-floating-box-shadow: 8px 8px 8px 0px rgba(83, 89, 93, 0.5);
--dv-overlay-z-index: 999;
--dv-tab-font-size: inherit;
--dv-border-radius: 0px;
--dv-tab-margin: 0;
--dv-sash-color: transparent;
--dv-active-sash-color: transparent;
--dv-active-sash-transition-duration: 0.1s;
--dv-active-sash-transition-delay: 0.5s;
--dv-tab-font-size: 12px;
--dv-border-radius: 20px;
--dv-tab-margin: 0.5rem 0.25rem;
--dv-tabs-and-actions-container-height: 44px;
--dv-border-radius: 20px;
--dv-color-abyss-dark: hsl(var(--background));
--dv-color-abyss: hsl(var(--muted));
--dv-color-abyss-light: hsl(var(--muted));
--dv-color-abyss-lighter: hsl(var(--background));
--dv-color-abyss-accent: rgb(59, 130, 246);
--dv-color-abyss-primary-text: hsl(var(--muted-foreground));
--dv-color-abyss-secondary-text: hsl(var(--muted-foreground));
--dv-drag-over-border: 2px solid var(--dv-color-abyss-accent);
--dv-group-view-background-color: var(--dv-color-abyss-dark);
--dv-tabs-and-actions-container-background-color: var(--dv-color-abyss);
--dv-activegroup-visiblepanel-tab-background-color: var(--dv-color-abyss-lighter);
--dv-activegroup-hiddenpanel-tab-background-color: var(--dv-color-abyss-light);
--dv-inactivegroup-visiblepanel-tab-background-color: var(--dv-color-abyss-lighter);
--dv-inactivegroup-hiddenpanel-tab-background-color: var(--dv-color-abyss-light);
--dv-tab-divider-color: transparent;
--dv-activegroup-visiblepanel-tab-color: var(--dv-color-abyss-primary-text);
--dv-activegroup-hiddenpanel-tab-color: var(--dv-color-abyss-secondary-text);
--dv-inactivegroup-visiblepanel-tab-color: var(--dv-color-abyss-primary-text);
--dv-inactivegroup-hiddenpanel-tab-color: var(--dv-color-abyss-secondary-text);
--dv-separator-border: transparent;
--dv-paneview-header-border-color: rgb(51, 51, 51);
--dv-active-sash-color: var(--dv-color-abyss-accent);
--dv-floating-box-shadow: 8px 8px 8px 0px rgba(0, 0, 0, 0.5);
background-color: var(--dv-color-abyss-dark);
}
.dockview-theme-abyss-spaced .dv-resize-container:has(> .dv-groupview) {
border-radius: 8px;
}
.dockview-theme-abyss-spaced .dv-sash {
border-radius: 4px;
}
.dockview-theme-abyss-spaced .dv-drop-target-anchor {
border-radius: calc(var(--dv-border-radius) / 4);
}
.dockview-theme-abyss-spaced .dv-drop-target-anchor.dv-drop-target-content {
border-radius: var(--dv-border-radius);
}
.dockview-theme-abyss-spaced .dv-resize-container {
border-radius: var(--dv-border-radius) !important;
border: none;
}
.dockview-theme-abyss-spaced .dv-tabs-overflow-container,
.dockview-theme-abyss-spaced .dv-tabs-overflow-dropdown-default {
border-radius: 8px;
height: unset !important;
}
.dockview-theme-abyss-spaced .dv-tab {
border-radius: 8px;
}
.dockview-theme-abyss-spaced .dv-tab .dv-svg {
height: 8px;
width: 8px;
}
.dockview-theme-abyss-spaced .dv-groupview {
border-radius: var(--dv-border-radius);
}
.dockview-theme-abyss-spaced .dv-groupview .dv-tabs-and-actions-container {
padding: 0px calc(var(--dv-border-radius) / 2);
}
.dockview-theme-abyss-spaced .dv-groupview .dv-content-container {
background-color: var(--dv-tabs-and-actions-container-background-color);
}
.dockview-theme-abyss-spaced .dv-resize-container .dv-groupview {
border: 2px solid var(--dv-color-abyss-dark);
}
.dv-drop-target-container {
position: absolute;
z-index: 9999;
top: 0px;
left: 0px;
height: 100%;
width: 100%;
pointer-events: none;
overflow: hidden;
--dv-transition-duration: 300ms;
}
.dv-drop-target-container .dv-drop-target-anchor {
position: relative;
border: var(--dv-drag-over-border);
transition: opacity var(--dv-transition-duration) ease-in, top var(--dv-transition-duration) ease-out, left var(--dv-transition-duration) ease-out, width var(--dv-transition-duration) ease-out, height var(--dv-transition-duration) ease-out;
background-color: var(--dv-drag-over-background-color);
opacity: 1;
}
.dv-drop-target {
position: relative;
--dv-transition-duration: 70ms;
}
.dv-drop-target>.dv-drop-target-dropzone {
position: absolute;
left: 0px;
top: 0px;
height: 100%;
width: 100%;
z-index: 1000;
pointer-events: none;
}
.dv-drop-target>.dv-drop-target-dropzone>.dv-drop-target-selection {
position: relative;
box-sizing: border-box;
height: 100%;
width: 100%;
border: var(--dv-drag-over-border);
background-color: var(--dv-drag-over-background-color);
transition: top var(--dv-transition-duration) ease-out, left var(--dv-transition-duration) ease-out, width var(--dv-transition-duration) ease-out, height var(--dv-transition-duration) ease-out, opacity var(--dv-transition-duration) ease-out;
will-change: transform;
pointer-events: none;
}
.dv-drop-target>.dv-drop-target-dropzone>.dv-drop-target-selection.dv-drop-target-top.dv-drop-target-small-vertical {
border-top: 1px solid var(--dv-drag-over-border-color);
}
.dv-drop-target>.dv-drop-target-dropzone>.dv-drop-target-selection.dv-drop-target-bottom.dv-drop-target-small-vertical {
border-bottom: 1px solid var(--dv-drag-over-border-color);
}
.dv-drop-target>.dv-drop-target-dropzone>.dv-drop-target-selection.dv-drop-target-left.dv-drop-target-small-horizontal {
border-left: 1px solid var(--dv-drag-over-border-color);
}
.dv-drop-target>.dv-drop-target-dropzone>.dv-drop-target-selection.dv-drop-target-right.dv-drop-target-small-horizontal {
border-right: 1px solid var(--dv-drag-over-border-color);
}
.dv-dockview {
position: relative;
background-color: var(--dv-group-view-background-color);
}
.dv-dockview .dv-watermark-container {
position: absolute;
top: 0px;
left: 0px;
height: 100%;
width: 100%;
z-index: 1;
}
.dv-dockview .dv-overlay-render-container {
position: relative;
}
.dv-groupview.dv-active-group>.dv-tabs-and-actions-container .dv-tabs-container>.dv-tab.dv-active-tab {
background-color: var(--dv-activegroup-visiblepanel-tab-background-color);
color: var(--dv-activegroup-visiblepanel-tab-color);
}
.dv-groupview.dv-active-group>.dv-tabs-and-actions-container .dv-tabs-container>.dv-tab.dv-inactive-tab {
background-color: var(--dv-activegroup-hiddenpanel-tab-background-color);
color: var(--dv-activegroup-hiddenpanel-tab-color);
}
.dv-groupview.dv-inactive-group>.dv-tabs-and-actions-container .dv-tabs-container>.dv-tab.dv-active-tab {
background-color: var(--dv-inactivegroup-visiblepanel-tab-background-color);
color: var(--dv-inactivegroup-visiblepanel-tab-color);
}
.dv-groupview.dv-inactive-group>.dv-tabs-and-actions-container .dv-tabs-container>.dv-tab.dv-inactive-tab {
background-color: var(--dv-inactivegroup-hiddenpanel-tab-background-color);
color: var(--dv-inactivegroup-hiddenpanel-tab-color);
}
/**
* when a tab is dragged we lose the above stylings because they are conditional on parent elements
* therefore we also set some stylings for the dragging event
**/
.dv-tab.dv-tab-dragging {
background-color: var(--dv-activegroup-visiblepanel-tab-background-color);
color: var(--dv-activegroup-visiblepanel-tab-color);
}
.dv-groupview {
display: flex;
flex-direction: column;
height: 100%;
background-color: var(--dv-group-view-background-color);
overflow: hidden;
}
.dv-groupview:focus {
outline: none;
}
.dv-groupview>.dv-content-container {
flex-grow: 1;
min-height: 0;
outline: none;
}
.dv-root-wrapper {
height: 100%;
width: 100%;
}
.dv-grid-view,
.dv-branch-node {
height: 100%;
width: 100%;
}
.dv-debug .dv-resize-container .dv-resize-handle-top {
background-color: red;
}
.dv-debug .dv-resize-container .dv-resize-handle-bottom {
background-color: green;
}
.dv-debug .dv-resize-container .dv-resize-handle-left {
background-color: yellow;
}
.dv-debug .dv-resize-container .dv-resize-handle-right {
background-color: blue;
}
.dv-debug .dv-resize-container .dv-resize-handle-topleft,
.dv-debug .dv-resize-container .dv-resize-handle-topright,
.dv-debug .dv-resize-container .dv-resize-handle-bottomleft,
.dv-debug .dv-resize-container .dv-resize-handle-bottomright {
background-color: cyan;
}
.dv-resize-container {
--dv-overlay-z-index: var(--dv-overlay-z-index, 999);
position: absolute;
z-index: calc(var(--dv-overlay-z-index) - 2);
border: 1px solid var(--dv-tab-divider-color);
box-shadow: var(--dv-floating-box-shadow);
}
.dv-resize-container.dv-hidden {
display: none;
}
.dv-resize-container.dv-resize-container-dragging {
opacity: 0.5;
}
.dv-resize-container .dv-resize-handle-top {
height: 4px;
width: calc(100% - 8px);
left: 4px;
top: -2px;
z-index: var(--dv-overlay-z-index);
position: absolute;
cursor: ns-resize;
}
.dv-resize-container .dv-resize-handle-bottom {
height: 4px;
width: calc(100% - 8px);
left: 4px;
bottom: -2px;
z-index: var(--dv-overlay-z-index);
position: absolute;
cursor: ns-resize;
}
.dv-resize-container .dv-resize-handle-left {
height: calc(100% - 8px);
width: 4px;
left: -2px;
top: 4px;
z-index: var(--dv-overlay-z-index);
position: absolute;
cursor: ew-resize;
}
.dv-resize-container .dv-resize-handle-right {
height: calc(100% - 8px);
width: 4px;
right: -2px;
top: 4px;
z-index: var(--dv-overlay-z-index);
position: absolute;
cursor: ew-resize;
}
.dv-resize-container .dv-resize-handle-topleft {
height: 4px;
width: 4px;
top: -2px;
left: -2px;
z-index: var(--dv-overlay-z-index);
position: absolute;
cursor: nw-resize;
}
.dv-resize-container .dv-resize-handle-topright {
height: 4px;
width: 4px;
right: -2px;
top: -2px;
z-index: var(--dv-overlay-z-index);
position: absolute;
cursor: ne-resize;
}
.dv-resize-container .dv-resize-handle-bottomleft {
height: 4px;
width: 4px;
left: -2px;
bottom: -2px;
z-index: var(--dv-overlay-z-index);
position: absolute;
cursor: sw-resize;
}
.dv-resize-container .dv-resize-handle-bottomright {
height: 4px;
width: 4px;
right: -2px;
bottom: -2px;
z-index: var(--dv-overlay-z-index);
position: absolute;
cursor: se-resize;
}
.dv-render-overlay {
--dv-overlay-z-index: var(--dv-overlay-z-index, 999);
position: absolute;
z-index: 1;
height: 100%;
}
.dv-render-overlay.dv-render-overlay-float {
z-index: calc(var(--dv-overlay-z-index) - 1);
}
.dv-debug .dv-render-overlay {
outline: 1px solid red;
outline-offset: -1;
}
.dv-pane-container {
height: 100%;
width: 100%;
}
.dv-pane-container.dv-animated .dv-view {
transition-duration: 0.15s;
transition-timing-function: ease-out;
}
.dv-pane-container .dv-view {
overflow: hidden;
display: flex;
flex-direction: column;
padding: 0px !important;
}
.dv-pane-container .dv-view:not(:first-child)::before {
background-color: transparent !important;
}
.dv-pane-container .dv-view:not(:first-child) .dv-pane>.dv-pane-header {
border-top: 1px solid var(--dv-paneview-header-border-color);
}
.dv-pane-container .dv-view .dv-default-header {
background-color: var(--dv-group-view-background-color);
color: var(--dv-activegroup-visiblepanel-tab-color);
display: flex;
padding: 0px 8px;
cursor: pointer;
}
.dv-pane-container .dv-view .dv-default-header .dv-pane-header-icon {
display: flex;
justify-content: center;
align-items: center;
}
.dv-pane-container .dv-view .dv-default-header>span {
padding-left: 8px;
flex-grow: 1;
}
.dv-pane-container:first-of-type>.dv-pane>.dv-pane-header {
border-top: none !important;
}
.dv-pane-container .dv-pane {
display: flex;
flex-direction: column;
overflow: hidden;
height: 100%;
}
.dv-pane-container .dv-pane .dv-pane-header {
box-sizing: border-box;
user-select: none;
position: relative;
outline: none;
}
.dv-pane-container .dv-pane .dv-pane-header.dv-pane-draggable {
cursor: pointer;
}
.dv-pane-container .dv-pane .dv-pane-header:focus:before,
.dv-pane-container .dv-pane .dv-pane-header:focus-within:before {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 5;
content: "";
pointer-events: none;
outline: 1px solid;
outline-width: -1px;
outline-style: solid;
outline-offset: -1px;
outline-color: var(--dv-paneview-active-outline-color);
}
.dv-pane-container .dv-pane .dv-pane-body {
overflow-y: auto;
overflow-x: hidden;
flex-grow: 1;
position: relative;
outline: none;
}
.dv-pane-container .dv-pane .dv-pane-body:focus:before,
.dv-pane-container .dv-pane .dv-pane-body:focus-within:before {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 5;
content: "";
pointer-events: none;
outline: 1px solid;
outline-width: -1px;
outline-style: solid;
outline-offset: -1px;
outline-color: var(--dv-paneview-active-outline-color);
}
.dv-debug .dv-split-view-container .dv-sash-container .dv-sash.dv-enabled {
background-color: black;
}
.dv-debug .dv-split-view-container .dv-sash-container .dv-sash.dv-disabled {
background-color: orange;
}
.dv-debug .dv-split-view-container .dv-sash-container .dv-sash.dv-maximum {
background-color: green;
}
.dv-debug .dv-split-view-container .dv-sash-container .dv-sash.dv-minimum {
background-color: red;
}
.dv-split-view-container {
position: relative;
overflow: hidden;
height: 100%;
width: 100%;
}
.dv-split-view-container.dv-splitview-disabled>.dv-sash-container>.dv-sash {
pointer-events: none;
}
.dv-split-view-container.dv-animation .dv-view,
.dv-split-view-container.dv-animation .dv-sash {
transition-duration: 0.15s;
transition-timing-function: ease-out;
}
.dv-split-view-container.dv-horizontal {
height: 100%;
}
.dv-split-view-container.dv-horizontal>.dv-sash-container>.dv-sash {
height: 100%;
width: 4px;
}
.dv-split-view-container.dv-horizontal>.dv-sash-container>.dv-sash.dv-enabled {
cursor: ew-resize;
}
.dv-split-view-container.dv-horizontal>.dv-sash-container>.dv-sash.dv-disabled {
cursor: default;
}
.dv-split-view-container.dv-horizontal>.dv-sash-container>.dv-sash.dv-maximum {
cursor: w-resize;
}
.dv-split-view-container.dv-horizontal>.dv-sash-container>.dv-sash.dv-minimum {
cursor: e-resize;
}
.dv-split-view-container.dv-horizontal>.dv-view-container>.dv-view:not(:first-child)::before {
height: 100%;
width: 1px;
}
.dv-split-view-container.dv-vertical {
width: 100%;
}
.dv-split-view-container.dv-vertical>.dv-sash-container>.dv-sash {
width: 100%;
height: 4px;
}
.dv-split-view-container.dv-vertical>.dv-sash-container>.dv-sash.dv-enabled {
cursor: ns-resize;
}
.dv-split-view-container.dv-vertical>.dv-sash-container>.dv-sash.dv-disabled {
cursor: default;
}
.dv-split-view-container.dv-vertical>.dv-sash-container>.dv-sash.dv-maximum {
cursor: n-resize;
}
.dv-split-view-container.dv-vertical>.dv-sash-container>.dv-sash.dv-minimum {
cursor: s-resize;
}
.dv-split-view-container.dv-vertical>.dv-view-container>.dv-view {
width: 100%;
}
.dv-split-view-container.dv-vertical>.dv-view-container>.dv-view:not(:first-child)::before {
height: 1px;
width: 100%;
}
.dv-split-view-container .dv-sash-container {
height: 100%;
width: 100%;
position: absolute;
}
.dv-split-view-container .dv-sash-container .dv-sash {
position: absolute;
z-index: 99;
outline: none;
user-select: none;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
touch-action: none;
background-color: var(--dv-sash-color, transparent);
}
.dv-split-view-container .dv-sash-container .dv-sash:not(.disabled):active,
.dv-split-view-container .dv-sash-container .dv-sash:not(.disabled):hover {
background-color: var(--dv-active-sash-color, transparent);
transition-property: background-color;
transition-timing-function: ease-in-out;
transition-duration: var(--dv-active-sash-transition-duration, 0.1s);
transition-delay: var(--dv-active-sash-transition-delay, 0.5s);
}
.dv-split-view-container .dv-view-container {
position: relative;
height: 100%;
width: 100%;
}
.dv-split-view-container .dv-view-container .dv-view {
height: 100%;
box-sizing: border-box;
overflow: auto;
position: absolute;
}
.dv-split-view-container.dv-separator-border .dv-view:not(:first-child)::before {
content: " ";
position: absolute;
top: 0;
left: 0;
z-index: 5;
pointer-events: none;
background-color: var(--dv-separator-border);
}
.dv-dragged {
transform: translate3d(0px, 0px, 0px);
/* forces tab to be drawn on a separate layer (see https://github.com/microsoft/vscode/issues/18733) */
}
.dv-tab {
flex-shrink: 0;
}
.dv-tab:focus-within,
.dv-tab:focus {
position: relative;
}
.dv-tab:focus-within::after,
.dv-tab:focus::after {
position: absolute;
content: "";
height: 100%;
width: 100%;
top: 0px;
left: 0px;
pointer-events: none;
outline: 1px solid var(--dv-tab-divider-color) !important;
outline-offset: -1px;
z-index: 5;
}
.dv-tab.dv-tab-dragging .dv-default-tab-action {
background-color: var(--dv-activegroup-visiblepanel-tab-color);
}
.dv-tab.dv-active-tab .dv-default-tab .dv-default-tab-action {
visibility: visible;
}
.dv-tab.dv-inactive-tab .dv-default-tab .dv-default-tab-action {
visibility: hidden;
}
.dv-tab.dv-inactive-tab .dv-default-tab:hover .dv-default-tab-action {
visibility: visible;
}
.dv-tab .dv-default-tab {
position: relative;
height: 100%;
display: flex;
align-items: center;
white-space: nowrap;
text-overflow: ellipsis;
}
.dv-tab .dv-default-tab .dv-default-tab-content {
flex-grow: 1;
margin-right: 4px;
}
.dv-tab .dv-default-tab .dv-default-tab-action {
padding: 4px;
display: flex;
align-items: center;
justify-content: center;
box-sizing: border-box;
}
.dv-tab .dv-default-tab .dv-default-tab-action:hover {
border-radius: 2px;
background-color: var(--dv-icon-hover-background-color);
}
.dv-tabs-overflow-dropdown-default {
height: 100%;
color: var(--dv-activegroup-hiddenpanel-tab-color);
margin: var(--dv-tab-margin);
display: flex;
align-items: center;
flex-shrink: 0;
padding: 0.25rem 0.5rem;
cursor: pointer;
}
.dv-tabs-overflow-dropdown-default>span {
padding-left: 0.25rem;
}
.dv-tabs-overflow-dropdown-default>svg {
transform: rotate(90deg);
}
.dv-tabs-container {
display: flex;
height: 100%;
overflow: auto;
scrollbar-width: thin;
/* Track */
/* Handle */
}
.dv-tabs-container.dv-horizontal .dv-tab:not(:first-child)::before {
content: " ";
position: absolute;
top: 0;
left: 0;
z-index: 5;
pointer-events: none;
background-color: var(--dv-tab-divider-color);
width: 1px;
height: 100%;
}
.dv-tabs-container::-webkit-scrollbar {
height: 3px;
}
.dv-tabs-container::-webkit-scrollbar-track {
background: transparent;
}
.dv-tabs-container::-webkit-scrollbar-thumb {
background: var(--dv-tabs-container-scrollbar-color);
}
.dv-scrollable>.dv-tabs-container {
overflow: hidden;
}
.dv-tab {
-webkit-user-drag: element;
outline: none;
padding: 0.25rem 0.5rem;
cursor: pointer;
position: relative;
box-sizing: border-box;
font-size: var(--dv-tab-font-size);
margin: var(--dv-tab-margin);
}
.dv-tabs-overflow-container {
flex-direction: column;
height: unset;
border: 1px solid var(--dv-tab-divider-color);
background-color: var(--dv-group-view-background-color);
}
.dv-tabs-overflow-container .dv-tab:not(:last-child) {
border-bottom: 1px solid var(--dv-tab-divider-color);
}
.dv-tabs-overflow-container .dv-active-tab {
background-color: var(--dv-activegroup-visiblepanel-tab-background-color);
color: var(--dv-activegroup-visiblepanel-tab-color);
}
.dv-tabs-overflow-container .dv-inactive-tab {
background-color: var(--dv-activegroup-hiddenpanel-tab-background-color);
color: var(--dv-activegroup-hiddenpanel-tab-color);
}
.dv-tabs-and-actions-container {
display: flex;
background-color: var(--dv-tabs-and-actions-container-background-color);
flex-shrink: 0;
box-sizing: border-box;
height: var(--dv-tabs-and-actions-container-height);
font-size: var(--dv-tabs-and-actions-container-font-size);
}
.dv-tabs-and-actions-container.dv-single-tab.dv-full-width-single-tab .dv-scrollable {
flex-grow: 1;
}
.dv-tabs-and-actions-container.dv-single-tab.dv-full-width-single-tab .dv-tabs-container {
flex-grow: 1;
}
.dv-tabs-and-actions-container.dv-single-tab.dv-full-width-single-tab .dv-tabs-container .dv-tab {
flex-grow: 1;
padding: 0px;
}
.dv-tabs-and-actions-container.dv-single-tab.dv-full-width-single-tab .dv-void-container {
flex-grow: 0;
}
.dv-tabs-and-actions-container .dv-void-container {
display: flex;
flex-grow: 1;
cursor: grab;
}
.dv-tabs-and-actions-container .dv-right-actions-container {
display: flex;
}
.dv-watermark {
display: flex;
height: 100%;
}