Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions apps/kimi-web/src/components/chat/Composer.vue
Original file line number Diff line number Diff line change
Expand Up @@ -1328,7 +1328,7 @@ function selectModel(modelId: string): void {
}
.att-lightbox-name {
max-width: 100%;
color: var(--color-text-on-accent);
color: var(--color-text-inverse);
font-family: var(--mono);
font-size: calc(var(--ui-font-size) - 2px);
overflow: hidden;
Expand All @@ -1344,7 +1344,7 @@ function selectModel(modelId: string): void {
border: 1px solid rgba(255,255,255,0.45);
border-radius: 50%;
background: rgba(20,23,28,0.82);
color: var(--color-text-on-accent);
color: var(--color-text-inverse);
cursor: pointer;
}

Expand Down
4 changes: 2 additions & 2 deletions apps/kimi-web/src/components/ui/Switch.vue
Original file line number Diff line number Diff line change
Expand Up @@ -48,9 +48,9 @@ const emit = defineEmits<{ 'update:modelValue': [value: boolean] }>();
width: 16px;
height: 16px;
border-radius: var(--radius-full);
background: var(--color-text-on-accent);
background: var(--color-text-inverse);
box-shadow: var(--shadow-xs);
transition: transform var(--duration-base) var(--ease-out);
}
.ui-switch.is-on .ui-switch__thumb { transform: translateX(16px); }
.ui-switch.is-on .ui-switch__thumb { background: var(--color-text-on-accent); transform: translateX(16px); }
</style>
6 changes: 5 additions & 1 deletion apps/kimi-web/src/style.css
Original file line number Diff line number Diff line change
Expand Up @@ -343,6 +343,7 @@ html[data-accent="mono"] {
html[data-color-scheme="dark"][data-accent="mono"] {
--accent-primary: #e8eaed;
--color-accent: #e8eaed;
--color-text-on-accent: #171717;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Keep overlay controls readable in dark mono

In the dark mono theme, changing the global --color-text-on-accent token to #171717 fixes near-white accent buttons, but this token is also used for non-accent overlay controls on dark backgrounds, such as Composer.vue's .att-video-badge, .att-lightbox-name, and .att-lightbox-close. When a user opens media attachments or sees a video badge in dark mono, those labels/icons become near-black on rgba(0,0,0,...) overlays and are effectively hidden; consider scoping the dark foreground to primary/accent-filled controls or overriding these overlay controls back to a light foreground.

Useful? React with 👍 / 👎.

@yearth yearth Jul 16, 2026

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in ab2906f. I rebased onto the latest main, kept --color-text-on-accent for accent-filled controls, and added a stable --color-text-inverse for the dark media overlay. .att-lightbox-name and .att-lightbox-close now use the inverse token. Regression coverage verifies both contracts; the full kimi-web suite (599 tests), typecheck, style check, and build pass.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Keep off switch thumbs visible in dark mono

In dark mono mode (and the repeated system-dark override below), this global token now resolves to #171717. The shared switch thumb uses background: var(--color-text-on-accent) in apps/kimi-web/src/components/ui/Switch.vue:51 even when the switch is off, while the off track remains the dark --color-line-strong; this makes every off switch in Settings nearly a dark thumb on a dark track (~1.8:1 contrast). Please either limit the dark foreground to accent-filled states or override the off-state switch thumb to a light/inverse fill.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 8a9d3ca. The off thumb now uses --color-text-inverse; the .is-on state explicitly switches back to --color-text-on-accent. This restores dark mono off-state contrast to 9.85:1 while preserving 14.87:1 for the on state. Regression coverage now locks both state-specific token contracts; the full kimi-web suite (601 tests), typecheck, style check, and build pass.

--color-accent-hover: #c9cdd4;
--color-accent-soft: #21262d;
--color-accent-bd: #444c56;
Expand All @@ -358,6 +359,7 @@ html[data-color-scheme="dark"][data-accent="mono"] {
html[data-color-scheme="system"][data-accent="mono"] {
--accent-primary: #e8eaed;
--color-accent: #e8eaed;
--color-text-on-accent: #171717;
--color-accent-hover: #c9cdd4;
--color-accent-soft: #21262d;
--color-accent-bd: #444c56;
Expand Down Expand Up @@ -398,11 +400,13 @@ html[data-color-scheme="dark"][data-accent="mono"] {
--color-surface-sunken: #f3f5f8;
/* Foreground text colours. `--color-text` is the default solid body / UI
colour (headings and emphasis share it); muted / faint step down for
secondary and tertiary copy; on-accent is text drawn on the accent fill. */
secondary and tertiary copy; on-accent is text drawn on the accent fill;
inverse stays light on dark image and modal overlays. */
--color-text: rgba(0, 0, 0, 0.9);
--color-text-muted: #6b7280;
--color-text-faint: #9aa3af;
--color-text-on-accent: #ffffff;
--color-text-inverse: #ffffff;
--color-line: #e7eaee;
--color-line-strong: #d4d9e0;
/* Neutral selected fill (sidebar rows, list pickers) — deliberately NOT
Expand Down
40 changes: 40 additions & 0 deletions apps/kimi-web/test/theme-contrast.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import { readFileSync } from 'node:fs';

import { describe, expect, it } from 'vitest';

const css = readFileSync(new URL('../src/style.css', import.meta.url), 'utf8');
const composer = readFileSync(new URL('../src/components/chat/Composer.vue', import.meta.url), 'utf8');
const switchComponent = readFileSync(new URL('../src/components/ui/Switch.vue', import.meta.url), 'utf8');
const designTokens = css.slice(css.indexOf('DESIGN TOKENS v2'));

function declarationBlock(source: string, selector: string): string {
const selectorIndex = source.indexOf(`${selector} {`);
expect(selectorIndex).toBeGreaterThanOrEqual(0);
const openBrace = source.indexOf('{', selectorIndex);
const closeBrace = source.indexOf('}', openBrace);
return source.slice(openBrace + 1, closeBrace);
}

describe('dark mono theme contrast', () => {
it('defines a stable light foreground for dark overlays', () => {
expect(declarationBlock(designTokens, ':root')).toMatch(/--color-text-inverse:\s*#ffffff;/);
});

it.each(['.att-lightbox-name', '.att-lightbox-close'])('keeps %s readable on the dark overlay', (selector) => {
expect(declarationBlock(composer, selector)).toMatch(/color:\s*var\(--color-text-inverse\);/);
});

it.each([
['.ui-switch__thumb', '--color-text-inverse'],
['.ui-switch.is-on .ui-switch__thumb', '--color-text-on-accent'],
])('uses %s background token %s', (selector, token) => {
expect(declarationBlock(switchComponent, selector)).toMatch(new RegExp(`background:\\s*var\\(${token}\\);`));
});

it.each([
'html[data-color-scheme="dark"][data-accent="mono"]',
'html[data-color-scheme="system"][data-accent="mono"]',
])('uses dark text on the near-white accent for %s', (selector) => {
expect(declarationBlock(css, selector)).toMatch(/--color-text-on-accent:\s*#171717;/);
});
});