feat: track VS Code theme and modern chrome live in the log view - #894
Closed
lukecotter wants to merge 13 commits into
Closed
feat: track VS Code theme and modern chrome live in the log view#894lukecotter wants to merge 13 commits into
lukecotter wants to merge 13 commits into
Conversation
Read every appearance value through one semantic `--lana-*` token layer backed by the host's own `--vscode-cornerRadius-*`/`--vscode-spacing-*`/`--vscode-surface-*` registries, so a theme or appearance change re-themes the UI without reopening the panel and an external host only has to supply that set. Colors held in JS (canvas, Pixi, tooltips, metric strip) now refresh from a new ThemeObserver instead of being cached at init, without re-initialising the renderer. VS Code's modern floating-card chrome is not observable from inside a webview, so `AppConfig` resolves it and pushes `configChanged`. Detection matches a name pattern over the `workbench` config tree rather than the experiment's setting id — it has been renamed once already — and `lana.appearance.chrome` (`auto`/`cards`/`flat`) is the user-facing override.
…bview `lana.database.*` is private globalState, not a registered setting, so the merged settings tree has no `database` branch on any profile that never wrote one — every fresh install. `LogView.resolveConfig` then threw while filling in the column overrides, taking down both the `getConfig` reply and every `configChanged` push: the webview received no settings at all, leaving the Timeline on its skeleton while the log itself loaded fine. `getConfig` now seeds the shape `Config` promises, keeping any value a legacy `settings.json` still carries.
getVsCodeAPI() returns null outside a webview, and request() bailed with a bare return after registering its listener, so the promise never settled. Fail the caller instead.
subscribeSettings() replaces the getSettings() + onSettingsChanged() pair every consumer had to wire by hand, shares one window listener, and drops a late reply that a push already superseded. TimelineView also tracks the persisted palette so an unrelated config push cannot re-apply the stored theme over a non-persisted quick-pick preview.
A lana.timeline.legacy toggle now swaps the element out while the panel is open, so disconnectedCallback has to tear the Pixi app down or each toggle leaks a WebGL context and its ticker.
Opening a log lands apexLog and themeName in one update, and initializeTimeline already reads the current appearance, so the themeName branch is an else.
…kind pixiToCssHex duplicated tooltip-utils' hexToCSS, so FlameChart now calls the shared one and ColorUtils drops the copy. ThemeObserver's ThemeKind and getThemeKind() had no caller, and its listeners take no argument. Rides along in the same hunk: setEditorColors restores the focus-ring fallback for selectionHighlightBorder, which many themes leave transparent, so a live theme switch matches what the orchestrator applies at init.
The cache holds bucket density, not colors, and setColors already redraws from it. Dropping it forced a full re-bucket of every event on each theme change.
setColors walked a labelCache no writer ever filled, so the live labels kept the old color. It now re-tints labelPool, the real store, and the dead map is gone.
…ton colors Both var() references had lost their fallback, so a host that injects no --vscode-* painted the bar and the skeleton transparent.
…tokens OverflowList rebuilt the popover surface from --lana-* by hand; it now uses the shared --filter-popover-* recipe global.styles.ts already builds from the same tokens. Tokens with no consumer are removed.
The first paint showed flat chrome until the getConfig reply landed, so the chrome is stamped on the markup instead. Any of the ~250 workbench.* settings fires the config listener, so the push is skipped when the resolved payload is unchanged.
This was referenced Aug 1, 2026
Collaborator
Author
|
Split into four smaller PRs — this one did too many unrelated jobs at once to review.
#896, #897 and #898 are independent and can be reviewed in parallel. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The log view now tracks every VS Code appearance change live — color theme, high contrast, and the
modern/floating-panels chrome — without reopening the panel.
Why
retainContextWhenHidden, so it is neverre-created and never re-read config on its own.
extractEditorColors()ran only frominitializeTimeline(), and the legacy timeline cached its colors in module state at init.flat and read as foreign.
What changed
Token layer — new
log-viewer/src/styles/tokens.cssdefines a--lana-*set, each entryvar(--vscode-…, <literal fallback>), injected at document level so it inherits into every shadowroot.
components/panelTokens.tsand the literal radii/shadows inglobal.styles.tsfold into it.The literal fallback is also the standalone-host seam: one stylesheet overriding
--lana-*themesthe UI outside the extension host.
Appearance signal —
AppConfig.detectModernChrome()matches a name pattern over theworkbenchconfig tree rather than a setting id. The experiment has been renamed once already(
floatingPanels→modernUI), so a rename must not need a release; the walk catches theunregistered pre-rename key too. New
lana.appearance.chrome(auto|cards|flat) is theuser override.
LogViewwatcheslanaandworkbenchand pushesconfigChanged, skipping thepush when the resolved payload is unchanged. This is also what makes live
lana.timeline.*editsapply without a reopen.
Cards chrome —
:root[data-chrome='cards']switches--lana-panel-{gap,radius,border,divider,edge}.Flat keeps today's rules; each component still has exactly one rule, not a second copy.
Live re-theme — new
core/theme/ThemeObserver.tswatches the body classes and thedocumentElementstyle block the webview preload rewrites, coalesced into one rAF tick. Consumersre-read their colors and redraw in place — the Pixi app is never re-initialised, which would blow
the perf budget on large logs.
The webview cannot detect the modern chrome itself: measured over CDP, all 1005 injected
--vscode-*properties are identical in every toggle state. It has to arrive from the extension.Data palettes stay literal — the timeline category palettes and the metric-strip tier colors encode
meaning, not chrome.
Verification
tsc -b,eslintand jest (91 suites / 1271 tests) are green. Still to do before this leavesdraft: the visual pass in flat and cards chrome, in a light and a dark theme, on both stable and
Insiders.