Introduction to Next.js
NextJS is a powerful React framework that enables developers to build performant and scalable web applications with ease. This documentation will guide you through creating a portfolio site using NextJS.
Key NextJS Features
App Router
NextJS 13+ introduces the App Router, a new routing system that provides:
Example of Routing Structure
app/
βββ page.tsx # Main landing page
βββ about/
β βββ page.tsx # About page
βββ projects/
β βββ page.tsx # Projects page
βββ layout.tsx # Global layout
Performance Optimizations
NextJS offers multiple optimization techniques:
Package Management
package-lock.json
Components in NextJS
Server Components
Client Components
Project Setup
Clone the repo
git clone https://github.com/Headstarter-AI-KN...-Portfolio.git
Initial Configuration
npm install
This command:
Diving into the codes
Overview
The Portfolio is a React functional component that composes multiple section components into a single page layout.
Page file contents
Component Imports
import React from "react";
import HeroSection from "./components/hero-section/HeroSection";
import ServiceSection from "./components/service-section/ServiceSection";
import Navbar from "./components/navbar/Navbar";
import ContactSection from "./components/contact-section/ContactSection";
import BrandSection from "./components/brand-section/BrandSection";
import Footer from "./components/footer/Footer";
Component Layout
const Portfolio = () => {
return (
Navbar />
HeroSection />
div className="min-h-screen p-8 pt-0">
BrandSection />
ServiceSection />
ContactSection />
Footer />
div>
>
);
};
Key Observations
Component Sections
Navbar Component:
useEffect(() => {
const handleScroll = () => {
setIsScrolled(window.scrollY > 0);
};
window.addEventListener("scroll", handleScroll);
return () => window.removeEventListener("scroll", handleScroll);
}, []);
const copyEmail = () => {
navigator.clipboard.writeText("isaacoboenimil@gmai l.com");
};
Button
variant="ghost"
onClick={() => setIsMobileMenuOpen(!isMobileMenuOpen)}
className="inline-flex items-center justify-center p-2"
>
{isMobileMenuOpen ? X className="h-6 w-6" /> : Menu className="h-6 w-6" />}
Button>
HeroSection Component
Imports
import { Button } from "@/components/ui/button";
import Image from "next/image";
import React from "react";
HeroSection Function
function HeroSection() {
return (
section className="grid min-h-[70vh] place-content-center rounded-b-[100px] bg-stone-400/50 p-10 text-center">
...
/section>
);
}
Details on Styling the Section
section className="grid min-h-[70vh] place-content-center rounded-b-[100px] bg-stone-400/50 p-10 text-center">
Image Component
Image
width={300}
height={300}
src="/assets/images/images.jpeg"
alt="Profile"
className="mx-auto mb-4 h-40 w-40 rounded-full object-cover"
/>
Heading
h1 className="mb-4 text-4xl font-bold">
Building digital
br />
products, brands, and
br />
experience.
/h1>
Button Component
Button className="mt-6 p-8 text-2xl">Latest Work/Button>
BrandSection Component
Imports
import Image from "next/image";
import React from "react";
BrandSection Function
function BrandSection() {
...
return (
section className="relative z-10 my-20 rounded-b-[100px] bg-white px-10 py-20">
...
/section>
);
}
Brands Array
const brands = [
{ name: "National Bank of Canada", link: "/assets/images/national-bank-of-canada-logo.png" },
{ name: "Matter", link: "/assets/images/matter.png" },
{ name: "Coca-Cola", link: "/assets/images/Coca-Cola.png" },
{ name: "Adobe", link: "/assets/images/Adobe-logo.png" },
{ name: "Subway", link: "/assets/images/subway-logo.png" },
{ name: "Code Academy", link: "/assets/images/code-academy.png" },
];
Styling the Section
section className="relative z-10 my-20 rounded-b-[100px] bg-white px-10 py-20">
Grid Layout
div className="grid grid-cols-6 items-center justify-items-center gap-8 opacity-50">
Dynamic Rendering of Brands
{brands.map((brand, index) => (
div key={index} className="text-sm font-medium">
Image
width={100}
height={100}
src={brand.link}
alt={brand.name}
className="mx-auto mb-4"
/>
/div>
))}
ServiceSection Component
Imports
import { Card } from "@/components/ui/card";
import React from "react";
ServiceSection Function
function ServiceSection() {
...
return (
section className="mb-20 py-52 px-20 w-full bg-stone-400/20 -my-52">
...
/section>
);
}
Services Array
const services = [
{
title: "UX & UI",
description: "Designing interfaces that are intuitive, efficient, and enjoyable to use",
icon: "π¨",
},
{
title: "Web & Mobile App",
description: "Transforming ideas into exceptional web and mobile app experiences",
icon: "π±",
},
{
title: "Design & Creative",
description: "Crafting visually stunning designs that connect with your audience",
icon: "β¨",
},
{
title: "Development",
description: "Bringing your vision to life with the latest technology and design trends",
icon: "π»",
},
];
Styling the Section
section className="mb-20 py-52 px-20 w-full bg-stone-400/20 -my-52">
Heading and Subheading
div className="mb-16 text-center">
h2 className="mb-2 text-3xl font-bold">
Collaborate with brands and agencies
/h2>
p className="text-xl text-gray-600">to create impactful results./p>
/div>
Grid Layout for Services
div className="grid sm:grid-cols-4 gap-8">
Dynamic Rendering of Services
{services.map((service, index) => (
Card key={index} className="p-6 bg-stone-400/20">
div className="mb-4 text-2xl">{service.icon}/div>
h3 className="mb-2 text-lg font-semibold">{service.title}/h3>
p className="text-sm text-gray-600">{service.description}/p>
/Card>
))}
ContactSection Component
Imports
import { Button } from "@/components/ui/button";
import { HandshakeIcon } from "lucide-react";
import React from "react";
ContactSection Function
function ContactSection() {
...
return (
section className="-my-40 rounded-t-[100px] bg-white p-28 text-center">
...
/section>
);
}
Styling the Section
section className="-my-40 rounded-t-[100px] bg-white p-28 text-center">
Icon Wrapper
div className="mb-8 grid place-content-center">
div className="rounded-full bg-muted p-8">
HandshakeIcon size={50} />
/div>
/div>
Heading
h2 className="mb-8 text-3xl font-bold">
Tell me about your next
br />
project
/h2>
Footer Component
Imports
import React from "react";
Footer Function
function Footer() {
...
return (
footer className="mt-20 flex items-center justify-between text-sm text-gray-600">
...
/footer>
);
}
Styling the Footer
footer className="mt-20 flex items-center justify-between text-sm text-gray-600">
Content in the Footer
div>Β© 2024 All rights reserved./div>
nav className="space-x-4">
Link href="#">HeadStarter/Link>
/nav>
Default Export
export default Footer;
Key Features
Best Practices
Performance Optimization Techniques
Recommended Packages
Deployment
Learning Resources
More...
NextJS is a powerful React framework that enables developers to build performant and scalable web applications with ease. This documentation will guide you through creating a portfolio site using NextJS.
Key NextJS Features
App Router
NextJS 13+ introduces the App Router, a new routing system that provides:
- File-based routing
- Nested layouts
- Simplified data fetching
- Automatic code splitting
- Server and client components
Example of Routing Structure
app/
βββ page.tsx # Main landing page
βββ about/
β βββ page.tsx # About page
βββ projects/
β βββ page.tsx # Projects page
βββ layout.tsx # Global layout
Performance Optimizations
NextJS offers multiple optimization techniques:
- Automatic image optimization
- Lazy loading of components
- Static and server-side rendering
- Incremental Static Regeneration (ISR)
- Automatic code splitting
Package Management
package-lock.json
- Locks dependency versions precisely
- Ensures consistent builds across different environments
- Prevents unexpected package updates
- Improves build reproducibility
Components in NextJS
Server Components
- Render on the server
- Reduce client-side JavaScript
- Improve initial page load performance
- Default in App Router
Client Components
- Interactive components
- Use client-side rendering
- Enable state and event handling
- Marked with 'use client' directive
Project Setup
Clone the repo
git clone https://github.com/Headstarter-AI-KN...-Portfolio.git
Initial Configuration
npm install
This command:
- Read the package.json file
- Download and install all listed dependencies
- Create a node_modules folder
- Generate or update the package-lock.json file to ensure
consistent installations across different environments
Diving into the codes
Overview
The Portfolio is a React functional component that composes multiple section components into a single page layout.
Page file contents
Component Imports
import React from "react";
import HeroSection from "./components/hero-section/HeroSection";
import ServiceSection from "./components/service-section/ServiceSection";
import Navbar from "./components/navbar/Navbar";
import ContactSection from "./components/contact-section/ContactSection";
import BrandSection from "./components/brand-section/BrandSection";
import Footer from "./components/footer/Footer";
Component Layout
const Portfolio = () => {
return (
Navbar />
HeroSection />
div className="min-h-screen p-8 pt-0">
BrandSection />
ServiceSection />
ContactSection />
Footer />
div>
>
);
};
Key Observations
- Uses React Fragment (...>) for wrapping components
- Utilizes a container div with utility classes for spacing
- Follows a top-to-bottom page composition strategy
- Separates Navbar and HeroSection from other content sections
Component Sections
- Navbar: Site navigation
- HeroSection: Landing/introduction area
- BrandSection: Brand or client showcase
- ServiceSection: Services or capabilities overview
- ContactSection: Contact information or form
- Footer: Page footer/additional links
Navbar Component:
- Scroll-Aware Design:
- The navbar dynamically changes its appearance (e.g., shadow and backdrop blur) based on the userβs scroll position. This ensures visibility while maintaining aesthetic appeal.
- Accomplished using the useEffect hook and the scrollY property from the window object.
useEffect(() => {
const handleScroll = () => {
setIsScrolled(window.scrollY > 0);
};
window.addEventListener("scroll", handleScroll);
return () => window.removeEventListener("scroll", handleScroll);
}, []);
- Copy-to-Clipboard Functionality:
- Includes a button that lets users copy an email address directly to their clipboard using the navigator.clipboard API.
const copyEmail = () => {
navigator.clipboard.writeText("isaacoboenimil@gmai l.com");
};
- Responsive Mobile Menu:
- The navbar adapts to smaller screen sizes by including a mobile menu button (Menu and X icons from Lucide).
- When toggled, the menu displays navigation links and actions in a user-friendly way for mobile devices.
Button
variant="ghost"
onClick={() => setIsMobileMenuOpen(!isMobileMenuOpen)}
className="inline-flex items-center justify-center p-2"
>
{isMobileMenuOpen ? X className="h-6 w-6" /> : Menu className="h-6 w-6" />}
Button>
- Desktop and Mobile Navigation Links:
- Provides social links (e.g., LinkedIn, Dribbble, Instagram) as well as buttons for copying an email or accessing a CV.
- These are conditionally rendered based on screen size using Tailwind CSSβs utility classes (e.g., hidden md:flex).
HeroSection Component
Imports
import { Button } from "@/components/ui/button";
import Image from "next/image";
import React from "react";
- Button Component: The button is imported from a custom UI library (@/components/ui/button). This approach indicates a modular design for reusability across the app.
- Image Component: The Image component is part of Next.js. Itβs a powerful tool for optimizing images in web applications, providing features like lazy loading, responsive sizing, and automatic format selection (e.g., WebP).
- React: A foundational import for all React components.
HeroSection Function
function HeroSection() {
return (
section className="grid min-h-[70vh] place-content-center rounded-b-[100px] bg-stone-400/50 p-10 text-center">
...
/section>
);
}
Details on Styling the Section
section className="grid min-h-[70vh] place-content-center rounded-b-[100px] bg-stone-400/50 p-10 text-center">
- grid: Establishes a grid layout. Combined with place-content-center, it centers the content both horizontally and vertically.
- min-h-[70vh]: Ensures the hero section takes up at least 70% of the viewport height.
- rounded-b-[100px]: Applies a custom, large rounded border radius to the bottom, adding a soft curve for a modern aesthetic.
- bg-stone-400/50: Sets a semi-transparent light gray background with Tailwind's opacity feature (/50).
- p-10: Adds padding around the section.
- text-center: Centers all text content inside this section.
Image Component
Image
width={300}
height={300}
src="/assets/images/images.jpeg"
alt="Profile"
className="mx-auto mb-4 h-40 w-40 rounded-full object-cover"
/>
- Optimization: The Image component ensures better performance through optimized loading and resizing.
- Props:
- src: Path to the image. Here, itβs served from /assets/images/images.jpeg.
- alt: Alt text for accessibility and SEO purposes.
- width and height: Fixed dimensions for better performance.
- Styling:
- mx-auto: Horizontally centers the image.
- h-40 w-40: Defines fixed height and width (10rem each).
- rounded-full: Creates a circular image.
- object-cover: Ensures the image scales without distortion.
Heading
h1 className="mb-4 text-4xl font-bold">
Building digital
br />
products, brands, and
br />
experience.
/h1>
- mb-4: Adds margin-bottom for spacing.
- text-4xl: Sets a large font size.
- font-bold: Applies bold styling for emphasis.
- Text Layout: The use of
tags breaks the text into multiple lines, creating a structured and visually appealing layout.
Button Component
Button className="mt-6 p-8 text-2xl">Latest Work/Button>
- Custom Button: The button component, likely styled and built within your custom library, is reusable.
- Props and Styling:
- mt-6: Adds top margin for spacing.
- p-8: Applies generous padding for a clickable and prominent button.
- text-2xl: Enlarges the text for better readability.
- Text: The button directs users to view the "Latest Work," potentially linking to a portfolio or case studies.
BrandSection Component
Imports
import Image from "next/image";
import React from "react";
- Image: Next.js's Image component ensures efficient image rendering with features like lazy loading and responsive sizing.
- React: Essential for defining React components.
BrandSection Function
function BrandSection() {
...
return (
section className="relative z-10 my-20 rounded-b-[100px] bg-white px-10 py-20">
...
/section>
);
}
Brands Array
const brands = [
{ name: "National Bank of Canada", link: "/assets/images/national-bank-of-canada-logo.png" },
{ name: "Matter", link: "/assets/images/matter.png" },
{ name: "Coca-Cola", link: "/assets/images/Coca-Cola.png" },
{ name: "Adobe", link: "/assets/images/Adobe-logo.png" },
{ name: "Subway", link: "/assets/images/subway-logo.png" },
{ name: "Code Academy", link: "/assets/images/code-academy.png" },
];
- Structure: Each brand has a name and a link to the corresponding image file.
- Scalability: Adding or removing brands is easyβjust update the array.
Styling the Section
section className="relative z-10 my-20 rounded-b-[100px] bg-white px-10 py-20">
- relative z-10: Positions the section above other elements for proper layering.
- my-20: Adds vertical margin for spacing.
- rounded-b-[100px]: Applies a curved bottom border for a smooth, modern look.
- bg-white: Sets a clean white background.
- px-10 py-20: Adds padding for a well-spaced layout.
Grid Layout
div className="grid grid-cols-6 items-center justify-items-center gap-8 opacity-50">
- grid: Establishes a grid layout for displaying the logos.
- grid-cols-6: Divides the grid into six equal columns, ensuring each brand gets its own space.
- items-center: Vertically centers the grid items.
- justify-items-center: Horizontally centers the grid items.
- gap-8: Adds consistent spacing between the items.
- opacity-50: Reduces the opacity, giving the logos a subdued, professional look.
Dynamic Rendering of Brands
{brands.map((brand, index) => (
div key={index} className="text-sm font-medium">
Image
width={100}
height={100}
src={brand.link}
alt={brand.name}
className="mx-auto mb-4"
/>
/div>
))}
- Mapping: The brands array is iterated with map() to render each brand dynamically.
- Key Prop: The key prop (index) ensures React efficiently updates the DOM.
- Image Component:
- src: Specifies the image path for each logo.
- alt: Improves accessibility and SEO with descriptive alt text.
- width and height: Ensures consistent logo sizing (100x100 px).
- className: Centers the image and adds a small margin at the bottom (mx-auto mb-4).
- Wrapper Div: Includes text-sm for small text size and font-medium for medium-weight font (if text is needed later).
ServiceSection Component
Imports
import { Card } from "@/components/ui/card";
import React from "react";
- Card: A reusable UI component likely styled for consistent card-based layouts. This simplifies the process of rendering each service as a visually cohesive block.
- React: Required to define and use React components.
ServiceSection Function
function ServiceSection() {
...
return (
section className="mb-20 py-52 px-20 w-full bg-stone-400/20 -my-52">
...
/section>
);
}
Services Array
const services = [
{
title: "UX & UI",
description: "Designing interfaces that are intuitive, efficient, and enjoyable to use",
icon: "π¨",
},
{
title: "Web & Mobile App",
description: "Transforming ideas into exceptional web and mobile app experiences",
icon: "π±",
},
{
title: "Design & Creative",
description: "Crafting visually stunning designs that connect with your audience",
icon: "β¨",
},
{
title: "Development",
description: "Bringing your vision to life with the latest technology and design trends",
icon: "π»",
},
];
- Structure: Each service has a title, description, and an icon to visually represent the service.
- Purpose: Makes the component dynamic and scalableβadding or updating services only requires modifying this array.
Styling the Section
section className="mb-20 py-52 px-20 w-full bg-stone-400/20 -my-52">
- mb-20: Adds vertical margin at the bottom for spacing between sections.
- py-52 px-20: Provides generous padding for a spacious layout.
- w-full: Ensures the section spans the full width of the viewport.
- bg-stone-400/20: Applies a semi-transparent background with a soft stone-gray tone.
- -my-52: Adds a negative margin to overlap the previous or next sections slightly for a layered effect.
Heading and Subheading
div className="mb-16 text-center">
h2 className="mb-2 text-3xl font-bold">
Collaborate with brands and agencies
/h2>
p className="text-xl text-gray-600">to create impactful results./p>
/div>
- Heading (h2): Styled with text-3xl for a prominent font size and font-bold for emphasis.
- Subheading (p): Smaller (text-xl) and styled with text-gray-600 for a subtle, secondary emphasis.
Grid Layout for Services
div className="grid sm:grid-cols-4 gap-8">
- grid: Enables a grid layout for the cards.
- sm:grid-cols-4: Defines a 4-column grid on small screens and larger.
- gap-8: Adds consistent spacing between grid items.
Dynamic Rendering of Services
{services.map((service, index) => (
Card key={index} className="p-6 bg-stone-400/20">
div className="mb-4 text-2xl">{service.icon}/div>
h3 className="mb-2 text-lg font-semibold">{service.title}/h3>
p className="text-sm text-gray-600">{service.description}/p>
/Card>
))}
- Mapping: Each service is rendered dynamically using the .map() function.
- Card Component:
- Wrapper (Card): Styled with p-6 for padding and bg-stone-400/20 for a consistent background.
- Icon: Displayed in text-2xl for a visually striking representation.
- Title: Styled with text-lg and font-semibold for emphasis.
- Description: Styled with text-sm and text-gray-600 for readability and a softer tone.
- Key Prop: Ensures each card has a unique identifier (index) for efficient rendering.
ContactSection Component
Imports
import { Button } from "@/components/ui/button";
import { HandshakeIcon } from "lucide-react";
import React from "react";
- Button: A customizable button component for creating consistent, styled buttons.
- HandshakeIcon: An icon imported from the lucide-react library to visually enhance the section.
- React: Enables the use of JSX to build the component.
ContactSection Function
function ContactSection() {
...
return (
section className="-my-40 rounded-t-[100px] bg-white p-28 text-center">
...
/section>
);
}
- The function defines the ContactSection component.
- The section element serves as the container for the entire component, styled with Tailwind CSS classes.
Styling the Section
section className="-my-40 rounded-t-[100px] bg-white p-28 text-center">
- -my-40: Adds negative vertical margins to overlap the previous section for a seamless flow.
- rounded-t-[100px]: Gives the section a unique curved top with a large border radius.
- bg-white: Sets a clean, white background.
- p-28: Adds ample padding to create a spacious layout.
- text-center: Centers all text and content horizontally.
Icon Wrapper
div className="mb-8 grid place-content-center">
div className="rounded-full bg-muted p-8">
HandshakeIcon size={50} />
/div>
/div>
- Outer Wrapper:
- mb-8: Adds a margin at the bottom to separate the icon from the heading.
- grid place-content-center: Centers the icon wrapper both vertically and horizontally.
- Inner Wrapper:
- rounded-full: Ensures the icon container is perfectly circular.
- bg-muted: Applies a muted background color, likely defined in the theme.
- p-8: Adds padding inside the circular wrapper for a spacious look.
- HandshakeIcon: The icon is rendered with a size of 50px, making it bold and noticeable.
Heading
h2 className="mb-8 text-3xl font-bold">
Tell me about your next
br />
project
/h2>
- mb-8: Creates separation from the buttons below.
- text-3xl: Sets a large, attention-grabbing font size.
- font-bold: Enhances readability by making the text bold
Footer Component
Imports
import React from "react";
- React: This import enables JSX and is essential for creating React components.
Footer Function
function Footer() {
...
return (
footer className="mt-20 flex items-center justify-between text-sm text-gray-600">
...
/footer>
);
}
- The function defines the Footer component.
- The footer element serves as the container for the footer content and is styled with Tailwind CSS classes.
Styling the Footer
footer className="mt-20 flex items-center justify-between text-sm text-gray-600">
- mt-20: Adds a margin-top of 20 units, creating space between the footer and the content above it.
- flex: Utilizes Flexbox for layout, allowing easy alignment of child elements.
- items-center: Vertically centers the content inside the footer.
- justify-between: Distributes space between the child elements, placing one at the left and the other at the right.
- text-sm: Sets a smaller text size for the footer content.
- text-gray-600: Applies a medium gray color to the text for a subtle and soft appearance.
Content in the Footer
- Copyright Text
div>Β© 2024 All rights reserved./div>
- Displays the copyright text with the year 2024.
- div: A simple container for the copyright notice.
- Navigation Links
nav className="space-x-4">
Link href="#">HeadStarter/Link>
/nav>
- nav: A semantic HTML element for navigation links. In this case, it contains only one link.
- space-x-4: Adds horizontal spacing between elements within the nav container (though there's only one link here, it can accommodate additional links with equal spacing).
- : A React component used for client-side navigation, though the href="#" here doesn't direct to any specific page.
Default Export
export default Footer;
Key Features
- Simple Layout:
- The footer is divided into two main sections: the copyright notice on the left and a navigation link on the right, using Flexbox for alignment.
- Small Text for Footer:
- The text is styled in a smaller, subtle gray, ensuring that the footer does not distract from the main content but remains legible.
- Extensibility:
- The navigation section () has space for additional links if needed, making it easy to expand in the future.
Best Practices
- Use server components by default
- Implement lazy loading for heavy components
- Optimize images with Next/Image
- Leverage built-in TypeScript support
- Modularize your code
Performance Optimization Techniques
- Use next/image for automatic image optimization
- Implement code splitting
- Utilize static generation for non-dynamic content
- Enable incremental static regeneration
Recommended Packages
- Tailwind CSS for styling
- Lucide React Icons for icons
- Shadcn UI for component library
Deployment
- Vercel (recommended)
- Netlify
- GitHub Pages
Learning Resources
- NextJS Official Documentation
- React Documentation
- Vercel Deployment Guides
More...