textmachine/frontend/src/ui/Tabs.module.css

120 lines
3.2 KiB
CSS

.tabs {
display: grid;
grid-template-rows: auto 1fr;
min-height: 0;
}
/* The strip is the panel's own canvas: the active tab is a rounded chip lying ON it, as in
fleet.png. An earlier round cut the tab out of a chrome plate instead; the owner prefers this. */
.row {
display: flex;
gap: var(--space-1);
align-items: center;
padding: var(--panel-padding) var(--panel-padding) 0;
}
/* The row scrolls instead of shrinking its tabs. Flex shrink distributed the overflow in
proportion to each tab's width, so a SHORT title could ellipsize while a longer neighbour
did not — the defect the owner reported. */
.list {
display: flex;
gap: var(--space-1);
min-width: 0;
overflow-x: auto;
scrollbar-width: none;
}
.tab {
display: flex;
height: var(--panel-header-height);
max-width: var(--tab-width-max);
flex: none;
align-items: center;
padding-inline: var(--tab-inset);
gap: var(--space-2);
border-radius: var(--radius-control);
color: var(--color-text-secondary);
white-space: nowrap;
cursor: pointer;
}
.tab[data-hovered] {
color: var(--color-text);
}
.tab[data-selected] {
background-color: var(--color-raised);
color: var(--color-text);
}
/* An open document reads blue where a tool tab reads grey: fleet.png draws that distinction with
the fill itself, not with a mark along an edge. */
.row[data-look='document'] .tab[data-selected] {
background-color: var(--color-tab-active);
}
.tab .title {
overflow: hidden;
text-overflow: ellipsis;
}
/* Preview is italic, as in VS Code: the tab is temporary and will be replaced by the next click. */
.tab[data-preview='true'] .title {
font-style: italic;
}
.tab[data-focus-visible] {
outline: 1px solid var(--color-accent);
outline-offset: -1px;
}
/* The close mark shows on the selected and hovered tab only. Its space is reserved always
(visibility, not display), or the row would jump on every switch. */
.close {
display: flex;
flex: none;
align-items: center;
border-radius: var(--radius-control);
color: var(--color-text-muted);
visibility: hidden;
cursor: pointer;
}
.close:hover {
color: var(--color-text);
}
.tab[data-selected] .close,
.tab[data-hovered] .close {
visibility: visible;
}
/* «+» follows the tabs but stays OUT of the scrolling list, so it cannot scroll away from them. */
.add {
display: flex;
flex: none;
align-items: center;
padding-inline: var(--space-1);
}
/* All the panels live in the SECOND grid row and lie on top of one another: with keepAlive they
are rendered at the same time, and without an explicit place the unselected ones would create
new grid rows. */
.panel {
display: flex;
grid-row: 2;
grid-column: 1;
flex-direction: column;
min-height: 0;
/* The scroll lives inside the tab's content: long lists are virtualized and scroll themselves. */
overflow: hidden;
padding: var(--space-1) var(--panel-padding) var(--panel-padding);
}
/* An unselected keep-alive panel: `content-visibility: hidden` skips layout and paint while keeping
state — `display: none` would destroy the scroll offset, `visibility: hidden` would still lay the
subtree out on every resize (that is what made the right separator drag twice as costly). */
.panel[data-inert] {
content-visibility: hidden;
}