A modern, single-page portfolio template built with the Next.js App Router and TypeScript. Sections use inline styles and shared CSS for a consistent max-width (1280px) layout. Scroll-triggered CSS animations (fade-up, fade-left, scale-in, etc.) reveal content smoothly as you scroll. Ideal for developers who want a production-ready portfolio with clear structure and no flash of unstyled content.
Live Demo: https://portfolio-ui-9.vercel.app/
- Features
- Tech Stack
- Project Structure
- Getting Started
- Environment Variables
- Scripts
- Routes & Pages
- API Endpoints
- Components & Functionality
- Scroll Animations
- Styling
- Reusing Components in Other Projects
- Keywords & SEO
- Conclusion
- License
- Next.js App Router – File-based routing with
app/; server and client components separated. - TypeScript – Full type safety and interfaces (e.g.
Project,TimelineItem). - Tailwind CSS – Utility classes for base styles; theme (colors, fonts) in
tailwind.config.ts. - Inline styles – Section layout and component styling use React inline
stylefor reliable, consistent rendering (max-width 1280px, alignment). - Scroll-triggered CSS animations – Sections and cards reveal on scroll (fade-up, fade-left, fade-right, scale-in, fade-rotate, staggered children) via
useScrollRevealandglobals.csskeyframes. - Responsive layout – Single container (max 1280px, centered); header uses CSS grid with media queries in
globals.css. - SEO – Metadata and viewport in
layout.tsx(title, description, Open Graph, Twitter, canonical, robots). - Single-page sections – Hero, Projects, Technologies, Timeline (About), Accomplishments, plus Header and Footer.
- Sample API –
GET /api/hellofor backend or serverless. - Linting – ESLint with
eslint-config-nextandnext lint.
| Category | Technology |
|---|---|
| Framework | Next.js 14 (App Router) |
| UI Library | React 18 |
| Language | TypeScript 5 |
| Styling | Tailwind CSS 3, inline styles, app/globals.css |
| Fonts | Next.js font (Space Grotesk via next/font/google) |
| Icons | react-icons |
| Animations | CSS @keyframes + IntersectionObserver (useScrollReveal hook) |
| Linting | ESLint, eslint-config-next |
portfolio-ui-9/
├── src/
│ ├── app/
│ │ ├── layout.tsx # Root layout, metadata, viewport, font, globals.css
│ │ ├── page.tsx # Home page (server); renders <Home />
│ │ ├── providers.tsx # Client wrapper (passthrough)
│ │ └── globals.css # Tailwind layers, scroll animation keyframes, header grid
│ │ └── api/
│ │ └── hello/
│ │ └── route.ts # GET /api/hello
│ ├── components/
│ │ ├── Home/ # Page composition (Layout + sections)
│ │ ├── Hero/
│ │ ├── Header/
│ │ ├── Footer/
│ │ ├── Projects/
│ │ ├── Technologies/
│ │ ├── TimeLine/
│ │ ├── Accomplishments/
│ │ ├── BackgroundAnimation/
│ │ └── NavDropDown/
│ ├── layout/
│ │ └── Layout.tsx # App shell (Header + main + Footer), 1280px container
│ ├── hooks/
│ │ └── useScrollReveal.ts # IntersectionObserver; adds .visible for CSS animations
│ ├── constants/
│ │ └── constants.ts # projects[], TimeLineData[], Project & TimelineItem types
│ ├── tailwind.config.ts
│ └── (no styles/, themes/, or types/ – styling is globals.css + inline + Tailwind)
├── public/
├── next.config.js
├── tsconfig.json
├── .eslintrc.json
└── package.json- Node.js 18.x or 20.x (LTS recommended)
- npm (or yarn / pnpm)
-
Clone the repository
git clone https://github.com/your-username/portfolio-ui-9.git cd portfolio-ui-9 -
Install dependencies
npm install
-
Run the development server
npm run dev
Open http://localhost:3000. The page hot-reloads on file changes.
-
Build for production
npm run build npm run start
This project does not require any environment variables to run or build. Config such as SITE_URL in src/app/layout.tsx is hardcoded.
To add env-based config later:
- Create
.env.localin the project root (git-ignored). - Use
NEXT_PUBLIC_*for client-visible values; no prefix for server-only. - In Vercel (or other host), set the same variables in the project settings.
| Command | Description |
|---|---|
npm run dev |
Start dev server at http://localhost:3000 |
npm run build |
Production build (output in .next) |
npm run start |
Run production server (run build first) |
npm run lint |
Run ESLint (next lint) |
| Route | File | Description |
|---|---|---|
/ |
app/page.tsx |
Home (server) renders client <Home />. |
/api/hello |
app/api/hello/route.ts |
GET returns { name: 'John Doe' }. |
app/layout.tsx – Root layout: <html>, <body>, Space Grotesk font, <Providers>, and import './globals.css'. Metadata and viewport are exported for SEO.
Sample API route for server/deployment checks.
Response: { "name": "John Doe" }
Example: curl http://localhost:3000/api/hello
File: src/app/api/hello/route.ts
app/page.tsx(server) renders<Home />.Home(components/Home/Home.tsx, client) renders:Layout→ hero section (grid:Hero+BackgroundAnimation), thenProjects,Technologies,Timeline,Accomplishments.
Single wrapper: max-width 1280px, padding, centered. Renders Header, main (children), and Footer. All sections share this container for aligned left/right edges.
Title (“Welcome To My Personal Portfolio”), description paragraph, and “Learn More” button. Uses useScrollReveal and class anim-fade-left so the block slides in from the left when it enters the viewport.
Grid of project cards from constants.projects. Each card: image, title, description, tags, Code/Source links. Section uses anim-fade-up; the grid has stagger-children so cards animate in sequence.
Three items (Front-End, Back-End, UI/UX) with icons and short text. Section uses anim-fade-down; list uses stagger-children.
“About” section: horizontal list of year + text from TimeLineData. Section uses anim-fade-rotate (slight rotation + fade).
Four stat-style blocks (e.g. “20+ Open Source Projects”). Section uses anim-scale-in; grid uses stagger-children.
- Header – Logo, nav links (#projects, #tech, #about), social icons. Inline styles +
.site-headergrid inglobals.cssfor responsive behavior. - Footer – Call/Email, slogan, social icons. Inline styles.
Decorative SVG with motion paths. Uses anim-fade-right for scroll-in from the right.
Dropdown panel (e.g. contact links). Used where a nav item opens a menu; styling is self-contained.
Animations are CSS-only (no Framer Motion for visibility). A small hook and global CSS drive them:
src/hooks/useScrollReveal.ts– UsesIntersectionObserver; when an element is in view (default 10–15% visible), it adds the classvisibleto that element. One-shot (observer disconnects after reveal).src/app/globals.css– Defines:- Keyframes:
fadeUp,fadeDown,fadeLeft,fadeRight,scaleIn,fadeRotate. - Classes:
.anim-fade-up,.anim-fade-down,.anim-fade-left,.anim-fade-right,.anim-scale-in,.anim-fade-rotate— each starts withopacity: 0and, when.visibleis added, runs the matching animation (forwards). - Stagger:
.stagger-children.visible > *— children runfadeUpwith increasinganimation-delay(e.g. 0.05s, 0.12s, …).
- Keyframes:
Usage in a component:
const ref = useScrollReveal<HTMLElement>(0.1);
return <section ref={ref} className="anim-fade-up" ... />;app/globals.css–@tailwind base/components/utilities; base styles forhtml/body/links/lists; scroll animation keyframes and classes;.site-headergrid and media queries.tailwind.config.ts–contentpaths,theme.extend(e.g.maxWidth['7xl'],colors.background,fontFamily.sans).- Components – Inline
styleobjects for layout and visuals (max-width 1280px, spacing, colors, gradients). This keeps sections visible and aligned even if Tailwind or class names change. - Layout – Single container:
maxWidth: 1280,width: '100%',margin: '0 auto',padding: '0 48px'.
- Copy the component folder (e.g.
Hero/,Projects/) and, if you use scroll animations, copyhooks/useScrollReveal.tsand the animation keyframes + classes fromglobals.css. - Install deps:
next,react,react-icons; for Tailwind,tailwindcss,postcss,autoprefixer. - Ensure path alias
@/*intsconfig.jsonif you keep@/imports. - Use the same data shapes (
Project,TimelineItem) or adapt props. Projects data lives inconstants/constants.ts; edit there or pass as props after a small refactor.
Metadata in app/layout.tsx includes: title, description, authors, canonical URL, robots, Open Graph (type, url, title, description, siteName, locale, images), Twitter card, favicon, apple-touch-icon, theme-color.
Keywords: portfolio, John Doe, developer, React, Next.js, web development, projects, frontend, full stack, Arnob Mahmud.
To customize: edit the metadata and viewport exports in src/app/layout.tsx and update SITE_URL (or switch to process.env.NEXT_PUBLIC_SITE_URL if you add env vars).
This repo is a single-page portfolio on Next.js 14 (App Router) and TypeScript. It uses Tailwind for base styles and inline styles for section layout so content is aligned and visible. Scroll-triggered CSS animations (and the useScrollReveal hook) make sections and cards appear smoothly from different directions. You can use it as a learning base or clone and edit constants, metadata, and copy for your own site.
This project is licensed under the MIT License. Feel free to use, modify, and distribute the code as per the terms of the license.
This is an open-source project — feel free to use, enhance, and extend it.
If you have questions or want to share your work, reach out via GitHub or https://www.arnobmahmud.com.
Enjoy building and learning! 🚀
Thank you! 😊



