Skip to content

A Markdown blog and CMS written in TypeScript using Next.js App Router. Publish and edit blog posts without a build using On-demand Revalidation.

License

Notifications You must be signed in to change notification settings

amirardalan/amirardalan.com

Repository files navigation

amirardalan.com

Amir Ardalan's personal website built with Startup. This is a Markdown Blog and CMS written in TypeScript leveraging React Server Components. Create, edit, and manage blog posts and categories inside a custom CMS. Update static posts without a build leveraging the power of on-demand revalidation.

Stack

Features

  • Custom CMS (Publish, Edit, Manage Drafts and Categories)
  • Light/Dark/System Theme toggle
  • Dynamic (theme-based) favicon
  • Dynamic Metadata and Page Titles
  • Route-based active navigation highlighting
  • Dynamic footer copyright date
  • Custom Tooltip, Modal, and Toast components
  • Next.js optimized fonts
  • OG Image metadata
  • Dynamically-generated sitemap.xml
  • Custom Cloudinary CMS Media Gallery
  • PostHog analytics and blog post view count
  • Blog likes with Upstash Redis
  • Accessibility, perfomance, and SEO best-practices
  • 100% Lighthouse score

Getting Started

Setup

bun install

Then, set up your GitHub oAuth App and add your GitHub Client ID and Secret in a .env.local file:

// .env.local

# Set for each environment
NEXT_PUBLIC_URL="http://localhost:3000"

# Set your timezone
NEXT_PUBLIC_TIMEZONE="America/Los_Angeles"

# Resume Link (redirect in next.config.ts)
RESUME_URL=<your-resume-url>

# Auth.js
AUTH_SECRET=<your-auth-secret>
AUTH_TRUST_HOST="NEXT_PUBLIC_URL"

# GitHub OAuth
AUTH_GITHUB_ID=<your-github-client-id>
AUTH_GITHUB_SECRET=<your-github-client-secret>

# Email verification (CMS Users)
ALLOWED_EMAILS=<[email protected], [email protected]>
ALLOWED_EMAIL_DOMAINS=<gmail.com, your-domain.com>

# Supabase (CMS Database)
DB_URL=<your-supabase-transaction-pooler-url>
DB_API_KEY=<your-supabase-api-key>

# Cloudinary (CMS Media Gallery)
NEXT_PUBLIC_CLOUDINARY_CLOUD_NAME=<your-cloudinary-cloud-name>
CLOUDINARY_URL=<your-cloudinary-url>
CLOUDINARY_API_KEY=<your-cloudinary-api-key>
CLOUDINARY_API_SECRET=<your-cloudinary-api-secret>

# PostHog (Analytics)
NEXT_PUBLIC_POSTHOG_KEY=<your-posthog-key>
NEXT_PUBLIC_POSTHOG_HOST=<your-posthog-host>
POSTHOG_API_KEY=<your-posthog-api-key>
POSTHOG_PROJECT_ID=<your-posthog-project-id>

# Upstash/Redis (Blog Likes)
ENABLE_DEV_CACHE="true"
KV_URL=<your-upstash-kv-url>
KV_REST_API_READ_ONLY_TOKEN=<your-kv-rest-api-read-only-token>
REDIS_URL=<your-redis-url>
KV_REST_API_TOKEN=<your-kv-rest-api-token>
KV_REST_API_URL=<your-kv-rest-api-url>

And finally, generate a Next Auth secret which will automatically overwrite the placeholder in the .env.local file:

npx auth secret

Database

npx drizzle-kit push

Note

This command will create the database tables and columns based on the schema defined in ./src/db/schema.ts file.

Run

bun dev

Preview

To test On-demand Revalidation of blog posts and to ensure the app is in good shape to run on production it is recommended to compile a preview build.

bun preview

Note

This script will format the project using Prettier, check linting, and then compile a preview build.

Drizzle Studio

To interact with the postgres database locally:

npx drizzle-kit studio

Note

If using Brave browser you must turn Brave Shield off for https://local.drizzle.studio/

Markdown Features

Images

Blog posts are written in Markdown. Markdown images will utilize the Next Image component for optimized loading. The markdown image can be passed a priority prop:

![Alt text](https://example.com/image.png 'priority')

Or you can use an image wrapped in a custom MDX <Figure> component to add a caption (this also works with an optional priority prop for images above the fold):

<Figure src="your-image-src.png" alt="Your Image Alt" caption="Your Image Caption" priority />

Code

Highlight individual lines or blocks of code (line 2 and lines 3-5):

```typescript{2,3-5}

About

A Markdown blog and CMS written in TypeScript using Next.js App Router. Publish and edit blog posts without a build using On-demand Revalidation.

Topics

Resources

License

Security policy

Stars

Watchers

Forks

Contributors 4

  •  
  •  
  •  
  •