/* src/layout/SidebarViewContainer.css */ .sidebar-view-container { display: flex; height: 100%; overflow: hidden; } /* Left panel: tab bar on right (inner edge toward editor) */ .sidebar-view-container[data-side="left"] { flex-direction: row-reverse; } /* Right panel: tab bar on left (inner edge toward editor) */ .sidebar-view-container[data-side="right"] { flex-direction: row; } /* Vertical icon tab bar (the "side-tab strip" that switches between * leaves inside a sidebar panel: Files / Outline / Tags / Backlinks / …). * * Width is locked to --icon-column-width (same token as the ribbon), so * the ribbon, the left sidebar's tab strip, and the right panel's tab * strip all share one icon-column metric across the app shell. The * tab buttons inside use --icon-tap-size to match ribbon icons. * * Top padding equals --chrome-row-height: the first slot is intentionally * empty so the chrome-row band reads as pure header chrome, and the first * actual side-tab icon lines up with the top of the panel body (one * uninterrupted horizontal line of "panel content begins here" across * ribbon ↔ icon strip ↔ panel body ↔ tab bar's bottom). */ .sidebar-view-tabs { display: flex; flex-direction: column; flex-shrink: 0; width: var(--icon-column-width); background-color: var(--bg-secondary); /* No horizontal padding, no gap: tab buttons span the full column * width so their hover/selected fill reads as a flush block aligned * with the surrounding rectilinear chrome (no rounded pill against a * grid of straight lines). The first slot is intentionally empty * (top padding = --chrome-row-height) so the chrome row reads as * pure header chrome next to the panel title. */ padding: var(--chrome-row-height) 0 0; gap: 0; /* The full-height vertical border (between icon strip and panel * content) is drawn via border-left / border-right per side below. * The ::after pseudo continues the chrome-row split horizontally * across the icon column so the header/body divider is unbroken * from outer panel edge to outer panel edge. */ position: relative; } /* Left panel: vertical separator on the inner edge (between icon strip * and the panel content to its left, since the icon strip sits on the * right of a row-reverse flex). */ .sidebar-view-container[data-side="left"] .sidebar-view-tabs { border-left: 1px solid var(--border-color); } /* Right panel: vertical separator on the inner edge. */ .sidebar-view-container[data-side="right"] .sidebar-view-tabs { border-right: 1px solid var(--border-color); } /* Horizontal segment of the chrome-row split, drawn across the icon * column so the header/body divider continues without a gap. * * Positioned at `top: calc(--chrome-row-height - 1px)` so the 1px-tall * pseudo sits at the same paint coordinates as the bottom 1px of * .sidebar-view-header (whose `border-bottom` is drawn inside its * --chrome-row-height box). Avoids `transform: translateY(...)` to * keep the divider in the same rendering pass as the border-bottom — * transformed elements get a separate compositor layer and can drift * by a subpixel at non-integer zoom levels. */ .sidebar-view-tabs::after { content: ''; position: absolute; left: 0; right: 0; top: calc(var(--chrome-row-height) - 1px); height: 1px; background-color: var(--border-color); pointer-events: none; } .sidebar-view-tab { display: flex; align-items: center; justify-content: center; /* Fill the full column width; height stays at --icon-tap-size so each * button is a square block flush with the next. No border-radius — * the selected/hover overlay fills the entire column edge to edge, * matching the rectilinear feel of the chrome row and tab bar. */ width: 100%; height: var(--icon-tap-size); padding: 0; color: var(--text-tertiary); background: none; border: none; border-radius: 0; cursor: pointer; transition: color 0.15s, background-color 0.15s; } .sidebar-view-tab:hover { color: var(--text-secondary); background-color: var(--bg-hover); } .sidebar-view-tab[aria-selected="true"] { color: var(--text-primary); background-color: var(--bg-active); } /* Icon sizing inside tabs */ .sidebar-view-tab .tab-icon svg, .sidebar-view-tab .tab-icon .lucide { width: 1.125rem; height: 1.125rem; } .sidebar-view-tab .tab-icon-fallback { font-size: 0.75rem; font-weight: 600; line-height: 1; text-transform: uppercase; } /* Content panel fills remaining space. Stacks the unified chrome row * (--chrome-row-height) on top of the leaf body. */ .sidebar-view-panel { flex: 1; display: flex; flex-direction: column; overflow: hidden; min-width: 0; } /* Unified chrome row — same height as the central TabBar, so the bottom * borders line up horizontally across the entire .app-shell-body. */ .sidebar-view-header { display: flex; align-items: center; justify-content: space-between; gap: 0.5rem; height: var(--chrome-row-height); flex-shrink: 0; padding: 0 0.5rem 0 0.75rem; background-color: var(--bg-secondary); border-bottom: 1px solid var(--border-color); } .sidebar-view-header__title { flex: 1; min-width: 0; font-size: 0.6875rem; font-weight: 600; letter-spacing: 0.05em; text-transform: uppercase; color: var(--text-tertiary); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } .sidebar-view-header__actions { display: flex; align-items: center; gap: 0.125rem; flex-shrink: 0; } /* DOM portal slot for Obsidian-compat ItemView.addAction() buttons. * The reparenting effect in SidebarViewContainer moves