add people
This commit is contained in:
parent
f42f90782f
commit
5437cae055
143
docs/adding-people.md
Normal file
143
docs/adding-people.md
Normal file
@ -0,0 +1,143 @@
|
|||||||
|
# Adding New People to the Team Page
|
||||||
|
|
||||||
|
This guide explains how to add new team members to the website. The system is designed to automatically display people based on existing component files.
|
||||||
|
|
||||||
|
## Current System
|
||||||
|
|
||||||
|
Currently, only **Adnan Fatayerji** appears on the people page because only his component exists in `src/components/people/People_Adnan.tsx`.
|
||||||
|
|
||||||
|
## How to Add a New Person
|
||||||
|
|
||||||
|
To add a new team member, follow these steps:
|
||||||
|
|
||||||
|
### 1. Create the Person's Component
|
||||||
|
|
||||||
|
Create a new file: `src/components/people/People_[Name].tsx`
|
||||||
|
|
||||||
|
Example for John Doe:
|
||||||
|
```typescript
|
||||||
|
import { PersonTemplate } from '@/components/PersonTemplate'
|
||||||
|
|
||||||
|
export const data = [
|
||||||
|
{
|
||||||
|
name: 'John Doe',
|
||||||
|
role: 'Software Engineer',
|
||||||
|
imageUrl: '/images/people/john_doe/john_doe.jpg',
|
||||||
|
xUrl: '#',
|
||||||
|
linkedinUrl: 'https://www.linkedin.com/in/johndoe/',
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
const biography = `
|
||||||
|
<p class="text-lg/7">
|
||||||
|
John is a passionate software engineer with expertise in modern web technologies.
|
||||||
|
He specializes in building scalable applications and has a keen interest in user experience design.
|
||||||
|
</p>
|
||||||
|
<p class="mt-5">
|
||||||
|
With over 5 years of experience in the tech industry, John has worked on various projects
|
||||||
|
ranging from startups to enterprise applications. He believes in writing clean, maintainable code
|
||||||
|
and is always eager to learn new technologies.
|
||||||
|
</p>
|
||||||
|
`
|
||||||
|
|
||||||
|
export function People_John() {
|
||||||
|
return <PersonTemplate personData={data[0]} biography={biography} />
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. Create the Person's Page Route
|
||||||
|
|
||||||
|
Create a directory and page: `src/app/people/John_Doe/page.tsx`
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
import { CallToAction } from '@/components/CallToAction'
|
||||||
|
import { Faqs } from '@/components/Faqs'
|
||||||
|
import { Footer } from '@/components/Footer'
|
||||||
|
import { Header_darkbg } from '@/components/Header_darkbg'
|
||||||
|
import { People_John } from '@/components/people/People_John'
|
||||||
|
|
||||||
|
export default function JohnDoePage() {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Header_darkbg />
|
||||||
|
<main>
|
||||||
|
<People_John />
|
||||||
|
<CallToAction />
|
||||||
|
<Faqs />
|
||||||
|
</main>
|
||||||
|
<Footer />
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. Update the People Data Registry
|
||||||
|
|
||||||
|
Add the new person's data import to `src/lib/peopleData.ts`:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// Add import
|
||||||
|
import { data as johnData } from '@/components/people/People_John'
|
||||||
|
|
||||||
|
// Add to getAllPeopleData function
|
||||||
|
export function getAllPeopleData(): PersonData[] {
|
||||||
|
const allPeopleData: PersonData[] = []
|
||||||
|
|
||||||
|
try {
|
||||||
|
allPeopleData.push(...adnanData)
|
||||||
|
allPeopleData.push(...johnData) // Add this line
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error loading people data:', error)
|
||||||
|
}
|
||||||
|
|
||||||
|
return allPeopleData
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4. Add Person's Images
|
||||||
|
|
||||||
|
Add the person's images to: `public/images/people/john_doe/`
|
||||||
|
- `john_doe.jpg` (or .png, .jpeg)
|
||||||
|
|
||||||
|
## Template System Benefits
|
||||||
|
|
||||||
|
The system now uses a **centralized template** (`PersonTemplate.tsx`) for all individual people pages. This means:
|
||||||
|
|
||||||
|
- **Global Styling**: Change image size, layout, or styling in `PersonTemplate.tsx` and it applies to ALL people's profiles
|
||||||
|
- **Consistency**: All people pages have the same structure and design
|
||||||
|
- **Easy Maintenance**: Update the template once instead of editing each person's component individually
|
||||||
|
- **Responsive Design**: Template handles all responsive breakpoints uniformly
|
||||||
|
|
||||||
|
### Customizing the Template
|
||||||
|
|
||||||
|
To change styling for all people pages (like image size), edit `src/components/PersonTemplate.tsx`:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// Example: To change image aspect ratio for all people
|
||||||
|
<img
|
||||||
|
alt={personData.name}
|
||||||
|
src={personData.imageUrl}
|
||||||
|
width={1184}
|
||||||
|
height={1376}
|
||||||
|
className="aspect-square w-full rounded-lg object-cover shadow-lg lg:aspect-auto" // Changed from aspect-12/7 to aspect-square
|
||||||
|
/>
|
||||||
|
```
|
||||||
|
|
||||||
|
## Important Notes
|
||||||
|
|
||||||
|
- **Data Structure**: Each person component must export a `data` array with the exact structure shown above
|
||||||
|
- **Biography Format**: Use HTML string for rich text formatting in the biography
|
||||||
|
- **Template Usage**: All person components should use `PersonTemplate` for consistency
|
||||||
|
- **Naming Convention**:
|
||||||
|
- Component files: `People_[FirstName].tsx`
|
||||||
|
- Page directories: `[First_Last]/page.tsx`
|
||||||
|
- Image directories: `first_last/`
|
||||||
|
- **Automatic Display**: Once all steps are completed, the person will automatically appear on the main people page
|
||||||
|
- **URL Structure**: Individual pages will be accessible at `/people/First_Last`
|
||||||
|
|
||||||
|
## Current Status
|
||||||
|
|
||||||
|
- ✅ Adnan Fatayerji - Complete (component, page, images)
|
||||||
|
- ❌ All other team members - Need to be added following the steps above
|
||||||
|
|
||||||
|
The system is designed to be scalable - each new person added will automatically appear on the team page without needing to modify the main PeopleHero component.
|
19
src/app/people/Adnan_Fatayerji/page.tsx
Normal file
19
src/app/people/Adnan_Fatayerji/page.tsx
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
import { CallToAction } from '@/components/CallToAction'
|
||||||
|
import { Faqs } from '@/components/Faqs'
|
||||||
|
import { Footer } from '@/components/Footer'
|
||||||
|
import { Header_darkbg } from '@/components/Header_darkbg'
|
||||||
|
import { People_Adnan } from '@/components/people/People_Adnan'
|
||||||
|
|
||||||
|
export default function AdnanFatayerjiPage() {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Header_darkbg />
|
||||||
|
<main>
|
||||||
|
<People_Adnan />
|
||||||
|
<CallToAction />
|
||||||
|
<Faqs />
|
||||||
|
</main>
|
||||||
|
<Footer />
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
32
src/app/people/page.tsx
Normal file
32
src/app/people/page.tsx
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
import { CallToAction } from '@/components/CallToAction'
|
||||||
|
import { Faqs } from '@/components/Faqs'
|
||||||
|
import { Footer } from '@/components/Footer'
|
||||||
|
import { Header_darkbg } from '@/components/Header_darkbg'
|
||||||
|
import { HomeAbout } from '@/components/HomeAbout'
|
||||||
|
import { Hero } from '@/components/Hero'
|
||||||
|
import { Pricing } from '@/components/Pricing'
|
||||||
|
import { PrimaryFeatures } from '@/components/PrimaryFeatures'
|
||||||
|
import { SecondaryFeatures } from '@/components/SecondaryFeatures'
|
||||||
|
import { Testimonials } from '@/components/Testimonials'
|
||||||
|
import { HomePrinciples } from '@/components/HomePrinciples'
|
||||||
|
import { HomeMilestones } from '@/components/HomeMilestones'
|
||||||
|
import { HomeVentures } from '@/components/HomeVentures'
|
||||||
|
import { Quote } from '@/components/Quote'
|
||||||
|
import { AboutHero } from '@/components/AboutHero'
|
||||||
|
import { AboutMission } from '@/components/AboutMission'
|
||||||
|
import { AboutExperience } from '@/components/AboutExperience'
|
||||||
|
import { PeopleHero } from '@/components/PeopleHero'
|
||||||
|
|
||||||
|
export default function People() {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Header_darkbg />
|
||||||
|
<main>
|
||||||
|
<PeopleHero />
|
||||||
|
<CallToAction />
|
||||||
|
<Faqs />
|
||||||
|
</main>
|
||||||
|
<Footer />
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
65
src/components/PeopleHero.tsx
Normal file
65
src/components/PeopleHero.tsx
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
import Link from 'next/link'
|
||||||
|
import { getAllPeopleData, PersonData } from '@/lib/peopleData'
|
||||||
|
|
||||||
|
// Function to convert name to URL slug
|
||||||
|
function nameToSlug(name: string): string {
|
||||||
|
return name.replace(/\s+/g, '_')
|
||||||
|
}
|
||||||
|
|
||||||
|
export function PeopleHero() {
|
||||||
|
const people = getAllPeopleData()
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="bg-white 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-gray-900 sm:text-5xl">Our team</h2>
|
||||||
|
<p className="mt-6 text-lg/8 text-gray-600">
|
||||||
|
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-16 sm:grid-cols-2 lg:mx-0 lg:max-w-none lg:grid-cols-4"
|
||||||
|
>
|
||||||
|
{people.map((person) => (
|
||||||
|
<li key={person.name}>
|
||||||
|
<img
|
||||||
|
alt=""
|
||||||
|
src={person.imageUrl}
|
||||||
|
className="aspect-1/1 w-full rounded-2xl object-cover outline-1 -outline-offset-1 outline-black/5"
|
||||||
|
/>
|
||||||
|
<Link href={`/people/${nameToSlug(person.name)}`}>
|
||||||
|
<h3 className="mt-6 text-lg/8 font-semibold tracking-tight text-gray-900 hover:text-indigo-600 cursor-pointer">{person.name}</h3>
|
||||||
|
</Link>
|
||||||
|
<p className="text-base/7 text-gray-600">{person.role}</p>
|
||||||
|
<ul role="list" className="mt-6 flex gap-x-6">
|
||||||
|
<li>
|
||||||
|
<a href={person.xUrl} className="text-gray-400 hover:text-gray-500">
|
||||||
|
<span className="sr-only">X</span>
|
||||||
|
<svg fill="currentColor" viewBox="0 0 20 20" aria-hidden="true" className="size-5">
|
||||||
|
<path d="M11.4678 8.77491L17.2961 2H15.915L10.8543 7.88256L6.81232 2H2.15039L8.26263 10.8955L2.15039 18H3.53159L8.87581 11.7878L13.1444 18H17.8063L11.4675 8.77491H11.4678ZM9.57608 10.9738L8.95678 10.0881L4.02925 3.03974H6.15068L10.1273 8.72795L10.7466 9.61374L15.9156 17.0075H13.7942L9.57608 10.9742V10.9738Z" />
|
||||||
|
</svg>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a href={person.linkedinUrl} className="text-gray-400 hover:text-gray-500">
|
||||||
|
<span className="sr-only">LinkedIn</span>
|
||||||
|
<svg fill="currentColor" viewBox="0 0 20 20" aria-hidden="true" className="size-5">
|
||||||
|
<path
|
||||||
|
d="M16.338 16.338H13.67V12.16c0-.995-.017-2.277-1.387-2.277-1.39 0-1.601 1.086-1.601 2.207v4.248H8.014v-8.59h2.559v1.174h.037c.356-.675 1.227-1.387 2.526-1.387 2.703 0 3.203 1.778 3.203 4.092v4.711zM5.005 6.575a1.548 1.548 0 11-.003-3.096 1.548 1.548 0 01.003 3.096zm-1.337 9.763H6.34v-8.59H3.667v8.59zM17.668 1H2.328C1.595 1 1 1.581 1 2.298v15.403C1 18.418 1.595 19 2.328 19h15.34c.734 0 1.332-.582 1.332-1.299V2.298C19 1.581 18.402 1 17.668 1z"
|
||||||
|
clipRule="evenodd"
|
||||||
|
fillRule="evenodd"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
))}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
87
src/components/PersonTemplate.tsx
Normal file
87
src/components/PersonTemplate.tsx
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
import { CameraIcon } from '@heroicons/react/20/solid'
|
||||||
|
import { PersonData } from '@/lib/peopleData'
|
||||||
|
|
||||||
|
interface PersonTemplateProps {
|
||||||
|
personData: PersonData
|
||||||
|
biography: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export function PersonTemplate({ personData, biography }: PersonTemplateProps) {
|
||||||
|
return (
|
||||||
|
<div className="overflow-hidden bg-white">
|
||||||
|
<div className="relative mx-auto max-w-7xl px-6 py-16 lg:px-8">
|
||||||
|
<div className="absolute top-0 bottom-0 left-3/4 hidden w-screen bg-gray-50 lg:block" />
|
||||||
|
<div className="mx-auto max-w-prose text-base lg:grid lg:max-w-none lg:grid-cols-2 lg:gap-8">
|
||||||
|
<div>
|
||||||
|
<h2 className="text-lg font-semibold text-indigo-600">Team Member</h2>
|
||||||
|
<h3 className="mt-2 text-3xl/8 font-bold tracking-tight text-gray-900 sm:text-4xl">Meet {personData.name}</h3>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="mt-8 lg:grid lg:grid-cols-2 lg:gap-8">
|
||||||
|
<div className="relative lg:col-start-2 lg:row-start-1">
|
||||||
|
<svg
|
||||||
|
fill="none"
|
||||||
|
width={404}
|
||||||
|
height={384}
|
||||||
|
viewBox="0 0 404 384"
|
||||||
|
aria-hidden="true"
|
||||||
|
className="absolute top-0 right-0 -mt-20 -mr-20 hidden lg:block"
|
||||||
|
>
|
||||||
|
<defs>
|
||||||
|
<pattern
|
||||||
|
x={0}
|
||||||
|
y={0}
|
||||||
|
id="de316486-4a29-4312-bdfc-fbce2132a2c1"
|
||||||
|
width={20}
|
||||||
|
height={20}
|
||||||
|
patternUnits="userSpaceOnUse"
|
||||||
|
>
|
||||||
|
<rect x={0} y={0} fill="currentColor" width={4} height={4} className="text-gray-200" />
|
||||||
|
</pattern>
|
||||||
|
</defs>
|
||||||
|
<rect fill="url(#de316486-4a29-4312-bdfc-fbce2132a2c1)" width={404} height={384} />
|
||||||
|
</svg>
|
||||||
|
<div className="relative mx-auto max-w-prose text-base lg:max-w-none">
|
||||||
|
<figure>
|
||||||
|
<img
|
||||||
|
alt={personData.name}
|
||||||
|
src={personData.imageUrl}
|
||||||
|
width={1184}
|
||||||
|
height={1376}
|
||||||
|
className="aspect-12/7 w-full rounded-lg object-cover shadow-lg lg:aspect-auto"
|
||||||
|
/>
|
||||||
|
<figcaption className="mt-3 flex text-sm text-gray-500">
|
||||||
|
<CameraIcon aria-hidden="true" className="size-5 flex-none text-gray-400" />
|
||||||
|
<span className="ml-2">Professional Photo</span>
|
||||||
|
</figcaption>
|
||||||
|
</figure>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="mt-8 lg:mt-0">
|
||||||
|
<div className="mx-auto text-base/7 text-gray-500">
|
||||||
|
<p className="text-lg/7 font-semibold text-gray-900 mb-4">{personData.role}</p>
|
||||||
|
<div
|
||||||
|
className="prose prose-gray max-w-none"
|
||||||
|
dangerouslySetInnerHTML={{ __html: biography }}
|
||||||
|
/>
|
||||||
|
|
||||||
|
{/* Social Links */}
|
||||||
|
{personData.linkedinUrl && personData.linkedinUrl !== '#' && (
|
||||||
|
<div className="mt-8">
|
||||||
|
<a
|
||||||
|
href={personData.linkedinUrl}
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
className="inline-flex items-center px-4 py-2 border border-transparent text-sm font-medium rounded-md text-white bg-indigo-600 hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500"
|
||||||
|
>
|
||||||
|
Connect on LinkedIn
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
24
src/components/people/People_Adnan.tsx
Normal file
24
src/components/people/People_Adnan.tsx
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
import { PersonTemplate } from '@/components/PersonTemplate'
|
||||||
|
|
||||||
|
export const data = [
|
||||||
|
{
|
||||||
|
name: 'Adnan Fatayerji',
|
||||||
|
role: 'Co-Founder, CEO',
|
||||||
|
imageUrl: '/images/people/adnan_fatayerji/adnan_fatayerji.jpg',
|
||||||
|
xUrl: '#',
|
||||||
|
linkedinUrl: 'https://www.linkedin.com/in/adnansf/',
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
const biography = `
|
||||||
|
<p class="text-lg/7">
|
||||||
|
Adnan is a systems thinker and venture architect with a lifelong focus on reimagining how digital systems serve people. With a background spanning economics, strategy, and frontier technologies, his work bridges innovation and impact—bringing visionary ideas into scalable, grounded execution.
|
||||||
|
</p>
|
||||||
|
<p class="mt-5">
|
||||||
|
He has spent over a decade exploring how infrastructure, governance, and technology can evolve to empower communities, not just corporations. At OurWorld, Adnan leads strategy, growth, and ecosystem development, guiding ventures that are rooted in sovereignty, collective intelligence, and long-term resilience.
|
||||||
|
</p>
|
||||||
|
`
|
||||||
|
|
||||||
|
export function People_Adnan() {
|
||||||
|
return <PersonTemplate personData={data[0]} biography={biography} />
|
||||||
|
}
|
31
src/lib/peopleData.ts
Normal file
31
src/lib/peopleData.ts
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
// This file dynamically imports all people data from components
|
||||||
|
// When new people components are added, they will automatically appear
|
||||||
|
|
||||||
|
export interface PersonData {
|
||||||
|
name: string
|
||||||
|
role: string
|
||||||
|
imageUrl: string
|
||||||
|
xUrl: string
|
||||||
|
linkedinUrl: string
|
||||||
|
}
|
||||||
|
|
||||||
|
// Import all existing people data
|
||||||
|
import { data as adnanData } from '@/components/people/People_Adnan'
|
||||||
|
|
||||||
|
// Function to get all people data
|
||||||
|
export function getAllPeopleData(): PersonData[] {
|
||||||
|
const allPeopleData: PersonData[] = []
|
||||||
|
|
||||||
|
// Add data from all existing people components
|
||||||
|
try {
|
||||||
|
allPeopleData.push(...adnanData)
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error loading Adnan data:', error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// When new people components are created, add their imports here:
|
||||||
|
// import { data as newPersonData } from '@/components/people/People_NewPerson'
|
||||||
|
// allPeopleData.push(...newPersonData)
|
||||||
|
|
||||||
|
return allPeopleData
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user