🌗 fix: Keep Code Block Header Visible in User Messages (#14856)

* fix: Keep Code Block Chrome Visible on the User Message Bubble

The code bar dropped its background in dark mode and inherited whatever
sat behind it. That works on the chat background, but a user message
bubble is surface-tertiary, which resolves to the same gray-700 as the
code block's border-light outline, so both the header bar and the
outline disappeared into the bubble and only the code body showed.

Paint the bar with surface-secondary instead. It resolves to the same
value as the old pair on the chat background (gray-50 in light,
gray-800 in dark, matching the presentation background), so assistant
messages are unchanged, while the bar keeps a surface of its own inside
the bubble. The execution output panel used the same pattern and gets
the same treatment.

* fix: Derive the Code Block Surface So Custom Themes Keep Their Colors

Painting the code bar with surface-secondary only reproduced the old
appearance because the built-in themes happen to give surface-secondary,
surface-primary-alt and presentation coinciding values. A custom theme
sets those three independently, so the bar could shift on the chat
background where nothing was meant to change.

Add a surface-code role that derives from whatever the bar used to show:
surface-primary-alt in light, where the bar was already opaque, and
presentation in dark, which is exactly what the transparent bar
inherited. Every theme therefore renders the bar as before on the chat
background, while the bubble no longer bleeds through it.

Give ResultSwitcher the same surface. It had no background of its own,
so once the output panel above it gained one it became a detached band
of bubble color, the same defect one element lower.

* fix: Scope the Opaque Code Surface to User Message Bubbles

CodeBar renders on more than the chat background. The terms dialog and
the subagent panel put MarkdownLite on surface-dialog and
surface-primary, and dark:bg-transparent was what let the bar sit on any
of them. Painting it unconditionally gave those surfaces a header that
contrasts with their own background.

Restore the original declarations and scope the opaque role with a
.user-turn ancestor selector, which MessageRow and SteerPart both
already set, so every user bubble is covered without threading context
through react-markdown. Outside a user bubble the classes are byte for
byte what they were, so no other surface and no custom theme can drift.
This commit is contained in:
Marco Beretta 2026-08-15 05:39:02 +02:00 committed by GitHub
parent 530a935a74
commit 8d99fd16fc
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 6 additions and 3 deletions

View file

@ -13,7 +13,7 @@ const CodeBar: React.FC<CodeBarProps> = React.memo(
const { isCopied, handleCopy } = useCopyCode(codeRef);
return (
<div className="flex items-center justify-between bg-surface-primary-alt px-1.5 py-1.5 font-sans text-xs text-text-secondary dark:bg-transparent">
<div className="flex items-center justify-between bg-surface-primary-alt px-1.5 py-1.5 font-sans text-xs text-text-secondary dark:bg-transparent [.user-turn_&]:bg-surface-code">
<span className="flex items-center gap-1.5 text-xs font-medium">
<LangIcon lang={lang} className="size-3.5" />
{lang}

View file

@ -140,7 +140,7 @@ const CodeBlock: React.FC<CodeBlockProps> = ({
/>
{allowExecution === true && toolCalls && toolCalls.length > 0 && (
<>
<div className="border-t border-border-light bg-surface-primary-alt p-4 text-xs dark:bg-transparent">
<div className="border-t border-border-light bg-surface-primary-alt p-4 text-xs dark:bg-transparent [.user-turn_&]:bg-surface-code">
<div className="mb-1 text-[10px] font-medium uppercase tracking-wide text-text-secondary">
{localize('com_ui_output')}
</div>

View file

@ -26,7 +26,7 @@ export default function ResultSwitcher({
return (
<nav
aria-label={localize('com_ui_navigate_results')}
className="flex items-center justify-center gap-1.5 border-t border-border-light px-3 py-1.5 text-xs"
className="flex items-center justify-center gap-1.5 border-t border-border-light px-3 py-1.5 text-xs [.user-turn_&]:bg-surface-code"
>
<button
type="button"

View file

@ -183,6 +183,7 @@ html {
--surface-destructive: var(--red-700);
--surface-destructive-hover: var(--red-800);
--surface-chat: var(--white);
--surface-code: var(--surface-primary-alt);
--surface-qr: var(--white);
--border-light: var(--gray-200);
--border-light-alpha: 1;
@ -280,6 +281,7 @@ html {
--surface-destructive: var(--red-800);
--surface-destructive-hover: var(--red-900);
--surface-chat: var(--gray-700);
--surface-code: var(--presentation);
--surface-qr: var(--white);
--border-light: var(--gray-700);
--border-medium-alt: var(--gray-600);

View file

@ -104,6 +104,7 @@ function createTailwindColors() {
'surface-destructive': cssVar('--surface-destructive'),
'surface-destructive-hover': cssVar('--surface-destructive-hover'),
'surface-chat': cssVar('--surface-chat'),
'surface-code': cssVar('--surface-code'),
'surface-qr': cssVar('--surface-qr'),
'surface-inverted': cssVar('--surface-inverted'),
'surface-inverted-hover': cssVar('--surface-inverted-hover'),