fix(vscode): consolidate diff theme CSS variables into shared utility class

Extract duplicated Pierre diff CSS custom properties from multiple
stylesheets into a single shared `.kilo-diff-theme` class in
`webview-ui/src/styles/diff.css`. Apply the class to all diff container
elements (DiffPanel, FullScreenDiffView, DiffVirtualApp, PermissionDiff)
so hover overrides are consistently defined.

This fixes diff hover styling by adding the missing
`--diffs-bg-addition-hover-override` and
`--diffs-bg-deletion-hover-override` variables and eliminates ~130 lines
of duplicated CSS variable declarations across the codebase.
This commit is contained in:
Imanol Maiztegui
2026-05-05 17:22:42 +02:00
parent 490df21393
commit d49b5b005c
10 changed files with 67 additions and 135 deletions
@@ -61,9 +61,14 @@ describe("Agent Manager CSS Prefix", () => {
const matches = [...css.matchAll(/\.([a-z][a-z0-9-]*)/gi)]
const names = [...new Set(matches.map((m) => m[1]))]
// VS Code sets these body classes on webview elements — they are scoping
// selectors for high contrast theme support, not agent-manager classes.
const host = new Set(["vscode-high-contrast", "vscode-high-contrast-light"])
// Exceptions:
// - VS Code sets these body classes on webview elements (scoping
// selectors for high contrast theme support).
// - `kilo-diff-theme` is the shared Pierre diff theme utility defined
// in webview-ui/src/styles/diff.css and reused across webviews.
// - `css` is matched from `@import "./diff.css"` file extension, not a
// class selector.
const host = new Set(["vscode-high-contrast", "vscode-high-contrast-light", "kilo-diff-theme", "css"])
const invalid = names.filter((n) => !n!.startsWith("am-") && !host.has(n!))
expect(invalid, `Classes missing "am-" prefix: ${invalid.join(", ")}`).toEqual([])
@@ -327,7 +327,13 @@ export const DiffPanel: Component<DiffPanelProps> = (props) => {
}))
return (
<div class="am-diff-panel" onKeyDown={handleKeyDown} onMouseDown={handleRootMouseDown} tabIndex={-1} ref={rootRef}>
<div
class="am-diff-panel kilo-diff-theme"
onKeyDown={handleKeyDown}
onMouseDown={handleRootMouseDown}
tabIndex={-1}
ref={rootRef}
>
<div class="am-diff-header">
<div class="am-diff-header-main">
<span class="am-diff-header-title">{t("session.review.change.other")}</span>
@@ -403,7 +403,7 @@ export const FullScreenDiffView: Component<FullScreenDiffViewProps> = (props) =>
return (
<div
class="am-review-layout"
class="am-review-layout kilo-diff-theme"
onKeyDown={handleKeyDown}
onMouseDown={handleRootMouseDown}
tabIndex={-1}
@@ -24,39 +24,6 @@
min-height: 0;
min-width: 0;
--am-diff-count-size: 12px;
/* Inherit pierre diffs CSS vars from am-diff-panel */
--diffs-light-bg: var(--vscode-editor-background, #1e1e1e);
--diffs-dark-bg: var(--vscode-editor-background, #1e1e1e);
--diffs-bg-addition-override: color-mix(
in lab,
var(--vscode-editor-background, #1e1e1e) 82%,
var(--syntax-diff-add, #318430)
);
--diffs-bg-addition-number-override: color-mix(
in lab,
var(--vscode-editor-background, #1e1e1e) 72%,
var(--syntax-diff-add, #318430)
);
--diffs-bg-addition-emphasis-override: color-mix(
in lab,
var(--vscode-editor-background, #1e1e1e) 60%,
var(--syntax-diff-add, #318430)
);
--diffs-bg-deletion-override: color-mix(
in lab,
var(--vscode-editor-background, #1e1e1e) 82%,
var(--syntax-diff-delete, #da3319)
);
--diffs-bg-deletion-number-override: color-mix(
in lab,
var(--vscode-editor-background, #1e1e1e) 72%,
var(--syntax-diff-delete, #da3319)
);
--diffs-bg-deletion-emphasis-override: color-mix(
in lab,
var(--vscode-editor-background, #1e1e1e) 60%,
var(--syntax-diff-delete, #da3319)
);
}
/* Review toolbar */
@@ -1,3 +1,5 @@
@import "../src/styles/diff.css";
/* Agent Manager layout */
.am-layout {
@@ -1383,46 +1385,6 @@ body.am-wt-dragging-active * {
flex: 1;
width: 100%;
min-height: 0;
/* Pierre diffs needs --diffs-light-bg/--diffs-dark-bg for the color-mix()
calculations that produce red/green line backgrounds. Without a Shiki
worker pool these are never set by the theme layer, so we provide
fallbacks mapped to VS Code's editor background. */
--diffs-light-bg: var(--vscode-editor-background, #1e1e1e);
--diffs-dark-bg: var(--vscode-editor-background, #1e1e1e);
/* The unsafeCSS in @opencode-ai/ui uses 98%/92% mix ratios for line
backgrounds — only 2-8% tint, nearly invisible. Override via the
*-override custom properties that the unsafeCSS checks first.
These inherit across the Shadow DOM boundary. */
--diffs-bg-addition-override: color-mix(
in lab,
var(--vscode-editor-background, #1e1e1e) 82%,
var(--syntax-diff-add, #318430)
);
--diffs-bg-addition-number-override: color-mix(
in lab,
var(--vscode-editor-background, #1e1e1e) 72%,
var(--syntax-diff-add, #318430)
);
--diffs-bg-addition-emphasis-override: color-mix(
in lab,
var(--vscode-editor-background, #1e1e1e) 60%,
var(--syntax-diff-add, #318430)
);
--diffs-bg-deletion-override: color-mix(
in lab,
var(--vscode-editor-background, #1e1e1e) 82%,
var(--syntax-diff-delete, #da3319)
);
--diffs-bg-deletion-number-override: color-mix(
in lab,
var(--vscode-editor-background, #1e1e1e) 72%,
var(--syntax-diff-delete, #da3319)
);
--diffs-bg-deletion-emphasis-override: color-mix(
in lab,
var(--vscode-editor-background, #1e1e1e) 60%,
var(--syntax-diff-delete, #da3319)
);
--am-diff-count-size: 12px;
}
@@ -3308,39 +3270,6 @@ body.am-wt-dragging-active * {
min-height: 0;
min-width: 0;
--am-diff-count-size: 12px;
/* Inherit pierre diffs CSS vars from am-diff-panel */
--diffs-light-bg: var(--vscode-editor-background, #1e1e1e);
--diffs-dark-bg: var(--vscode-editor-background, #1e1e1e);
--diffs-bg-addition-override: color-mix(
in lab,
var(--vscode-editor-background, #1e1e1e) 82%,
var(--syntax-diff-add, #318430)
);
--diffs-bg-addition-number-override: color-mix(
in lab,
var(--vscode-editor-background, #1e1e1e) 72%,
var(--syntax-diff-add, #318430)
);
--diffs-bg-addition-emphasis-override: color-mix(
in lab,
var(--vscode-editor-background, #1e1e1e) 60%,
var(--syntax-diff-add, #318430)
);
--diffs-bg-deletion-override: color-mix(
in lab,
var(--vscode-editor-background, #1e1e1e) 82%,
var(--syntax-diff-delete, #da3319)
);
--diffs-bg-deletion-number-override: color-mix(
in lab,
var(--vscode-editor-background, #1e1e1e) 72%,
var(--syntax-diff-delete, #da3319)
);
--diffs-bg-deletion-emphasis-override: color-mix(
in lab,
var(--vscode-editor-background, #1e1e1e) 60%,
var(--syntax-diff-delete, #da3319)
);
}
/* Review toolbar */
@@ -75,7 +75,7 @@ const DiffVirtualContent: Component = () => {
})
return (
<div class="am-review-layout">
<div class="am-review-layout kilo-diff-theme">
<Show when={diff()}>
{(d) => (
<>
@@ -69,7 +69,7 @@ export const PermissionDiff: Component<PermissionDiffProps> = (props) => {
}
return (
<div data-slot="permission-diff">
<div data-slot="permission-diff" class="kilo-diff-theme">
<div data-slot="permission-diff-header">
<div data-slot="permission-diff-file-info">
<div data-slot="permission-diff-icon">
@@ -13,6 +13,7 @@
@import "./prompt-input.css";
@import "./prompt-dropdowns.css";
@import "./model-selector.css";
@import "./diff.css";
@import "./permission-dock.css";
@import "./dialogs.css";
@import "./history.css";
@@ -0,0 +1,46 @@
.kilo-diff-theme {
--diffs-light-bg: var(--vscode-editor-background, #1e1e1e);
--diffs-dark-bg: var(--vscode-editor-background, #1e1e1e);
--diffs-bg-addition-override: color-mix(
in lab,
var(--vscode-editor-background, #1e1e1e) 82%,
var(--syntax-diff-add, #318430)
);
--diffs-bg-addition-number-override: color-mix(
in lab,
var(--vscode-editor-background, #1e1e1e) 72%,
var(--syntax-diff-add, #318430)
);
--diffs-bg-addition-emphasis-override: color-mix(
in lab,
var(--vscode-editor-background, #1e1e1e) 60%,
var(--syntax-diff-add, #318430)
);
--diffs-bg-addition-hover-override: color-mix(
in lab,
var(--vscode-editor-background, #1e1e1e) 72%,
var(--syntax-diff-add, #318430)
);
--diffs-bg-deletion-override: color-mix(
in lab,
var(--vscode-editor-background, #1e1e1e) 82%,
var(--syntax-diff-delete, #da3319)
);
--diffs-bg-deletion-number-override: color-mix(
in lab,
var(--vscode-editor-background, #1e1e1e) 72%,
var(--syntax-diff-delete, #da3319)
);
--diffs-bg-deletion-emphasis-override: color-mix(
in lab,
var(--vscode-editor-background, #1e1e1e) 60%,
var(--syntax-diff-delete, #da3319)
);
--diffs-bg-deletion-hover-override: color-mix(
in lab,
var(--vscode-editor-background, #1e1e1e) 72%,
var(--syntax-diff-delete, #da3319)
);
}
@@ -124,30 +124,8 @@
border: 1px solid var(--border-weak-base);
border-radius: 4px;
overflow: hidden;
--diffs-light-bg: var(--vscode-editor-background, #1e1e1e);
--diffs-dark-bg: var(--vscode-editor-background, #1e1e1e);
--syntax-diff-add: #2ea043;
--syntax-diff-delete: #da3633;
--diffs-bg-deletion-override: color-mix(
in lab,
var(--vscode-editor-background, #1e1e1e) 82%,
var(--syntax-diff-delete, #da3633)
);
--diffs-bg-deletion-number-override: color-mix(
in lab,
var(--vscode-editor-background, #1e1e1e) 72%,
var(--syntax-diff-delete, #da3633)
);
--diffs-bg-addition-override: color-mix(
in lab,
var(--vscode-editor-background, #1e1e1e) 82%,
var(--syntax-diff-add, #2ea043)
);
--diffs-bg-addition-number-override: color-mix(
in lab,
var(--vscode-editor-background, #1e1e1e) 72%,
var(--syntax-diff-add, #2ea043)
);
}
[data-slot="permission-diff-header"] {