- Added Tailwind CSS configuration with custom theme colors and animations. - Created global styles in index.css including custom scrollbar and button components. - Set up main entry point in main.tsx to render the App component. - Configured TypeScript with strict settings and path mapping. - Added support for high contrast mode and reduced motion in styles. - Included print styles for better printing experience.
129 lines
4.3 KiB
JavaScript
129 lines
4.3 KiB
JavaScript
#!/usr/bin/env node
|
|
|
|
/**
|
|
* Generate Open Graph images for Miracles In Motion
|
|
* This script creates social media preview images
|
|
*/
|
|
|
|
import fs from 'fs'
|
|
import path from 'path'
|
|
|
|
const OG_CONFIG = {
|
|
width: 1200,
|
|
height: 630,
|
|
title: 'Miracles In Motion',
|
|
subtitle: 'Essentials for Every Student',
|
|
description: '501(c)3 Non-Profit Organization'
|
|
}
|
|
|
|
/**
|
|
* Create SVG template for OG image
|
|
*/
|
|
function createOGImageSVG(config = OG_CONFIG) {
|
|
return `
|
|
<svg width="${config.width}" height="${config.height}" viewBox="0 0 ${config.width} ${config.height}" xmlns="http://www.w3.org/2000/svg">
|
|
<defs>
|
|
<linearGradient id="bg-gradient" x1="0%" y1="0%" x2="100%" y2="100%">
|
|
<stop offset="0%" style="stop-color:#ec4899;stop-opacity:1" />
|
|
<stop offset="50%" style="stop-color:#8b5cf6;stop-opacity:1" />
|
|
<stop offset="100%" style="stop-color:#3b82f6;stop-opacity:1" />
|
|
</linearGradient>
|
|
<filter id="shadow" x="-20%" y="-20%" width="140%" height="140%">
|
|
<feDropShadow dx="0" dy="4" stdDeviation="8" flood-color="rgba(0,0,0,0.25)"/>
|
|
</filter>
|
|
</defs>
|
|
|
|
<!-- Background -->
|
|
<rect width="100%" height="100%" fill="url(#bg-gradient)"/>
|
|
|
|
<!-- Pattern overlay -->
|
|
<pattern id="dots" patternUnits="userSpaceOnUse" width="40" height="40">
|
|
<circle cx="20" cy="20" r="2" fill="rgba(255,255,255,0.1)"/>
|
|
</pattern>
|
|
<rect width="100%" height="100%" fill="url(#dots)"/>
|
|
|
|
<!-- Content container -->
|
|
<g transform="translate(80, 0)">
|
|
<!-- Logo area -->
|
|
<rect x="0" y="120" width="80" height="80" rx="20" fill="rgba(255,255,255,0.2)" filter="url(#shadow)"/>
|
|
<circle cx="40" cy="160" r="20" fill="white"/>
|
|
|
|
<!-- Text content -->
|
|
<text x="120" y="140" font-family="system-ui, -apple-system, sans-serif" font-size="48" font-weight="700" fill="white">
|
|
${config.title}
|
|
</text>
|
|
<text x="120" y="180" font-family="system-ui, -apple-system, sans-serif" font-size="28" font-weight="400" fill="rgba(255,255,255,0.9)">
|
|
${config.subtitle}
|
|
</text>
|
|
<text x="120" y="220" font-family="system-ui, -apple-system, sans-serif" font-size="20" font-weight="300" fill="rgba(255,255,255,0.8)">
|
|
${config.description}
|
|
</text>
|
|
|
|
<!-- Call to action -->
|
|
<rect x="120" y="280" width="200" height="50" rx="25" fill="rgba(255,255,255,0.2)" filter="url(#shadow)"/>
|
|
<text x="220" y="310" font-family="system-ui, -apple-system, sans-serif" font-size="18" font-weight="500" fill="white" text-anchor="middle">
|
|
Learn More
|
|
</text>
|
|
</g>
|
|
|
|
<!-- Bottom accent -->
|
|
<rect x="0" y="580" width="100%" height="50" fill="rgba(0,0,0,0.1)"/>
|
|
<text x="600" y="610" font-family="system-ui, -apple-system, sans-serif" font-size="16" fill="rgba(255,255,255,0.8)" text-anchor="middle">
|
|
miraclesinmotion.org
|
|
</text>
|
|
</svg>
|
|
`.trim()
|
|
}
|
|
|
|
/**
|
|
* Generate OG images
|
|
*/
|
|
function generateOGImages() {
|
|
const publicDir = path.join(process.cwd(), 'public')
|
|
|
|
// Ensure public directory exists
|
|
if (!fs.existsSync(publicDir)) {
|
|
fs.mkdirSync(publicDir, { recursive: true })
|
|
}
|
|
|
|
// Create default OG image
|
|
const defaultOG = createOGImageSVG()
|
|
fs.writeFileSync(path.join(publicDir, 'og-image.svg'), defaultOG)
|
|
|
|
console.log('✅ Generated og-image.svg')
|
|
|
|
// Create page-specific OG images
|
|
const pages = [
|
|
{ name: 'donate', title: 'Donate', subtitle: 'Help Students Succeed' },
|
|
{ name: 'volunteer', title: 'Volunteer', subtitle: 'Make a Difference' },
|
|
{ name: 'stories', title: 'Stories', subtitle: 'Impact in Action' },
|
|
]
|
|
|
|
pages.forEach(page => {
|
|
const pageOG = createOGImageSVG({
|
|
...OG_CONFIG,
|
|
title: page.title,
|
|
subtitle: page.subtitle
|
|
})
|
|
fs.writeFileSync(path.join(publicDir, `og-image-${page.name}.svg`), pageOG)
|
|
console.log(`✅ Generated og-image-${page.name}.svg`)
|
|
})
|
|
|
|
console.log('\n🎉 All OG images generated successfully!')
|
|
console.log('\nNote: These are SVG files. For production, consider converting to PNG using a tool like:')
|
|
console.log('- Puppeteer for programmatic conversion')
|
|
console.log('- Online converters')
|
|
console.log('- Design tools like Figma or Canva')
|
|
}
|
|
|
|
// Run if called directly
|
|
if (import.meta.url === `file://${process.argv[1]}`) {
|
|
try {
|
|
generateOGImages()
|
|
} catch (error) {
|
|
console.error('❌ Error generating OG images:', error)
|
|
process.exit(1)
|
|
}
|
|
}
|
|
|
|
export { generateOGImages, createOGImageSVG } |