Skip to content

Repository files navigation

🍳 cooked-folio

A minimal, editorial portfolio built with Next.js 14, Tailwind, and TypeScript.
Real-time Discord presence, Spotify now-playing, GitHub heatmap, MDX blog with syntax highlighting, dynamic OG images, and a chat-style contact form.


Discord

⚡ Deploy

One-click deploy on Vercel:

Deploy with Vercel


✨ Features

  • Discord presence via Lanyard with real status dot + current activity
  • Spotify now playing with album art
  • GitHub contributions heatmap + live star count badge in footer
  • MDX blog at /writing — auto reading time, per-post dynamic OG images, share menu (X, Facebook, Discord, copy link), related posts, syntax highlighted code blocks with copy button
  • Chat-style contact form — sequential prompts, posts to Discord webhook
  • Cal.com booking modal embedded in homepage footer
  • Sound feedback via Cuelume — hover ticks, press sounds, success chimes on every interaction
  • Dark/light theme with instant swap
  • SEO-optimized — full metadata, JSON-LD Person + WebSite + BlogPosting schema, robots.txt, dynamic sitemap
  • AI crawler friendly — GPTBot, ClaudeBot, Gemini, Perplexity explicitly allowed
  • Dark mode extension blocker — locks out Dark Reader, Night Eye, etc. so your theme stays yours
  • Editorial typography (Inter + Geist Mono), squircle avatars, no unnecessary animations, instant client-side navigation

🛠️ Tech Stack

  • Framework: Next.js 14.2 (App Router)
  • Language: TypeScript
  • Styling: Tailwind CSS
  • Fonts: Inter (body) + Geist Mono (meta/labels)
  • Content: MDX via next-mdx-remote, gray-matter, reading-time
  • Syntax highlighting: rehype-pretty-code + shiki (github-dark-dimmed theme)
  • OG images: @vercel/og with bundled Inter fonts and per-post cards
  • Icons: lucide-react, react-icons
  • Data: SWR + async server components
  • Analytics: Vercel Analytics
  • Booking: @calcom/embed-react
  • Sound feedback: cuelume

🚀 Getting Started

git clone https://github.com/shahriaravi/cooked-folio.git
cd cooked-folio
npm install
npm run dev

Open http://localhost:3000.


⚙️ Environment Variables

Copy .env.example to .env.local:

cp .env.example .env.local
Variable Description
NEXT_PUBLIC_URL Your live site URL
DISCORD_WEBHOOK_URL Discord webhook for contact messages
NEXT_PUBLIC_DISCORD_USER_ID Your Discord User ID
SPOTIFY_CLIENT_ID Spotify app Client ID
SPOTIFY_CLIENT_SECRET Spotify app Client Secret
SPOTIFY_REFRESH_TOKEN Spotify refresh token
GITHUB_USERNAME Your GitHub username
GITHUB_TOKEN GitHub PAT with read:user

🔧 Configuration

Contentsrc/lib/config.ts Socials, stack, experience, education, projects, external links.

SEOsrc/lib/site-config.ts Metadata, keywords, JSON-LD schema, OpenGraph, Twitter cards. Every page defaults to Shahriar Avi as title unless overridden per-page.

Blog postssrc/content/writing/*.mdx Filename becomes slug. Frontmatter is minimal:

---
title: "Post Title"
date: "2026-01-15"
---

Reading time, word count, slug, and per-post OG image all auto-generated.

OG imagessrc/app/writing/[slug]/opengraph-image.tsx Dynamic per-post preview cards using your background at public/images/og-bg.png, avatar, post title, and reading time. Fonts bundled at public/fonts/Inter-Regular.ttf + Inter-Bold.ttf.


📂 Project Structure

src/
├─ app/
│  ├─ api/                                # contact, discord, spotify, github routes
│  ├─ writing/
│  │  ├─ page.tsx                         # blog list
│  │  └─ [slug]/
│  │     ├─ page.tsx                      # dynamic post page (SSG)
│  │     └─ opengraph-image.tsx           # per-post OG image generator
│  ├─ contact/                            # chat-style form
│  ├─ layout.tsx                          # root: Providers, NavbarWrapper, SiteFooterWrapper, JSON-LD, fonts
│  ├─ sitemap.ts                          # dynamic sitemap
│  └─ page.tsx                            # homepage
├─ components/
│  ├─ common/                             # Container, ThemeToggle, CodeBlock, CopyButton, CustomScrollArea
│  ├─ layout/                             # Hero, Navbar, NavbarWrapper, HomeFooter, SiteFooter, SiteFooterWrapper, Providers
│  ├─ sections/                           # Experience, Education, Projects, Stack
│  ├─ integrations/                       # Discord, Spotify, GitHub cards
│  ├─ contact/                            # ContactForm
│  ├─ writing/                            # WritingList, MdxComponents, ShareMenu, MorePosts, ArticleJsonLd
│  └─ ui/                                 # TimeDisplay, Folder, LogoLoop, PixelBlast
├─ content/writing/                       # MDX blog posts
├─ hooks/                                 # useDiscordPresence
└─ lib/                                   # config, site-config, writing, utils
public/
├─ fonts/                                 # Inter-Regular.ttf, Inter-Bold.ttf (for OG images)
├─ images/                                # og-bg.png (OG background)
└─ avatar/                                # avatar.png, luffy.png, avatar-fill.png

🎨 Design System

  • Content width: 44rem (704px) centered column
  • Fonts: Inter body, Geist Mono for meta/labels/dates
  • Section overline: text-[11px] font-mono uppercase tracking-[0.14em]
  • Body copy: 16px / 24px / 0.2px
  • Headings: 22–28px semibold, tight letter-spacing
  • Avatars: squircle with fixed px radius
  • Cards: rounded-2xl with subtle border + hover tint
  • Interactions: instant CSS transitions, no page fade animations, no unnecessary pop-ins
  • Sticky footer: flex min-h-[100dvh] flex-col layout keeps footer at bottom on short pages
  • Sound design: Cuelume for tactile audio feedback on hover, press, success, error

📝 Writing System

Add a new blog post by creating a .mdx file:

src/content/writing/my-new-post.mdx

Filename becomes the URL slug (/writing/my-new-post). The list page, related posts, sitemap, and per-post OG image all update automatically on next build.

Code blocks support syntax highlighting when you specify a language after the opening backticks (tsx, ts, css, bash, powershell, python, and 100+ more via shiki). Every code block gets an always-visible copy button.


🔒 Dark Mode Extension Blocking

The site actively blocks browser extensions like Dark Reader from overriding its theme, since it already ships proper dark mode. Handled via:

  • <meta name="darkreader-lock" /> in the head
  • darkreader-ignore class + data-darkreader-ignore attribute on <html>
  • CSS reset for any [data-darkreader-inline-*] attributes
  • color-scheme: only light/dark locks

Full explanation in /writing/block-dark-mode-extensions.


🤝 Contributing

  1. Fork
  2. git checkout -b feat/thing
  3. git commit -m "feat: add thing"
  4. git push origin feat/thing
  5. Open PR

📄 License

MIT © 2026 Shahriar Avi

About

A minimal, editorial portfolio built with Next.js 14, Tailwind CSS, and TypeScript. Real-time Discord presence, Spotify integration, GitHub heatmap, MDX blog with syntax highlighting and dynamic OG images, and a chat-style contact form.

Topics

Resources

Stars

22 stars

Watchers

0 watching

Forks

Contributors

Languages