Skip to content

oc-2 light theme: icon-weak-base is missing its #, so every consumer silently falls back #41503

Description

@quickbeard

Summary

packages/ui/src/theme/themes/oc-2.json line 28 declares the light variant's icon-weak-base without a leading #:

"icon-base": "#8F8F8F",
"icon-weak-base": "C7C7C7",

The dark variant (line 264) is correct: "icon-weak-base": "#343434".

oc-2 is the only theme of the 37 in that directory that declares this token literally — every other theme takes the derived neutral[6] from resolve.ts — and it is the only malformed value among them. Since oc-2 is the default, this is the default light-mode experience.

Why it fails silently

resolveThemeVariant passes the string through verbatim, and the resolved tokens are injected into a <style> element (theme/context.tsx), which overrides the static --icon-weak-base: #dbdbdb in styles/theme.css. So the malformed value wins the cascade.

Custom properties accept almost any token sequence, so nothing errors at parse time. The failure lands at substitution: var(--icon-weak-base) resolves to C7C7C7, which is invalid at computed-value time, so the property falls back to the inherited value if it is an inherited property and the initial value otherwise. That means the same token fails differently depending on where it is used.

Measured in a running app on the default light theme:

--icon-weak-base                    →  "C7C7C7"
color: var(--icon-weak-base)        →  rgb(1, 2, 3)      // the parent's color, not grey
background: var(--icon-weak-base)   →  rgba(0, 0, 0, 0)  // transparent
--icon-base (control)               →  rgb(143, 143, 143) // fine

What it affects

Light mode only; dark is unaffected.

Site Property Result
app/src/components/dialog-release-notes.tsx bg-icon-weak-base inactive carousel indicators render transparent
ui/src/components/diff-changes.tsx fill on <rect> inside <svg fill="none"> neutral diff blocks inherit fill: none and don't render
app/src/components/file-tree.tsx color icon inherits the parent text color, so it renders at full strength instead of weak
app/src/components/settings-keybinds.tsx color same
app/src/components/settings-models.tsx color same

Fix

Add the #. The intended value looks unambiguous — #C7C7C7 matches text-weaker declared a few lines above in the same block.

-      "icon-weak-base": "C7C7C7",
+      "icon-weak-base": "#C7C7C7",

Possibly worth a guard too, so this can't recur silently: the theme schema could require ^# on literal color values, or resolveThemeVariant could warn on a value that is neither a #-prefixed hex nor a var(...) reference.

Happy to open a PR if useful.

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions