authorgravatar for 97427849+flamboh@users.noreply.github.comoliver <97427849+flamboh@users.noreply.github.com> 2026-09-01 15:03:15-07:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2026-09-01 18:03:15-04:00
logd0b4acbd13b2b602710e4a7d60c42f4799a409be
tree38666deb4bfece005486a0ad8a4246460e94af1b
parent3b3465f2a9dbc541a8806e39d2889abb77b93f5d
signature Signed by PGP key B5690EEEBB952194

fix(web): keep theme placeholder text dimmer than entered text (#9104)


3 files changed, 26 insertions(+), 1 deletions(-)

apps/web/src/themePalette.test.ts+3
...@@ -157,6 +157,9 @@ describe("theme files", () => {...@@ -157,6 +157,9 @@ describe("theme files", () => {
157 expect(contrastRatio(colors.textMuted, colors.canvas)).toBeLessThan(5.5);157 expect(contrastRatio(colors.textMuted, colors.canvas)).toBeLessThan(5.5);
158 expect(contrastRatio(colors.mutedForeground, colors.muted)).toBeGreaterThanOrEqual(4.5);158 expect(contrastRatio(colors.mutedForeground, colors.muted)).toBeGreaterThanOrEqual(4.5);
159 expect(contrastRatio(colors.placeholder, colors.surfaceRaised)).toBeGreaterThanOrEqual(4.5);159 expect(contrastRatio(colors.placeholder, colors.surfaceRaised)).toBeGreaterThanOrEqual(4.5);
160 expect(contrastRatio(colors.placeholder, colors.surfaceRaised)).toBeLessThan(
161 contrastRatio(colors.text, colors.surfaceRaised),
162 );
160 expect(colors.secondaryLabel).toBe(colors.textMuted);163 expect(colors.secondaryLabel).toBe(colors.textMuted);
161 expect(contrastRatio(colors.accentForeground, colors.accent)).toBeGreaterThanOrEqual(4.5);164 expect(contrastRatio(colors.accentForeground, colors.accent)).toBeGreaterThanOrEqual(4.5);
162 expect(165 expect(
apps/web/src/themePalette.ts+1-1
...@@ -917,7 +917,7 @@ export function createVividThemeColors(...@@ -917,7 +917,7 @@ export function createVividThemeColors(
917 solveOklchLightness(textBase, surfaceRgb, 4.6, dark ? "lighter" : "darker"),917 solveOklchLightness(textBase, surfaceRgb, 4.6, dark ? "lighter" : "darker"),
918 );918 );
919 const mutedForeground = foregroundOn(mutedRgb);919 const mutedForeground = foregroundOn(mutedRgb);
920 const placeholder = foregroundOn(surfaceRaisedRgb);920 const placeholder = themeRgbToThemeColor(readableThemeText(surfaceRaisedRgb, textRgb, 1, 4.6));
921921
922 const actionHover: ThemeOklch = { ...action, L: action.L + (dark ? 0.06 : -0.06) };922 const actionHover: ThemeOklch = { ...action, L: action.L + (dark ? 0.06 : -0.06) };
923923
apps/web/src/vscodeThemeImport.test.ts+22
...@@ -90,6 +90,28 @@ describe("VS Code theme import", () => {...@@ -90,6 +90,28 @@ describe("VS Code theme import", () => {
90 expect(theme.colors.sidebarRowSelected).not.toBe(theme.colors.sidebar);90 expect(theme.colors.sidebarRowSelected).not.toBe(theme.colors.sidebar);
91 });91 });
9292
93 it("keeps a fallback placeholder dimmer than entered text", () => {
94 const theme = parseVsCodeThemeFile({
95 name: "Dark placeholder fallback",
96 type: "dark",
97 colors: {
98 "editor.background": "#1e1e2e",
99 "editor.foreground": "#cdd6f4",
100 "input.placeholderForeground": "#cdd6f473",
101 },
102 });
103
104 expect(
105 contrastRatio(theme.colors.placeholder, theme.colors.surfaceRaised),
106 ).toBeGreaterThanOrEqual(4.5);
107 expect(contrastRatio(theme.colors.placeholder, theme.colors.canvas)).toBeGreaterThanOrEqual(
108 4.5,
109 );
110 expect(contrastRatio(theme.colors.placeholder, theme.colors.canvas)).toBeLessThan(
111 contrastRatio(theme.colors.text, theme.colors.canvas),
112 );
113 });
114
93 it("fills every role the file omits with a readable derived value", () => {115 it("fills every role the file omits with a readable derived value", () => {
94 const theme = parseVsCodeThemeFile(VSCODE_DARK);116 const theme = parseVsCodeThemeFile(VSCODE_DARK);
95 const colors = getThemeColorsForMode(theme, "dark")!;117 const colors = getThemeColorsForMode(theme, "dark")!;