fix(desktop): keep quick-entry options readable in dark themes

This commit is contained in:
Nagisa-3000
2026-09-24 19:52:46 +08:00
committed by brooklyn!
parent a4c31d592b
commit 5b7fed2700
2 changed files with 70 additions and 3 deletions

View File

@@ -0,0 +1,55 @@
/** Regression coverage for #77429: native picker options must paint a readable surface. */
import { act, cleanup, render, screen } from '@testing-library/react'
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
import type { QuickEntryStatePush } from '@/store/quick-entry'
import { QuickEntryApp } from './quick-entry-app'
const initialHermesDesktop = window.hermesDesktop
describe('QuickEntryApp', () => {
let pushState: ((payload: QuickEntryStatePush) => void) | undefined
beforeEach(() => {
pushState = undefined
window.hermesDesktop = {
quickEntry: {
dismiss: vi.fn(),
onShown: vi.fn(() => vi.fn()),
onState: vi.fn(callback => {
pushState = callback
return vi.fn()
}),
submit: vi.fn()
}
} as never
})
afterEach(() => {
cleanup()
window.hermesDesktop = initialHermesDesktop
vi.restoreAllMocks()
})
it('paints every native target option with matching theme foreground and background tokens', () => {
render(<QuickEntryApp />)
act(() => {
pushState?.({
connected: true,
sessions: [{ id: 'session-1', title: 'A recent session' }]
})
})
const options = screen.getAllByRole('option') as HTMLOptionElement[]
expect(options).toHaveLength(3)
for (const option of options) {
expect(option.style.color).toBe('var(--ui-text-primary, var(--foreground))')
expect(option.style.backgroundColor).toBe('var(--ui-bg-elevated, var(--background))')
}
})
})

View File

@@ -10,6 +10,14 @@ import {
type QuickComposerState
} from '@/store/quick-entry'
// Native select popups do not reliably inherit the closed control's colors.
// Paint both sides of the contrast pair on every option so Chromium cannot
// combine a dark-theme foreground with an OS-provided light popup surface.
const QUICK_TARGET_OPTION_STYLE = {
backgroundColor: 'var(--ui-bg-elevated, var(--background))',
color: 'var(--ui-text-primary, var(--foreground))'
}
/**
* The Quick Entry composer — the whole renderer surface of the global-hotkey
* mini window. Deliberately one input plus a session-target picker and nothing
@@ -187,10 +195,14 @@ export function QuickEntryApp() {
}}
value={state.target}
>
<option value={QUICK_TARGET_CURRENT}>Current chat</option>
<option value={QUICK_TARGET_NEW}>New session</option>
<option style={QUICK_TARGET_OPTION_STYLE} value={QUICK_TARGET_CURRENT}>
Current chat
</option>
<option style={QUICK_TARGET_OPTION_STYLE} value={QUICK_TARGET_NEW}>
New session
</option>
{state.sessions.map(session => (
<option key={session.id} value={session.id}>
<option key={session.id} style={QUICK_TARGET_OPTION_STYLE} value={session.id}>
{session.title}
</option>
))}