Files
vs-code-vertical-tabs/media/tabs.css
T
maxandClaude Opus 5 8eae35af3e Stand the pin upright once a tab is pinned
The pinned state and the hover affordance drew the same slanted pin, so the
only difference was opacity. Rotating the pinned one to vertical separates
"this is pinned" from "click to pin", and the short transition reads as the
toggle landing.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-11 16:37:57 +02:00

267 lines
5.4 KiB
CSS

/* Vertical Tabs — the tab list */
:root {
--row-gap: 2px;
--border-width: 3px;
}
* {
box-sizing: border-box;
}
html,
body {
height: 100%;
margin: 0;
padding: 0;
overflow: hidden;
}
body {
color: var(--vscode-foreground);
background: var(--vscode-sideBar-background, transparent);
font-family: var(--vscode-font-family);
font-size: var(--vscode-font-size);
}
#list {
height: 100%;
padding: 3px 0;
overflow-x: hidden;
overflow-y: auto;
outline: none;
}
/* --- a row -------------------------------------------------------------- */
.tab {
display: flex;
align-items: center;
gap: 5px;
min-height: 24px;
margin: 0 2px var(--row-gap);
padding: 2px 4px 2px 5px;
border-left: var(--border-width) solid var(--tab-color, transparent);
border-radius: 0 3px 3px 0;
cursor: pointer;
user-select: none;
/* the close button only takes space while it is visible */
overflow: hidden;
}
.tab:hover {
background: var(--vscode-list-hoverBackground);
}
.tab.active {
color: var(--vscode-list-activeSelectionForeground);
background: var(--vscode-list-activeSelectionBackground);
}
.tab.selected:not(.active) {
background: var(--vscode-list-inactiveSelectionBackground);
}
#list:focus-visible .tab.selected {
outline: 1px solid var(--vscode-focusBorder);
outline-offset: -1px;
}
.tab.inert {
cursor: default;
}
.tab.inert .name {
font-style: italic;
opacity: 0.75;
}
/* --- the file name ------------------------------------------------------ */
/* The name is the point of the row, so it shrinks last: the detail text has a huge
shrink factor and gives up its width first. */
.name {
display: flex;
flex: 1 1 auto;
min-width: 0;
align-items: baseline;
white-space: nowrap;
}
/* The stem shrinks and ellipsizes; the extension never does, so ".cs" stays
readable on a long name in a narrow strip. */
.stem {
overflow: hidden;
text-overflow: ellipsis;
}
.ext {
flex: 0 0 auto;
opacity: 0.8;
}
.tab.preview .name {
font-style: italic;
}
.detail {
flex: 0 1000 auto;
min-width: 0;
max-width: 45%;
overflow: hidden;
color: var(--vscode-descriptionForeground);
font-size: 0.9em;
text-align: right;
text-overflow: ellipsis;
white-space: nowrap;
}
/* --- markers and buttons ------------------------------------------------ */
.marker {
flex: 0 0 auto;
width: 16px;
height: 16px;
display: flex;
align-items: center;
justify-content: center;
color: var(--vscode-icon-foreground);
border-radius: 3px;
opacity: 0.85;
}
.marker svg {
width: 12px;
height: 12px;
fill: currentColor;
}
button.marker {
padding: 0;
background: none;
border: none;
cursor: pointer;
opacity: 0;
}
.tab:hover button.marker,
.tab.active button.marker,
button.marker.on,
button.marker:focus-visible {
opacity: 1;
}
button.marker:hover {
background: var(--vscode-toolbar-hoverBackground);
}
button.marker:focus-visible {
outline: 1px solid var(--vscode-focusBorder);
outline-offset: -1px;
}
/* The pin leans over while it is only an offer; once the tab is really pinned it
stands upright, so the state reads apart from the hover affordance. */
button.pin svg {
transition: transform 80ms ease-out;
}
button.pin.on svg {
transform: rotate(-45deg);
}
/* An unsaved file shows a dot, which the close button replaces on hover. */
.dirty {
flex: 0 0 auto;
width: 16px;
display: flex;
justify-content: center;
}
.dirty::before {
content: '';
width: 8px;
height: 8px;
border-radius: 50%;
background: currentColor;
}
.tab:hover .dirty,
.tab.active .dirty {
display: none;
}
.tab:not(.is-dirty) .dirty {
display: none;
}
.tab:not(:hover):not(.active) button.close {
display: none;
}
/* --- the pinned block --------------------------------------------------- */
.separator {
height: 1px;
margin: 4px 6px 5px;
background: var(--vscode-sideBarSectionHeader-border, var(--vscode-panel-border));
opacity: 0.6;
}
/* --- context menu ------------------------------------------------------- */
#menu {
position: fixed;
z-index: 20;
min-width: 180px;
padding: 4px;
color: var(--vscode-menu-foreground, var(--vscode-foreground));
background: var(--vscode-menu-background, var(--vscode-editorWidget-background));
border: 1px solid var(--vscode-menu-border, var(--vscode-editorWidget-border));
border-radius: 4px;
box-shadow: 0 2px 8px var(--vscode-widget-shadow, rgba(0, 0, 0, 0.36));
}
#menu[hidden] {
display: none;
}
#menu button {
display: block;
width: 100%;
padding: 4px 8px;
color: inherit;
background: none;
border: none;
border-radius: 2px;
font-family: inherit;
font-size: inherit;
text-align: left;
white-space: nowrap;
cursor: pointer;
}
#menu button:hover,
#menu button:focus-visible {
color: var(--vscode-menu-selectionForeground, inherit);
background: var(--vscode-menu-selectionBackground, var(--vscode-list-hoverBackground));
outline: none;
}
#menu .menu-separator {
height: 1px;
margin: 4px 2px;
background: var(--vscode-menu-separatorBackground, var(--vscode-panel-border));
}
/* --- empty state -------------------------------------------------------- */
#empty {
padding: 10px 12px;
color: var(--vscode-descriptionForeground);
}
#empty[hidden] {
display: none;
}