feat: add skin logo support

This commit is contained in:
Austin Pickett 2026-04-07 23:59:11 -04:00
parent af077b2c0d
commit ebd2d83ef2
6 changed files with 108 additions and 13 deletions

View file

@ -2,6 +2,50 @@ import type { ThemeColors } from './theme.js'
type Line = [string, string]
// ── Rich markup parser ──────────────────────────────────────────────
// Parses Python Rich markup like "[bold #A3261F]text[/]" into Line[].
const RICH_RE = /\[(?:bold\s+)?(?:dim\s+)?(#(?:[0-9a-fA-F]{3,8}))\]([\s\S]*?)(\[\/\])/g
export function parseRichMarkup(markup: string): Line[] {
const lines: Line[] = []
for (const raw of markup.split('\n')) {
const trimmed = raw.trimEnd()
if (!trimmed) {
lines.push(['', ' '])
continue
}
let lastIndex = 0
let matched = false
let m: RegExpExecArray | null
RICH_RE.lastIndex = 0
while ((m = RICH_RE.exec(trimmed)) !== null) {
matched = true
const before = trimmed.slice(lastIndex, m.index)
if (before) {
lines.push(['', before])
}
lines.push([m[1]!, m[2]!])
lastIndex = m.index + m[0].length
}
if (!matched) {
lines.push(['', trimmed])
} else if (lastIndex < trimmed.length) {
lines.push(['', trimmed.slice(lastIndex)])
}
}
return lines
}
const LOGO_ART = [
'██╗ ██╗███████╗██████╗ ███╗ ███╗███████╗███████╗ █████╗ ██████╗ ███████╗███╗ ██╗████████╗',
'██║ ██║██╔════╝██╔══██╗████╗ ████║██╔════╝██╔════╝ ██╔══██╗██╔════╝ ██╔════╝████╗ ██║╚══██╔══╝',
@ -39,6 +83,22 @@ function colorize(art: string[], gradient: readonly number[], c: ThemeColors): L
}
export const LOGO_WIDTH = 98
export const CADUCEUS_WIDTH = 30
export const logo = (c: ThemeColors) => colorize(LOGO_ART, LOGO_GRADIENT, c)
export const caduceus = (c: ThemeColors) => colorize(CADUCEUS_ART, CADUC_GRADIENT, c)
export const logo = (c: ThemeColors, customLogo?: string): Line[] =>
customLogo ? parseRichMarkup(customLogo) : colorize(LOGO_ART, LOGO_GRADIENT, c)
export const caduceus = (c: ThemeColors, customHero?: string): Line[] =>
customHero ? parseRichMarkup(customHero) : colorize(CADUCEUS_ART, CADUC_GRADIENT, c)
export function artWidth(lines: Line[]): number {
let max = 0
for (const [, text] of lines) {
if (text.length > max) {
max = text.length
}
}
return max
}