fix(icons): say "background work", not "to-do list", and lighten the terminal glyph

Two glyphs read wrong in the live instance:

- Tasks shows subagent sessions AND the host's background jobs, so a checklist
  glyph described a page that does not exist. `VscLayers` (sheets stacked, i.e.
  work running behind the conversation) says what the page is; the amber token
  stays, so it still reads as live activity.
- The terminal was the widest glyph in the set and the only bare fill in a
  strip of the plugin's own 1.5px-stroked icons, which made it look like a
  heavy foreign block. It now renders a step down (0.85x the strip size, floor
  10px) and every colored tab glyph gets a hairline outline of its own ink
  (`stroke: currentColor` + `non-scaling-stroke`, so the line stays one device
  pixel across the sets' mixed 16- and 24-unit viewBoxes; `paint-order: stroke`
  centres it on the fill edge instead of fattening the shape).

tests/builtins.spec.ts pins both readings by glyph identity (tasks = layers,
terminal = the shrunk, outlined VscTerminal), so a future swap has to argue
with a failing assertion rather than with a comment.

Gates: typecheck / lint green, pnpm test 127 files / 1343 passed / 9 skipped.
This commit is contained in:
Menghuan1918
2026-09-11 15:40:32 +08:00
parent 6317dde7c0
commit fe2017af49
3 changed files with 80 additions and 9 deletions
+32
View File
@@ -8,6 +8,8 @@
* tab (git lens + session lens, PR #471's file-trace merged in).
*/
import { describe, expect, it } from 'vitest'
import type { ReactElement } from 'react'
import { VscCommentDiscussion, VscGitCommit, VscGlobe, VscLayers, VscTerminal } from 'react-icons/vsc'
// First import: browser globals before the xterm-carrying builtin graph loads.
import './browser-globals.ts'
@@ -235,6 +237,36 @@ describe('built-in tab registrations', () => {
expect(tab.icon, tab.id).toBeDefined()
}
})
it('the tab glyphs say what the page shows (colored, token-driven)', () => {
const { service } = setup()
const iconOf = (id: string): ReactElement => {
const icon = service.getTab(id)?.icon
expect(icon, id).toBeDefined()
return (typeof icon === 'function' ? icon(14) : icon) as ReactElement
}
// Every colored glyph is [wrapper][glyph]; unwrap the themed wrapper.
const glyphOf = (id: string): unknown => {
const wrapper = iconOf(id) as ReactElement<{ children?: ReactElement }>
return (wrapper.props.children as ReactElement | undefined)?.type ?? wrapper.type
}
// Tasks lists subagent sessions AND background jobs — layered sheets say
// "work running in the background"; a checklist glyph would say "to-do
// list", which this page is not.
expect(glyphOf('subagent')).toBe(VscLayers)
expect(glyphOf('git')).toBe(VscGitCommit)
expect(glyphOf('sidechat')).toBe(VscCommentDiscussion)
expect(glyphOf('browser')).toBe(VscGlobe)
// The terminal glyph is the widest in the set: it renders a step down from
// the strip's size and keeps a hairline outline so it matches the plugin's
// own drawn chrome instead of reading as a heavy filled block.
const wrapper = iconOf('terminal') as ReactElement<{ children?: ReactElement }>
const terminal = wrapper.props.children as ReactElement<{ size?: number; style?: Record<string, unknown> }>
expect(terminal.type).toBe(VscTerminal)
expect(terminal.props.size).toBeLessThan(14)
expect(terminal.props.style?.strokeWidth).toBe(1)
expect(terminal.props.style?.vectorEffect).toBe('non-scaling-stroke')
})
})
describe('built-in file viewer registrations', () => {