188 lines
5.8 KiB
Markdown

# Nicholai's website
This is my personal website built with Next.js 15, Tailwind CSS, and TypeScript.
## Tech Stack
Next.js 15, Tailwind CSS, Cabin font family, Turbopack, Typescript.
### Prerequisites
- Node.js 18+ installed (node modules: densest thing in the known universe.)
- npm, yarn, pnpm, whatever honestly.
### Installation
1. Clone the repository:
```bash
git clone https://git.biohazardvfx.com/Nicholai/nicholais-website.git
```
2. Install dependencies:
```bash
npm install
```
### Development
Run the development server:
```bash
npm run dev
# or
yarn dev
# or
pnpm dev
# or
bun dev
```
Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
### Pushing to Git and Docker
1. Commit changed files to main branch on gitea
`git add . && git commit -m "added higher res profile image" && git push origin main`
2. Build docker image
`docker build -t git.biohazardvfx.com/nicholai/nicholais-website:latest .`
3. Push docker package to gitea
`docker push git.biohazardvfx.com/nicholai/nicholais-website:latest`
### Building for Production
```bash
npm run build
```
### Deployment
#### Docker Deployment
This project includes a Dockerfile for containerized deployment. To build and run the application using Docker:
1. Build the image:
```bash
docker build -t nicholais-website .
```
2. Run the container:
```bash
docker run -p 3000:3000 nicholais-website
```
3. Or with environment variables:
```bash
docker run -p 3000:3000 -e NODE_ENV=production nicholais-website
```
#### Environment Variables
The application supports the following environment variables:
| Variable | Description | Default |
|----------|-------------|---------|
| `NODE_ENV` | Node.js environment | `development` |
| `PORT` | Port to run the server on | `3000` |
### Blog Authoring (MDX)
You can write posts in MDX and have them show up on `/blog`.
- Local posts: add `.mdx` files to `app/blog/posts/` (these are always included).
- Optional GitHub-backed posts: if you configure the `BLOG_*` environment variables, MDX files from your GitHub repo are fetched and merged with local posts. GitHub posts override local ones on duplicate slugs.
Setup:
1) Copy `.env.local.example` to `.env.local` and fill in values.
2) For GitHub-backed content, set:
- `BLOG_REPO=owner/repo`
- `BLOG_PATH=path/to/mdx/folder` (relative to repo root)
- `BLOG_BRANCH=main` (or your branch)
- `GITHUB_TOKEN=` (only required for private repos or higher rate limits)
Frontmatter template (put at the top of each `.mdx` file):
```md
---
title: "Post Title"
publishedAt: "2025-01-15" # YYYY-MM-DD
summary: "One-liner summary"
tags: ["tag1", "tag2"]
image: "https://your.cdn/path-or-absolute-url.jpg"
---
```
Images:
- Prefer absolute URLs (CDN or repo raw URLs) to avoid build-time asset issues.
- The MDX renderer handles links and images for you (see `components/mdx.tsx`).
How updates appear on the site:
- Incremental Static Regeneration (ISR): GitHub responses are cached with `next: { revalidate: BLOG_REVALIDATE_SECONDS }`. New/edited posts appear automatically after the configured window (default 300s).
- On-demand revalidation: trigger an immediate refresh via the `/api/revalidate` endpoint (see below) or configure a GitHub webhook to call it on each push.
### Blog Environment Variables
| Variable | Description | Default |
|----------|-------------|---------|
| `BLOG_REPO` | GitHub `owner/repo` containing your MDX files. Leave empty to use only local posts. | — |
| `BLOG_PATH` | Path in the repo where `.mdx` files live (relative to repo root). | `app/blog/posts` |
| `BLOG_BRANCH` | Branch name to read from. | `main` |
| `GITHUB_TOKEN` | GitHub token. Required for private repos or higher rate limits. | — |
| `BLOG_REVALIDATE_SECONDS` | ISR interval (seconds) for GitHub fetch cache. | `300` |
| `BLOG_CACHE_TAG` | Cache tag used for on-demand invalidation (`revalidateTag`). | `blog-content` |
| `REVALIDATE_SECRET` | Shared secret for the revalidate API and GitHub webhook signature. | — |
### On-demand Revalidation
An API route at `/api/revalidate` invalidates the blog listing and post pages, and also busts the cache tag used for GitHub content.
- GET (simple manual trigger):
- Revalidate listing:
```bash
curl -sS "https://your-domain/api/revalidate?secret=REVALIDATE_SECRET"
```
- Revalidate a specific post (by slug):
```bash
curl -sS "https://your-domain/api/revalidate?secret=REVALIDATE_SECRET&slug=my-post-slug"
```
- Optionally revalidate additional paths:
```bash
curl -sS "https://your-domain/api/revalidate?secret=REVALIDATE_SECRET&path=/blog/my-post-slug"
```
- POST (advanced, supports multiple slugs/paths):
```bash
curl -sS -X POST "https://your-domain/api/revalidate" \
-H "x-revalidate-secret: REVALIDATE_SECRET" \
-H "content-type: application/json" \
-d '{
"slugs": ["my-post-slug"],
"paths": ["/blog", "/blog/my-post-slug"]
}'
```
- GitHub Webhook (recommended):
1) In your repo settings, add a Webhook:
- Payload URL: `https://your-domain/api/revalidate`
- Content type: `application/json`
- Secret: set to the same value as `REVALIDATE_SECRET`
- Event: “Just the push event”
2) On push, the webhook sends changed file paths. The API will:
- Revalidate the `BLOG_CACHE_TAG` to refresh GitHub fetches.
- Revalidate `/blog` and any changed post slugs under `BLOG_PATH`.
Security notes:
- Do not expose `REVALIDATE_SECRET` publicly. For manual GET usage, keep the URL private.
- For CI/CD, use the POST form with the `x-revalidate-secret` header.
## License
This project is open source, take it. I don't give a fuck. I am not your dad.
## Author
Nicholai - VFX Supervisor & Developer
- Website: [nicholai.work](https://nicholai.work)
- Email: nicholai@biohazardvfx.com
- Instagram: [@nicholai.exe](https://www.instagram.com/nicholai.exe/)