Skip to content
4 changes: 2 additions & 2 deletions .github/instructions/design-tokens.instructions.md
Original file line number Diff line number Diff line change
Expand Up @@ -168,8 +168,8 @@ to its `*Compact` variant (e.g. `Codicon.close` → `Codicon.closeCompact`) so t
icon is visually optimized for the small size. CSS `font-size` alone only scales
the icon — it does not change to the compact glyph. Only swap the glyph when no
CSS selector targets the original glyph class (e.g. `.codicon-close`), otherwise
update that selector too. Some icons (settings/sliders, agent, vm, info, lock,
plus) have no compact variant — keep the regular glyph at the compact size.
update that selector too. Some icons (agent, vm, info, lock) have no compact
variant — keep the regular glyph at the compact size.

## Stroke — border width

Expand Down
8 changes: 0 additions & 8 deletions src/vs/sessions/browser/parts/media/sessionsPart.css
Original file line number Diff line number Diff line change
Expand Up @@ -116,14 +116,6 @@
max-width: 150px;
}

.monaco-workbench .part.sessionspart .interactive-session .chat-input-toolbars > .chat-execute-toolbar .monaco-action-bar .action-item:has(> .action-label.codicon-arrow-up-compact) {
border-radius: var(--vscode-cornerRadius-small);
}

.monaco-workbench .part.sessionspart .interactive-session .chat-input-toolbars > .chat-execute-toolbar .monaco-action-bar .action-item > .action-label.codicon-arrow-up-compact {
border-radius: var(--vscode-cornerRadius-small);
}

/* Nudge icon position to ensure it looks optically aligned within the button */
.monaco-workbench .part.sessionspart .interactive-session .chat-input-toolbars > .chat-execute-toolbar .monaco-action-bar .action-item > .action-label.codicon-arrow-up-compact::before {
display: inline-block;
Expand Down
27 changes: 17 additions & 10 deletions src/vs/sessions/contrib/chat/browser/media/chatInput.css
Original file line number Diff line number Diff line change
Expand Up @@ -184,15 +184,18 @@
position: relative;
}

/* Match the send button's control tier (22×22, control radius) and the compact
/* Match the send button's control tier (22×22, fully rounded) and the compact
glyph size used by the pickers, so the voice controls, the dictation mic and
Send all read as one row. */
Send all read as one row. On their own these lose the segmented pill's
enclosure, so each carries the pill's border as a ring of its own — see the
matching rule in chat.css for the editor composer. */
.sessions-chat-voice-toolbar .monaco-action-bar .action-item > .action-label {
box-sizing: border-box;
width: 22px;
height: 22px;
justify-content: center;
border-radius: var(--vscode-cornerRadius-small);
border: var(--vscode-strokeThickness) solid var(--vscode-input-border, var(--vscode-editorWidget-border));
border-radius: var(--vscode-cornerRadius-circle);
font-size: var(--vscode-codiconFontSize-compact);
}

Expand Down Expand Up @@ -311,7 +314,8 @@
gap: 2px;
}

/* Send button - wraps a Button widget */
/* Send button - wraps a Button widget. Circular, matching the send button in the
editor chat composer (chat.css) and the Agents window's active chat. */
.sessions-chat-send-button {
display: flex;
align-items: center;
Expand All @@ -320,7 +324,7 @@
position: relative;
width: 22px;
height: 22px;
border-radius: var(--vscode-cornerRadius-small);
border-radius: var(--vscode-cornerRadius-circle);
}

.sessions-chat-send-button .monaco-button {
Expand All @@ -332,7 +336,7 @@
min-width: 22px;
padding: 0;
font-size: var(--vscode-codiconFontSize-compact);
border-radius: var(--vscode-cornerRadius-small);
border-radius: var(--vscode-cornerRadius-circle);
color: var(--vscode-icon-foreground);
background: transparent;
border: none;
Expand Down Expand Up @@ -449,10 +453,12 @@
}

.monaco-workbench .sessions-chat-attach-button .codicon[class*='codicon-'] {
font-size: 14px;
font-size: var(--vscode-codiconFontSize-compact);
}

/* Dictation (speech-to-text) mic button */
/* Dictation (speech-to-text) mic button. Same ringed circle as the voice
controls beside it, so the standalone mic reads as a single-cell version of
the segmented pill rather than a bare glyph. */
.sessions-chat-stt-button {
display: flex;
align-items: center;
Expand All @@ -461,11 +467,12 @@
width: 22px;
height: 22px;
flex-shrink: 0;
border-radius: var(--vscode-cornerRadius-small);
box-sizing: border-box;
border: var(--vscode-strokeThickness) solid var(--vscode-input-border, var(--vscode-editorWidget-border));
border-radius: var(--vscode-cornerRadius-circle);
cursor: pointer;
color: var(--vscode-icon-foreground);
background: transparent;
border: none;
outline: none;
}

Expand Down
2 changes: 1 addition & 1 deletion src/vs/sessions/contrib/chat/browser/newChatInput.ts
Original file line number Diff line number Diff line change
Expand Up @@ -771,7 +771,7 @@ export class NewChatInputWidget extends Disposable implements IHistoryNavigation
position: { hoverPosition: HoverPosition.BELOW },
appearance: { showPointer: true }
}));
dom.append(attachButton, renderIcon(Codicon.add));
dom.append(attachButton, renderIcon(Codicon.addCompact));
this._register(dom.addDisposableListener(attachButton, dom.EventType.CLICK, () => {
this._contextAttachments.showPicker(this.options.getContextFolderUri());
}));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -471,7 +471,7 @@ export class AttachContextAction extends Action2 {
super({
id: 'workbench.action.chat.attachContext',
title: localize2('workbench.action.chat.attachContext.label.2', "Add Context..."),
icon: Codicon.add,
icon: Codicon.addCompact,
category: CHAT_CATEGORY,
keybinding: {
when: ContextKeyExpr.and(ChatContextKeys.inChatInput, ChatContextKeys.location.isEqualTo(ChatAgentLocation.Chat)),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ export class ConfigureToolsAction extends Action2 {
super({
id: ConfigureToolsAction.ID,
title: localize('label', "Configure Tools..."),
icon: Codicon.settings,
icon: Codicon.settingsCompact,
f1: false,
category: CHAT_CATEGORY,
precondition: ChatContextKeys.chatModeKind.isEqualTo(ChatModeKind.Agent),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2683,11 +2683,11 @@ pane is first mounted. View switches inside the modal are not animated. */
* Hide chips from the embedded chat input's primary toolbar that don't fit
* the automation dialog's reduced surface:
* - "Configure Tools" (`workbench.action.chat.configureTools`,
* `.codicon-settings`) — tool selection is not relevant for a scheduled
* prompt.
* - "Add Context" (`workbench.action.chat.attachContext`, `.codicon-add`,
* the `+`) — the dialog doesn't support attachments; the prompt is the
* only payload sent at run time.
* `.codicon-settings-compact`) — tool selection is not relevant for a
* scheduled prompt.
* - "Add Context" (`workbench.action.chat.attachContext`,
* `.codicon-add-compact`, the `+`) — the dialog doesn't support
* attachments; the prompt is the only payload sent at run time.
* - "List MCP Servers" (`workbench.mcp.listServer`, `.codicon-server`) —
* MCP server management belongs in the live chat surface, not a one-off
* prompt definition.
Expand All @@ -2705,8 +2705,8 @@ pane is first mounted. View switches inside the modal are not animated. */
* will migrate to `newChatInput.ts`, which builds its own toolbars and never
* renders these `MenuId.ChatInput` chips at all.
*/
.automation-form-prompt-host .chat-input-toolbar .action-label.codicon-settings,
.automation-form-prompt-host .chat-input-toolbar .action-label.codicon-add,
.automation-form-prompt-host .chat-input-toolbar .action-label.codicon-settings-compact,
.automation-form-prompt-host .chat-input-toolbar .action-label.codicon-add-compact,
.automation-form-prompt-host .chat-input-toolbar .action-item.chat-mcp {
display: none;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,14 @@
--dictation-mic-glow-radius: var(--vscode-cornerRadius-circle);
}

/* Standalone dictation buttons are discs, so the glow has to be one too —
otherwise the light spills past the button's own edge. Covers the editor
chat toolbar and the Agents window composer's mic button. */
.chat-execute-toolbar .monaco-action-bar .action-item.dictation-mic-active,
.sessions-chat-stt-button.dictation-mic-active {
--dictation-mic-glow-radius: var(--vscode-cornerRadius-circle);
}

/* High-contrast themes replace the soft glow with a solid outline, which must
stay fully opaque to keep its contrast at low levels. */
.hc-black .dictation-mic-active::after,
Expand Down
59 changes: 36 additions & 23 deletions src/vs/workbench/contrib/chat/browser/widget/media/chat.css
Original file line number Diff line number Diff line change
Expand Up @@ -1293,7 +1293,7 @@ have to be updated for changes to the rules above, or to support more deeply nes

.interactive-session .chat-input-toolbars > .chat-execute-toolbar .monaco-action-bar .action-item.chat-submit-button {
position: relative;
border-radius: var(--vscode-cornerRadius-small);
border-radius: var(--vscode-cornerRadius-circle);
}

.interactive-session .chat-input-toolbars > .chat-execute-toolbar .monaco-action-bar .action-item.chat-submit-button > .action-label {
Expand All @@ -1302,9 +1302,9 @@ have to be updated for changes to the rules above, or to support more deeply nes
height: 22px;
justify-content: center;
font-size: var(--vscode-codiconFontSize-compact);
/* Keep the control corner radius in both states — the enabled rule below only
/* Keep the fully-rounded shape in both states — the enabled rule below only
adds the filled background, it shouldn't be what defines the shape. */
border-radius: var(--vscode-cornerRadius-small);
border-radius: var(--vscode-cornerRadius-circle);
transition: background-color 250ms ease, color 250ms ease;
}

Expand All @@ -1323,7 +1323,7 @@ have to be updated for changes to the rules above, or to support more deeply nes
.interactive-session .chat-input-toolbars > .chat-execute-toolbar .monaco-action-bar .action-item.chat-submit-button:not(.disabled):has(> .action-label:focus-visible) {
outline: 1px solid var(--vscode-focusBorder);
outline-offset: 1px;
border-radius: var(--vscode-cornerRadius-small);
border-radius: var(--vscode-cornerRadius-circle);
}

.interactive-session .chat-input-toolbars > .chat-execute-toolbar .monaco-action-bar .action-item.chat-submit-button > .action-label:focus,
Expand Down Expand Up @@ -2101,15 +2101,16 @@ have to be updated for changes to the rules above, or to support more deeply nes
}


/* Add context button icon sizing */
.interactive-session .chat-input-toolbar .action-item:has(.codicon-add) .action-label {
display: flex;
align-items: center;
/* Icon-only chips in the primary input toolbar (add context, configure tools,
MCP servers) all sit on the compact tier, so the row reads as one dense strip
of chrome instead of a 16px glyph towering over the 12px send / mic buttons
across the toolbar. The base action-bar rule gives these labels a fixed 16px
box with no inline centering, so a 12px glyph would otherwise sit flush left
inside it — center it explicitly. Scoped to labels that are *themselves*
codicons, so the text chips (mode / model pickers) keep their own type size. */
.monaco-workbench .interactive-session .chat-input-toolbar .monaco-action-bar .action-item > .action-label.codicon[class*='codicon-'] {
justify-content: center;
}

.interactive-session .chat-input-toolbar .action-item:has(.codicon-add) .codicon-add {
font-size: 14px;
font-size: var(--vscode-codiconFontSize-compact);
Comment thread
hawkticehurst marked this conversation as resolved.
}

.monaco-workbench .interactive-session .chat-input-toolbar .chat-input-picker-item .action-label .codicon-chevron-down,
Expand Down Expand Up @@ -4680,11 +4681,18 @@ have to be updated for changes to the rules above, or to support more deeply nes

/* Standalone dictation / Voice Mode buttons (shown when the segmented voice pill
isn't active). Give them the same control tier as the send button they sit
beside — a 22×22 surface with the control corner radius — and the compact 12px
glyph used by the agent / model pickers, so the mic group reads as one
consistent row in every state: dictation idle / recording / preparing /
connecting, and Voice Mode idle / connecting / listening / speaking /
disconnect. */
beside — a 22×22 surface with the compact 12px glyph used by the agent /
model pickers — so the mic group reads as one consistent row in every state:
dictation idle / recording / preparing / connecting, and Voice Mode idle /
connecting / listening / speaking / disconnect.

On their own they lose the segmented pill's enclosure, so each one carries a
circular outline of its own and reads as a single-cell version of it rather
than a bare glyph. The ring uses the pill's exact border declaration so the
two enclosures are indistinguishable when the UI swaps between them —
`input.border` is `null` outside high contrast and resolves to a soft
20%-alpha `editorWidget.border`, and in high contrast it resolves to
`contrastBorder` so the ring stays fully opaque there. */
.interactive-session .chat-input-toolbars > .chat-execute-toolbar .monaco-action-bar .action-item > .action-label.codicon-mic,
.interactive-session .chat-input-toolbars > .chat-execute-toolbar .monaco-action-bar .action-item > .action-label.codicon-mic-filled,
.interactive-session .chat-input-toolbars > .chat-execute-toolbar .monaco-action-bar .action-item > .action-label.codicon-mic-download-compact,
Expand All @@ -4695,7 +4703,8 @@ have to be updated for changes to the rules above, or to support more deeply nes
width: 22px;
height: 22px;
justify-content: center;
border-radius: var(--vscode-cornerRadius-small);
border: var(--vscode-strokeThickness) solid var(--vscode-input-border, var(--vscode-editorWidget-border));
border-radius: var(--vscode-cornerRadius-circle);
font-size: var(--vscode-codiconFontSize-compact);
}

Expand All @@ -4712,11 +4721,11 @@ have to be updated for changes to the rules above, or to support more deeply nes

/* Voice mode: blue when listening. The glow keeps the button's resting shape —
only its color and the pulse change between states, so the control never
morphs from a rounded square into a circle mid-session. */
morphs from a circle into a rounded square mid-session. */
.chat-input-container.voice-active.voice-listening .chat-input-toolbars .action-label.codicon-voice-mode-compact {
--chat-voice-icon-glow-color: rgba(88, 166, 255, 0.4);
color: var(--vscode-charts-blue, #58a6ff) !important;
border-radius: var(--vscode-cornerRadius-small);
border-radius: var(--vscode-cornerRadius-circle);
}

.monaco-workbench.monaco-enable-motion .chat-input-container.voice-active.voice-listening .chat-input-toolbars .action-label.codicon-voice-mode-compact {
Expand All @@ -4727,15 +4736,19 @@ have to be updated for changes to the rules above, or to support more deeply nes
.chat-input-container.voice-active.voice-speaking .chat-input-toolbars .action-label.codicon-voice-mode-compact {
--chat-voice-icon-glow-color: rgba(163, 113, 247, 0.4);
color: var(--vscode-charts-purple, #a371f7) !important;
border-radius: var(--vscode-cornerRadius-small);
border-radius: var(--vscode-cornerRadius-circle);
}

.monaco-workbench.monaco-enable-motion .chat-input-container.voice-active.voice-speaking .chat-input-toolbars .action-label.codicon-voice-mode-compact {
animation: chat-voice-icon-glow 1.4s ease-in-out infinite;
}

/* Voice mode: green disconnect button */
.chat-input-container .chat-input-toolbars .codicon-debug-disconnect-compact {
/* Voice mode: green disconnect button. This has to out-specify the blanket
`icon-foreground !important` rule that colors every toolbar codicon, so it
carries the full toolbar path rather than a short `.chat-input-container`
prefix — with equal `!important` the higher specificity wins, and the short
form silently lost the cascade and rendered grey. */
.interactive-session .chat-input-toolbars > .chat-execute-toolbar .monaco-action-bar .action-item > .action-label.codicon-debug-disconnect-compact {
color: var(--vscode-charts-green, #3fb950) !important;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -103,4 +103,15 @@ export default defineThemedFixtureGroup({ path: 'chat/input/' }, {
todos: sampleTodos,
})
}),
// Standalone dictation / Voice Mode controls, shown when the segmented voice
// pill isn't active. Each state changes part of the border / color / glow
// cascade, so they are covered individually.
VoiceDictationIdle: defineComponentFixture({ render: context => renderChatInput(context, { voiceControl: 'dictationIdle' }) }),
VoiceDictationRecording: defineComponentFixture({ render: context => renderChatInput(context, { voiceControl: 'dictationRecording' }) }),
VoiceDictationPreparing: defineComponentFixture({ render: context => renderChatInput(context, { voiceControl: 'dictationPreparing' }) }),
VoiceModeIdle: defineComponentFixture({ render: context => renderChatInput(context, { voiceControl: 'voiceIdle' }) }),
VoiceModeConnecting: defineComponentFixture({ render: context => renderChatInput(context, { voiceControl: 'voiceConnecting' }) }),
VoiceModeListening: defineComponentFixture({ render: context => renderChatInput(context, { voiceControl: 'voiceListening' }) }),
VoiceModeSpeaking: defineComponentFixture({ render: context => renderChatInput(context, { voiceControl: 'voiceSpeaking' }) }),
VoiceModeDisconnect: defineComponentFixture({ render: context => renderChatInput(context, { voiceControl: 'voiceDisconnect' }) }),
});
Loading
Loading