Personal website and blog, covering portfolio, experience, and writing about Spark, Delta Lake, and Databricks.
🔗 Live site: https://anhcodes.dev/
- Next.js 15 (App Router) + TypeScript
- Tailwind CSS v4 — warm editorial theme
- Markdown content via
gray-matter+unified(remark/rehype), withrehype-pretty-codefor syntax highlighting - Firebase Hosting — served as a static export (site
anhcodesdev)
The entire app lives in the web/ subdirectory.
.
├── firebase.json # Firebase Hosting config (serves web/out)
├── .firebaserc # Firebase project alias (anhcodesdev)
├── web/
│ ├── content/blog/ # Blog posts (Markdown + front matter)
│ ├── public/images/ # Static assets (blog covers, portfolio)
│ └── src/
│ ├── app/ # App Router routes (home, blog, resume, …)
│ ├── components/ # Section + UI components
│ ├── data/site.ts # Typed homepage/site content (edit here)
│ └── lib/posts.ts # Markdown parsing & rendering
└── .github/workflows/ # CI: build + deploy to Firebase
All commands run from web/:
cd web
npm install # first-time setup
npm run dev # dev server at http://localhost:3000 (live reload)
npm run build # static export → web/out/
npm run lint # eslintThere is no test suite; use npm run build and npx tsc --noEmit to catch errors.
- Homepage — edit the relevant export in
web/src/data/site.ts(hero,about,experience,skills,projects,testimonials,contact,socials), not the components. - New blog post — add
web/content/blog/<slug>.mdwith front matter (title,date,description,cover,categories,tags,author,draft). Put images inweb/public/images/single-blog/<slug>/. Posts withdraft: trueshow in dev but are hidden in production builds. - New project — add an entry to the
projectsarray inweb/src/data/site.ts; thumbnails go inweb/public/images/portfolio/.
The site is a static export (next.config.ts sets output: "export", images.unoptimized: true, trailingSlash: true). npm run build emits directory-style HTML to web/out/.
Deployment is automated via GitHub Actions:
firebase-hosting-merge.yml— on push tomaster, runsnpm ci && npm run buildinweb/and deploys to the Firebase live channel.firebase-hosting-pull-request.yml— on PRs, deploys to a temporary preview channel.
To deploy manually:
cd web && npm ci && npm run build
cd .. && npx firebase-tools deploy --only hosting # requires `firebase login`