diff options
| author | Kit Langton <[email protected]> | 2026-01-15 01:04:11 -0500 |
|---|---|---|
| committer | GitHub <[email protected]> | 2026-01-15 00:04:11 -0600 |
| commit | 3a9fd1bb36af1b40f88415be6a80785c56f2c3b8 (patch) | |
| tree | 2a7b31a55f18b5a89892f2956ccf4a54879a4e52 | |
| parent | f84ac697dc1093705dadbee933fe29cd48e7fb08 (diff) | |
| download | opencode-3a9fd1bb36af1b40f88415be6a80785c56f2c3b8.tar.gz opencode-3a9fd1bb36af1b40f88415be6a80785c56f2c3b8.zip | |
fix: restore brand integrity of TUI wordmark (#8584)
| -rw-r--r-- | packages/opencode/src/cli/cmd/tui/component/logo.tsx | 73 | ||||
| -rw-r--r-- | packages/opencode/src/cli/cmd/tui/context/theme.tsx | 14 |
2 files changed, 69 insertions, 18 deletions
diff --git a/packages/opencode/src/cli/cmd/tui/component/logo.tsx b/packages/opencode/src/cli/cmd/tui/component/logo.tsx index d1be06a7f..6fd744794 100644 --- a/packages/opencode/src/cli/cmd/tui/component/logo.tsx +++ b/packages/opencode/src/cli/cmd/tui/component/logo.tsx @@ -1,24 +1,75 @@ -import { TextAttributes } from "@opentui/core" -import { For } from "solid-js" -import { useTheme } from "@tui/context/theme" +import { TextAttributes, RGBA } from "@opentui/core" +import { For, type JSX } from "solid-js" +import { useTheme, tint } from "@tui/context/theme" -const LOGO_LEFT = [` `, `█▀▀█ █▀▀█ █▀▀█ █▀▀▄`, `█░░█ █░░█ █▀▀▀ █░░█`, `▀▀▀▀ █▀▀▀ ▀▀▀▀ ▀ ▀`] +// Shadow markers (rendered chars in parens): +// _ = full shadow cell (space with bg=shadow) +// ^ = letter top, shadow bottom (▀ with fg=letter, bg=shadow) +// ~ = shadow top only (▀ with fg=shadow) +const SHADOW_MARKER = /[_^~]/ -const LOGO_RIGHT = [` ▄ `, `█▀▀▀ █▀▀█ █▀▀█ █▀▀█`, `█░░░ █░░█ █░░█ █▀▀▀`, `▀▀▀▀ ▀▀▀▀ ▀▀▀▀ ▀▀▀▀`] +const LOGO_LEFT = [ + ` `, + `█▀▀█ █▀▀█ █▀▀█ █▀▀▄`, + `█__█ █__█ █^^^ █__█`, + `▀▀▀▀ █▀▀▀ ▀▀▀▀ ▀~~▀`, +] + +const LOGO_RIGHT = [ + ` ▄ `, + `█▀▀▀ █▀▀█ █▀▀█ █▀▀█`, + `█___ █__█ █__█ █^^^`, + `▀▀▀▀ ▀▀▀▀ ▀▀▀▀ ▀▀▀▀`, +] export function Logo() { const { theme } = useTheme() + + const renderLine = (line: string, fg: RGBA, bold: boolean): JSX.Element[] => { + const shadow = tint(theme.background, fg, 0.25) + const attrs = bold ? TextAttributes.BOLD : undefined + const elements: JSX.Element[] = [] + let i = 0 + + while (i < line.length) { + const rest = line.slice(i) + const markerIndex = rest.search(SHADOW_MARKER) + + if (markerIndex === -1) { + elements.push(<text fg={fg} attributes={attrs} selectable={false}>{rest}</text>) + break + } + + if (markerIndex > 0) { + elements.push(<text fg={fg} attributes={attrs} selectable={false}>{rest.slice(0, markerIndex)}</text>) + } + + const marker = rest[markerIndex] + switch (marker) { + case "_": + elements.push(<text fg={fg} bg={shadow} attributes={attrs} selectable={false}> </text>) + break + case "^": + elements.push(<text fg={fg} bg={shadow} attributes={attrs} selectable={false}>▀</text>) + break + case "~": + elements.push(<text fg={shadow} attributes={attrs} selectable={false}>▀</text>) + break + } + + i += markerIndex + 1 + } + + return elements + } + return ( <box> <For each={LOGO_LEFT}> {(line, index) => ( <box flexDirection="row" gap={1}> - <text fg={theme.textMuted} selectable={false}> - {line} - </text> - <text fg={theme.text} attributes={TextAttributes.BOLD} selectable={false}> - {LOGO_RIGHT[index()]} - </text> + <box flexDirection="row">{renderLine(line, theme.textMuted, false)}</box> + <box flexDirection="row">{renderLine(LOGO_RIGHT[index()], theme.text, true)}</box> </box> )} </For> diff --git a/packages/opencode/src/cli/cmd/tui/context/theme.tsx b/packages/opencode/src/cli/cmd/tui/context/theme.tsx index 6489fc0e1..127be0dfc 100644 --- a/packages/opencode/src/cli/cmd/tui/context/theme.tsx +++ b/packages/opencode/src/cli/cmd/tui/context/theme.tsx @@ -417,6 +417,13 @@ async function getCustomThemes() { return result } +export function tint(base: RGBA, overlay: RGBA, alpha: number): RGBA { + const r = base.r + (overlay.r - base.r) * alpha + const g = base.g + (overlay.g - base.g) * alpha + const b = base.b + (overlay.b - base.b) * alpha + return RGBA.fromInts(Math.round(r * 255), Math.round(g * 255), Math.round(b * 255)) +} + function generateSystem(colors: TerminalColors, mode: "dark" | "light"): ThemeJson { const bg = RGBA.fromHex(colors.defaultBackground ?? colors.palette[0]!) const fg = RGBA.fromHex(colors.defaultForeground ?? colors.palette[7]!) @@ -428,13 +435,6 @@ function generateSystem(colors: TerminalColors, mode: "dark" | "light"): ThemeJs return ansiToRgba(i) } - const tint = (base: RGBA, overlay: RGBA, alpha: number) => { - const r = base.r + (overlay.r - base.r) * alpha - const g = base.g + (overlay.g - base.g) * alpha - const b = base.b + (overlay.b - base.b) * alpha - return RGBA.fromInts(Math.round(r * 255), Math.round(g * 255), Math.round(b * 255)) - } - // Generate gray scale based on terminal background const grays = generateGrayScale(bg, isDark) const textMuted = generateMutedTextColor(bg, isDark) |
