Files
soroban-abacus-flashcards/apps/web/scripts/generateDayIcon.tsx
Thomas Hallock e1369fa275 fix: configure favicon metadata and improve bead visibility
Metadata fixes:
- Update icon path from /icon.svg to /icon to match route handler
- Ensure proper MIME type (image/svg+xml) is set in both metadata and response

Favicon visibility improvements:
- Increase AbacusReact scaleFactor from 1.0 to 1.8 for larger beads
- Add hideInactiveBeads prop to hide inactive beads
- Add hide-inactive-mode class to wrapper for CSS to take effect
- Adjust outer scale to 0.48 to fit larger abacus in 100x100 viewBox
- Reposition abacus with translate(28, -2) for proper centering

CSS cleanup:
- Strip !important declarations from generated SVG (production code policy)
- Apply same fix to OG image generator

User needs to restart dev server to clear in-memory cache.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-03 08:59:14 -06:00

89 lines
2.7 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env tsx
/**
* Generate a single day-of-month favicon
* Usage: npx tsx scripts/generateDayIcon.tsx <day>
* Example: npx tsx scripts/generateDayIcon.tsx 15
*/
import React from 'react'
import { renderToStaticMarkup } from 'react-dom/server'
import { AbacusReact } from '@soroban/abacus-react'
// Extract just the SVG element content from rendered output
function extractSvgContent(markup: string): string {
const svgMatch = markup.match(/<svg[^>]*>([\s\S]*?)<\/svg>/)
if (!svgMatch) {
throw new Error('No SVG element found in rendered output')
}
return svgMatch[1]
}
// Get day from command line argument
const day = parseInt(process.argv[2], 10)
if (!day || day < 1 || day > 31) {
console.error('Usage: npx tsx scripts/generateDayIcon.tsx <day>')
console.error('Example: npx tsx scripts/generateDayIcon.tsx 15')
process.exit(1)
}
// Render 2-column abacus showing day of month
const abacusMarkup = renderToStaticMarkup(
<AbacusReact
value={day}
columns={2}
scaleFactor={1.8}
animated={false}
interactive={false}
showNumbers={false}
hideInactiveBeads={true}
customStyles={{
columnPosts: {
fill: '#1c1917',
stroke: '#0c0a09',
strokeWidth: 2,
},
reckoningBar: {
fill: '#1c1917',
stroke: '#0c0a09',
strokeWidth: 3,
},
columns: {
0: {
// Ones place - Bold Blue (high contrast)
heavenBeads: { fill: '#2563eb', stroke: '#1e40af', strokeWidth: 2 },
earthBeads: { fill: '#2563eb', stroke: '#1e40af', strokeWidth: 2 },
},
1: {
// Tens place - Bold Green (high contrast)
heavenBeads: { fill: '#16a34a', stroke: '#15803d', strokeWidth: 2 },
earthBeads: { fill: '#16a34a', stroke: '#15803d', strokeWidth: 2 },
},
},
}}
/>
)
let svgContent = extractSvgContent(abacusMarkup)
// Remove !important from CSS (production code policy)
svgContent = svgContent.replace(/\s*!important/g, '')
// Wrap in SVG with proper viewBox for favicon sizing
// AbacusReact with 2 columns + scaleFactor 1.8 = ~90×216px
// Scale 0.48 = ~43×104px (slightly overflows height, but fine for icon)
const svg = `<svg width="100" height="100" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg">
<!-- Background circle with border for definition -->
<circle cx="50" cy="50" r="48" fill="#fef3c7" stroke="#d97706" stroke-width="2"/>
<!-- Abacus showing day ${day.toString().padStart(2, '0')} (US Central Time) -->
<g class="hide-inactive-mode" transform="translate(28, -2) scale(0.48)">
${svgContent}
</g>
</svg>
`
// Output to stdout so parent process can capture it
process.stdout.write(svg)