diff --git a/packages/client/ui-models/src/client/ModelListEditor.tsx b/packages/client/ui-models/src/client/ModelListEditor.tsx index 5cc0233fd1..27f706f642 100644 --- a/packages/client/ui-models/src/client/ModelListEditor.tsx +++ b/packages/client/ui-models/src/client/ModelListEditor.tsx @@ -427,10 +427,10 @@ export function ModelListEditor(props: ModelListEditorProps): ReactNode { checked={picked.has(candidate.id)} onChange={() => { toggle(candidate.id) }} /> + {/* The id alone: it is the string adoption writes, and the + capacities the endpoint reported are adopted with it and + editable in the row that appears. */} {candidate.id} - {candidate.contextWindow === undefined - ? null - : {candidate.contextWindow}} ))} diff --git a/packages/client/ui-models/src/client/ModelsSection.module.css b/packages/client/ui-models/src/client/ModelsSection.module.css index 797d67d4b4..e8232e2d81 100644 --- a/packages/client/ui-models/src/client/ModelsSection.module.css +++ b/packages/client/ui-models/src/client/ModelsSection.module.css @@ -583,6 +583,7 @@ select.input { .customizedSummary::before { transition: none; } +} .fetchDialog { max-width: 520px; @@ -620,13 +621,7 @@ select.input { .candidateId { flex: 1 1 auto; - font-family: var(--dsh-font-mono, monospace); + font-family: var(--ds-font-family-code); font-size: 13px; overflow-wrap: anywhere; } - -.candidateMeta { - color: var(--dsh-text-tertiary, #888); - font-size: 12px; - font-variant-numeric: tabular-nums; -} diff --git a/packages/client/ui-models/tests/styles.spec.ts b/packages/client/ui-models/tests/styles.spec.ts index 37ac894938..e13cd2baf5 100644 --- a/packages/client/ui-models/tests/styles.spec.ts +++ b/packages/client/ui-models/tests/styles.spec.ts @@ -6,17 +6,20 @@ * still renders and only the dark theme looks wrong. Checking the names against * the sheet that declares them is what turns that into a test failure. */ -import { readFileSync } from 'node:fs' +import { readdirSync, readFileSync } from 'node:fs' import { fileURLToPath } from 'node:url' import { describe, expect, it } from 'vitest' const css = readFileSync(fileURLToPath(new URL('../src/client/ModelsSection.module.css', import.meta.url)), 'utf8') // The theme package maps `./styles/*` to `./src/styles/*`, so the declarations // stay on the source plane rather than needing a build. -const tokens = readFileSync( - fileURLToPath(new URL('../../ui-theme/src/styles/design-platform.css', import.meta.url)), - 'utf8', -) +// Every theme sheet, not just the platform tokens: font and scrollbar +// variables are declared in siblings, and a gate reading one file would call +// their names undeclared. +const tokens = readdirSync(fileURLToPath(new URL('../../ui-theme/src/styles/', import.meta.url))) + .filter(name => name.endsWith('.css')) + .map(name => readFileSync(fileURLToPath(new URL(`../../ui-theme/src/styles/${name}`, import.meta.url)), 'utf8')) + .join('\n') /** The declarations of one top-level rule, by selector. */ function block(selector: string): string { @@ -31,12 +34,24 @@ describe('ModelsSection theme styles', () => { // resolves to whatever literal sits in its fallback slot, which is how this // section stayed light under the dark theme before. Undeclared names have // no fallback at all and inherit, so both spellings must fail here. - const named = [...css.matchAll(/var\((--dsw-[a-z0-9-]+)/g)].map(match => match[1]) + // Every theme-variable prefix the sheets actually use, not just `--dsw-`: + // a `--dsh-` name reads as a plausible sibling and would otherwise slip + // past this gate into a fallback literal. + const named = [...css.matchAll(/var\((--(?:dsw|dsh|ds)-[a-z0-9-]+)/g)].map(match => match[1]) const undeclared = [...new Set(named)].filter(name => !tokens.includes(` ${String(name)}:`)) expect(undeclared).toEqual([]) expect(css).not.toMatch(/var\(--(?:surface|text-|border|accent-strong)/) }) + it('closes every block, so no rule is swallowed by the one above it', () => { + // A missing `}` on an `@media` block is not a parse error: every rule after + // it silently becomes conditional, and the whole fetch dialog once painted + // unstyled for anyone whose system does not ask for reduced motion. Nothing + // downstream reports this — the sheet loads and the classes still attach. + const bare = css.replace(/\/\*[\s\S]*?\*\//g, '') + expect((bare.match(/\}/g) ?? []).length).toBe((bare.match(/\{/g) ?? []).length) + }) + it('separates the row card from the editor it expands into', () => { // `bg-layer-3` and `bg-module-platform` both resolve to neutral-bluish-800 // under the dark theme, so filling the row with either erases the nested