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({rest}) + break + } + + if (markerIndex > 0) { + elements.push({rest.slice(0, markerIndex)}) + } + + const marker = rest[markerIndex] + switch (marker) { + case "_": + elements.push( ) + break + case "^": + elements.push() + break + case "~": + elements.push() + break + } + + i += markerIndex + 1 + } + + return elements + } + return ( {(line, index) => ( - - {line} - - - {LOGO_RIGHT[index()]} - + {renderLine(line, theme.textMuted, false)} + {renderLine(LOGO_RIGHT[index()], theme.text, true)} )} 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)