diff --git a/public/blog_cover_poster.png b/public/blog_cover_poster.png new file mode 100644 index 0000000..85be596 Binary files /dev/null and b/public/blog_cover_poster.png differ diff --git a/src/app/blogs/components/blogCard.jsx b/src/app/blogs/components/blogCard.jsx new file mode 100644 index 0000000..936fcc4 --- /dev/null +++ b/src/app/blogs/components/blogCard.jsx @@ -0,0 +1,167 @@ +import React, { useState } from "react"; +import Image from "next/image"; +import Link from "next/link"; + +import { Avatar, AvatarImage, AvatarFallback } from "@/components/ui/avatar" + +import { Montserrat } from "next/font/google"; +const montserratFont = Montserrat({ weight: ["100", "200", "400", "500", "600"], subsets: ["latin"] }); + +export default function BlogCard(props) { + const [blog, setBlog] = useState(props.blog); + const [blogPosterUrl, setBlogPosterUrl] = useState(blog.posterUrl); + const [blogTitle, setBlogTitle] = useState(blog.title); + const [blogIntro, setBlogIntro] = useState(blog.intro); + const [creatorName, setCreatorName] = useState("Devesh Sawant") + const [createdAt, setCreatedAt] = useState(blog.created_at); + const [blogPoster, setblogPoster] = useState("/event_poster.avif"); + const [blogLikes, setBlogLikes] = useState("10"); + const [blogComments, setBlogComments] = useState("10"); + + console.log(trimString(blogTitle, 45)); + + return ( +
+ +
+ Blog Poster +
+ + +
+
+

{formatDate(new Date(createdAt))}

+ +
+ +
+ +
+
+

{trimString(blogTitle, 45)}

+
+

{trimString(blogIntro, 200)}

+ +
+
+
+
+ + + +

{creatorName}

+
+
+
+ +

{blogLikes}

+
+
+ +

{blogComments}

+
+
+
+
+
+ +
+
+ ) +} + + +function trimString(str, length) { + // Use Intl.Segmenter to handle grapheme clusters (e.g., emojis) + const segmenter = new Intl.Segmenter(undefined, { granularity: "grapheme" }); + const segments = segmenter.segment(str); + + // Convert segments iterator to an array of strings + const graphemes = Array.from(segments, segment => segment.segment); + + // Check if truncation is needed + if (graphemes.length > length) { + return graphemes.slice(0, length).join('') + "..."; + } + + // Return the original string if no truncation is needed + return str; +} + + +function formatDate(date) { + // Array of month names + const monthNames = [ + "Jan", "Feb", "Mar", "Apr", "May", "Jun", + "Jul", "Aug", "Sept", "Oct", "Nov", "Dec" + ]; + + // Extract day, month, and year from the date + const day = date.getDate(); + const month = monthNames[date.getMonth()]; + const year = date.getFullYear(); + + // Format the date + return `${day} ${month}, ${year}`; +} + + + +const ShareButton = (props) => { + const handleShare = async () => { + if (navigator.share) { + try { + await navigator.share({ + title: 'Check this out!', + text: 'This is an awesome React app.', + url: window.location.origin + props.href + }); + + } catch (error) { + console.error('Error sharing:', error); + } + } else { + console.log('Web Share API not supported'); + // Optionally handle fallback here + } + }; + + return ( + + ); +}; + +const ShareIcon = () => ( + + + +); + + +const CommentIcon = () => ( + + + +); + + +const LikeIcon = () => ( + + + +); diff --git a/src/app/blogs/components/blogCoverPoster.jsx b/src/app/blogs/components/blogCoverPoster.jsx new file mode 100644 index 0000000..1cf9ff8 --- /dev/null +++ b/src/app/blogs/components/blogCoverPoster.jsx @@ -0,0 +1,10 @@ + +import Image from 'next/image'; +export default function Blogs() { + const blogCoverImage = "/blog_cover_poster.png"; + return( +
+ Blog cover poster +
+ ) +} \ No newline at end of file diff --git a/src/app/blogs/components/comment.jsx b/src/app/blogs/components/comment.jsx new file mode 100644 index 0000000..4c7cf94 --- /dev/null +++ b/src/app/blogs/components/comment.jsx @@ -0,0 +1,11 @@ +const LikeIcon = () => ( + + + +); diff --git a/src/app/blogs/components/generateBlogCards.jsx b/src/app/blogs/components/generateBlogCards.jsx new file mode 100644 index 0000000..d9203e3 --- /dev/null +++ b/src/app/blogs/components/generateBlogCards.jsx @@ -0,0 +1,23 @@ +import React, { useEffect } from "react"; +import BlogCard from "./blogCard"; + +import "@/styles/blogs.css" + +import { Montserrat,Alata} from "next/font/google"; +const alataFont = Alata({weight: ["400"], subsets: ["latin"]}); +const montserratFont = Montserrat({weight: ["100","200","400","600"], subsets: ["latin"]}); + +export default function GenerateBlogCards(props){ + const blogs = props.blogs; + + return( +
+
+

Blogs

+
+ {blogs.map((blog)=>)} +
+
+
+ ) +} \ No newline at end of file diff --git a/src/app/blogs/components/heart.svg b/src/app/blogs/components/heart.svg new file mode 100644 index 0000000..5dde482 --- /dev/null +++ b/src/app/blogs/components/heart.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/app/blogs/fetchBlogs.jsx b/src/app/blogs/fetchBlogs.jsx new file mode 100644 index 0000000..c501145 --- /dev/null +++ b/src/app/blogs/fetchBlogs.jsx @@ -0,0 +1,29 @@ +import { useState, useEffect } from 'react'; +import axios from 'axios'; + +const useFetchBlog = (currentPage) => { + const [blogs, setBlogs] = useState({}); + const [loading, setLoading] = useState(true); + const [error, setError] = useState(null); + + useEffect(() => { + setLoading(true); + const fetchBlog = async () => { + try { + const response = await axios.get(`/api/v1/get/blogs?page=${currentPage}`); + const result = response.data; + setBlogs(result.blogs); + setLoading(false); + } catch (error) { + setError(error); + setLoading(false); + } + }; + + fetchBlog(); + },[currentPage]); + + return { blogs, loading, error }; +}; + +export default useFetchBlog; \ No newline at end of file diff --git a/src/app/blogs/layout.tsx b/src/app/blogs/layout.tsx new file mode 100644 index 0000000..1bcbaa6 --- /dev/null +++ b/src/app/blogs/layout.tsx @@ -0,0 +1,18 @@ +import React from 'react'; +import Navbar from "@/components/navbar" +import Footer from "@/components/footer" + + +interface RootLayoutProps { + children: React.ReactNode; +} + +export default function RootLayout({ children } : RootLayoutProps) { + return ( + <> + + {children} +