claude-prism/apps/desktop/scripts/generate-previews.ts
delibae 95c4072ec1 chore: fix all lint and formatting issues (biome check)
- Fix unused imports and variables
- Apply biome formatting (template literals, semicolons, line width)
- Fix a11y issues (label associations, anchor content)
- Fix Node.js import protocol (node:fs, node:path)
- Use self.onmessage in web worker

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-16 17:04:36 +09:00

140 lines
4.1 KiB
TypeScript

/**
* Generate example projects for all LaTeX templates.
*
* Usage: pnpm --filter @claude-prism/desktop generate-previews
*
* Requires pdflatex to be installed (part of TeX Live / MacTeX).
* Output: public/examples/{template-id}/main.tex, main.pdf, references.bib (if applicable)
*/
import { execSync } from "node:child_process";
import fs from "node:fs";
import path from "node:path";
import os from "node:os";
import { fileURLToPath } from "node:url";
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
// Import template registry (pure data, no DOM dependencies)
const registryPath = path.resolve(__dirname, "../src/lib/template-registry.ts");
// Since this is a .ts file with exports, we rely on tsx to handle it
async function loadTemplates() {
const mod = await import(registryPath);
return mod.getAllTemplates() as Array<{
id: string;
name: string;
mainFileName: string;
content: string;
hasBibliography: boolean;
}>;
}
const EXAMPLES_DIR = path.resolve(__dirname, "../public/examples");
const COMPILE_TIMEOUT = 30_000;
async function main() {
console.log("Generating example projects...\n");
const templates = await loadTemplates();
let successCount = 0;
let failCount = 0;
for (const template of templates) {
process.stdout.write(` ${template.id}... `);
const exampleDir = path.join(EXAMPLES_DIR, template.id);
fs.mkdirSync(exampleDir, { recursive: true });
const tmpDir = fs.mkdtempSync(
path.join(os.tmpdir(), `prism-preview-${template.id}-`),
);
try {
// Write .tex file (inject \null for blank templates to force a page)
let content = template.content;
if (template.id === "blank") {
content = content.replace(
"\\begin{document}",
"\\begin{document}\n\\null",
);
}
const texPath = path.join(tmpDir, template.mainFileName);
fs.writeFileSync(texPath, content, "utf-8");
// Write stub .bib if template uses bibliography
if (template.hasBibliography) {
fs.writeFileSync(
path.join(tmpDir, "references.bib"),
"% empty bibliography\n",
"utf-8",
);
}
const cmd = [
"pdflatex",
"-interaction=nonstopmode",
`-output-directory=${tmpDir}`,
texPath,
].join(" ");
// First pass
execSync(cmd, { cwd: tmpDir, timeout: COMPILE_TIMEOUT, stdio: "pipe" });
// Second pass (for TOC, references, etc.)
try {
execSync(cmd, { cwd: tmpDir, timeout: COMPILE_TIMEOUT, stdio: "pipe" });
} catch {
// Second pass failure is non-fatal
}
// Copy source files to example folder
fs.copyFileSync(texPath, path.join(exampleDir, template.mainFileName));
if (template.hasBibliography) {
fs.copyFileSync(
path.join(tmpDir, "references.bib"),
path.join(exampleDir, "references.bib"),
);
}
// Copy compiled PDF to example folder
const pdfName = template.mainFileName.replace(/\.tex$/, ".pdf");
const pdfPath = path.join(tmpDir, pdfName);
if (fs.existsSync(pdfPath)) {
fs.copyFileSync(pdfPath, path.join(exampleDir, pdfName));
const sizeKb = Math.round(
fs.statSync(path.join(exampleDir, pdfName)).size / 1024,
);
console.log(`OK (${sizeKb} KB)`);
successCount++;
} else {
console.log("WARN: no PDF output");
failCount++;
}
} catch (err) {
const msg =
err instanceof Error ? err.message.slice(0, 120) : String(err);
console.log(`FAIL: ${msg}`);
failCount++;
} finally {
fs.rmSync(tmpDir, { recursive: true, force: true });
}
}
console.log(`\nDone: ${successCount} succeeded, ${failCount} failed`);
if (failCount > 0) {
console.log(
"Note: Failed templates may require document classes not installed in your TeX distribution.",
);
console.log(
"The gallery will show CSS fallback thumbnails for those templates.",
);
}
}
main().catch((err) => {
console.error("Fatal error:", err);
process.exit(1);
});