From 5285598171dc1aee24cb73c68d6cdd1126675edf Mon Sep 17 00:00:00 2001 From: hellodk Date: Sun, 30 Aug 2026 19:27:10 +0530 Subject: [PATCH] refactor: use standard codicons for mode picker icons MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The chat mode picker (agent / ask / manual / plan / composer) rendered its mode glyphs with emoji (`⚙ 💬 🛡 📋 🎼`), which render inconsistently across platforms and clash with the theme's icon font used everywhere else in the webview. Each mode now maps to a standard VS Code codicon and is rendered through the existing `codicon()` helper, matching the rest of the UI. Closes #125 --- test/unit/webview/mode-icons.test.ts | 38 ++++++++++++++++++++++++++++ webview-ui/static/main.js | 37 +++++++++++++++++++-------- 2 files changed, 65 insertions(+), 10 deletions(-) create mode 100644 test/unit/webview/mode-icons.test.ts diff --git a/test/unit/webview/mode-icons.test.ts b/test/unit/webview/mode-icons.test.ts new file mode 100644 index 0000000..2ccaa81 --- /dev/null +++ b/test/unit/webview/mode-icons.test.ts @@ -0,0 +1,38 @@ +import { describe, it, expect } from "vitest"; +import { readFileSync } from "node:fs"; +import path from "node:path"; + +/** + * The chat UI's mode picker (agent / ask / manual / plan / composer) must + * use standard VS Code codicon glyphs, not emoji. Emoji render differently + * across platforms and never match the editor theme's icon font. + */ +const ROOT = path.resolve(__dirname, "../../.."); +const MAIN_JS = readFileSync( + path.join(ROOT, "webview-ui/static/main.js"), + "utf8", +); + +const MODE_SECTION = MAIN_JS.slice( + MAIN_JS.indexOf("const modeIcons"), + MAIN_JS.indexOf("const modeDescs"), +); + +describe("mode picker icons use standard codicons", () => { + it("maps every mode to a codicon name (no emoji)", () => { + const names = ["agent", "ask", "manual", "plan", "composer"]; + for (const mode of names) { + expect(MODE_SECTION, `mode '${mode}' must have a codicon entry`).toMatch( + new RegExp(`${mode}:\\s*'[a-z-]+'`), + ); + } + }); + + it("does not use emoji glyphs in the mode icon map", () => { + expect(MODE_SECTION).not.toMatch(/[\u{1F300}-\u{1FAFF}]/u); + }); + + it("renders mode icons through the codicon() helper", () => { + expect(MAIN_JS).toMatch(/codicon\(modeIcons\[m\] \|\| 'circuit-board'\)/); + }); +}); diff --git a/webview-ui/static/main.js b/webview-ui/static/main.js index e437efd..7fc1334 100644 --- a/webview-ui/static/main.js +++ b/webview-ui/static/main.js @@ -673,15 +673,30 @@ const bottomBar = el('div', { class: 'bottom-bar' }); // Mode picker — styled popup replacing native