From a2df3a5fea531e33da366cc0b496be665d9b761d Mon Sep 17 00:00:00 2001 From: akash Date: Tue, 23 Dec 2025 16:48:44 +0530 Subject: [PATCH] pagenation updated blog page --- app/blog/page.js | 60 +----------------- components/elements/BlogList.js | 95 ++++++++++++++++++++++++++++ components/elements/Pagination.js | 83 ++++++++++++++++++++++++ public/assets/css/Pagination.css | 102 ++++++++++++++++++++++++++++++ 4 files changed, 283 insertions(+), 57 deletions(-) create mode 100644 components/elements/BlogList.js create mode 100644 components/elements/Pagination.js create mode 100644 public/assets/css/Pagination.css diff --git a/app/blog/page.js b/app/blog/page.js index be9e933..22c9256 100644 --- a/app/blog/page.js +++ b/app/blog/page.js @@ -2,27 +2,13 @@ import Link from "next/link"; import Layout from "@/components/layout/Layout"; import Blogs from "@/utils/constant.utils"; +import BlogList from "@/components/elements/BlogList"; export const metadata = { title: "Street-Food Stories from Sixty5 Street", description: "Dive into the Sixty5 Street blog for behind-the-scenes stories, flavor experiments, new dish launches and street-food culture updates.", }; -const truncateWords = (text, limit) => { - const words = text.split(" "); - return words.length > limit ? words.slice(0, limit).join(" ") + " ..." : text; -}; - -const stripHtml = (html) => { - if (!html) return ""; - return html.replace(/<[^>]*>/g, ""); -}; - -const truncateTitle = (text, limit) => { - if (!text) return ""; - return text.length > limit ? text.slice(0, limit) + "..." : text; -}; - export default function Blog() { return ( -
+
Our Blogs
@@ -39,47 +25,7 @@ export default function Blog() {
-
- {Blogs.sort((a, b) => new Date(b.date) - new Date(a.date)).map((blog) => ( -
-
- {/* Blog Image */} -
- {blog.title} -
- - {/* Blog Title */} -
-

- - {truncateTitle(stripHtml(blog.title), 40)} - -

- - {/* Blog Excerpt */} -

- {truncateWords(stripHtml(blog.para))} -

- - {/* Read More Button */} - - Read More - -
-
-
- ))} -
+
diff --git a/components/elements/BlogList.js b/components/elements/BlogList.js new file mode 100644 index 0000000..1918777 --- /dev/null +++ b/components/elements/BlogList.js @@ -0,0 +1,95 @@ +"use client"; +import { useState } from "react"; +import Link from "next/link"; +import Pagination from "./Pagination"; +import "public/assets/css/Pagination.css"; + +const truncateWords = (text, limit = 20) => { + const words = text.split(" "); + return words.length > limit ? words.slice(0, limit).join(" ") + " ..." : text; +}; + +const stripHtml = (html) => { + if (!html) return ""; + return html.replace(/<[^>]*>/g, ""); +}; + +const truncateTitle = (text, limit) => { + if (!text) return ""; + return text.length > limit ? text.slice(0, limit) + "..." : text; +}; + +const BlogList = ({ blogs }) => { + const [currentPage, setCurrentPage] = useState(1); + const postsPerPage = 12; + + // Sort posts by date descending (newest first) - exactly like original code + const sortedPosts = [...blogs].sort((a, b) => new Date(b.date) - new Date(a.date)); + + // Calculate pagination + const totalPages = Math.ceil(sortedPosts.length / postsPerPage); + const indexOfLastPost = currentPage * postsPerPage; + const indexOfFirstPost = indexOfLastPost - postsPerPage; + const currentPosts = sortedPosts.slice(indexOfFirstPost, indexOfLastPost); + + const handlePageChange = (page) => { + setCurrentPage(page); + }; + + return ( +
{/* Wrapper for scroll functionality */} +
+ {currentPosts.map((blog) => ( +
+
+ {/* Blog Image */} +
+ {blog.title} +
+ + {/* Blog Title */} +
+

+ + {truncateTitle(stripHtml(blog.title), 40)} + +

+ + {/* Blog Excerpt */} +

+ {truncateWords(stripHtml(blog.para))} +

+ + {/* Read More Button */} + + Read More + +
+
+
+ ))} +
+ + {/* Pagination Component */} + {totalPages > 1 && ( + + )} +
+ ); +}; + +export default BlogList; diff --git a/components/elements/Pagination.js b/components/elements/Pagination.js new file mode 100644 index 0000000..4c7a0af --- /dev/null +++ b/components/elements/Pagination.js @@ -0,0 +1,83 @@ +import React from 'react'; + +const Pagination = ({ currentPage, totalPages, onPageChange }) => { + const handlePageClick = (e, page) => { + if (e) { + e.preventDefault(); + } + + if (page !== currentPage && page >= 1 && page <= totalPages) { + onPageChange(page); + // Scroll to top of blog section smoothly + const blogSection = document.querySelector('.blog-section'); + if (blogSection) { + const offset = 100; // Offset from top + const elementPosition = blogSection.getBoundingClientRect().top; + const offsetPosition = elementPosition + window.pageYOffset - offset; + + window.scrollTo({ + top: offsetPosition, + behavior: 'smooth' + }); + } + } + }; + + const renderPageNumbers = () => { + const pages = []; + const maxVisiblePages = 5; + + let startPage = Math.max(1, currentPage - Math.floor(maxVisiblePages / 2)); + let endPage = Math.min(totalPages, startPage + maxVisiblePages - 1); + + if (endPage - startPage < maxVisiblePages - 1) { + startPage = Math.max(1, endPage - maxVisiblePages + 1); + } + + for (let i = startPage; i <= endPage; i++) { + pages.push( + + ); + } + + return pages; + }; + + return ( +
+
+ {/* Previous Button */} + + + {/* Page Numbers */} + {renderPageNumbers()} + + {/* Next Button */} + +
+
+ ); +}; + +export default Pagination; diff --git a/public/assets/css/Pagination.css b/public/assets/css/Pagination.css new file mode 100644 index 0000000..471ba87 --- /dev/null +++ b/public/assets/css/Pagination.css @@ -0,0 +1,102 @@ +:root { + --theme: #cf2d1f; + --title: #ffffff; + --text: #777777; + --body-font: 'Poppins', sans-serif; +} + +.pagination-wrapper { + display: flex; + justify-content: center; + align-items: center; + margin-top: 60px; + margin-bottom: 40px; +} + +.pagination-container { + display: flex; + gap: 8px; + align-items: center; +} + +.pagination-arrow { + min-width: 45px; + height: 45px; + display: flex; + align-items: center; + justify-content: center; + border: 1px solid #e0e0e0; + background-color: #fff; + color: var(--theme); + font-family: var(--body-font); + font-size: 20px; + font-weight: 700; + cursor: pointer; + transition: all 0.3s ease; + border-radius: 4px; + padding: 0 15px; +} + +.pagination-arrow:hover:not(:disabled) { + background-color: var(--theme); + border-color: var(--theme); + color: var(--title); +} + +.pagination-arrow:disabled { + opacity: 0.4; + cursor: not-allowed; +} + +.pagination-number { + min-width: 45px; + height: 45px; + display: flex; + align-items: center; + justify-content: center; + border: 1px solid #e0e0e0; + background-color: #fff; + color: var(--text); + font-family: var(--body-font); + font-size: 16px; + font-weight: 500; + cursor: pointer; + transition: all 0.3s ease; + border-radius: 4px; + padding: 0 12px; +} + +.pagination-number:hover { + background-color: var(--theme); + border-color: var(--theme); + color: var(--title); +} + +.pagination-number.active { + background-color: var(--theme); + border-color: var(--theme); + color: var(--title); + font-weight: 600; +} + +/* Responsive Design */ +@media (max-width: 575px) { + .pagination-container { + gap: 5px; + } + + .pagination-arrow, + .pagination-number { + min-width: 38px; + height: 38px; + font-size: 14px; + } + + .pagination-arrow { + padding: 0 12px; + } + + .pagination-number { + padding: 0 10px; + } +} \ No newline at end of file