Download lib/visual.mjs from teddyoas/Asnip: direct link, hf CLI and curl.
- Browser
- Download file 4.82 kB
-
https://huggingface.co/teddyoas/Asnip/resolve/main/lib/visual.mjs
- Command line
-
hf download hf://teddyoas/Asnip/lib/visual.mjs
-
curl -L -o visual.mjs https://huggingface.co/teddyoas/Asnip/resolve/main/lib/visual.mjs
4.82 kB
| // Phantom β shared visual components | |
| // ANSI colors, ASCII art, banners, prompts, separators | |
| // Neon violet/cyan on dark β hacker-in-hoodie aesthetic | |
| // ββ ANSI helpers (local β no dependency on phantom.mjs) ββ | |
| function fg(name) { | |
| const colors = { black:30, red:31, green:32, yellow:33, blue:34, magenta:35, cyan:36, white:37, dim:2 }; | |
| const n = colors[name] ?? 37; | |
| return `\x1b[${n}m`; | |
| } | |
| const _R = "\x1b[0m"; | |
| const _B = "\x1b[1m"; | |
| const _D = "\x1b[2m"; | |
| // ββ Hooded figure logo (cyberpunk neon) βββββββββββββββββ | |
| export function renderLogo(opts = {}) { | |
| const { | |
| mode = "", // "non-interactive", "v0.2.0" | |
| tools = 0, | |
| wide = false, | |
| } = opts; | |
| const M = fg("magenta"); | |
| const C = fg("cyan"); | |
| const G = fg("green"); | |
| const Y = fg("yellow"); | |
| const dim = fg("dim"); | |
| const _r = _R; | |
| const b = _B; | |
| const d = _D; | |
| // Shadow figlet logo β no box-drawing borders, clean | |
| const lines = [ | |
| ` ${M}${b} _ \\ | | \\ \\ |__ __| _ \\ \\ |${_r}`, | |
| ` ${M}${b} | | | | _ \\ \\ | | | | |\\/ |${_r}`, | |
| ` ${M}${b} ___/ ___ | ___ \\ |\\ | | | | | |${_r}`, | |
| ` ${M}${b} _| _| _|_/ _\\_| \\_| _| \\___/ _| _|${_r}`, | |
| ` ${C}${b}P${_r} ${M}${b}H${_r} ${Y}${b}A${_r} ${C}${b}N${_r} ${M}${b}T${_r} ${Y}${b}O${_r} ${C}${b}M${_r}`, | |
| ]; | |
| if (tools) lines.push(` ${dim}${tools} tools${_r}`); | |
| return lines.join("\n"); | |
| } | |
| // ββ Simple banner (small terminals / DesktopUI) ββ | |
| export function renderBanner(text = "PHANTOM", subtitle = "") { | |
| const C = fg("cyan"); | |
| const dim = fg("dim"); | |
| const _r = _R; | |
| const b = _B; | |
| return `${C}${b}${text}${_r}${subtitle ? ` ${dim}${subtitle}${_r}` : ""}`; | |
| } | |
| // ββ Prompt symbols ββββββββββββββββββββββββββββββββ | |
| export const prompt = { | |
| ghost: `${fg("green")}π»${_R} `, | |
| bolt: `${fg("cyan")}β‘${_R} `, | |
| hash: `${fg("magenta")}#${_R} `, | |
| arrow: `${fg("green")}β${_R} `, | |
| dim: `${fg("dim")}β§©${_R} `, | |
| }; | |
| // ββ Separator line ββββββββββββββββββββββββββββββββββ | |
| export function separator(char = "β", len = 50) { | |
| return `${fg("dim")}${char.repeat(len)}${_R}`; | |
| } | |
| // ββ Status icons ββββββββββββββββββββββββββββββββββββ | |
| // ββ Animated spinner ββββββββββββββββββββββββββββββββββ | |
| // Minimal frame-based spinner; no external deps. | |
| export function createSpinner(startTime, opts = {}) { | |
| const frames = ['β ', 'β ', 'β Ή', 'β Έ', 'β Ό', 'β ΄', 'β ¦', 'β §', 'β ', 'β ']; | |
| let i = 0, timer = null; | |
| const write = opts.write || ((s) => process.stdout.write(s)); | |
| const fmt = (ts) => { | |
| const s = Math.floor((Date.now() - ts) / 1000); | |
| return s > 3600 ? `${Math.floor(s/3600)}h ${Math.floor((s%3600)/60)}m` | |
| : s > 60 ? `${Math.floor(s/60)}m ${s%60}s` | |
| : `${s}s`; | |
| }; | |
| return { | |
| start(msg) { | |
| if (timer) return; | |
| timer = setInterval(() => { | |
| const f = frames[i = (i + 1) % frames.length]; | |
| write(`\r${fg("cyan")}${_B}${f}${_R} [${fmt(startTime)}] ${msg}`); | |
| }, 80); | |
| }, | |
| stop() { | |
| if (!timer) return; | |
| clearInterval(timer); timer = null; | |
| write('\r\x1b[K'); | |
| }, | |
| update(msg) { | |
| const f = timer ? frames[i] : frames[0]; | |
| write(`\r${fg("cyan")}${_B}${f}${_R} [${fmt(startTime)}] ${msg}`); | |
| } | |
| }; | |
| } | |
| export const icons = { | |
| ok: `${fg("green")}β${_R}`, | |
| err: `${fg("red")}β${_R}`, | |
| warn: `${fg("yellow")}β ${_R}`, | |
| info: `${fg("cyan")}β${_R}`, | |
| bullet: `${fg("magenta")}β${_R}`, | |
| arrow: `${fg("green")}β${_R}`, | |
| }; | |
| // ββ Chat border β wraps multi-line text in a bordered box ββ | |
| // width = total width (defaults to terminal cols - 2) | |
| // title = optional top-left label | |
| // color = border color function (default dim) | |
| export function chatBorder(text, opts = {}) { | |
| const { width, title, color = fg("dim") } = opts; | |
| const cols = width || (process.stdout.columns || 80) - 4; | |
| const c = color; | |
| const _r = _R; | |
| const lines = text.split("\n"); | |
| const out = []; | |
| const top = title | |
| ? `${c}ββ ${_B}${title}${_R}${c} ${"β".repeat(Math.max(0, cols - title.length - 4))}β${_r}` | |
| : `${c}β${"β".repeat(cols + 2)}β${_r}`; | |
| out.push(top); | |
| for (const line of lines) { | |
| const wrapped = line.length > cols ? line.substring(0, cols - 1) + "β¦" : line; | |
| const pad = " ".repeat(Math.max(0, cols - wrapped.length + 2)); | |
| out.push(`${c}β${_r} ${wrapped}${pad}${c}β${_r}`); | |
| } | |
| out.push(`${c}β${"β".repeat(cols + 2)}β${_r}`); | |
| return out.join("\n"); | |
| } | |