|
|
@@ -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>
|