From 3ac5cdc86898542b9cba095a5cbb3ddcd8fa680e Mon Sep 17 00:00:00 2001 From: Ariane Emory Date: Fri, 21 Nov 2025 01:57:53 -0500 Subject: [PATCH 1/7] feat: provide a solution to Issue 4369 by addding optional 'primaryText' theme color for better transparency support (i.e, when background colour = none). Adds a new optional `primaryText` color property to the theme system that specifies the text color when displayed on a `primary` background (e.g., selected list items, active buttons). This change solves the invisible text issue that occurs when users set `background: none` in custom themes to enable terminal transparency. Previously, selected items would use the background color as text color, making text invisible when background was transparent. --- .../cmd/tui/component/prompt/autocomplete.tsx | 4 ++-- .../src/cli/cmd/tui/context/theme.tsx | 19 ++++++++++++++++--- .../src/cli/cmd/tui/ui/dialog-alert.tsx | 2 +- .../src/cli/cmd/tui/ui/dialog-confirm.tsx | 2 +- .../src/cli/cmd/tui/ui/dialog-help.tsx | 2 +- .../src/cli/cmd/tui/ui/dialog-select.tsx | 8 ++++---- packages/web/public/theme.json | 1 + 7 files changed, 26 insertions(+), 12 deletions(-) diff --git a/packages/opencode/src/cli/cmd/tui/component/prompt/autocomplete.tsx b/packages/opencode/src/cli/cmd/tui/component/prompt/autocomplete.tsx index 3029eafcce3..3ed46ac6c4d 100644 --- a/packages/opencode/src/cli/cmd/tui/component/prompt/autocomplete.tsx +++ b/packages/opencode/src/cli/cmd/tui/component/prompt/autocomplete.tsx @@ -471,11 +471,11 @@ export function Autocomplete(props: { backgroundColor={index() === store.selected ? theme.primary : undefined} flexDirection="row" > - + {option.display} - + {option.description} diff --git a/packages/opencode/src/cli/cmd/tui/context/theme.tsx b/packages/opencode/src/cli/cmd/tui/context/theme.tsx index 4b7c4de0ae4..3adb88547e1 100644 --- a/packages/opencode/src/cli/cmd/tui/context/theme.tsx +++ b/packages/opencode/src/cli/cmd/tui/context/theme.tsx @@ -43,6 +43,7 @@ type Theme = { info: RGBA text: RGBA textMuted: RGBA + primaryText: RGBA background: RGBA backgroundPanel: RGBA backgroundElement: RGBA @@ -96,7 +97,9 @@ type ColorValue = HexColor | RefName | Variant | RGBA type ThemeJson = { $schema?: string defs?: Record - theme: Record + theme: Omit, "primaryText"> & { + primaryText?: ColorValue + } } export const DEFAULT_THEMES: Record = { @@ -145,11 +148,20 @@ function resolveTheme(theme: ThemeJson, mode: "dark" | "light") { } return resolveColor(c[mode]) } - return Object.fromEntries( + + const resolved = Object.fromEntries( Object.entries(theme.theme).map(([key, value]) => { return [key, resolveColor(value)] }), - ) as Theme + ) as Partial + + // Backward compatibility: if primaryText is not defined, use background color + // This preserves the current behavior for all existing themes + if (!theme.theme.primaryText) { + resolved.primaryText = resolved.background + } + + return resolved as Theme } export const { use: useTheme, provider: ThemeProvider } = createSimpleContext({ @@ -286,6 +298,7 @@ function generateSystem(colors: TerminalColors, mode: "dark" | "light"): ThemeJs // Text colors text: fg, textMuted, + primaryText: bg, // Background colors background: bg, diff --git a/packages/opencode/src/cli/cmd/tui/ui/dialog-alert.tsx b/packages/opencode/src/cli/cmd/tui/ui/dialog-alert.tsx index 6bb59d6c7bd..306c8cb108b 100644 --- a/packages/opencode/src/cli/cmd/tui/ui/dialog-alert.tsx +++ b/packages/opencode/src/cli/cmd/tui/ui/dialog-alert.tsx @@ -38,7 +38,7 @@ export function DialogAlert(props: DialogAlertProps) { dialog.clear() }} > - ok + ok diff --git a/packages/opencode/src/cli/cmd/tui/ui/dialog-confirm.tsx b/packages/opencode/src/cli/cmd/tui/ui/dialog-confirm.tsx index dd5b238b11b..1058a206f9d 100644 --- a/packages/opencode/src/cli/cmd/tui/ui/dialog-confirm.tsx +++ b/packages/opencode/src/cli/cmd/tui/ui/dialog-confirm.tsx @@ -53,7 +53,7 @@ export function DialogConfirm(props: DialogConfirmProps) { dialog.clear() }} > - {Locale.titlecase(key)} + {Locale.titlecase(key)} )} diff --git a/packages/opencode/src/cli/cmd/tui/ui/dialog-help.tsx b/packages/opencode/src/cli/cmd/tui/ui/dialog-help.tsx index f522fca9eeb..c90b4499c33 100644 --- a/packages/opencode/src/cli/cmd/tui/ui/dialog-help.tsx +++ b/packages/opencode/src/cli/cmd/tui/ui/dialog-help.tsx @@ -28,7 +28,7 @@ export function DialogHelp() { dialog.clear()}> - ok + ok diff --git a/packages/opencode/src/cli/cmd/tui/ui/dialog-select.tsx b/packages/opencode/src/cli/cmd/tui/ui/dialog-select.tsx index 7beef9b08dd..6e37abf93ed 100644 --- a/packages/opencode/src/cli/cmd/tui/ui/dialog-select.tsx +++ b/packages/opencode/src/cli/cmd/tui/ui/dialog-select.tsx @@ -268,7 +268,7 @@ function Option(props: { ◆ @@ -276,18 +276,18 @@ function Option(props: { {Locale.truncate(props.title, 62)} - {props.description} + {props.description} - {props.footer} + {props.footer} diff --git a/packages/web/public/theme.json b/packages/web/public/theme.json index b3e97f7ca89..ee8c2b1dd1a 100644 --- a/packages/web/public/theme.json +++ b/packages/web/public/theme.json @@ -46,6 +46,7 @@ "info": { "$ref": "#/definitions/colorValue" }, "text": { "$ref": "#/definitions/colorValue" }, "textMuted": { "$ref": "#/definitions/colorValue" }, + "primaryText": { "$ref": "#/definitions/colorValue" }, "background": { "$ref": "#/definitions/colorValue" }, "backgroundPanel": { "$ref": "#/definitions/colorValue" }, "backgroundElement": { "$ref": "#/definitions/colorValue" }, From 6322c940c3ef5dc1dd489d5a9c03abf4dfea4c0b Mon Sep 17 00:00:00 2001 From: Ariane Emory Date: Fri, 21 Nov 2025 02:08:08 -0500 Subject: [PATCH 2/7] fix: prevent errors during bun turbo typecheck. --- .../src/cli/cmd/tui/context/theme.tsx | 21 ++++++++++++------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/packages/opencode/src/cli/cmd/tui/context/theme.tsx b/packages/opencode/src/cli/cmd/tui/context/theme.tsx index 3adb88547e1..0a8adeb9067 100644 --- a/packages/opencode/src/cli/cmd/tui/context/theme.tsx +++ b/packages/opencode/src/cli/cmd/tui/context/theme.tsx @@ -140,8 +140,8 @@ function resolveTheme(theme: ThemeJson, mode: "dark" | "light") { if (defs[c]) { return resolveColor(defs[c]) - } else if (theme.theme[c as keyof Theme]) { - return resolveColor(theme.theme[c as keyof Theme]) + } else if (theme.theme[c as keyof Theme] !== undefined) { + return resolveColor(theme.theme[c as keyof Theme]!) } else { throw new Error(`Color reference "${c}" not found in defs or theme`) } @@ -150,14 +150,19 @@ function resolveTheme(theme: ThemeJson, mode: "dark" | "light") { } const resolved = Object.fromEntries( - Object.entries(theme.theme).map(([key, value]) => { - return [key, resolveColor(value)] - }), + Object.entries(theme.theme) + .filter(([key]) => key !== "primaryText") + .map(([key, value]) => { + return [key, resolveColor(value)] + }), ) as Partial - // Backward compatibility: if primaryText is not defined, use background color - // This preserves the current behavior for all existing themes - if (!theme.theme.primaryText) { + // Handle primaryText separately since it's optional + if (theme.theme.primaryText !== undefined) { + resolved.primaryText = resolveColor(theme.theme.primaryText) + } else { + // Backward compatibility: if primaryText is not defined, use background color + // This preserves the current behavior for all existing themes resolved.primaryText = resolved.background } From ac0bae760b8ca5ba221156cdb5c801bf5035d5c9 Mon Sep 17 00:00:00 2001 From: knanao Date: Fri, 21 Nov 2025 16:28:17 +0900 Subject: [PATCH 3/7] fix: ensure selected list items are readable with transparent background --- .../cli/cmd/tui/component/prompt/autocomplete.tsx | 6 +++--- .../opencode/src/cli/cmd/tui/context/theme.tsx | 9 +++++++++ .../opencode/src/cli/cmd/tui/ui/dialog-select.tsx | 15 ++++++--------- 3 files changed, 18 insertions(+), 12 deletions(-) diff --git a/packages/opencode/src/cli/cmd/tui/component/prompt/autocomplete.tsx b/packages/opencode/src/cli/cmd/tui/component/prompt/autocomplete.tsx index 3029eafcce3..2f36a1d1a4d 100644 --- a/packages/opencode/src/cli/cmd/tui/component/prompt/autocomplete.tsx +++ b/packages/opencode/src/cli/cmd/tui/component/prompt/autocomplete.tsx @@ -5,7 +5,7 @@ import { createMemo, createResource, createEffect, onMount, For, Show } from "so import { createStore } from "solid-js/store" import { useSDK } from "@tui/context/sdk" import { useSync } from "@tui/context/sync" -import { useTheme } from "@tui/context/theme" +import { useTheme, selectedForeground } from "@tui/context/theme" import { SplitBorder } from "@tui/component/border" import { useCommandDialog } from "@tui/component/dialog-command" import { Locale } from "@/util/locale" @@ -471,11 +471,11 @@ export function Autocomplete(props: { backgroundColor={index() === store.selected ? theme.primary : undefined} flexDirection="row" > - + {option.display} - + {option.description} diff --git a/packages/opencode/src/cli/cmd/tui/context/theme.tsx b/packages/opencode/src/cli/cmd/tui/context/theme.tsx index 4b7c4de0ae4..54609d2079e 100644 --- a/packages/opencode/src/cli/cmd/tui/context/theme.tsx +++ b/packages/opencode/src/cli/cmd/tui/context/theme.tsx @@ -86,6 +86,15 @@ type Theme = { syntaxPunctuation: RGBA } +export function selectedForeground(theme: Theme): RGBA { + if (theme.background.a === 0) { + const { r, g, b } = theme.primary + const luminance = 0.299 * r + 0.587 * g + 0.114 * b + return luminance > 0.5 ? RGBA.fromInts(0, 0, 0) : RGBA.fromInts(255, 255, 255) + } + return theme.background +} + type HexColor = `#${string}` type RefName = string type Variant = { diff --git a/packages/opencode/src/cli/cmd/tui/ui/dialog-select.tsx b/packages/opencode/src/cli/cmd/tui/ui/dialog-select.tsx index 285c039c11e..aadb7d27092 100644 --- a/packages/opencode/src/cli/cmd/tui/ui/dialog-select.tsx +++ b/packages/opencode/src/cli/cmd/tui/ui/dialog-select.tsx @@ -1,5 +1,5 @@ import { InputRenderable, RGBA, ScrollBoxRenderable, TextAttributes } from "@opentui/core" -import { useTheme } from "@tui/context/theme" +import { useTheme, selectedForeground } from "@tui/context/theme" import { entries, filter, flatMap, groupBy, pipe, take } from "remeda" import { batch, createEffect, createMemo, For, Show } from "solid-js" import { createStore } from "solid-js/store" @@ -259,31 +259,28 @@ function Option(props: { onMouseOver?: () => void }) { const { theme } = useTheme() + const fg = selectedForeground(theme) return ( <> - + {Locale.truncate(props.title, 62)} - {props.description} + {props.description} - {props.footer} + {props.footer} From 23f082e190a8eb8c86ad4c8809a0c8cbf9f7a026 Mon Sep 17 00:00:00 2001 From: Ariane Emory Date: Fri, 21 Nov 2025 02:36:09 -0500 Subject: [PATCH 4/7] ... --- .../cmd/tui/component/prompt/autocomplete.tsx | 4 ++-- .../src/cli/cmd/tui/context/theme.tsx | 20 +++++++++---------- .../src/cli/cmd/tui/ui/dialog-alert.tsx | 2 +- .../src/cli/cmd/tui/ui/dialog-confirm.tsx | 4 +++- .../src/cli/cmd/tui/ui/dialog-help.tsx | 2 +- .../src/cli/cmd/tui/ui/dialog-select.tsx | 8 ++++---- packages/web/public/theme.json | 2 +- 7 files changed, 22 insertions(+), 20 deletions(-) diff --git a/packages/opencode/src/cli/cmd/tui/component/prompt/autocomplete.tsx b/packages/opencode/src/cli/cmd/tui/component/prompt/autocomplete.tsx index 3ed46ac6c4d..72da7856a7c 100644 --- a/packages/opencode/src/cli/cmd/tui/component/prompt/autocomplete.tsx +++ b/packages/opencode/src/cli/cmd/tui/component/prompt/autocomplete.tsx @@ -471,11 +471,11 @@ export function Autocomplete(props: { backgroundColor={index() === store.selected ? theme.primary : undefined} flexDirection="row" > - + {option.display} - + {option.description} diff --git a/packages/opencode/src/cli/cmd/tui/context/theme.tsx b/packages/opencode/src/cli/cmd/tui/context/theme.tsx index 0a8adeb9067..5405ba62d55 100644 --- a/packages/opencode/src/cli/cmd/tui/context/theme.tsx +++ b/packages/opencode/src/cli/cmd/tui/context/theme.tsx @@ -43,7 +43,7 @@ type Theme = { info: RGBA text: RGBA textMuted: RGBA - primaryText: RGBA + selectedListItemText: RGBA background: RGBA backgroundPanel: RGBA backgroundElement: RGBA @@ -97,8 +97,8 @@ type ColorValue = HexColor | RefName | Variant | RGBA type ThemeJson = { $schema?: string defs?: Record - theme: Omit, "primaryText"> & { - primaryText?: ColorValue + theme: Omit, "selectedListItemText"> & { + selectedListItemText?: ColorValue } } @@ -151,19 +151,19 @@ function resolveTheme(theme: ThemeJson, mode: "dark" | "light") { const resolved = Object.fromEntries( Object.entries(theme.theme) - .filter(([key]) => key !== "primaryText") + .filter(([key]) => key !== "selectedListItemText") .map(([key, value]) => { return [key, resolveColor(value)] }), ) as Partial - // Handle primaryText separately since it's optional - if (theme.theme.primaryText !== undefined) { - resolved.primaryText = resolveColor(theme.theme.primaryText) + // Handle selectedListItemText separately since it's optional + if (theme.theme.selectedListItemText !== undefined) { + resolved.selectedListItemText = resolveColor(theme.theme.selectedListItemText) } else { - // Backward compatibility: if primaryText is not defined, use background color + // Backward compatibility: if selectedListItemText is not defined, use background color // This preserves the current behavior for all existing themes - resolved.primaryText = resolved.background + resolved.selectedListItemText = resolved.background } return resolved as Theme @@ -303,7 +303,7 @@ function generateSystem(colors: TerminalColors, mode: "dark" | "light"): ThemeJs // Text colors text: fg, textMuted, - primaryText: bg, + selectedListItemText: bg, // Background colors background: bg, diff --git a/packages/opencode/src/cli/cmd/tui/ui/dialog-alert.tsx b/packages/opencode/src/cli/cmd/tui/ui/dialog-alert.tsx index 306c8cb108b..96ef982d7f2 100644 --- a/packages/opencode/src/cli/cmd/tui/ui/dialog-alert.tsx +++ b/packages/opencode/src/cli/cmd/tui/ui/dialog-alert.tsx @@ -38,7 +38,7 @@ export function DialogAlert(props: DialogAlertProps) { dialog.clear() }} > - ok + ok diff --git a/packages/opencode/src/cli/cmd/tui/ui/dialog-confirm.tsx b/packages/opencode/src/cli/cmd/tui/ui/dialog-confirm.tsx index 1058a206f9d..9d0e7d2c74f 100644 --- a/packages/opencode/src/cli/cmd/tui/ui/dialog-confirm.tsx +++ b/packages/opencode/src/cli/cmd/tui/ui/dialog-confirm.tsx @@ -53,7 +53,9 @@ export function DialogConfirm(props: DialogConfirmProps) { dialog.clear() }} > - {Locale.titlecase(key)} + + {Locale.titlecase(key)} + )} diff --git a/packages/opencode/src/cli/cmd/tui/ui/dialog-help.tsx b/packages/opencode/src/cli/cmd/tui/ui/dialog-help.tsx index c90b4499c33..db9648f2c7d 100644 --- a/packages/opencode/src/cli/cmd/tui/ui/dialog-help.tsx +++ b/packages/opencode/src/cli/cmd/tui/ui/dialog-help.tsx @@ -28,7 +28,7 @@ export function DialogHelp() { dialog.clear()}> - ok + ok diff --git a/packages/opencode/src/cli/cmd/tui/ui/dialog-select.tsx b/packages/opencode/src/cli/cmd/tui/ui/dialog-select.tsx index 6e37abf93ed..607d715f551 100644 --- a/packages/opencode/src/cli/cmd/tui/ui/dialog-select.tsx +++ b/packages/opencode/src/cli/cmd/tui/ui/dialog-select.tsx @@ -268,7 +268,7 @@ function Option(props: { ◆ @@ -276,18 +276,18 @@ function Option(props: { {Locale.truncate(props.title, 62)} - {props.description} + {props.description} - {props.footer} + {props.footer} diff --git a/packages/web/public/theme.json b/packages/web/public/theme.json index ee8c2b1dd1a..7c80776344f 100644 --- a/packages/web/public/theme.json +++ b/packages/web/public/theme.json @@ -46,7 +46,7 @@ "info": { "$ref": "#/definitions/colorValue" }, "text": { "$ref": "#/definitions/colorValue" }, "textMuted": { "$ref": "#/definitions/colorValue" }, - "primaryText": { "$ref": "#/definitions/colorValue" }, + "selectedListItemText": { "$ref": "#/definitions/colorValue" }, "background": { "$ref": "#/definitions/colorValue" }, "backgroundPanel": { "$ref": "#/definitions/colorValue" }, "backgroundElement": { "$ref": "#/definitions/colorValue" }, From 9adbbee1cc751dfba42e8e71e3758cf43ce71437 Mon Sep 17 00:00:00 2001 From: Ariane Emory Date: Fri, 21 Nov 2025 04:03:21 -0500 Subject: [PATCH 5/7] ... --- .../opencode/src/cli/cmd/tui/context/theme.tsx | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/packages/opencode/src/cli/cmd/tui/context/theme.tsx b/packages/opencode/src/cli/cmd/tui/context/theme.tsx index c9ec5151e96..8d6e2612c23 100644 --- a/packages/opencode/src/cli/cmd/tui/context/theme.tsx +++ b/packages/opencode/src/cli/cmd/tui/context/theme.tsx @@ -44,6 +44,7 @@ type Theme = { text: RGBA textMuted: RGBA selectedListItemText: RGBA + _hasSelectedListItemText: boolean background: RGBA backgroundPanel: RGBA backgroundElement: RGBA @@ -88,11 +89,19 @@ type Theme = { } export function selectedForeground(theme: Theme): RGBA { + // If theme explicitly defines selectedListItemText, use it + if (theme._hasSelectedListItemText) { + return theme.selectedListItemText + } + + // For transparent backgrounds, calculate contrast based on primary color if (theme.background.a === 0) { const { r, g, b } = theme.primary - const luminance = 0.299 * r + 0.587 * g + 0.114 * b - return luminance > 0.5 ? RGBA.fromInts(0, 0, 0) : RGBA.fromInts(255, 255, 255) + const luminance = 0.299 * r + 0.587 * g + 0.114 * b + return luminance > 0.5 ? RGBA.fromInts(0, 0, 0) : RGBA.fromInts(255, 255, 255) } + + // Fall back to background color return theme.background } @@ -106,7 +115,7 @@ type ColorValue = HexColor | RefName | Variant | RGBA type ThemeJson = { $schema?: string defs?: Record - theme: Omit, "selectedListItemText"> & { + theme: Omit, "selectedListItemText" | "_hasSelectedListItemText"> & { selectedListItemText?: ColorValue } } @@ -169,10 +178,12 @@ function resolveTheme(theme: ThemeJson, mode: "dark" | "light") { // Handle selectedListItemText separately since it's optional if (theme.theme.selectedListItemText !== undefined) { resolved.selectedListItemText = resolveColor(theme.theme.selectedListItemText) + resolved._hasSelectedListItemText = true } else { // Backward compatibility: if selectedListItemText is not defined, use background color // This preserves the current behavior for all existing themes resolved.selectedListItemText = resolved.background + resolved._hasSelectedListItemText = false } return resolved as Theme From d24f783522f66849795b2cff4eb51917bd33df65 Mon Sep 17 00:00:00 2001 From: Ariane Emory Date: Fri, 21 Nov 2025 04:06:51 -0500 Subject: [PATCH 6/7] refactor: integrate knanao's luminance-based coloring as a fallback --- .../src/cli/cmd/tui/context/theme.tsx | 27 +++++++++++-------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/packages/opencode/src/cli/cmd/tui/context/theme.tsx b/packages/opencode/src/cli/cmd/tui/context/theme.tsx index 8d6e2612c23..ebd1c922aab 100644 --- a/packages/opencode/src/cli/cmd/tui/context/theme.tsx +++ b/packages/opencode/src/cli/cmd/tui/context/theme.tsx @@ -33,7 +33,7 @@ import { createStore, produce } from "solid-js/store" import { Global } from "@/global" import { Filesystem } from "@/util/filesystem" -type Theme = { +type ThemeColors = { primary: RGBA secondary: RGBA accent: RGBA @@ -44,7 +44,6 @@ type Theme = { text: RGBA textMuted: RGBA selectedListItemText: RGBA - _hasSelectedListItemText: boolean background: RGBA backgroundPanel: RGBA backgroundElement: RGBA @@ -88,6 +87,10 @@ type Theme = { syntaxPunctuation: RGBA } +type Theme = ThemeColors & { + _hasSelectedListItemText: boolean +} + export function selectedForeground(theme: Theme): RGBA { // If theme explicitly defines selectedListItemText, use it if (theme._hasSelectedListItemText) { @@ -115,7 +118,7 @@ type ColorValue = HexColor | RefName | Variant | RGBA type ThemeJson = { $schema?: string defs?: Record - theme: Omit, "selectedListItemText" | "_hasSelectedListItemText"> & { + theme: Omit, "selectedListItemText"> & { selectedListItemText?: ColorValue } } @@ -158,8 +161,8 @@ function resolveTheme(theme: ThemeJson, mode: "dark" | "light") { if (defs[c]) { return resolveColor(defs[c]) - } else if (theme.theme[c as keyof Theme] !== undefined) { - return resolveColor(theme.theme[c as keyof Theme]!) + } else if (theme.theme[c as keyof ThemeColors] !== undefined) { + return resolveColor(theme.theme[c as keyof ThemeColors]!) } else { throw new Error(`Color reference "${c}" not found in defs or theme`) } @@ -173,20 +176,22 @@ function resolveTheme(theme: ThemeJson, mode: "dark" | "light") { .map(([key, value]) => { return [key, resolveColor(value)] }), - ) as Partial + ) as Partial // Handle selectedListItemText separately since it's optional - if (theme.theme.selectedListItemText !== undefined) { - resolved.selectedListItemText = resolveColor(theme.theme.selectedListItemText) - resolved._hasSelectedListItemText = true + const hasSelectedListItemText = theme.theme.selectedListItemText !== undefined + if (hasSelectedListItemText) { + resolved.selectedListItemText = resolveColor(theme.theme.selectedListItemText!) } else { // Backward compatibility: if selectedListItemText is not defined, use background color // This preserves the current behavior for all existing themes resolved.selectedListItemText = resolved.background - resolved._hasSelectedListItemText = false } - return resolved as Theme + return { + ...resolved, + _hasSelectedListItemText: hasSelectedListItemText, + } as Theme } export const { use: useTheme, provider: ThemeProvider } = createSimpleContext({ From c107e3c376c23bfb812394ae1c0a9d3f5d41dcfc Mon Sep 17 00:00:00 2001 From: knanao Date: Sat, 22 Nov 2025 21:17:03 +0900 Subject: [PATCH 7/7] feat: add backgroundMenu config to make autocomplete list visible with transparent bg --- .../cli/cmd/tui/component/prompt/autocomplete.tsx | 2 +- .../src/cli/cmd/tui/component/prompt/index.tsx | 15 +++++++++++---- .../opencode/src/cli/cmd/tui/context/theme.tsx | 10 +++++++--- 3 files changed, 19 insertions(+), 8 deletions(-) diff --git a/packages/opencode/src/cli/cmd/tui/component/prompt/autocomplete.tsx b/packages/opencode/src/cli/cmd/tui/component/prompt/autocomplete.tsx index 2f36a1d1a4d..8371c395fbe 100644 --- a/packages/opencode/src/cli/cmd/tui/component/prompt/autocomplete.tsx +++ b/packages/opencode/src/cli/cmd/tui/component/prompt/autocomplete.tsx @@ -455,7 +455,7 @@ export function Autocomplete(props: { {...SplitBorder} borderColor={theme.border} > - + diff --git a/packages/opencode/src/cli/cmd/tui/context/theme.tsx b/packages/opencode/src/cli/cmd/tui/context/theme.tsx index 54609d2079e..ddd13d4425d 100644 --- a/packages/opencode/src/cli/cmd/tui/context/theme.tsx +++ b/packages/opencode/src/cli/cmd/tui/context/theme.tsx @@ -46,6 +46,7 @@ type Theme = { background: RGBA backgroundPanel: RGBA backgroundElement: RGBA + backgroundMenu: RGBA border: RGBA borderActive: RGBA borderSubtle: RGBA @@ -89,8 +90,8 @@ type Theme = { export function selectedForeground(theme: Theme): RGBA { if (theme.background.a === 0) { const { r, g, b } = theme.primary - const luminance = 0.299 * r + 0.587 * g + 0.114 * b - return luminance > 0.5 ? RGBA.fromInts(0, 0, 0) : RGBA.fromInts(255, 255, 255) + const luminance = 0.299 * r + 0.587 * g + 0.114 * b + return luminance > 0.5 ? RGBA.fromInts(0, 0, 0) : RGBA.fromInts(255, 255, 255) } return theme.background } @@ -154,11 +155,13 @@ function resolveTheme(theme: ThemeJson, mode: "dark" | "light") { } return resolveColor(c[mode]) } - return Object.fromEntries( + const resolved = Object.fromEntries( Object.entries(theme.theme).map(([key, value]) => { return [key, resolveColor(value)] }), ) as Theme + if (!theme.theme.backgroundMenu) resolved.backgroundMenu = resolved.backgroundElement + return resolved } export const { use: useTheme, provider: ThemeProvider } = createSimpleContext({ @@ -300,6 +303,7 @@ function generateSystem(colors: TerminalColors, mode: "dark" | "light"): ThemeJs background: bg, backgroundPanel: grays[2], backgroundElement: grays[3], + backgroundMenu: grays[3], // Border colors borderSubtle: grays[6],