Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
e2657b9
Add chat contrast and terminal interface matching
brennanb2025 Oct 5, 2026
644dabf
Fix matching chat palettes and contrast controls
brennanb2025 Oct 5, 2026
ecda8bd
Verify rebased appearance settings and preserve slider focus
brennanb2025 Oct 5, 2026
c96ae45
Memoize chat appearance and narrow settings subscriptions
brennanb2025 Oct 5, 2026
ad1f3a6
Wrap native chat tool-run summaries in the terminal font
brennanb2025 Oct 5, 2026
6c679e9
Use the matched chat foreground for inherited controls
brennanb2025 Oct 5, 2026
7948d26
fix(native-chat): bound collapsed tool summaries
brennanb2025 Oct 5, 2026
7261be0
Restore code foreground token for matched chat themes
brennanb2025 Oct 6, 2026
17cc304
Reset all chat appearance controls through serialized writer
brennanb2025 Oct 6, 2026
2864697
Make terminal matching control chat size and contrast
brennanb2025 Oct 6, 2026
1b6a7a6
Verify terminal match controls on Chat settings page
brennanb2025 Oct 6, 2026
8dd4bca
Share native chat appearance store selection
brennanb2025 Oct 6, 2026
9fcd774
Align matched chat palette test with full-strength foreground
brennanb2025 Oct 6, 2026
586ea47
Merge remote-tracking branch 'origin/main' into brennanb2025/native-c…
brennanb2025 Oct 6, 2026
b8dd211
Keep tool-run header marks on the summary's first line
brennanb2025 Oct 6, 2026
04518c1
Explain terminal-matched chat controls on hover
brennanb2025 Oct 6, 2026
1367e14
Name the tool-run alignment test case by summary length
brennanb2025 Oct 6, 2026
7562c8b
Merge remote-tracking branch 'origin/main' into brennanb2025/native-c…
brennanb2025 Oct 6, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
211 changes: 144 additions & 67 deletions src/renderer/src/assets/main.css
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@
unicode-range: U+E000-F8FF, U+F0000-FFFFD, U+100000-10FFFD;
}

@custom-variant dark (&:is(.dark *));
/* A matching chat can use a different scheme from the document; portaled menus stay outside it. */
@custom-variant dark (&:is(.dark *:not(:where([data-native-chat-scheme='light'], [data-native-chat-scheme='light'] *)), [data-native-chat-scheme='dark'], [data-native-chat-scheme='dark'] *));

/* Why: hover-reveal controls (sidebar/row action buttons) hide with `opacity-0`
and fade in via `group-hover`. Touch devices have no hover, so those controls
Expand Down Expand Up @@ -173,19 +174,20 @@
--background: #fff;
--editor-surface: #ffffff;
--foreground: #0a0a0a;
--chat-canvas: var(--background);
--chat-foreground: color-mix(in srgb, var(--foreground) 82%, var(--chat-canvas));
--chat-foreground-strong: color-mix(in srgb, var(--foreground) 92%, var(--chat-canvas));
--chat-foreground-faint: var(--muted-foreground);
--chat-user-surface: color-mix(in srgb, var(--foreground) 4%, var(--chat-canvas));
--chat-user-border: color-mix(in srgb, var(--foreground) 7%, transparent);
--chat-code-foreground: color-mix(in srgb, var(--foreground) 85%, var(--chat-canvas));
--chat-code-surface: color-mix(in srgb, var(--foreground) 2%, var(--chat-canvas));
--chat-code-border: color-mix(in srgb, var(--foreground) 7%, transparent);
--chat-inline-code-surface: color-mix(in srgb, var(--foreground) 4%, var(--chat-canvas));
--chat-inline-code-border: color-mix(in srgb, var(--foreground) 9%, transparent);
--chat-composer-surface: var(--chat-canvas);
--chat-composer-border: color-mix(in srgb, var(--foreground) 11%, transparent);
--chat-canvas-mix: 0%;
--chat-foreground-mix: 82%;
--chat-strong-mix: 92%;
--chat-faint-mix: 100%;
--chat-user-mix: 4%;
--chat-user-border-mix: 7%;
--chat-code-mix: 2%;
--chat-code-base: var(--chat-canvas);
--chat-inline-code-mix: 4%;
--chat-inline-code-base: var(--chat-canvas);
--chat-inline-code-border-mix: 9%;
--chat-composer-mix: 0%;
--chat-composer-base: var(--chat-canvas);
--chat-composer-border-mix: 11%;
--chat-content-max-width: 46rem;
--card: #fff;
--card-foreground: #0a0a0a;
Expand All @@ -199,8 +201,6 @@
--muted-foreground: #737373;
--accent: #f5f5f5;
--accent-foreground: #171717;
--destructive: #e40014;
--destructive-foreground: #fcf3f3;
--border: #e5e5e5;
--input: #e5e5e5;
--ring: #a1a1a1;
Expand All @@ -212,14 +212,6 @@
--agent-question: var(--color-orange-600);
/* Legible weight for text/glyphs on a tinted --agent-question surface. */
--agent-question-text: var(--color-orange-700);
--status-success: #15803d;
--status-success-background: color-mix(in srgb, var(--status-success) 10%, transparent);
--status-success-border: color-mix(in srgb, var(--status-success) 25%, transparent);
/* Needs-attention state that is not an error: a resume that did not carry on, an update that
failed. Yellow, so it stays apart from destructive red and from the orange working state. */
--status-warning: #ca8a04;
--status-warning-background: color-mix(in srgb, var(--status-warning) 10%, transparent);
--status-warning-border: color-mix(in srgb, var(--status-warning) 25%, transparent);
/* Workspace PR-state tones: same hue in both themes so a status keeps its
identity when the theme flips. */
--workspace-status-done: #c7a594;
Expand Down Expand Up @@ -258,17 +250,6 @@
--terminal-pane-title-on-light-button-hover-fg: rgb(24 24 27);
--terminal-pane-title-on-light-input-bg: rgb(24 24 27 / 0.05);
--terminal-pane-title-on-light-separator: rgb(24 24 27 / 0.1);
--git-decoration-added: #587c0c;
--git-decoration-modified: #895503;
--git-decoration-deleted: #ad0707;
--git-decoration-renamed: #007acc;
--git-decoration-untracked: #007100;
--git-decoration-copied: #007acc;
--git-decoration-ignored: #8c8c8c;
--diff-added-ground: color-mix(in srgb, var(--git-decoration-added) 13%, transparent);
--diff-added-gutter: color-mix(in srgb, var(--git-decoration-added) 26%, transparent);
--diff-removed-ground: color-mix(in srgb, var(--git-decoration-deleted) 11%, transparent);
--diff-removed-gutter: color-mix(in srgb, var(--git-decoration-deleted) 22%, transparent);
--git-graph-ref: #007acc;
--git-graph-remote-ref: #b66dff;
--git-graph-base-ref: #ea5c00;
Expand Down Expand Up @@ -310,19 +291,20 @@
--background: #0a0a0a;
--editor-surface: #1e1e1e;
--foreground: #fafafa;
--chat-canvas: color-mix(in srgb, var(--foreground) 5%, var(--background));
--chat-foreground: color-mix(in srgb, var(--foreground) 78%, var(--chat-canvas));
--chat-foreground-strong: color-mix(in srgb, var(--foreground) 90%, var(--chat-canvas));
--chat-foreground-faint: color-mix(in srgb, var(--muted-foreground) 83%, var(--chat-canvas));
--chat-user-surface: color-mix(in srgb, var(--foreground) 7%, var(--chat-canvas));
--chat-user-border: color-mix(in srgb, var(--foreground) 6%, transparent);
--chat-code-foreground: color-mix(in srgb, var(--foreground) 85%, var(--chat-canvas));
--chat-code-surface: color-mix(in srgb, var(--foreground) 3.5%, transparent);
--chat-code-border: color-mix(in srgb, var(--foreground) 7%, transparent);
--chat-inline-code-surface: color-mix(in srgb, var(--foreground) 6%, transparent);
--chat-inline-code-border: color-mix(in srgb, var(--foreground) 8%, transparent);
--chat-composer-surface: color-mix(in srgb, var(--foreground) 4%, transparent);
--chat-composer-border: color-mix(in srgb, var(--foreground) 9%, transparent);
--chat-canvas-mix: 5%;
--chat-foreground-mix: 78%;
--chat-strong-mix: 90%;
--chat-faint-mix: 83%;
--chat-user-mix: 7%;
--chat-user-border-mix: 6%;
--chat-code-mix: 3.5%;
--chat-code-base: transparent;
--chat-inline-code-mix: 6%;
--chat-inline-code-base: transparent;
--chat-inline-code-border-mix: 8%;
--chat-composer-mix: 4%;
--chat-composer-base: transparent;
--chat-composer-border-mix: 9%;
--chat-content-max-width: 46rem;
--card: #171717;
--card-foreground: #fafafa;
Expand All @@ -336,21 +318,13 @@
--muted-foreground: #a1a1a1;
--accent: #404040;
--accent-foreground: #fafafa;
--destructive: #ff6568;
--destructive-foreground: #df2225;
--border: rgb(255 255 255 / 0.07);
--input: rgb(255 255 255 / 0.15);
--ring: #737373;
--terminal-pane-locate: var(--color-blue-400);
--ai-action-accent: var(--color-violet-400);
--agent-question: var(--color-orange-500);
--agent-question-text: var(--color-orange-300);
--status-success: #86efac;
--status-success-background: color-mix(in srgb, var(--status-success) 10%, transparent);
--status-success-border: color-mix(in srgb, var(--status-success) 25%, transparent);
--status-warning: #eab308;
--status-warning-background: color-mix(in srgb, var(--status-warning) 10%, transparent);
--status-warning-border: color-mix(in srgb, var(--status-warning) 25%, transparent);
--workspace-status-done: #c7a594;
--workspace-status-review: #16a34a;
--workspace-status-progress: #d4a300;
Expand Down Expand Up @@ -391,17 +365,6 @@
--terminal-pane-title-on-light-button-hover-fg: rgb(24 24 27);
--terminal-pane-title-on-light-input-bg: rgb(24 24 27 / 0.05);
--terminal-pane-title-on-light-separator: rgb(24 24 27 / 0.1);
--git-decoration-added: #81b88b;
--git-decoration-modified: #e2c08d;
--git-decoration-deleted: #c74e39;
--git-decoration-renamed: #73c991;
--git-decoration-untracked: #73c991;
--git-decoration-copied: #73c991;
--git-decoration-ignored: #6e6e6e;
--diff-added-ground: color-mix(in srgb, var(--git-decoration-added) 16%, transparent);
--diff-added-gutter: color-mix(in srgb, var(--git-decoration-added) 30%, transparent);
--diff-removed-ground: color-mix(in srgb, var(--git-decoration-deleted) 18%, transparent);
--diff-removed-gutter: color-mix(in srgb, var(--git-decoration-deleted) 32%, transparent);
--git-graph-ref: #3794ff;
--git-graph-remote-ref: #b66dff;
--git-graph-base-ref: #ea5c00;
Expand All @@ -418,6 +381,54 @@
--tab-group-split-divider-strong: #a1a1aa;
}

/* Status and diff colors follow the chat scheme without copying the app palette. */
:root,
.native-chat-appearance[data-native-chat-scheme='light'] {
--destructive: #e40014;
--destructive-foreground: #fcf3f3;
--status-success: #15803d;
--status-success-background: color-mix(in srgb, var(--status-success) 10%, transparent);
--status-success-border: color-mix(in srgb, var(--status-success) 25%, transparent);
/* Needs-attention states use yellow, separate from errors and working states. */
--status-warning: #ca8a04;
--status-warning-background: color-mix(in srgb, var(--status-warning) 10%, transparent);
--status-warning-border: color-mix(in srgb, var(--status-warning) 25%, transparent);
--git-decoration-added: #587c0c;
--git-decoration-modified: #895503;
--git-decoration-deleted: #ad0707;
--git-decoration-renamed: #007acc;
--git-decoration-untracked: #007100;
--git-decoration-copied: #007acc;
--git-decoration-ignored: #8c8c8c;
--diff-added-ground: color-mix(in srgb, var(--git-decoration-added) 13%, transparent);
--diff-added-gutter: color-mix(in srgb, var(--git-decoration-added) 26%, transparent);
--diff-removed-ground: color-mix(in srgb, var(--git-decoration-deleted) 11%, transparent);
--diff-removed-gutter: color-mix(in srgb, var(--git-decoration-deleted) 22%, transparent);
}

.dark,
.native-chat-appearance[data-native-chat-scheme='dark'] {
--destructive: #ff6568;
--destructive-foreground: #df2225;
--status-success: #86efac;
--status-success-background: color-mix(in srgb, var(--status-success) 10%, transparent);
--status-success-border: color-mix(in srgb, var(--status-success) 25%, transparent);
--status-warning: #eab308;
--status-warning-background: color-mix(in srgb, var(--status-warning) 10%, transparent);
--status-warning-border: color-mix(in srgb, var(--status-warning) 25%, transparent);
--git-decoration-added: #81b88b;
--git-decoration-modified: #e2c08d;
--git-decoration-deleted: #c74e39;
--git-decoration-renamed: #73c991;
--git-decoration-untracked: #73c991;
--git-decoration-copied: #73c991;
--git-decoration-ignored: #6e6e6e;
--diff-added-ground: color-mix(in srgb, var(--git-decoration-added) 16%, transparent);
--diff-added-gutter: color-mix(in srgb, var(--git-decoration-added) 30%, transparent);
--diff-removed-ground: color-mix(in srgb, var(--git-decoration-deleted) 18%, transparent);
--diff-removed-gutter: color-mix(in srgb, var(--git-decoration-deleted) 32%, transparent);
}

.plugin-security-chrome {
/* Why: plugin themes may style the app, but provenance and consent must
retain host-owned contrast so a pack cannot disguise a trust decision. */
Expand Down Expand Up @@ -529,6 +540,72 @@ body:has(> [data-slot='dialog-overlay'], > [data-slot='sheet-overlay']) {

/* ── Base Layer ──────────────────────────────────────── */

/* Re-evaluate chat colors where the appearance producer supplies their source colors. */
:root,
.dark,
.native-chat-appearance {
--chat-source-background: var(--background);
--chat-source-foreground: var(--foreground);
--chat-source-muted-foreground: var(--muted-foreground);
--chat-canvas: color-mix(
in srgb,
var(--chat-source-foreground) var(--chat-canvas-mix),
var(--chat-source-background)
);
--chat-foreground: color-mix(
in srgb,
var(--chat-source-foreground) var(--chat-foreground-mix),
var(--chat-canvas)
);
--chat-foreground-strong: color-mix(
in srgb,
var(--chat-source-foreground) var(--chat-strong-mix),
var(--chat-canvas)
);
--chat-foreground-faint: color-mix(
in srgb,
var(--chat-source-muted-foreground) var(--chat-faint-mix),
var(--chat-canvas)
);
--chat-user-surface: color-mix(
in srgb,
var(--chat-source-foreground) var(--chat-user-mix),
var(--chat-canvas)
);
--chat-user-border: color-mix(
in srgb,
var(--chat-source-foreground) var(--chat-user-border-mix),
transparent
);
--chat-code-foreground: color-mix(in srgb, var(--chat-source-foreground) 85%, var(--chat-canvas));
--chat-code-surface: color-mix(
in srgb,
var(--chat-source-foreground) var(--chat-code-mix),
var(--chat-code-base)
);
--chat-code-border: color-mix(in srgb, var(--chat-source-foreground) 7%, transparent);
--chat-inline-code-surface: color-mix(
in srgb,
var(--chat-source-foreground) var(--chat-inline-code-mix),
var(--chat-inline-code-base)
);
--chat-inline-code-border: color-mix(
in srgb,
var(--chat-source-foreground) var(--chat-inline-code-border-mix),
transparent
);
--chat-composer-surface: color-mix(
in srgb,
var(--chat-source-foreground) var(--chat-composer-mix),
var(--chat-composer-base)
);
--chat-composer-border: color-mix(
in srgb,
var(--chat-source-foreground) var(--chat-composer-border-mix),
transparent
);
}

@layer base {
*,
*::before,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
import { cn } from '@/lib/utils'
import {
NATIVE_CHAT_APPEARANCE_ROOT_CLASS,
useNativeChatAppearanceStyle
} from './native-chat-appearance-style'
import { NATIVE_CHAT_APPEARANCE_ROOT_CLASS } from './native-chat-appearance-style'
import { useNativeChatStoreAppearanceStyle } from './use-native-chat-store-appearance-style'
import { useCallback, useEffect, useMemo, useRef, useState } from 'react'
import { useNativeChatComposerRevealFocus } from './use-native-chat-composer-reveal-focus'
import { useAppStore } from '../../store'
Expand Down Expand Up @@ -327,8 +325,7 @@ export function NativeChatResolvedView({

// Only the focused conversation accepts chat text-size shortcuts.
useNativeChatFontSize(isConversation && isVisible && isFocusedGroup, rootRef)
const appearanceSettings = useAppStore((state) => state.settings?.nativeChatAppearance)
const appearanceStyle = useNativeChatAppearanceStyle({ nativeChatAppearance: appearanceSettings })
const appearanceStyle = useNativeChatStoreAppearanceStyle()

return (
<div
Expand Down Expand Up @@ -371,6 +368,7 @@ export function NativeChatResolvedView({
'flex h-full min-h-0 w-full flex-col focus:outline-none'
)}
style={appearanceStyle}
data-native-chat-scheme={appearanceStyle.colorScheme}
>
<div className="flex min-h-0 flex-1 flex-col">
{viewState.kind === 'loading' ? (
Expand Down
Loading
Loading