The source for amir.sh: a portfolio, MDX blog, and custom content management system built with TypeScript and React Server Components.
The CMS supports creating, editing, publishing, and organizing posts without a full redeploy by using on-demand revalidation.
- Next.js App Router and React Server Components
- TypeScript
- Auth.js with GitHub OAuth
- Tailwind CSS
- Supabase Postgres
- Drizzle ORM
- MDX with Sugar High syntax highlighting
- Zustand for client state
- Cloudinary for CMS media
- PostHog for analytics and post views
- Upstash Redis for post likes
- Custom CMS for posts, drafts, and categories
- Owner-only GitHub OAuth
- Light, dark, and system themes
- Dynamic metadata, social images, sitemap, favicon, and page titles
- Cloudinary-backed media gallery
- PostHog analytics and post view counts
- Redis-backed post likes
- Custom tooltip, modal, toast, and navigation components
- Responsive and accessible interface
npm installCreate a .env file in the project root. It is ignored by Git.
# Application
NEXT_PUBLIC_URL="http://localhost:3000"
RESUME_URL="https://example.com/resume.pdf"
# Auth.js and GitHub OAuth
AUTH_SECRET="your-auth-secret"
AUTH_TRUST_HOST="true"
AUTH_GITHUB_ID="your-github-client-id"
AUTH_GITHUB_SECRET="your-github-client-secret"
# Postgres
DB_URL="your-postgres-connection-string"Create the GitHub OAuth app using the Auth.js GitHub provider guide. CMS authorization is restricted in src/lib/auth.ts to the repository owner's exact GitHub account ID and primary email. Forks must replace both owner identity constants before the CMS can be accessed by a different account.
Generate AUTH_SECRET with:
npx auth secretThe optional integrations use these additional variables:
# Cloudinary media gallery
NEXT_PUBLIC_CLOUDINARY_CLOUD_NAME="your-cloud-name"
CLOUDINARY_API_KEY="your-api-key"
CLOUDINARY_API_SECRET="your-api-secret"
# PostHog analytics and post views
NEXT_PUBLIC_POSTHOG_KEY="your-project-key"
NEXT_PUBLIC_POSTHOG_HOST="https://us.i.posthog.com"
POSTHOG_API_KEY="your-personal-api-key"
POSTHOG_PROJECT_ID="your-project-id"
# POSTHOG_API_HOST="https://app.posthog.com"
# Upstash Redis post likes
KV_REST_API_URL="your-rest-url"
KV_REST_API_TOKEN="your-rest-token"
# Avoid Redis writes while developing when the in-memory cache is warm
ENABLE_DEV_CACHE="true"npx drizzle-kit pushThis applies the schema in src/db/schema.ts to the database configured by DB_URL.
npm run devThe development site is available at http://localhost:3000.
npm run previewThis command formats the repository with Prettier, runs ESLint, creates a production build, and starts the production server. It modifies files when formatting changes are needed.
npx drizzle-kit studioNote
If you use Brave, you may need to disable Shields for https://local.drizzle.studio/.
Posts support Markdown and MDX.
Markdown images use the Next.js Image component. Set the optional title to priority for an image above the fold:
Use the custom Figure component to add a caption:
<Figure
src="https://example.com/image.png"
alt="Descriptive alt text"
caption="Image caption"
priority
/>Set aspect="wide" to display a full-width figure in a cropped 16:9 frame.
Use the optional position prop to control the focal point of the crop:
<Figure
src="https://example.com/image.png"
alt="Descriptive alt text"
caption="Image caption"
aspect="wide"
position="center"
/>Use the ProjectCTA component to give a live project a prominent link within a
post:
<ProjectCTA
href="https://manifold.observer"
title="Explore manifold.observer"
description="Add a source, change the conditions, and watch the form reorganize in real time."
label="Open project"
/>The optional eyebrow defaults to Live project, and the optional label
defaults to Open project. External destinations open in a new tab; internal
paths use Next.js navigation.
Add line numbers or ranges after the language identifier:
```typescript{2,3-5}
const first = true;
const second = true;
const third = true;
const fourth = true;
const fifth = true;
```Please report vulnerabilities according to the security policy. Do not disclose suspected vulnerabilities in a public issue.
This project is available under its custom source-available license. Derivative works must preserve attribution, remain publicly available, use the same terms, and substantially differ in content, visual design, and branding.