From f0c86dde12b1cc8ce05ad5a4141cdb77b0910043 Mon Sep 17 00:00:00 2001 From: Tajudeen Date: Wed, 22 Jul 2026 23:13:19 +0100 Subject: [PATCH] Phase 1 Sprint 2+3: design system tokens and composer a11y Activate cortex design-system classes for buttons and composer shell, make submit/stop theme-aware, and improve keyboard/ARIA coverage in the chat composer. Co-authored-by: Cursor --- package.json | 2 +- .../react/src/sidebar-tsx/SidebarChat.tsx | 35 ++-- .../sidebar-tsx/chat/UserMessageComponent.tsx | 40 ++--- .../sidebar-tsx/composer/ContextUsageBar.tsx | 51 ++++++ .../src/sidebar-tsx/composer/VoidChatArea.tsx | 29 ++-- .../sidebar-tsx/landing/SuggestedPrompts.tsx | 9 +- .../src/sidebar-tsx/tools/ToolHeader.tsx | 23 ++- .../cortexide/browser/react/src/styles.css | 154 +++++++++++++++--- .../test/common/designSystem.test.ts | 49 ++++++ 9 files changed, 305 insertions(+), 87 deletions(-) create mode 100644 src/vs/workbench/contrib/cortexide/browser/react/src/sidebar-tsx/composer/ContextUsageBar.tsx create mode 100644 src/vs/workbench/contrib/cortexide/test/common/designSystem.test.ts diff --git a/package.json b/package.json index 66cc2016108..b17406d217d 100644 --- a/package.json +++ b/package.json @@ -14,7 +14,7 @@ "test-browser": "npx playwright install && node test/unit/browser/index.js", "test-browser-no-install": "node test/unit/browser/index.js", "test-node": "mocha test/unit/node/index.js --delay --ui=tdd --timeout=5000 --exit", - "test-phase0-qa": "npm run test-node -- --runGlob \"**/cortexide/test/common/{providerSettingsValidation,onboardingHelpers,attachFileToChat,chatThreadStorageReviver,providerToolFormat,phase0ClaimVerification,modelCapabilities,menubarStackingFix}.test.js\"", + "test-phase0-qa": "npm run test-node -- --runGlob \"**/cortexide/test/common/{providerSettingsValidation,onboardingHelpers,attachFileToChat,chatThreadStorageReviver,providerToolFormat,phase0ClaimVerification,modelCapabilities,menubarStackingFix,designSystem}.test.js\"", "test-extension": "vscode-test", "test-build-scripts": "cd build && npm run test", "check-cyclic-dependencies": "node build/lib/checkCyclicDependencies.ts out", diff --git a/src/vs/workbench/contrib/cortexide/browser/react/src/sidebar-tsx/SidebarChat.tsx b/src/vs/workbench/contrib/cortexide/browser/react/src/sidebar-tsx/SidebarChat.tsx index 664ab756416..2f135cb3d55 100644 --- a/src/vs/workbench/contrib/cortexide/browser/react/src/sidebar-tsx/SidebarChat.tsx +++ b/src/vs/workbench/contrib/cortexide/browser/react/src/sidebar-tsx/SidebarChat.tsx @@ -17,6 +17,7 @@ import { PastThreadsList } from './SidebarThreadSelector.js'; import { VoidChatArea, ButtonSubmit, ButtonStop } from './composer/VoidChatArea.js'; import { SelectedFiles } from './composer/SelectedFiles.js'; import { ScrollToBottomContainer } from './composer/ScrollToBottomContainer.js'; +import { ContextUsageBar } from './composer/ContextUsageBar.js'; import { LandingPage } from './landing/LandingPage.js'; import { ComposerTabs } from './chrome/ComposerTabs.js'; import { ThreadHeader } from './chrome/ThreadHeader.js'; @@ -1164,17 +1165,12 @@ export const SidebarChat = () => { {/* Context usage indicator */} {modelSel ? ( - (() => { - const pctNum = Math.max(0, Math.min(100, Math.round(contextPct * 100))) - const color = contextPct >= 1 ? 'text-[var(--cortex-danger)]' : contextPct > 0.8 ? 'text-[var(--cortex-warning)]' : 'text-void-fg-3' - const barColor = contextPct >= 1 ? 'bg-[var(--cortex-danger)]' : contextPct > 0.8 ? 'bg-[var(--cortex-warning)]' : 'bg-void-fg-3/60' - return
-
Context ~{contextTotal} / {contextBudget} tokens ({pctNum}%)
-
-
-
-
- })() + ) : null}
@@ -1183,17 +1179,12 @@ export const SidebarChat = () => {
{inputChatArea} {modelSel ? ( - (() => { - const pctNum = Math.max(0, Math.min(100, Math.round(contextPct * 100))) - const color = contextPct >= 1 ? 'text-[var(--cortex-danger)]' : contextPct > 0.8 ? 'text-[var(--cortex-warning)]' : 'text-void-fg-3' - const barColor = contextPct >= 1 ? 'bg-[var(--cortex-danger)]' : contextPct > 0.8 ? 'bg-[var(--cortex-warning)]' : 'bg-void-fg-3/60' - return
-
Context ~{contextTotal} / {contextBudget} tokens ({pctNum}%)
-
-
-
-
- })() + ) : null}
diff --git a/src/vs/workbench/contrib/cortexide/browser/react/src/sidebar-tsx/chat/UserMessageComponent.tsx b/src/vs/workbench/contrib/cortexide/browser/react/src/sidebar-tsx/chat/UserMessageComponent.tsx index aebb967c09d..bf5a02f23ea 100644 --- a/src/vs/workbench/contrib/cortexide/browser/react/src/sidebar-tsx/chat/UserMessageComponent.tsx +++ b/src/vs/workbench/contrib/cortexide/browser/react/src/sidebar-tsx/chat/UserMessageComponent.tsx @@ -215,36 +215,36 @@ export const UserMessageComponent = ({ chatMessage, messageIdx, isCheckpointGhos onMouseEnter={() => setIsHovered(true)} onMouseLeave={() => setIsHovered(false)} > -
{ if (mode === 'display') { onOpenEdit() } }} - > - {chatbubbleContents} -
+ {mode === 'display' ? ( + + ) : ( +
+ {chatbubbleContents} +
+ )}
- { if (mode === 'display') { onOpenEdit() @@ -252,7 +252,9 @@ export const UserMessageComponent = ({ chatMessage, messageIdx, isCheckpointGhos onCloseEdit() } }} - /> + > +
diff --git a/src/vs/workbench/contrib/cortexide/browser/react/src/sidebar-tsx/composer/ContextUsageBar.tsx b/src/vs/workbench/contrib/cortexide/browser/react/src/sidebar-tsx/composer/ContextUsageBar.tsx new file mode 100644 index 00000000000..b889ed8114d --- /dev/null +++ b/src/vs/workbench/contrib/cortexide/browser/react/src/sidebar-tsx/composer/ContextUsageBar.tsx @@ -0,0 +1,51 @@ +/*-------------------------------------------------------------------------------------- + * Copyright 2025 Glass Devtools, Inc. All rights reserved. + * Licensed under the Apache License, Version 2.0. See LICENSE.txt for more information. + *--------------------------------------------------------------------------------------*/ + +import React, { useId } from 'react'; + +export type ContextUsageBarProps = { + contextTotal: number; + contextBudget: number; + contextPct: number; + className?: string; +}; + +export const ContextUsageBar = ({ + contextTotal, + contextBudget, + contextPct, + className = '', +}: ContextUsageBarProps) => { + const labelId = useId(); + const pctNum = Math.max(0, Math.min(100, Math.round(contextPct * 100))); + const color = contextPct >= 1 + ? 'text-[var(--cortex-danger)]' + : contextPct > 0.8 + ? 'text-[var(--cortex-warning)]' + : 'text-void-fg-3'; + const barColor = contextPct >= 1 + ? 'bg-[var(--cortex-danger)]' + : contextPct > 0.8 + ? 'bg-[var(--cortex-warning)]' + : 'bg-void-fg-3/60'; + + return ( +
+
+ Context ~{contextTotal} / {contextBudget} tokens ({pctNum}%) +
+
+
+
+
+ ); +}; diff --git a/src/vs/workbench/contrib/cortexide/browser/react/src/sidebar-tsx/composer/VoidChatArea.tsx b/src/vs/workbench/contrib/cortexide/browser/react/src/sidebar-tsx/composer/VoidChatArea.tsx index 13bb4daad81..6a0ae93f047 100644 --- a/src/vs/workbench/contrib/cortexide/browser/react/src/sidebar-tsx/composer/VoidChatArea.tsx +++ b/src/vs/workbench/contrib/cortexide/browser/react/src/sidebar-tsx/composer/VoidChatArea.tsx @@ -390,12 +390,10 @@ export const VoidChatArea: React.FC = ({ }} className={` gap-x-1 - flex flex-col p-2.5 relative input text-left shrink-0 + flex flex-col p-2.5 relative cortex-composer-shell text-left shrink-0 rounded-2xl - bg-[#030304] transition-all duration-200 - border border-[rgba(255,255,255,0.08)] focus-within:border-[rgba(255,255,255,0.12)] hover:border-[rgba(255,255,255,0.12)] - ${isDragOver ? 'border-blue-500 bg-blue-500/10' : ''} + ${isDragOver ? 'border-[var(--cortex-brand)] bg-[var(--cortex-brand-soft)]' : ''} max-h-[80vh] overflow-y-auto ${className} `} @@ -483,12 +481,19 @@ export const VoidChatArea: React.FC = ({ {/* Close button (X) if onClose is provided */} {onClose && ( -
- +
)}
@@ -524,8 +529,8 @@ export const ButtonSubmit = ({ className, disabled, ...props }: ButtonProps & Re return ))} ); diff --git a/src/vs/workbench/contrib/cortexide/browser/react/src/sidebar-tsx/tools/ToolHeader.tsx b/src/vs/workbench/contrib/cortexide/browser/react/src/sidebar-tsx/tools/ToolHeader.tsx index 45f9a9e6140..4062c794cd2 100644 --- a/src/vs/workbench/contrib/cortexide/browser/react/src/sidebar-tsx/tools/ToolHeader.tsx +++ b/src/vs/workbench/contrib/cortexide/browser/react/src/sidebar-tsx/tools/ToolHeader.tsx @@ -79,12 +79,22 @@ export const ToolHeaderWrapper = ({ {/* title eg "> Edited File" */}
{ if (isDropdown) { setIsOpen(v => !v); } if (onClick) { onClick(); } }} + onKeyDown={(e) => { + if (!isClickable) return; + if (e.key === 'Enter' || e.key === ' ') { + e.preventDefault(); + if (isDropdown) { setIsOpen(v => !v); } + if (onClick) { onClick(); } + } + }} > {isDropdown && ( {/* header */}
{ if (isDropdown) { setIsOpen(v => !v); } }} + onKeyDown={(e) => { + if (!isDropdown) return; + if (e.key === 'Enter' || e.key === ' ') { + e.preventDefault(); + setIsOpen(v => !v); + } + }} > {isDropdown && ( pattern.test(styles); + +suite('designSystem (Phase 1 Sprint 2 — composer tokens)', () => { + + test('.btn-primary uses cortex brand tokens', () => { + assert.ok( + hasRule(/\.void-scope\s+\.btn-primary\s*\{[^}]*background:\s*var\(--cortex-brand\)/s), + 'expected .void-scope .btn-primary to use --cortex-brand', + ); + }); + + test('.btn-submit is theme-aware (light override)', () => { + assert.ok( + hasRule(/body\.vscode-light\s+\.void-scope\s+\.btn-submit/s), + 'expected light-theme submit button override', + ); + }); + + test('.cortex-composer-shell uses cortex surface tokens', () => { + assert.ok( + hasRule(/\.void-scope\s+\.cortex-composer-shell\s*\{[^}]*background:\s*var\(--cortex-surface-2\)/s), + 'expected composer shell background token', + ); + }); + + test('.input uses cortex border tokens', () => { + assert.ok( + hasRule(/\.void-scope\s+\.input[^}]*border:\s*1px solid var\(--cortex-border-weak\)/s), + 'expected input border token', + ); + }); +});