Personal portfolio of Lail Ilham Ramadhan — full-stack engineer based in Indonesia. Built with Next.js 16 App Router, TypeScript, Tailwind v4, shadcn/ui, Motion, and next-intl.
- Next.js 16 (App Router, Turbopack, React 19)
- TypeScript strict mode
- Tailwind CSS v4 + shadcn/ui (Nova preset, radix base)
- Motion (formerly Framer Motion) for fades + scroll reveals
- @teispace/next-themes (React 19-friendly fork) for dark / light / system theme
- next-intl for bilingual routing (
/en,/id) - Resend for the contact form
- @vercel/og for dynamic Open Graph image
- Vercel Analytics
yarn install
cp .env.example .env.local # fill in RESEND_API_KEY etc.
yarn devOpen http://localhost:3000 — the middleware redirects / to /en.
| Script | Purpose |
|---|---|
yarn dev |
Start dev server (Turbopack). |
yarn build |
Production build. |
yarn start |
Run the production build. |
yarn lint |
ESLint over src/. |
Edit these typed files — no rebuild needed in dev, but you'll need to redeploy after changes.
| File | What it controls |
|---|---|
profile.ts |
Name, role, country, email, socials, hero photo path. |
projects.ts |
All projects. Toggle featured: true to show on the homepage grid. |
experience.ts |
Roles, dates, bullets. Toggle featured: true to expand by default; false rolls into the "earlier career" accordion. |
skills.ts |
Tech grid. Each entry maps to a react-icons/si component via src/components/sections/skills.tsx. |
UI strings live in messages/en.json and messages/id.json. Section bodies (project descriptions, bullets, bios) currently stay in English — add *_id fields and wire them through if you want fully bilingual content.
Drop a square portrait at public/avatar.jpg, then point profile.photo to it. The placeholder SVG at public/avatar.svg ships by default so the hero never breaks.
| Var | Required | Purpose |
|---|---|---|
RESEND_API_KEY |
Production | Sends contact-form submissions. Without it in dev, submissions log to the server console and the UI still shows success. |
CONTACT_TO_EMAIL |
Production | Inbox that receives form submissions. |
CONTACT_FROM_EMAIL |
Optional | Sender header. Defaults to Portfolio <onboarding@resend.dev> (Resend's sandbox sender — fine until you verify a custom domain). |
- Push the branch to GitHub.
- Import the repo at https://vercel.com/new.
- Add the env vars from
.env.example. - Hit deploy. Vercel Analytics + the OG image route work out of the box.
- (Later) Point a custom domain at the project from the Vercel dashboard.
- Open DevTools → Console for a stylized greeting.
- Press the Konami code (
↑ ↑ ↓ ↓ ← → ← → B A) on any page for a surprise.
Code: MIT. Content + photo: © Lail Ilham Ramadhan.