Blogging Platform using Next JS
In this project, we will explore the process of building The Blogging Platform with Next.js. Blogging Platform is a web application that allows users to create and publish blog posts. The platform provides a user-friendly interface for managing blog content and includes functionalities to create new blogs, search for blogs, and read the detailed content of specific blogs.
Output Preview: Let us have a look at how the final output will look like.
Prerequisites:
Approach to Create Blogging Platform:
- Setup the Project by Creating a new NextJS project Install the necessary libraries.
- Design the layout of blogging platform, including components like Navbar, BlogList, Blogdetail, SearchBar, etc.
- We will use local storage to store the blog details.
- We will utilize useState and useEffect hooks to manage state and fetch blog data. we will use useRouter hook to access route parameters such as blog id.
- Implement a search feature for filtering blog posts based on the search query.
- We will implement Next.js routing to navigate between different pages (e.g., list of blogs, individual blog posts, create new blogs).
- We will style the application using bootstrap.
Steps to Create the Blogging Platform:
Step 1: Create a application of NextJS using the following command.
npx create-next-app blog-app
Step 2: Navigate to project directory
cd blog-app
Step 3: Install the necessary package in your project using the following command.
npm install bootstrap
Step 4: Create the folder structure as shown below and create the files in respective folders.
Project Structure:
The updated dependencies in package.json file will look like:
"dependencies": {
"bootstrap": "^5.3.3",
"next": "14.1.3",
"react": "^18",
"react-dom": "^18"
}
Example: Below are the components which describes the implementation of the Blogging platform.
- Navbar.js: This component defines a navigation bar for blogging platform. It uses the Link component from Next.js to create links to different pages of the website.
- Createblog.js: This component allows users to add new blog posts by entering blog details.
- BlogList.js: This component is responsible to retrieve and display a list of published blog posts.
- [id].js: This component displays the details of a specific blog post using dynamic routing.
// page.js
import React from 'react'
import BlogList from '@/Components/BlogList';
const page = () => {
return (
<>
<BlogList />
</>
)
}
export default page
// Navbar.js
import React from 'react';
import Link from 'next/link';
const Navbar = () => {
return (
<div>
<nav className="navbar navbar-expand-lg navbar-light
bg-dark bg-opacity-75 fixed-top text-light">
<div className="container">
<Link className="navbar-brand
text-light font-bold" href="/">
GFG Blogs
</Link>
<button className="navbar-toggler"
type="button"
data-toggle="collapse"
data-target="#navbarNav"
aria-controls="navbarNav"
aria-expanded="false"
aria-label="Toggle navigation">
<span className="navbar-toggler-icon"></span>
</button>
<div className="collapse navbar-collapse"
id="navbarNav">
<ul className="navbar-nav mr-auto">
<li className="nav-item">
<Link href="/"
className="nav-item nav-link
text-light">
Home
</Link>
</li>
<li className="nav-item">
<Link href="/Createblog"
className="nav-item nav-link
text-light">
Create new Blog
</Link>
</li>
</ul>
</div>
</div>
</nav>
</div>
);
};
export default Navbar;
// BlogList.js
'use client'
import React,
{
useState,
useEffect
} from 'react';
import 'bootstrap/dist/css/bootstrap.min.css';
import Navbar from '@/Components/Navbar';
import Link from 'next/link';
function BlogList() {
const [data, setData] = useState([]);
const [expandedId, setExpandedId] = useState(null);
const [searchQuery, setSearchQuery] = useState('');
useEffect(() => {
const blogs =
JSON.parse(localStorage.getItem('myData') || '[]');
setData(blogs);
}, []);
const toggleExpanded = (id) => {
setExpandedId(expandedId === id ? null : id);
};
let filteredData = data;
if (searchQuery.trim() !== '') {
filteredData = data.filter(item =>
item.title.toLowerCase()
.includes(searchQuery.toLowerCase())
);
}
return (
<div>
<Navbar />
<div className="container bg-light"
style={{ marginTop: '5rem' }}>
<input
type="text"
className="form-control mb-2"
placeholder="Search..."
value={searchQuery}
onChange={(e) => setSearchQuery(e.target.value)}
/>
<div className="row">
{
filteredData.map((item) => (
<div key={item.id} className="col-md-4">
<div className="card mb-3">
<img src={item.imageUrl}
className="card-img-top"
alt="Blog" />
<div className="card-body">
<h5 className="card-title">
{item.title}
</h5>
<p className="card-text">
{
expandedId ===
item.id ?
item.description :
`${item.description.substring(0, 50)}...`
}
</p>
<div className="d-flex justify-content-between
align-items-center row">
<div>
<p className="m-0 small col">
{"posted by "}
{item.author}
</p>
<small className="text-muted">
{item.date}
</small>
</div>
</div>
<Link href={`/blog/${item.id}`}>
<button className='btn btn-primary'>
Read more
</button>
</Link>
</div>
</div>
</div>
))}
</div>
</div>
</div>
);
}
export default BlogList;
// Createblog.js
'use client'
import React, { useState, useEffect } from 'react';
import 'bootstrap/dist/css/bootstrap.min.css';
import Navbar from '@/Components/Navbar';
const Createblog = () => {
const [author, setAuthor] = useState('');
const [title, setTitle] = useState('');
const [description, setDescription] = useState('');
const [imageUrl, setImageUrl] = useState('');
const initialBlogs =
typeof window !== 'undefined' ?
JSON.parse(localStorage.getItem('myData')) || [] : [];
const [data, setData] = useState(initialBlogs);
useEffect(() => {
// Save habits to localStorage whenever they change
localStorage.setItem('myData', JSON.stringify(data));
}, [data]);
const addData = () => {
const currentDate = new Date().toLocaleDateString();
const newData =
{
id: data.length + 1,
author: author,
date: currentDate,
title: title,
description: description,
imageUrl: imageUrl
};
const updatedData = [...data, newData];
setData(updatedData);
setAuthor('');
setTitle('');
setDescription('');
setImageUrl('');
};
return (
<div>
<Navbar />
<div className="container bg-light"
style={{ marginTop: '5rem' }}>
<div className="row">
<div className="col">
<input
type="text"
className="form-control mb-2"
placeholder="Author"
value={author}
onChange={(e) => setAuthor(e.target.value)}
/>
<input
type="text"
className="form-control mb-2"
placeholder="Title"
value={title}
onChange={(e) => setTitle(e.target.value)}
/>
<textarea
className="form-control mb-2"
placeholder="Description"
value={description}
onChange={(e) => setDescription(e.target
.value)}
/>
<input
type="text"
className="form-control mb-2"
placeholder="Image URL"
value={imageUrl}
onChange={(e) =>setImageUrl(e.target.value)}
/>
<button onClick={addData}
className="btn btn-primary mb-2">
Add Data
</button>
</div>
</div>
</div>
</div>
);
};
export default Createblog;
// pages/[id].js
import React,
{
useEffect,
useState
} from 'react';
import { useRouter } from 'next/router';
import Navbar from '@/Components/Navbar';
import 'bootstrap/dist/css/bootstrap.min.css';
const BlogDetails = () => {
const [blogDetail, setBlogDetail] = useState([]);
const router = useRouter();
const { id } = router.query;
useEffect(() => {
const blogs = JSON.parse(localStorage.getItem('myData'));
const selectedBlog=blogs.find(blog => blog.id === parseInt(id));
setBlogDetail(selectedBlog);
}, [id]);
if (!blogDetail) {
return <div>Loading...</div>;
}
return (
<div className="container bg-light"
style={{ marginTop: '5rem' }}>
<Navbar />
<div className="card mt-5">
<img src={blogDetail.imageUrl}
style={
{
maxWidth: '100%',
maxHeight: '300px'
}}
className="card-img-top" alt="Blog" />
<div className="card-body">
<h1 className="card-title">{blogDetail.title}</h1>
<p className="card-text">
{blogDetail.description}
</p>
<p className="card-text">
Author: {blogDetail.author}
</p>
<p className="card-text">Date: {blogDetail.date}</p>
</div>
</div>
</div>
);
};
export default BlogDetails;
Start your application using the following command:
npm run dev
Output: Naviage to the URL http://localhost:3000: