
Portfolio Website Development ποΈ - Part 3
28 Oct, 2023 β’ 2 min read
Part 3: Next.js 13 App Router, Contentlayer + MDX in the repo for blogs and mind nuggets, CSS modules, Framer Motion, real URLs instead of scroll sections.
Listen
Playback speed

This blog is the 3rd part after Portfolio Website Development - Part 1 and Part 2.
Part 2 ended with a single long page: anchor jumps, Hashnode pulling the latest four posts, and a layout I still liked visually. The problem showed up in day-to-day use. I kept pasting links and then typing βscroll toβ¦β or sending people to Hashnode for the full post. That is fine for a launch story. It is a bad fit when you actually want this domain to be where the writing lives.
So I rebuilt the shape of the site around real routes and MDX in the repo.
β‘ Next.js 13 and the App Router
I am on Next.js 13.4.x with the App Router (
experimental.appDir in next.config.js). The src/app/ tree now owns /, /blogs, /blogs/[slug], /mindNuggets, /mindNuggets/[slug], nested /aboutMe/*, /ideas, /mentorship, and the rest. Clicking the menu is navigation, not scrollIntoView on one canvas.The tradeoff is honest: I lost some of that βone continuous landing pageβ feel. I gained URLs I can drop in a DM, Open Graph that points at souravdey.space, and room to grow without turning
page.tsx into a junk drawer.π¦ Contentlayer + MDX
Blogs and mind nuggets are
.mdx files under src/content/. Contentlayer with next-contentlayer is what turns those files into typed documents and generated imports from contentlayer/generated (allBlogs, and the same pattern for other types). My build is yarn contentlayer build && next build.In
contentlayer.config.js I defined Blog, MindNugget, Idea, and Book document types. MDX goes through remark-gfm, rehype-slug, rehype-pretty-code (Shiki, github-dark), and rehype-autolink-headings so code blocks and headings behave the way I expect in long posts.The homepage still composes
intro.mdx and friends via @next/mdx, with experimental.mdxRs where it helps. Two MDX paths sound like extra noise. In practice it let me ship the marketing shell and the article pipeline without blocking one on the other.π¨ Styling and motion
I did not move to Tailwind for this pass. Most surfaces use CSS Modules (
page.module.css, component-level *.module.css) plus tokens in globals.css. prefers-color-scheme: dark drives a simple light or dark flip through CSS variables so I get a baseline theme without a custom toggle yet.Framer Motion is still doing the heavy lifting for scroll progress and the small transitions that stop long pages from feeling dead. Icons are lucide-react and @icons-pack/react-simple-icons where I need brand marks.
Tooling snapshot
Node 18.x in
engines, React 18.2, TypeScript 5.0.x, eslint-config-next. On blog pages dayjs, reading-time, and clsx handle dates, read time, and class names. Nothing here is trying to be clever. It is the stack I could operate while still shipping features after work.What is next?
- Tighten metadata and sharing cards per route so every blog and nugget looks right when linked on Twitter or LinkedIn.
- Keep pulling more writing off third-party hosts so souravdey.space stays the canonical place.
- Revisit the
/aboutMesubtree and side pages so they match the same content model where it makes sense. - I am sure I will find ten more rough edges once I stop touching the same three files on repeat.
If you are on a similar journey: routes first, content compiler second, polish third. I spent too long in Part 2 pretending scroll targets were URLs. Fixing that unlocked everything else.
β¨ Live site: souravdey.space