DEV Community

Cover image for Introduction to Next.js and Building a Portfolio Site with Next.jsπŸš€βœ¨
JeffMint
JeffMint

Posted on

2

Introduction to Next.js and Building a Portfolio Site with Next.jsπŸš€βœ¨

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

Initial Configuration

npm install
Enter fullscreen mode Exit fullscreen mode

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";
Enter fullscreen mode Exit fullscreen mode

Component Layout

const Portfolio = () => {
  return (
    <>
      <Navbar />
      <HeroSection />
      <div className="min-h-screen p-8 pt-0">        
        <BrandSection />
        <ServiceSection />
        <ContactSection />
        <Footer />
      </div>
    </>
  );
};
Enter fullscreen mode Exit fullscreen mode

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

  1. Navbar: Site navigation
  2. HeroSection: Landing/introduction area
  3. BrandSection: Brand or client showcase
  4. ServiceSection: Services or capabilities overview
  5. ContactSection: Contact information or form
  6. 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);
   }, []);
Enter fullscreen mode Exit fullscreen mode
  • 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@gmail.com");
   };
Enter fullscreen mode Exit fullscreen mode
  • 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>
Enter fullscreen mode Exit fullscreen mode
  • 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";
Enter fullscreen mode Exit fullscreen mode
  • 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>
  );
}
Enter fullscreen mode Exit fullscreen mode

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">
Enter fullscreen mode Exit fullscreen mode
  • 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"
/>
Enter fullscreen mode Exit fullscreen mode
  • 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>
Enter fullscreen mode Exit fullscreen mode
  • 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>
Enter fullscreen mode Exit fullscreen mode
  • 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";
Enter fullscreen mode Exit fullscreen mode
  • 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>
  );
}
Enter fullscreen mode Exit fullscreen mode

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" },
];
Enter fullscreen mode Exit fullscreen mode
  • 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">
Enter fullscreen mode Exit fullscreen mode
  • 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">
Enter fullscreen mode Exit fullscreen mode
  • 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>
))}
Enter fullscreen mode Exit fullscreen mode
  • 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";
Enter fullscreen mode Exit fullscreen mode
  • 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>
  );
}
Enter fullscreen mode Exit fullscreen mode

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: "πŸ’»",
  },
];
Enter fullscreen mode Exit fullscreen mode
  • 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">
Enter fullscreen mode Exit fullscreen mode
  • 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>
Enter fullscreen mode Exit fullscreen mode
  • 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">
Enter fullscreen mode Exit fullscreen mode
  • 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>
))}
Enter fullscreen mode Exit fullscreen mode
  • 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";
Enter fullscreen mode Exit fullscreen mode
  • 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>
  );
}
Enter fullscreen mode Exit fullscreen mode
  • 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">
Enter fullscreen mode Exit fullscreen mode
  • -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>
Enter fullscreen mode Exit fullscreen mode
  • 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>
Enter fullscreen mode Exit fullscreen mode
  • 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";
Enter fullscreen mode Exit fullscreen mode
  • 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>
  );
}
Enter fullscreen mode Exit fullscreen mode
  • 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">
Enter fullscreen mode Exit fullscreen mode
  • 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

  1. Copyright Text
   <div>Β© 2024 All rights reserved.</div>
Enter fullscreen mode Exit fullscreen mode
  • Displays the copyright text with the year 2024.
  • div: A simple container for the copyright notice.
  1. Navigation Links
   <nav className="space-x-4">
     <Link href="#">HeadStarter</Link>
   </nav>
Enter fullscreen mode Exit fullscreen mode
  • 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).
  • <Link>: A React component used for client-side navigation, though the href="#" here doesn't direct to any specific page.

Default Export

export default Footer;
Enter fullscreen mode Exit fullscreen mode

Key Features

  1. 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.
  2. 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.
  3. Extensibility:

    • The navigation section (<nav>) 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

  1. Use next/image for automatic image optimization
  2. Implement code splitting
  3. Utilize static generation for non-dynamic content
  4. 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

Billboard image

Deploy and scale your apps on AWS and GCP with a world class developer experience

Coherence makes it easy to set up and maintain cloud infrastructure. Harness the extensibility, compliance and cost efficiency of the cloud.

Learn more

Top comments (0)

A Workflow Copilot. Tailored to You.

Pieces.app image

Our desktop app, with its intelligent copilot, streamlines coding by generating snippets, extracting code from screenshots, and accelerating problem-solving.

Read the docs

πŸ‘‹ Kindness is contagious

Engage with a sea of insights in this enlightening article, highly esteemed within the encouraging DEV Community. Programmers of every skill level are invited to participate and enrich our shared knowledge.

A simple "thank you" can uplift someone's spirits. Express your appreciation in the comments section!

On DEV, sharing knowledge smooths our journey and strengthens our community bonds. Found this useful? A brief thank you to the author can mean a lot.

Okay