fix: add xmlns to AbacusStatic for Typst SVG parsing

- Add xmlns="http://www.w3.org/2000/svg" to AbacusStatic root svg element
- Fixes "failed to parse SVG (missing root node)" Typst error
- React's renderToStaticMarkup doesn't add xmlns by default
- Required for standalone SVG files used outside HTML context
- Added debug logging to calendar generation route

Root cause: Typst's SVG parser requires explicit XML namespace declaration.
React assumes SVGs are embedded in HTML where xmlns is optional.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Thomas Hallock
2025-11-03 20:10:06 -06:00
parent 858a1b4976
commit 98cd019d4a
2 changed files with 35 additions and 10 deletions

View File

@@ -37,20 +37,44 @@ export async function POST(request: NextRequest) {
// Generate day SVGs (1 to maxDay)
for (let day = 1; day <= maxDay; day++) {
const svg = execSync(`npx tsx "${scriptPath}" ${day} 2`, {
encoding: 'utf-8',
cwd: process.cwd(),
})
writeFileSync(join(tempDir, `day-${day}.svg`), svg)
try {
const svg = execSync(`npx tsx "${scriptPath}" ${day} 2`, {
encoding: 'utf-8',
cwd: process.cwd(),
stdio: ['pipe', 'pipe', 'pipe'],
})
if (!svg || svg.trim().length === 0) {
console.error(`Empty SVG for day ${day}`)
throw new Error(`Generated empty SVG for day ${day}`)
}
writeFileSync(join(tempDir, `day-${day}.svg`), svg)
} catch (error: any) {
console.error(`Error generating day ${day} SVG:`, error.stderr || error.message)
throw error
}
}
// Generate year SVG
const yearColumns = Math.max(1, Math.ceil(Math.log10(year + 1)))
const yearSvg = execSync(`npx tsx "${scriptPath}" ${year} ${yearColumns}`, {
encoding: 'utf-8',
cwd: process.cwd(),
})
writeFileSync(join(tempDir, 'year.svg'), yearSvg)
try {
const yearSvg = execSync(`npx tsx "${scriptPath}" ${year} ${yearColumns}`, {
encoding: 'utf-8',
cwd: process.cwd(),
stdio: ['pipe', 'pipe', 'pipe'],
})
console.log(`Year SVG length: ${yearSvg.length}, starts with: ${yearSvg.substring(0, 100)}`)
if (!yearSvg || yearSvg.trim().length === 0) {
console.error(`Empty SVG for year ${year}`)
throw new Error(`Generated empty SVG for year ${year}`)
}
writeFileSync(join(tempDir, 'year.svg'), yearSvg)
// Debug: also save to /tmp for inspection
writeFileSync('/tmp/debug-year.svg', yearSvg)
console.log('Saved debug year.svg to /tmp/debug-year.svg')
} catch (error: any) {
console.error(`Error generating year ${year} SVG:`, error.stderr || error.message)
throw error
}
// Generate Typst document
const typstContent =

View File

@@ -205,6 +205,7 @@ export function AbacusStatic({
return (
<svg
xmlns="http://www.w3.org/2000/svg"
width={width * scaleFactor}
height={height * scaleFactor}
viewBox={`0 0 ${width} ${height}`}