From b7fc36cf3cfcc57856e55d46c9f842da7d5cf5ea Mon Sep 17 00:00:00 2001 From: Brooklyn Nicholson Date: Mon, 27 Jul 2026 21:28:00 -0500 Subject: [PATCH] feat(desktop): strip the header chrome off markdown code blocks MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A fenced block carried a bordered card with a "Code · " title row and a pinned copy button, which read as an attached artifact next to the reply. Drop the border and the header: the block is now a tinted slab on --ui-bg-editor with syntax highlighting and a copy button that reveals on hover. The streaming glow moves entirely to box-shadow since there is no border left to animate. --- .../desktop/src/components/chat/code-card.tsx | 42 +++--------------- .../src/components/chat/shiki-highlighter.tsx | 43 ++++++------------- apps/desktop/src/styles.css | 4 -- 3 files changed, 20 insertions(+), 69 deletions(-) diff --git a/apps/desktop/src/components/chat/code-card.tsx b/apps/desktop/src/components/chat/code-card.tsx index 0481951b433..6a5881165d2 100644 --- a/apps/desktop/src/components/chat/code-card.tsx +++ b/apps/desktop/src/components/chat/code-card.tsx @@ -4,15 +4,16 @@ import { Codicon, type CodiconProps } from '@/components/ui/codicon' import { cn } from '@/lib/utils' /** - * Rounded-card shell for fenced code (and any equivalent: diffs, raw payloads, - * etc.) sized for the conversation column. Mirrors the expanded tool-row - * pattern so code blocks read as the same family of artifact. + * Rounded surface for fenced code (and any equivalent: diffs, raw payloads, + * etc.) sized for the conversation column. Background only — no border, no + * header, no language label — so a code block reads as a tinted slab of the + * reply rather than an attached artifact. */ function CodeCard({ className, ...props }: React.ComponentProps<'div'>) { return (
) { ) } -function CodeCardHeader({ className, ...props }: React.ComponentProps<'div'>) { - return ( -
- ) -} - -function CodeCardTitle({ className, children, ...props }: React.ComponentProps<'span'>) { - return ( - - {children} - - ) -} - function CodeCardIcon({ className, ...props }: CodiconProps) { return ( ) { - return ( - - ) -} - function CodeCardBody({ className, ...props }: React.ComponentProps<'div'>) { return (
) { ) } -export { CodeCard, CodeCardBody, CodeCardHeader, CodeCardIcon, CodeCardSubtitle, CodeCardTitle } +export { CodeCard, CodeCardBody, CodeCardIcon } diff --git a/apps/desktop/src/components/chat/shiki-highlighter.tsx b/apps/desktop/src/components/chat/shiki-highlighter.tsx index ba59a31da89..6823bba7cfd 100644 --- a/apps/desktop/src/components/chat/shiki-highlighter.tsx +++ b/apps/desktop/src/components/chat/shiki-highlighter.tsx @@ -4,24 +4,18 @@ import type { SyntaxHighlighterProps } from '@assistant-ui/react-streamdown' import { type ComponentProps, type FC, lazy, Suspense, useMemo } from 'react' import type ShikiHighlighter from 'react-shiki' -import { - CodeCard, - CodeCardBody, - CodeCardHeader, - CodeCardIcon, - CodeCardSubtitle, - CodeCardTitle -} from '@/components/chat/code-card' +import { CodeCard, CodeCardBody } from '@/components/chat/code-card' import { ExpandableBlock } from '@/components/chat/expandable-block' import { CopyButton } from '@/components/ui/copy-button' import { useI18n } from '@/i18n' -import { codiconForLanguage, isLikelyProseCodeBlock, sanitizeLanguageTag } from '@/lib/markdown-code' +import { isLikelyProseCodeBlock } from '@/lib/markdown-code' /** * Streamdown's code adapter renders header + body as inline siblings, so we * own the wrapping `` here and neutralize the upstream - * `data-streamdown="code-block"` chrome from styles.css. Anything that wants - * a card-shaped code surface should compose `CodeCard*` directly. + * `data-streamdown="code-block"` chrome from styles.css. The card is + * background-only — no header row, no language label — so a fence reads as a + * tinted slab of the reply; copy is a hover-reveal control in the corner. * * `react-shiki` full bundle so all `bundledLanguages` work; theme switches * follow the document `color-scheme` via `defaultColor="light-dark()"`. @@ -148,28 +142,19 @@ export const SyntaxHighlighter: FC = ({ return
{trimmed}
} - const cleanLanguage = sanitizeLanguageTag(language || '') - const label = cleanLanguage && cleanLanguage !== 'unknown' ? cleanLanguage : '' const plain = defer || exceedsHighlightBudget(trimmed) return ( - - - - {t.assistant.tool.code} - {label && · {label}} - - - - + +
             {plain ? (
diff --git a/apps/desktop/src/styles.css b/apps/desktop/src/styles.css
index 541da35b6bc..76579e42fd3 100644
--- a/apps/desktop/src/styles.css
+++ b/apps/desktop/src/styles.css
@@ -1356,7 +1356,6 @@ text-* variant utilities. */ .btn-arc {
   margin-block: var(--paragraph-gap) 0;
   position: relative;
   transition:
-    border-color 180ms ease-out,
     box-shadow 180ms ease-out,
     background-color 180ms ease-out;
 }
@@ -1365,7 +1364,6 @@ text-* variant utilities. */ .btn-arc {
   animation:
     code-card-stream-enter 180ms cubic-bezier(0.16, 1, 0.3, 1) both,
     code-card-stream-glow 1.8s ease-in-out 180ms infinite alternate;
-  border-color: color-mix(in srgb, var(--dt-ring) 24%, var(--ui-stroke-tertiary));
   box-shadow:
     0 0 0 0.0625rem color-mix(in srgb, var(--dt-ring) 10%, transparent),
     0 0.625rem 1.75rem color-mix(in srgb, var(--dt-ring) 8%, transparent);
@@ -1678,14 +1676,12 @@ text-* variant utilities. */ .btn-arc {
 
 @keyframes code-card-stream-glow {
   from {
-    border-color: color-mix(in srgb, var(--dt-ring) 18%, var(--ui-stroke-tertiary));
     box-shadow:
       0 0 0 0.0625rem color-mix(in srgb, var(--dt-ring) 6%, transparent),
       0 0.5rem 1.5rem color-mix(in srgb, var(--dt-ring) 5%, transparent);
   }
 
   to {
-    border-color: color-mix(in srgb, var(--dt-ring) 32%, var(--ui-stroke-tertiary));
     box-shadow:
       0 0 0 0.0625rem color-mix(in srgb, var(--dt-ring) 12%, transparent),
       0 0.75rem 2rem color-mix(in srgb, var(--dt-ring) 10%, transparent);