Files
vs-code-vertical-tabs/media/tabs.css
T
maxandClaude Opus 5 925e55d619 Give the file name the row, and stop repeating the project
On a real project the name lost the width fight and the trailing text read
"MyGame.Runtime MyGame.Runtime" — the directory and the project were the
same string, printed twice.

- The detail text now has a shrink factor of 1000 against the name's 1, plus
  a 45% cap, so it gives up its width first and the name is the last thing to
  ellipsize.
- A directory that already begins with the project name says everything the
  project name would, so only one of the two is shown.
- verticalTabs.showDirectory became never / duplicates / always, defaulting
  to duplicates: width goes to a directory only when two open tabs share a
  file name, which is the usual reason to want it. Turning showProject off
  as well gives the name the whole row.
- The trailing text is composed in the extension now rather than the webview,
  so the deduplication is unit-testable and there is one implementation.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-07 18:42:14 +02:00

257 lines
5.2 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;
}
/* 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;
}