/**
* Generate theme screenshots for documentation
*
* Run with: npx tsx scripts/generate-theme-screenshots.ts
*/
import xterm from "@xterm/headless";
import * as fs from "fs";
import * as path from "path";
import { bufferToSvg } from "../src/lib/buffer-to-svg.js";
import { themes, Theme } from "../src/lib/themes.js";
const COLS = 50;
const ROWS = 8;
const OUTPUT_DIR = path.join(import.meta.dirname, "../docs/themes");
const LABEL_HEIGHT = 45;
const FONT_SIZE = 14;
// ANSI color codes
const RESET = "\x1b[0m";
const BOLD = "\x1b[1m";
const GREEN = "\x1b[32m";
const YELLOW = "\x1b[33m";
const BLUE = "\x1b[34m";
const CYAN = "\x1b[36m";
const WHITE = "\x1b[37m";
const BRIGHT_BLACK = "\x1b[90m";
function addLabelToSvg(svg: string, label: string, theme: Theme): string {
// Parse dimensions from SVG
const widthMatch = svg.match(/width="([^"]+)"/);
const heightMatch = svg.match(/height="([^"]+)"/);
if (!widthMatch || !heightMatch) return svg;
const width = parseFloat(widthMatch[1]);
const height = parseFloat(heightMatch[1]);
const newHeight = height + LABEL_HEIGHT;
// Text color: white for dark themes, black for light
const textColor = theme.type === "light" ? "#000000" : "#ffffff";
// Update height and add label
let newSvg = svg.replace(/height="[^"]+"/, `height="${newHeight}"`);
// Add background extension and label before closing
const labelSvg = `
${label}
`;
newSvg = newSvg.replace(/<\/svg>$/, labelSvg);
return newSvg;
}
async function generateScreenshots() {
// Ensure output directory exists
if (!fs.existsSync(OUTPUT_DIR)) {
fs.mkdirSync(OUTPUT_DIR, { recursive: true });
}
for (const [themeName, theme] of Object.entries(themes)) {
console.log(`Generating ${themeName}...`);
// Create a fresh terminal for each theme
const terminal = new xterm.Terminal({
cols: COLS,
rows: ROWS,
allowProposedApi: true,
});
// Write colorful content demonstrating the theme
terminal.write(`${GREEN}~/projects/shellwright${RESET} ${CYAN}main${RESET} ${YELLOW}✓${RESET}\r\n`);
terminal.write(`${BOLD}${WHITE}$ ${RESET}ls -la\r\n`);
terminal.write(`${BLUE}drwxr-xr-x${RESET} ${GREEN}src${RESET}/\r\n`);
terminal.write(`${BLUE}drwxr-xr-x${RESET} ${GREEN}docs${RESET}/\r\n`);
terminal.write(`-rw-r--r-- ${WHITE}README.md${RESET}\r\n`);
terminal.write(`-rw-r--r-- ${YELLOW}package.json${RESET}\r\n`);
terminal.write(`${BRIGHT_BLACK}4 items${RESET}\r\n`);
// Wait for terminal to process
await new Promise(resolve => setTimeout(resolve, 50));
// Generate SVG with this theme
let svg = bufferToSvg(terminal, COLS, ROWS, {
theme,
fontSize: FONT_SIZE,
fontFamily: "Hack, Monaco, Courier, monospace",
});
// Add label with theme name (use exact theme name)
svg = addLabelToSvg(svg, themeName, theme);
// Save SVG
const basePath = path.join(OUTPUT_DIR, themeName);
fs.writeFileSync(`${basePath}.svg`, svg);
console.log(` -> ${themeName}.svg`);
terminal.dispose();
}
console.log("\nDone! Screenshots saved to docs/themes/");
}
generateScreenshots().catch(console.error);