add people

This commit is contained in:
2025-07-22 15:09:30 +02:00
parent 5437cae055
commit 6e613aad17
47 changed files with 1443 additions and 87 deletions

View File

@@ -0,0 +1,230 @@
#!/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 }

View File

@@ -0,0 +1,127 @@
#!/usr/bin/env node
const fs = require('fs')
const path = require('path')
// Paths
const peopleComponentsDir = path.join(__dirname, '../src/components/people')
const peopleDataFile = path.join(__dirname, '../src/lib/peopleData.ts')
// Function to get all People_*.tsx files
function getPeopleComponents() {
if (!fs.existsSync(peopleComponentsDir)) {
console.log('People components directory not found')
return []
}
const files = fs.readdirSync(peopleComponentsDir)
return files
.filter(file => file.startsWith('People_') && file.endsWith('.tsx'))
.map(file => {
const componentName = file.replace('.tsx', '')
const importName = componentName.toLowerCase().replace('people_', '')
return {
fileName: file,
componentName,
importName,
importPath: `@/components/people/${componentName}`
}
})
}
// Function to generate the peopleData.ts content
function generatePeopleDataContent(components) {
const imports = components
.map(comp => `import { data as ${comp.importName}Data } from '${comp.importPath}'`)
.join('\n')
const dynamicImports = components
.map(comp => ` () => import('${comp.importPath}'),`)
.join('\n')
const syncDataPush = components
.map(comp => `
try {
allPeopleData.push(...${comp.importName}Data)
} catch (error) {
console.error('Error loading ${comp.importName} data:', error)
}`)
.join('\n')
return `// This file is auto-generated by scripts/generate-people-data.js
// When new people components are added, run: npm run generate-people-data
export interface PersonData {
name: string
role: string
imageUrl: string
xUrl: string
linkedinUrl: string
}
// Function to dynamically get all people data
export async function getAllPeopleData(): Promise<PersonData[]> {
const allPeopleData: PersonData[] = []
// Auto-generated list of all people components
const peopleComponents = [
${dynamicImports}
]
for (const importComponent of peopleComponents) {
try {
const module = await importComponent()
if (module.data && Array.isArray(module.data)) {
allPeopleData.push(...module.data)
}
} catch (error) {
console.error('Error loading people data:', error)
}
}
return allPeopleData
}
// Synchronous version using static imports for immediate data access
${imports}
export function getAllPeopleDataSync(): PersonData[] {
const allPeopleData: PersonData[] = []
${syncDataPush}
return allPeopleData
}
`
}
// Main function
function main() {
console.log('🔍 Scanning for people components...')
const components = getPeopleComponents()
if (components.length === 0) {
console.log('❌ No people components found')
return
}
console.log(`✅ Found ${components.length} people component(s):`)
components.forEach(comp => {
console.log(` - ${comp.componentName}`)
})
console.log('📝 Generating peopleData.ts...')
const content = generatePeopleDataContent(components)
fs.writeFileSync(peopleDataFile, content, 'utf8')
console.log('✅ Successfully updated src/lib/peopleData.ts')
console.log('\n🎉 All people components will now automatically appear on the people page!')
}
// Run the script
if (require.main === module) {
main()
}
module.exports = { main, getPeopleComponents, generatePeopleDataContent }