www_ourworld_new/scripts/generate-all-people.js
2025-07-22 15:09:30 +02:00

231 lines
6.8 KiB
JavaScript

#!/usr/bin/env node
const fs = require('fs')
const path = require('path')
// Paths
const peopleImagesDir = path.join(__dirname, '../public/images/people')
const peopleComponentsDir = path.join(__dirname, '../src/components/people')
const peopleAppDir = path.join(__dirname, '../src/app/people')
// Function to parse markdown frontmatter
function parseFrontmatter(content) {
const frontmatterRegex = /^---\n([\s\S]*?)\n---\n([\s\S]*)$/
const match = content.match(frontmatterRegex)
if (!match) return null
const frontmatter = {}
const body = match[2].trim()
// Parse YAML-like frontmatter
const lines = match[1].split('\n')
let currentKey = null
for (const line of lines) {
const trimmed = line.trim()
if (!trimmed) continue
if (trimmed.includes(':') && !trimmed.startsWith(' ')) {
const [key, ...valueParts] = trimmed.split(':')
const value = valueParts.join(':').trim()
currentKey = key.trim()
if (value) {
if (value.startsWith('[') && value.endsWith(']')) {
// Array value
frontmatter[currentKey] = value.slice(1, -1).split(',').map(v => v.trim())
} else if (value.startsWith('{') && value.endsWith('}')) {
// Object value - parse simple key-value pairs
const obj = {}
const objContent = value.slice(1, -1)
const pairs = objContent.split(',')
for (const pair of pairs) {
const [k, v] = pair.split(':').map(s => s.trim())
if (k && v) {
obj[k] = v
}
}
frontmatter[currentKey] = obj
} else {
frontmatter[currentKey] = value
}
}
}
}
return { frontmatter, body }
}
// Function to convert name to component name
function nameToComponentName(name) {
return name.replace(/\s+/g, '_').replace(/[^a-zA-Z0-9_]/g, '')
}
// Function to convert name to function name
function nameToFunctionName(name) {
return 'People_' + nameToComponentName(name)
}
// Function to generate people component
function generatePeopleComponent(personData) {
const { name, role, imageUrl, linkedinUrl, description } = personData
const functionName = nameToFunctionName(name)
return `import { PersonTemplate } from '@/components/PersonTemplate'
export const data = [
{
name: '${name}',
role: '${role}',
imageUrl: '${imageUrl}',
xUrl: '#',
linkedinUrl: '${linkedinUrl || '#'}',
},
]
const biography = \`
<p class="text-lg/7">
${description || `${name} is a valued member of our team, bringing expertise and dedication to their role as ${role}.`}
</p>
\`
export function ${functionName}() {
return <PersonTemplate personData={data[0]} biography={biography} />
}
`
}
// Function to generate page component
function generatePageComponent(personData) {
const { name } = personData
const functionName = nameToFunctionName(name)
const componentName = nameToComponentName(name)
const pageFunctionName = name.replace(/\s+/g, '') + 'Page'
return `import { CallToAction } from '@/components/CallToAction'
import { Faqs } from '@/components/Faqs'
import { Footer } from '@/components/Footer'
import { Header_darkbg } from '@/components/Header_darkbg'
import { ${functionName} } from '@/components/people/People_${componentName}'
export default function ${pageFunctionName}() {
return (
<>
<Header_darkbg />
<main>
<${functionName} />
<CallToAction />
<Faqs />
</main>
<Footer />
</>
)
}
`
}
// Main function
function main() {
console.log('🔍 Scanning for people data...')
if (!fs.existsSync(peopleImagesDir)) {
console.log('❌ People images directory not found')
return
}
const peopleDirectories = fs.readdirSync(peopleImagesDir)
.filter(dir => {
const dirPath = path.join(peopleImagesDir, dir)
return fs.statSync(dirPath).isDirectory() && dir !== '_index.md'
})
console.log(`✅ Found ${peopleDirectories.length} people directories`)
let generatedCount = 0
let updatedCount = 0
for (const personDir of peopleDirectories) {
try {
const indexPath = path.join(peopleImagesDir, personDir, 'index.md')
if (!fs.existsSync(indexPath)) {
console.log(`⚠️ No index.md found for ${personDir}`)
continue
}
const content = fs.readFileSync(indexPath, 'utf8')
const parsed = parseFrontmatter(content)
if (!parsed) {
console.log(`⚠️ Could not parse frontmatter for ${personDir}`)
continue
}
const { frontmatter, body } = parsed
// Find the actual image file
const imageExtensions = ['jpg', 'jpeg', 'png']
let actualImagePath = frontmatter.extra?.imgPath
if (!actualImagePath) {
// Try to find the image file with different extensions
for (const ext of imageExtensions) {
const imagePath = path.join(peopleImagesDir, personDir, `${personDir}.${ext}`)
if (fs.existsSync(imagePath)) {
actualImagePath = `${personDir}.${ext}`
break
}
}
// Fallback to jpg if no image found
actualImagePath = actualImagePath || `${personDir}.jpg`
}
// Extract person data
const personData = {
name: frontmatter.title || personDir.replace(/_/g, ' '),
role: frontmatter.description || 'Team Member',
imageUrl: `/images/people/${personDir}/${actualImagePath}`,
linkedinUrl: frontmatter.extra?.socialLinks?.LinkedIn || '#',
description: body || `${frontmatter.title} is a valued member of our team.`
}
// Generate component
const componentName = nameToComponentName(personData.name)
const componentPath = path.join(peopleComponentsDir, `People_${componentName}.tsx`)
if (!fs.existsSync(componentPath)) {
const componentContent = generatePeopleComponent(personData)
fs.writeFileSync(componentPath, componentContent, 'utf8')
console.log(`✅ Generated component: People_${componentName}.tsx`)
generatedCount++
}
// Update page.tsx
const pagePath = path.join(peopleAppDir, personDir, 'page.tsx')
if (fs.existsSync(pagePath)) {
const pageContent = generatePageComponent(personData)
fs.writeFileSync(pagePath, pageContent, 'utf8')
console.log(`✅ Updated page: ${personDir}/page.tsx`)
updatedCount++
}
} catch (error) {
console.error(`❌ Error processing ${personDir}:`, error.message)
}
}
console.log(`\n🎉 Generation complete!`)
console.log(` - Generated ${generatedCount} new components`)
console.log(` - Updated ${updatedCount} page files`)
console.log(`\n📝 Run 'npm run generate-people-data' to update the data registry`)
}
// Run the script
if (require.main === module) {
main()
}
module.exports = { main }