chore: add gray-matter dependency for markdown frontmatter parsing
This commit is contained in:
90
src/app/(main)/people/page.tsx
Normal file
90
src/app/(main)/people/page.tsx
Normal file
@@ -0,0 +1,90 @@
|
||||
import { promises as fs } from 'fs';
|
||||
import path from 'path';
|
||||
import Image from 'next/image';
|
||||
import matter from 'gray-matter';
|
||||
|
||||
interface Person {
|
||||
name: string;
|
||||
excerpt: string;
|
||||
title: string;
|
||||
imageUrl: string;
|
||||
}
|
||||
|
||||
async function getPeople(): Promise<Person[]> {
|
||||
const peopleDirectory = path.join(process.cwd(), 'public/images/people');
|
||||
try {
|
||||
const peopleFolders = await fs.readdir(peopleDirectory, { withFileTypes: true });
|
||||
|
||||
const people = await Promise.all(
|
||||
peopleFolders
|
||||
.filter(dirent => dirent.isDirectory())
|
||||
.map(async (dirent) => {
|
||||
const personDir = path.join(peopleDirectory, dirent.name);
|
||||
const files = await fs.readdir(personDir);
|
||||
const markdownFile = files.find(file => file.endsWith('.md') || file.endsWith('.mdx'));
|
||||
|
||||
if (!markdownFile) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const markdownFilePath = path.join(personDir, markdownFile);
|
||||
const fileContents = await fs.readFile(markdownFilePath, 'utf8');
|
||||
const { data } = matter(fileContents);
|
||||
|
||||
if (!data.name || !data.title || !data.image) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const imageUrl = `/images/people/${dirent.name}/${data.image.replace('./', '')}`;
|
||||
|
||||
return {
|
||||
name: data.name,
|
||||
excerpt: data.excerpt || '',
|
||||
title: data.title,
|
||||
imageUrl,
|
||||
};
|
||||
})
|
||||
);
|
||||
|
||||
return people.filter((p): p is Person => p !== null);
|
||||
} catch (error) {
|
||||
console.error('Error reading people directory:', error);
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
export default async function PeoplePage() {
|
||||
const people = await getPeople();
|
||||
|
||||
return (
|
||||
<div className=" py-24 sm:py-32">
|
||||
<div className="mx-auto max-w-7xl px-6 lg:px-8">
|
||||
<div className="mx-auto max-w-2xl lg:mx-0">
|
||||
<h2 className="text-4xl font-semibold tracking-tight text-pretty text-white sm:text-5xl">Our Team</h2>
|
||||
<p className="mt-6 text-lg/8 text-gray-400">
|
||||
We’re a dynamic group of individuals who are passionate about what we do and dedicated to delivering the
|
||||
best results for our clients.
|
||||
</p>
|
||||
</div>
|
||||
<ul
|
||||
role="list"
|
||||
className="mx-auto mt-20 grid max-w-2xl grid-cols-1 gap-x-8 gap-y-14 sm:grid-cols-2 lg:mx-0 lg:max-w-none xl:grid-cols-4"
|
||||
>
|
||||
{people.map((person, index) => (
|
||||
<li key={index}>
|
||||
<Image
|
||||
alt={person.name}
|
||||
src={person.imageUrl}
|
||||
className="aspect-square w-full rounded-2xl object-cover outline-1 -outline-offset-1 outline-white/10"
|
||||
width={400}
|
||||
height={400}
|
||||
/>
|
||||
<h3 className="mt-6 text-lg/8 font-semibold tracking-tight text-white">{person.name}</h3>
|
||||
<p className="text-base/7 text-gray-300">{person.title}</p>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user