This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
Recent changes: Read latest 3-5 entries in CHANGELOG.md for context.
Package manager is pnpm (see packageManager in package.json). Dev server runs on http://localhost:3000.
-
pnpm install— install dependencies -
pnpm dev— start dev server -
pnpm generate— produce a static site in.output/public(this is the production build used for deployment, notbuild) -
pnpm build/pnpm preview— SSR server build + local preview -
pnpm test— run the Vitest unit tests once (test:watchfor watch mode)
Testing is deliberately minimal: Vitest + jsdom cover only genuine logic (e.g. utils/lightbox.ts), not presentational markup/copy. There is no linter or formatter configured.
This is a single-developer personal portfolio site for Abdul Haseeb, built with Nuxt 4 (Vue 3, <script setup lang="ts">), Tailwind CSS, and statically generated. Nuxt modules in use: @nuxtjs/tailwindcss, @nuxt/fonts, @nuxt/image, nuxt-aos (scroll animations).
app.vue— root; holds all SEO/useHeadmetadata (Open Graph, Twitter cards, JSON-LD Person schema). The site domain is read fromconfig.public.domainand woven into canonical/OG URLs, so SEO is domain-aware.layouts/default.vue— global nav + footer wrapping every page.pages/index.vue— home, composed ofHome/*section components (Intro,About,Projects,UpworkReviews,StayInTouch).pages/projects/—index.vueis the project gallery; each<project>.vue(andalus, capitalclub, ezelogs, stirling_cooper, tabootv, warroom) is a standalone case-study page. Before adding or editing any project page, readpages/projects/PATTERN.mdfirst — it documents the shared structure (section order, scroll-spy TOC, styling, starter template, and registering the gallery card). New pages follow the andalus.vue pattern.
- Auto-imports & component naming: Nuxt auto-imports components by path. A file at
components/Home/UpworkReviews.vueis used as<HomeUpworkReviews/>;components/Project/TableOfContents.vueis<ProjectTableOfContents/>. TheLazy*prefix (e.g.<LazyHomeUpworkReviewCard/>) lazy-loads a component. Composables incomposables/(e.g.useProjectObserver) are auto-imported too. - Scroll-spy TOC:
composables/useProjectObserver.tsuses anIntersectionObserverover everysection[id]to track visible sections; project pages feed itsactiveSectionsto the recursiveTableOfContentscomponent to highlight the current section. - Upwork gating:
config.public.upwork(envNUXT_PUBLIC_UPWORK) is a feature flag. When true, social links are hidden and Upwork review cards/CTAs are shown instead (seeIntro.vue,StayInTouch.vue,UpworkReviews.vue). The GitHub Pages deploy sets ittrue. - Content data: client testimonials live in
data/reviews.tsas a typedReview[], consumed by the Upwork review components. - Styling: global CSS variables (colors, fluid type) are defined in
assets/css/main.css:root— use vars likevar(--primary-color),var(--black-color)rather than hardcoding. Tailwind utilities are used alongside scoped<style>blocks.
Runtime config is environment-driven via nuxt.config.ts runtimeConfig.public (see .env.example):
NUXT_PUBLIC_UPWORK— Upwork feature flag (above)NUXT_PUBLIC_DOMAIN— canonical domain for SEO (defaults tozrinasoft.com)NUXT_BASE_URL— app base URLUPWORK_PROFILE_LINK— Upwork profile URL
Two deploy targets, each on its own branch:
- GitHub Pages (
.github/workflows/github-pages.yml) — on push tomaster, runspnpm generatewithNUXT_PUBLIC_UPWORK=trueandNUXT_PUBLIC_DOMAIN=code-creeper.github.io, publishes.output/publictogh-pages. - EC2 (
.github/workflows/deploy-ec2.yml) — on push toec2, SSHes into the host and rebuilds inside theportfolio_node_containerDocker container (docker-compose.yml, Node 22 alpine, port 3000).