Browse Source

fix(tui): ensure fatal error UI is readable in light mode (#5387)

Koichi Nakayamada 2 months ago
parent
commit
1fd005838c
1 changed files with 34 additions and 14 deletions
  1. 34 14
      packages/opencode/src/cli/cmd/tui/app.tsx

+ 34 - 14
packages/opencode/src/cli/cmd/tui/app.tsx

@@ -107,7 +107,9 @@ export function tui(input: { url: string; args: Args; onExit?: () => Promise<voi
     render(
     render(
       () => {
       () => {
         return (
         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}>
             <ArgsProvider {...input.args}>
               <ExitProvider onExit={onExit}>
               <ExitProvider onExit={onExit}>
                 <KVProvider>
                 <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()
   const term = useTerminalDimensions()
   useKeyboard((evt) => {
   useKeyboard((evt) => {
     if (evt.ctrl && evt.name === "c") {
     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")
   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) {
   if (props.error.message) {
     issueURL.searchParams.set("title", `opentui: fatal: ${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 (
   return (
-    <box flexDirection="column" gap={1}>
+    <box flexDirection="column" gap={1} backgroundColor={colors.bg}>
       <box flexDirection="row" gap={1} alignItems="center">
       <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>
         </box>
-        {copied() && <text>Successfully copied</text>}
+        {copied() && <text fg={colors.muted}>Successfully copied</text>}
       </box>
       </box>
       <box flexDirection="row" gap={2} alignItems="center">
       <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>
-        <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>
       </box>
       </box>
       <scrollbox height={Math.floor(term().height * 0.7)}>
       <scrollbox height={Math.floor(term().height * 0.7)}>
-        <text>{props.error.stack}</text>
+        <text fg={colors.muted}>{props.error.stack}</text>
       </scrollbox>
       </scrollbox>
-      <text>{props.error.message}</text>
+      <text fg={colors.text}>{props.error.message}</text>
     </box>
     </box>
   )
   )
 }
 }