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:
- 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-KNUST-Chapter/Personal-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 thescrollY
property from thewindow
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.
- Includes a button that lets users copy an email address directly to their clipboard using the
const copyEmail = () => {
navigator.clipboard.writeText("isaacoboenimil@gmail.com");
};
-
Responsive Mobile Menu:
- The navbar adapts to smaller screen sizes by including a mobile menu button (
Menu
andX
icons from Lucide). - When toggled, the menu displays navigation links and actions in a user-friendly way for mobile devices.
- The navbar adapts to smaller screen sizes by including a mobile menu button (
<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 withplace-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
andheight
: 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
<br />
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 alink
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 withmap()
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
andheight
: 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 andfont-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 anicon
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 withtext-3xl
for a prominent font size andfont-bold
for emphasis. -
Subheading (
p
): Smaller (text-xl
) and styled withtext-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 withp-6
for padding andbg-stone-400/20
for a consistent background. -
Icon: Displayed in
text-2xl
for a visually striking representation. -
Title: Styled with
text-lg
andfont-semibold
for emphasis. -
Description: Styled with
text-sm
andtext-gray-600
for readability and a softer tone.
-
Wrapper (
-
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 thelucide-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 of20
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 thenav
container (though there's only one link here, it can accommodate additional links with equal spacing). -
<Link>
: A React component used for client-side navigation, though thehref="#"
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 (
<nav>
) has space for additional links if needed, making it easy to expand in the future.
- The navigation section (
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
Top comments (0)