add people
This commit is contained in:
230
scripts/generate-all-people.js
Normal file
230
scripts/generate-all-people.js
Normal 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 }
|
127
scripts/generate-people-data.js
Normal file
127
scripts/generate-people-data.js
Normal 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 }
|
Reference in New Issue
Block a user