Personal portfolio for a full-stack software engineering job search. Showcases shipped projects (Healthcare Management System, VeloSim/BIXI Montreal, Hand-in-Hand Auction, Campus Navigation) with metrics, architecture, and source.
Live: https://jpuntul.github.io/Portfolio/
- Framework: React 19 + TypeScript + Vite 6 (SWC)
- Styling: Tailwind CSS v4 (zero-config, via
@tailwindcss/vite) - Routing: React Router 7
- Forms: EmailJS for the contact form
- Tooling: ESLint (flat config) · Prettier · Husky + lint-staged · GitHub Actions
- Hosting: GitHub Pages (deployed from
main)
git clone https://github.com/Jpuntul/Portfolio.git
cd Portfolio
npm install
npm run devOpen http://localhost:5173/Portfolio/ — note the /Portfolio/ basename, set in vite.config.ts and src/App.tsx so it matches the GitHub Pages path.
| Command | What it does |
|---|---|
npm run dev |
Vite dev server with HMR |
npm run build |
Typecheck + production build to dist/ |
npm run preview |
Serve the production build locally |
npm run lint |
ESLint over **/*.{js,jsx,ts,tsx} |
npm run typecheck |
tsc --noEmit for full project typecheck |
npm test |
Run the Vitest suite once |
npm run test:watch |
Watch-mode tests |
npm run test:coverage |
Vitest with V8 coverage report |
src/
├── App.tsx # Router + layout
├── main.tsx # React entry point
├── index.css # Tailwind import + design tokens
├── constants/
│ └── ui.ts # Magic-number constants (scroll thresholds, etc.)
├── data/
│ └── portfolio.ts # Typed source of truth (personalInfo, projects, skills)
├── pages/ # Home, About, Projects, Contact, NotFound
├── components/
│ ├── layout/ # Header, Footer
│ ├── sections/ # Hero, About, Projects, Skills (composed on Home)
│ └── *.tsx # Reusable widgets (ProjectCard, BackToTop, etc.)
└── vite-env.d.ts # Vite + import.meta.env types
public/
├── images/projects/ # Project screenshots
├── resume.pdf # Downloadable resume
└── 404.html # SPA fallback for GitHub Pages
All project content lives in src/data/portfolio.ts — adding a project or updating metrics is a one-file edit, no component changes needed. The typed schema (Project, Skill, PersonalInfo) is enforced at build time.
The contact form posts via EmailJS. Set these in .env (see .env.example) or as GitHub repo secrets for the deploy workflow:
VITE_EMAILJS_SERVICE_ID=...
VITE_EMAILJS_TEMPLATE_ID=...
VITE_EMAILJS_PUBLIC_KEY=...
Pushes to main trigger .github/workflows/deploy.yml: install → lint → build → publish to GitHub Pages. The /Portfolio/ basename in vite.config.ts is required for the Pages subpath.
- Email: p.jutipong13@gmail.com
- LinkedIn: linkedin.com/in/jpuntul
- GitHub: github.com/Jpuntul