diff options
| author | Koichi Nakayamada <[email protected]> | 2025-12-11 14:39:27 -0800 |
|---|---|---|
| committer | GitHub <[email protected]> | 2025-12-11 16:39:27 -0600 |
| commit | 1fd005838c90b987f64d1f3bf047d7c39db3acab (patch) | |
| tree | 18eb1120c9c1bb4257347f2e200ecff22fa617bb | |
| parent | 61ba844234c86eac15537229c7de2b1d8cc3984f (diff) | |
| download | opencode-1fd005838c90b987f64d1f3bf047d7c39db3acab.tar.gz opencode-1fd005838c90b987f64d1f3bf047d7c39db3acab.zip | |
fix(tui): ensure fatal error UI is readable in light mode (#5387)
| -rw-r--r-- | packages/opencode/src/cli/cmd/tui/app.tsx | 48 |
1 files changed, 34 insertions, 14 deletions
diff --git a/packages/opencode/src/cli/cmd/tui/app.tsx b/packages/opencode/src/cli/cmd/tui/app.tsx index 16544d008..28e841122 100644 --- a/packages/opencode/src/cli/cmd/tui/app.tsx +++ b/packages/opencode/src/cli/cmd/tui/app.tsx @@ -107,7 +107,9 @@ export function tui(input: { url: string; args: Args; onExit?: () => Promise<voi render( () => { return ( - <ErrorBoundary fallback={(error, reset) => <ErrorComponent error={error} reset={reset} onExit={onExit} />}> + <ErrorBoundary + fallback={(error, reset) => <ErrorComponent error={error} reset={reset} onExit={onExit} mode={mode} />} + > <ArgsProvider {...input.args}> <ExitProvider onExit={onExit}> <KVProvider> @@ -536,7 +538,12 @@ function App() { ) } -function ErrorComponent(props: { error: Error; reset: () => void; onExit: () => Promise<void> }) { +function ErrorComponent(props: { + error: Error + reset: () => void + onExit: () => Promise<void> + mode?: "dark" | "light" +}) { const term = useTerminalDimensions() useKeyboard((evt) => { if (evt.ctrl && evt.name === "c") { @@ -547,6 +554,15 @@ function ErrorComponent(props: { error: Error; reset: () => void; onExit: () => const issueURL = new URL("https://github.com/sst/opencode/issues/new?template=bug-report.yml") + // Choose safe fallback colors per mode since theme context may not be available + const isLight = props.mode === "light" + const colors = { + bg: isLight ? "#ffffff" : "#0a0a0a", + text: isLight ? "#1a1a1a" : "#eeeeee", + muted: isLight ? "#8a8a8a" : "#808080", + primary: isLight ? "#3b7dd8" : "#fab283", + } + if (props.error.message) { issueURL.searchParams.set("title", `opentui: fatal: ${props.error.message}`) } @@ -567,27 +583,31 @@ function ErrorComponent(props: { error: Error; reset: () => void; onExit: () => } return ( - <box flexDirection="column" gap={1}> + <box flexDirection="column" gap={1} backgroundColor={colors.bg}> <box flexDirection="row" gap={1} alignItems="center"> - <text attributes={TextAttributes.BOLD}>Please report an issue.</text> - <box onMouseUp={copyIssueURL} backgroundColor="#565f89" padding={1}> - <text attributes={TextAttributes.BOLD}>Copy issue URL (exception info pre-filled)</text> + <text attributes={TextAttributes.BOLD} fg={colors.text}> + Please report an issue. + </text> + <box onMouseUp={copyIssueURL} backgroundColor={colors.primary} padding={1}> + <text attributes={TextAttributes.BOLD} fg={colors.bg}> + Copy issue URL (exception info pre-filled) + </text> </box> - {copied() && <text>Successfully copied</text>} + {copied() && <text fg={colors.muted}>Successfully copied</text>} </box> <box flexDirection="row" gap={2} alignItems="center"> - <text>A fatal error occurred!</text> - <box onMouseUp={props.reset} backgroundColor="#565f89" padding={1}> - <text>Reset TUI</text> + <text fg={colors.text}>A fatal error occurred!</text> + <box onMouseUp={props.reset} backgroundColor={colors.primary} padding={1}> + <text fg={colors.bg}>Reset TUI</text> </box> - <box onMouseUp={props.onExit} backgroundColor="#565f89" padding={1}> - <text>Exit</text> + <box onMouseUp={props.onExit} backgroundColor={colors.primary} padding={1}> + <text fg={colors.bg}>Exit</text> </box> </box> <scrollbox height={Math.floor(term().height * 0.7)}> - <text>{props.error.stack}</text> + <text fg={colors.muted}>{props.error.stack}</text> </scrollbox> - <text>{props.error.message}</text> + <text fg={colors.text}>{props.error.message}</text> </box> ) } |
