diff --git a/packages/opencode/src/cli/cmd/tui/component/logo.tsx b/packages/opencode/src/cli/cmd/tui/component/logo.tsx index 771962b75..8e6208b14 100644 --- a/packages/opencode/src/cli/cmd/tui/component/logo.tsx +++ b/packages/opencode/src/cli/cmd/tui/component/logo.tsx @@ -1,16 +1,13 @@ import { TextAttributes, RGBA } from "@opentui/core" import { For, type JSX } from "solid-js" import { useTheme, tint } from "@tui/context/theme" +import { logo, marks } from "@/cli/logo" // 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_LEFT = [` `, `█▀▀█ █▀▀█ █▀▀█ █▀▀▄`, `█__█ █__█ █^^^ █__█`, `▀▀▀▀ █▀▀▀ ▀▀▀▀ ▀~~▀`] - -const LOGO_RIGHT = [` ▄ `, `█▀▀▀ █▀▀█ █▀▀█ █▀▀█`, `█___ █__█ █__█ █^^^`, `▀▀▀▀ ▀▀▀▀ ▀▀▀▀ ▀▀▀▀`] +const SHADOW_MARKER = new RegExp(`[${marks}]`) export function Logo() { const { theme } = useTheme() @@ -75,11 +72,11 @@ export function Logo() { return ( - + {(line, index) => ( {renderLine(line, theme.textMuted, false)} - {renderLine(LOGO_RIGHT[index()], theme.text, true)} + {renderLine(logo.right[index()], theme.text, true)} )} diff --git a/packages/opencode/src/cli/logo.ts b/packages/opencode/src/cli/logo.ts new file mode 100644 index 000000000..44fb93c15 --- /dev/null +++ b/packages/opencode/src/cli/logo.ts @@ -0,0 +1,6 @@ +export const logo = { + left: [" ", "█▀▀█ █▀▀█ █▀▀█ █▀▀▄", "█__█ █__█ █^^^ █__█", "▀▀▀▀ █▀▀▀ ▀▀▀▀ ▀~~▀"], + right: [" ▄ ", "█▀▀▀ █▀▀█ █▀▀█ █▀▀█", "█___ █__█ █__█ █^^^", "▀▀▀▀ ▀▀▀▀ ▀▀▀▀ ▀▀▀▀"], +} + +export const marks = "_^~" diff --git a/packages/opencode/src/cli/ui.ts b/packages/opencode/src/cli/ui.ts index acd1383a0..9df1f4ac5 100644 --- a/packages/opencode/src/cli/ui.ts +++ b/packages/opencode/src/cli/ui.ts @@ -1,15 +1,9 @@ import z from "zod" import { EOL } from "os" import { NamedError } from "@opencode-ai/util/error" +import { logo as glyphs } from "./logo" export namespace UI { - const LOGO = [ - [`  `, ` ▄ `], - [`█▀▀█ █▀▀█ █▀▀█ █▀▀▄ `, `█▀▀▀ █▀▀█ █▀▀█ █▀▀█`], - [`█░░█ █░░█ █▀▀▀ █░░█ `, `█░░░ █░░█ █░░█ █▀▀▀`], - [`▀▀▀▀ █▀▀▀ ▀▀▀▀ ▀ ▀ `, `▀▀▀▀ ▀▀▀▀ ▀▀▀▀ ▀▀▀▀`], - ] - export const CancelledError = NamedError.create("UICancelledError", z.void()) export const Style = { @@ -47,15 +41,50 @@ export namespace UI { } export function logo(pad?: string) { - const result = [] - for (const row of LOGO) { - if (pad) result.push(pad) - result.push(Bun.color("gray", "ansi")) - result.push(row[0]) - result.push("\x1b[0m") - result.push(row[1]) - result.push(EOL) + const result: string[] = [] + const reset = "\x1b[0m" + const left = { + fg: Bun.color("gray", "ansi") ?? "", + shadow: "\x1b[38;5;235m", + bg: "\x1b[48;5;235m", } + const right = { + fg: reset, + shadow: "\x1b[38;5;238m", + bg: "\x1b[48;5;238m", + } + const gap = " " + const draw = (line: string, fg: string, shadow: string, bg: string) => { + const parts: string[] = [] + for (const char of line) { + if (char === "_") { + parts.push(bg, " ", reset) + continue + } + if (char === "^") { + parts.push(fg, bg, "▀", reset) + continue + } + if (char === "~") { + parts.push(shadow, "▀", reset) + continue + } + if (char === " ") { + parts.push(" ") + continue + } + parts.push(fg, char, reset) + } + return parts.join("") + } + glyphs.left.forEach((row, index) => { + if (pad) result.push(pad) + result.push(draw(row, left.fg, left.shadow, left.bg)) + result.push(gap) + const other = glyphs.right[index] ?? "" + result.push(draw(other, right.fg, right.shadow, right.bg)) + result.push(EOL) + }) return result.join("").trimEnd() }