DEV Community

Cover image for The Weekend I Finally Finished 17 Projects
Ado Daniel Nj
Ado Daniel Nj

Posted on

The Weekend I Finally Finished 17 Projects

You know that feeling when you open a folder you haven't touched in months and find... yourself?

Not metaphorically. I mean literally — old projects you don't even remember writing, with code that's somehow good? And you're sitting there like, "wait, I wrote this?"

That was my Saturday.


The Mess

I decided it was time. My portfolio was a ghost town. My GitHub was full of half-finished dreams. You know the drill — you start a project, get 80% there, then a shinier thing comes along and suddenly it's gathering dust for a year.

I had 17 of those.

  • LIS — An AI tutoring app for Cameroonian students. Works offline. Has a Learning DNA that adapts to how you study. I literally submitted this for a social impact prize and then... just left it there.
  • Mbende Stay — A booking platform with mobile money payments. Fully functional. Zero visitors.
  • "418 I'm a Teapot" — A game where you play as a teapot that can never win and an AI roasts you every time you fail. I'm not kidding.
  • elementTouch — A JavaScript library I built from scratch. Drag and drop. Typewriter effects, and more. A whole code editor. Just... sitting there.

And I'm looking at all of this thinking: bro, you really just built things and then forgot to tell anyone?

So I made a decision: polish them all, put them in my portfolio, and actually show the work.

First step: build an admin import tool. One click, seed 17 projects into Firestore. Felt like a genius.


Then the Universe Laughed

npm run build

ReferenceError: location is not defined
    at v (.next/server/app/admin/blog/new/page.js:1:11128)
    at y (.next/server/app/admin/projects/import/page.js:1:16875)
    at y (.next/server/app/admin/projects/new/page.js:1:8262)
    at j (.next/server/app/admin/resumes/new/page.js:1:4056)
Enter fullscreen mode Exit fullscreen mode

Four pages. Dead. And I have no idea where location is coming from.

You ever debug a Firebase + Next.js app and feel like you're chasing a ghost? Because I was definitely chasing a ghost.

Turns out, Firebase's SDK references location (as in window.location) at the module level. Not inside a function you call. At import time. So when Next.js tries to server-render your admin page, Node.js is like "what's location? never heard of her."

The fix?

import dynamic from "next/dynamic"
export default dynamic(() => import("./page.client"), { ssr: false })
Enter fullscreen mode Exit fullscreen mode

I wrapped each page in next/dynamic with ssr: false. Basically told Next.js: "Don't even look at this page on the server. Not once. Not ever. Just send the JS and let the browser figure it out."

Moved all the actual code to page.client.tsx. Build passed. I felt like a god for approximately 12 minutes.


The Betrayal

Then I looked at my blog.

You see, my blog posts are stored in Firestore as HTML. And somewhere along the way, I'd written them with beautiful Tailwind dark mode classes:

<div class="not-dark:bg-white dark:bg-gray-900 dark:shadow-lg">
Enter fullscreen mode Exit fullscreen mode

Here's the problem: Tailwind v4's JIT compiler has never heard of your database.

It scans your source files — your app/, your components/, your lib/. It does NOT make a Firebase query to find class names.

So dark:bg-gray-900 in a blog post? Never compiled. It renders as plain text with zero styles. My "beautiful blog content" was just... floating in the void. No background. No shadow. Nothing.

I sat there staring at the screen feeling personally betrayed by a CSS framework.

But hey, I fixed it:

function prepareHtml(html: string): string {
  return html.replace(/\b(?:not-)?dark:[^\s"'>]+/g, "").trim()
}
Enter fullscreen mode Exit fullscreen mode

Strip the prefixes. Then override everything with CSS variables:

.blog-content .text-gray-900 { color: inherit !important; }
.blog-content .bg-white, .blog-content .bg-gray-900 { background: transparent !important; }
.blog-content .shadow-md, .blog-content .shadow-lg { box-shadow: none !important; }
Enter fullscreen mode Exit fullscreen mode

Now every hardcoded class respects the theme. Dark mode, light mode, it just works. The blog content is finally alive.


Then There Were 17

So now I've got 17 projects in my portfolio. On one page. One. Grid. Screen. You see the problem.

I needed pagination. Not the boring kind — something that actually looks good:

  • Chevrons that bounce when you hover
  • Page numbers with the accent color on active
  • Ellipsis that only show when there's actually a gap
  • A quiet little "Page X of Y · N projects" at the bottom

The button logic nearly broke me. You try handling "first page, last page, exactly 5 pages, exactly 6 pages, ellipsis-or-no-ellipsis" without your brain melting:

const pages = useMemo(() => {
  const p: (number | "...")[] = []
  if (totalPages <= 5) {
    for (let i = 0; i < totalPages; i++) p.push(i)
  } else {
    p.push(0)
    if (safePage > 2) p.push("...")
    // ... more edge cases
  }
  return p
}, [safePage, totalPages])
Enter fullscreen mode Exit fullscreen mode

It works. It's clean. I'm proud of it.


What I Actually Learned

1. You probably have better code than you think

Open that old project. The one you're embarrassed about. I bet it's not as bad as you remember. We're all way too hard on ourselves.

2. Admin pages don't need SSR

If your page is behind a login wall, there's zero SEO value in server-rendering it. Just use ssr: false and save yourself the headache. Your admin panel will survive without being indexed by Google.

3. Tailwind v4 JIT is amazing until your content is dynamic

If your HTML lives in a database, plan ahead. CSS variables are your escape hatch. Hardcoded utility classes in data strings will come back to haunt you.

4. A portfolio is never done

Every time I thought "okay this is final," I found another project, another bug, another thing to improve. That's not failure. That's just what building in public looks like.


What's Left

elementTouch still has 2 unfinished tasks out of 7. I'll get to them.

And there's a missing admin/blog/edit/[id] page that keeps crashing the build. Just one day.


Anyway, that's my weekend. What's the most embarrassing bug you've fought with Next.js + Firebase? Drop it below so I don't feel alone.

My Portfolio

Top comments (0)