A personal portfolio showcasing my journey as a developer, featured projects, and blog posts about tech.
- Live site: nathanlewis.dev
- Hosted on: Netlify
- Content managed with: Sanity.io
| Category | Technology |
|---|---|
| Frontend | React 19, React Router v6 |
| Build | Vite 6 |
| Styling | Tailwind CSS v4 |
| CMS | Sanity Studio v3 (headless) |
| Icons | Phosphor Icons |
| Content rendering | @portabletext/react (rich text), react-markdown + remark-gfm (markdown) |
| Utilities | Prism.js (code highlighting), react-social-icons |
- Node.js 22+ (see
.nvmrc) - Yarn package manager
yarn installyarn startRuns the app at http://localhost:3000.
To edit content locally:
yarn start:studioOpens Sanity Studio for managing blog posts, projects, and authors.
| Command | Description |
|---|---|
yarn start |
Start Vite dev server |
yarn dev |
Alias for yarn start |
yarn build |
Build for production |
yarn preview |
Preview production build locally |
yarn start:studio |
Start Sanity Studio for content editing |
yarn generate:sitemap |
Regenerate public/sitemap.xml |
yarn export:blog |
Export all blog posts from Sanity to markdown files |
Sanity Studio powers content for:
- Posts — Blog posts with title, slug, author, image, and body. Posts support both a Markdown body field and a rich text (Portable Text) body field. If the Markdown field has content, the frontend renders that; otherwise it falls back to the rich text body.
- Projects — Projects with title, date, place, description, type, link, and tags.
- Authors — Author profiles referenced by posts.
Changes made in Sanity are reflected in both development and production without redeploying. The frontend fetches content from the Sanity API at runtime.
- Connect the repo to Netlify.
- Build command:
yarn build - Publish directory:
build _redirectshandles SPA routing for client-side routes.
The Sanity client uses project ID 46knf8eh and dataset production. No additional env vars are required for local development.
Private portfolio project.