feat: TUI chrome refresh — steel theme, home card, session topbar (0.9.24)
Cooler brand palette, compact CST-agent home with tagline and framed composer, session topbar (model + chair chip), sidebar off by default. Screenshot pipeline in tools/tui_shot.py; docs/screenshots for before/after. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,153 @@
|
||||
#!/usr/bin/env python3
|
||||
"""ANSI pane dump → HTML → PNG (chrome headless). Usage: tui_shot.py in.ansi out.png"""
|
||||
from __future__ import annotations
|
||||
|
||||
import html
|
||||
import subprocess
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
SPECIAL = {
|
||||
75: "#6ea8fe",
|
||||
74: "#61b8c7",
|
||||
216: "#faa06b",
|
||||
233: "#0e0f12",
|
||||
234: "#14161e",
|
||||
235: "#1a1c24",
|
||||
244: "#80848f",
|
||||
250: "#bcbcbc",
|
||||
252: "#d1d4d9",
|
||||
255: "#ffffff",
|
||||
242: "#6a6a6a",
|
||||
114: "#66bf73",
|
||||
167: "#d95252",
|
||||
157: "#afff87",
|
||||
22: "#005f00",
|
||||
203: "#ff5f5f",
|
||||
52: "#5f0000",
|
||||
}
|
||||
|
||||
|
||||
def ansi_to_html(text: str) -> str:
|
||||
cmap = {
|
||||
30: "#3c3c46",
|
||||
31: "#e65a5a",
|
||||
32: "#5ad278",
|
||||
33: "#faa06b",
|
||||
34: "#6ea8fe",
|
||||
35: "#d282d2",
|
||||
36: "#5ad2e6",
|
||||
37: "#bcbcbc",
|
||||
90: "#80848f",
|
||||
91: "#ff8282",
|
||||
92: "#82ff96",
|
||||
93: "#ffeb82",
|
||||
94: "#96beff",
|
||||
95: "#eba0eb",
|
||||
96: "#82ebff",
|
||||
97: "#ffffff",
|
||||
}
|
||||
out: list[str] = []
|
||||
i = 0
|
||||
bold = dim = False
|
||||
fg = "#d1d4d9"
|
||||
open_span = False
|
||||
|
||||
def close() -> None:
|
||||
nonlocal open_span
|
||||
if open_span:
|
||||
out.append("</span>")
|
||||
open_span = False
|
||||
|
||||
def reopen() -> None:
|
||||
nonlocal open_span
|
||||
close()
|
||||
styles = [f"color:{fg}"]
|
||||
if bold:
|
||||
styles.append("font-weight:700")
|
||||
if dim:
|
||||
styles.append("opacity:.65")
|
||||
out.append(f'<span style="{";".join(styles)}">')
|
||||
open_span = True
|
||||
|
||||
reopen()
|
||||
while i < len(text):
|
||||
if text[i] == "\x1b" and i + 1 < len(text) and text[i + 1] == "[":
|
||||
j = i + 2
|
||||
while j < len(text) and text[j] != "m":
|
||||
j += 1
|
||||
seq = text[i + 2 : j]
|
||||
i = j + 1 if j < len(text) else len(text)
|
||||
parts = [int(p) for p in seq.split(";") if p.isdigit()] if seq else [0]
|
||||
k = 0
|
||||
while k < len(parts):
|
||||
c = parts[k]
|
||||
if c == 0:
|
||||
bold = dim = False
|
||||
fg = "#d1d4d9"
|
||||
elif c == 1:
|
||||
bold = True
|
||||
elif c == 2:
|
||||
dim = True
|
||||
elif c == 22:
|
||||
bold = dim = False
|
||||
elif c == 38 and k + 2 < len(parts) and parts[k + 1] == 5:
|
||||
fg = SPECIAL.get(parts[k + 2], fg)
|
||||
k += 2
|
||||
elif c in cmap:
|
||||
fg = cmap[c]
|
||||
elif c == 39:
|
||||
fg = "#d1d4d9"
|
||||
k += 1
|
||||
reopen()
|
||||
continue
|
||||
if text[i] == "\n":
|
||||
out.append("\n")
|
||||
i += 1
|
||||
continue
|
||||
if text[i] == "\r":
|
||||
i += 1
|
||||
continue
|
||||
out.append(html.escape(text[i]))
|
||||
i += 1
|
||||
close()
|
||||
body = "".join(out)
|
||||
return f"""<!doctype html><meta charset=utf-8>
|
||||
<style>
|
||||
html,body{{margin:0;background:#07080a}}
|
||||
pre{{margin:0;padding:18px 22px;background:#0e0f12;color:#d1d4d9;
|
||||
font:14px/1.35 "JetBrains Mono","Cascadia Mono",Menlo,Consolas,monospace;
|
||||
white-space:pre; min-height:100vh; letter-spacing:0.01em}}
|
||||
</style><pre>{body}</pre>"""
|
||||
|
||||
|
||||
def main() -> int:
|
||||
if len(sys.argv) < 3:
|
||||
print("usage: tui_shot.py in.ansi out.png", file=sys.stderr)
|
||||
return 2
|
||||
ansi = Path(sys.argv[1]).read_text(encoding="utf-8", errors="replace")
|
||||
html_path = Path(sys.argv[2]).with_suffix(".html")
|
||||
html_path.write_text(ansi_to_html(ansi), encoding="utf-8")
|
||||
png = Path(sys.argv[2])
|
||||
chrome = "google-chrome"
|
||||
subprocess.run(
|
||||
[
|
||||
chrome,
|
||||
"--headless=new",
|
||||
"--disable-gpu",
|
||||
"--no-sandbox",
|
||||
"--hide-scrollbars",
|
||||
"--window-size=1280,800",
|
||||
f"--screenshot={png}",
|
||||
html_path.resolve().as_uri(),
|
||||
],
|
||||
check=False,
|
||||
stdout=subprocess.DEVNULL,
|
||||
stderr=subprocess.DEVNULL,
|
||||
)
|
||||
print(png, png.stat().st_size if png.exists() else 0)
|
||||
return 0 if png.exists() else 1
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
Reference in New Issue
Block a user