Projects Feature
The portfolio showcases GitHub projects with dynamic documentation rendering.
Features
- Project Gallery - Grid display of portfolio projects
- Dynamic Docs - Render docs from GitHub repositories
- GitHub Integration - Pull project metadata via API
- Search - Filter projects by technology or name
Architecture
┌─────────────────────────────────────────────────────────────────┐
│ /projects │
│ ┌─────────────────────────────────────────────────────────────┐│
│ │ Project Gallery ││
│ │ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ ││
│ │ │Project 1│ │Project 2│ │Project 3│ │Project 4│ ││
│ │ └────┬────┘ └────┬────┘ └────┬────┘ └────┬────┘ ││
│ └───────┼────────────┼────────────┼────────────┼──────────────┘│
└──────────┼────────────┼────────────┼────────────┼───────────────┘
│ │ │ │
└────────────┴────────────┴────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────┐
│ /projects/[pid]/doc/[...path] │
│ ┌─────────────────────────────────────────────────────────────┐│
│ │ Dynamic Documentation ││
│ │ Rendered from GitHub repository docs ││
│ └─────────────────────────────────────────────────────────────┘│
└─────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────┐
│ GitHub API │
│ ┌─────────────────┐ ┌─────────────────┐ │
│ │ Portfolio Gist │ │ Repository Docs │ │
│ │ (projects.json) │ │ (/docs, README) │ │
│ └─────────────────┘ └─────────────────┘ │
└─────────────────────────────────────────────────────────────────┘
Data Sources
Portfolio Gist
Projects defined in GitHub gist (PORTFOLIO_GIST_ID):
// projects.json
{
"projects": [
{
"id": "my-project",
"name": "My Project",
"description": "A cool project",
"repo": "owner/my-project",
"technologies": ["React", "TypeScript"],
"featured": true,
"docsPath": "docs"
}
]
}
GitHub Repository
Additional metadata fetched from GitHub:
- Stars, forks, watchers
- Last updated timestamp
- Topics/tags
- Languages
Routes
Project List
Route: /projects
Displays grid of all portfolio projects:
// src/app/projects/page.tsx
export default async function ProjectsPage() {
const projects = await getProjects();
return <ProjectGrid projects={projects} />;
}
Project Detail
Route: /projects/[pid]
Shows single project with README:
// src/app/projects/[pid]/page.tsx
export default async function ProjectPage({ params }) {
const project = await getProject(params.pid);
const readme = await getRepoReadme(project.repo);
return <ProjectDetail project={project} readme={readme} />;
}
Project Documentation
Route: /projects/[pid]/doc/[...path]
Renders documentation from repository:
// src/app/projects/[pid]/doc/[...path]/page.tsx
export default async function DocPage({ params }) {
const { pid, path } = params;
const project = await getProject(pid);
const content = await getRepoFile(project.repo, path.join('/'));
return <MarkdownRenderer content={content} />;
}
API Endpoints
| Endpoint | Method | Description |
|----------|--------|-------------|
| /api/github/portfolio-repos | GET | List all portfolio repos |
| /api/github/repos/[owner]/[repo] | GET | Get repo metadata |
| /api/github/repos/[owner]/[repo]/readme | GET | Get repo README |
| /api/github/repos/[owner]/[repo]/contents/[...path] | GET | Get file contents |
GitHub Integration
Authentication
GH_TOKEN=ghp_your_personal_access_token
@portfolio/github-data
Uses Octokit for API access:
import { createGitHubClient, fetchRepoFile } from '@portfolio/github-data';
const client = createGitHubClient(process.env.GH_TOKEN);
const content = await fetchRepoFile(client, 'owner/repo', 'docs/guide.md');
Caching
ISR Configuration
Projects page uses ISR with revalidation:
export const revalidate = 3600; // 1 hour
Cache Tags
// Revalidate all projects
await revalidateTag('github-repos');
// Revalidate specific project
await revalidateTag(`project:${projectId}`);
Search and Filtering
Client-Side Search
const filteredProjects = projects.filter(p =>
p.name.toLowerCase().includes(query) ||
p.technologies.some(t => t.toLowerCase().includes(query))
);
Technology Filters
Filter by technology stack:
const reactProjects = projects.filter(p =>
p.technologies.includes('React')
);
Development
Fixture Mode
Use mock projects during development:
PORTFOLIO_TEST_FIXTURES=true pnpm dev
Real Data
Connect to GitHub API:
PORTFOLIO_TEST_FIXTURES= pnpm dev
Preprocessing
Projects are preprocessed for chat search:
pnpm chat:preprocess
Generates:
generated/projects.json- Project listgenerated/projects-embeddings.json- Vector embeddings
Related Documentation
- Chat Overview - How projects integrate with chat
- GitHub Data Package - API client
