From c2423f8873c227247762b91aa6b8838edb597c53 Mon Sep 17 00:00:00 2001 From: ZDDC Date: Fri, 15 May 2026 16:40:41 -0500 Subject: [PATCH] feat(browse): make virtual tree rows visually distinct MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Folders the cascade declares but disk doesn't carry (working/, staging/, reviewing/, mdl/, the canonical folders before they're materialised) previously got just opacity:0.65 + an "(empty)" hint — easy to miss, especially next to dimmed-but-real items. Now they read as placeholders at a glance: - Dashed left rail (2px, accent-muted) inside the row gutter. - Italic label in muted text color. - Lucide icon switches to outline-only (fill:none + stroke:currentColor) so virtual folders look sketched, not filled. - "(empty)" hint italic + accent-muted to match the rail. - Selected virtual row keeps the rail but switches it to the selection accent so "selected + placeholder" reads as both. Co-Authored-By: Claude Opus 4.7 (1M context) --- browse/css/tree.css | 51 +++++++++++++++++++++++++++++++++++++-------- 1 file changed, 42 insertions(+), 9 deletions(-) diff --git a/browse/css/tree.css b/browse/css/tree.css index 9c6d912..28051d3 100644 --- a/browse/css/tree.css +++ b/browse/css/tree.css @@ -496,19 +496,52 @@ body { word-break: break-all; } -/* Virtual rows: synthesized client-side for folders that aren't on - disk yet (canonical project folders). Rendered muted so the user - reads them as "available but empty" rather than ordinary entries. - Hover/select states still apply; the hint sits to the right of the - label. */ -.tree-row--virtual .tree-name__icon, -.tree-row--virtual .tree-name__label { - opacity: 0.65; +/* Virtual rows: synthesized for folders/files declared by the + cascade but absent from disk. The visual language reads as + "expected, not yet materialized" — italic label, muted accent + color, dashed left rail, and an outlined icon. Hover/select + chrome still applies on top; the dashed rail sits inside the row + so it doesn't fight padding-left indentation. */ +.tree-row--virtual { + box-shadow: inset 2px 0 0 0 transparent; + position: relative; } +.tree-row--virtual::before { + content: ''; + position: absolute; + top: 4px; + bottom: 4px; + left: 2px; + border-left: 2px dashed var(--accent-muted, #8aa4cc); + pointer-events: none; +} +.tree-row--virtual .tree-name__label { + font-style: italic; + color: var(--text-muted, #6b7280); +} +.tree-row--virtual .tree-name__icon { + /* Hollow out the filled Lucide glyph: reduce fill opacity so + the icon reads as an outline-only sketch — the conventional + "placeholder, not actual" cue across UI systems. */ + opacity: 0.5; +} +.tree-row--virtual .tree-name__icon svg { + fill: none; + stroke: currentColor; + stroke-width: 1.5; + stroke-linecap: round; + stroke-linejoin: round; +} +.tree-row--virtual.is-selected::before { + /* Selected virtual row: rail brightens to selection accent so the + row reads as both selected and placeholder. */ + border-left-color: var(--accent, #2868c8); +} + .tree-name__hint { margin-left: 0.5rem; font-size: 0.78rem; - color: var(--text-muted); + color: var(--accent-muted, #8aa4cc); font-style: italic; }