Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
9614776
Initial plan
Copilot Oct 31, 2025
c7dfdc0
Initial plan
Copilot Oct 31, 2025
bb1293a
Initial plan
Copilot Oct 31, 2025
8ecd032
Add error handling to blogs page fetch operation
Copilot Oct 31, 2025
9da4faa
Replace native img tags with Next.js Image component
Copilot Oct 31, 2025
36b16f6
Replace HTML img tag with Next.js Image component for optimization
Copilot Oct 31, 2025
9da10ec
Add sizes prop to Image components for responsive optimization
Copilot Oct 31, 2025
760b4a4
Optimize header image sizes prop for max-w-6xl container
Copilot Oct 31, 2025
130d386
Merge pull request #11 from CSSL-GenZ-Chapter-UCSC/copilot/sub-pr-7-a…
DRlFTER Nov 4, 2025
4a7cdae
Merge branch 'feature/blogsPage' into copilot/sub-pr-7-again
DRlFTER Nov 4, 2025
befe631
Merge pull request #9 from CSSL-GenZ-Chapter-UCSC/copilot/sub-pr-7
DRlFTER Nov 4, 2025
2bdfb69
Merge pull request #10 from CSSL-GenZ-Chapter-UCSC/copilot/sub-pr-7-a…
DRlFTER Nov 4, 2025
c5f767a
bloglist and blog detail pages
Sivajan-Jeyaseelan Nov 10, 2025
cc1fa7b
Add blog pages and updates
Sivajan-Jeyaseelan Nov 10, 2025
6b4cfca
Added BlogsList page and Blogdetails page
Sivajan-Jeyaseelan Nov 11, 2025
3cc2cce
some changes
Sivajan-Jeyaseelan Nov 12, 2025
29786cf
blocklist and blogdetails page
Sivajan-Jeyaseelan Nov 12, 2025
ad6fa5b
Merge branch 'dev' of https://github.com/CSSL-GenZ-Chapter-UCSC/CSSL-…
Sivajan-Jeyaseelan Nov 12, 2025
2eda4d0
Update app/blogs/page.tsx
DRlFTER Nov 13, 2025
d83444c
Update sanity/schemaTypes/index.ts
DRlFTER Nov 13, 2025
c173cd2
Merge branch 'dev' of https://github.com/CSSL-GenZ-Chapter-UCSC/CSSL-…
Sivajan-Jeyaseelan Nov 15, 2025
db60a55
made changes on blogs page
Sivajan-Jeyaseelan Nov 19, 2025
56afb4d
Merge branch 'dev' of https://github.com/CSSL-GenZ-Chapter-UCSC/CSSL-…
Sivajan-Jeyaseelan Nov 19, 2025
588c90f
BlogListing page in progress
Sivajan-Jeyaseelan Nov 24, 2025
b6ecf3d
BlogListing page still in progress
Sivajan-Jeyaseelan Nov 24, 2025
96d3df3
changedBlogListingComponent
Sivajan-Jeyaseelan Nov 24, 2025
e1e9fca
pulled from dev and solved conflicts and pushed to github for compare…
Sivajan-Jeyaseelan Nov 26, 2025
bb7abe0
when comparing my feature/blogsPage with dev there is a difference be…
Sivajan-Jeyaseelan Nov 26, 2025
a6554e0
Merge branch 'dev' of https://github.com/CSSL-GenZ-Chapter-UCSC/CSSL-…
Sivajan-Jeyaseelan Nov 26, 2025
bfde7b6
recently i'm pulling from dev
Sivajan-Jeyaseelan Nov 26, 2025
264baa5
I am trying to refactor blogs page by dividingg sub components as a f…
Sivajan-Jeyaseelan Nov 26, 2025
3b42496
I deleted BlockListing.tsx and I added BlogFetcher.tsx for blog fetch…
Sivajan-Jeyaseelan Nov 26, 2025
d0947cb
I deleted BlockFetcher.tsx and I added DisplayBlogs.tsx for displayin…
Sivajan-Jeyaseelan Nov 26, 2025
d094891
I modified app/blogs/page.tsx,Display.tsx,DynamicButtons.tsx
Sivajan-Jeyaseelan Nov 26, 2025
7a0650c
added Dynamic Buttons display behaviour
Sivajan-Jeyaseelan Nov 26, 2025
33f030f
fix some errors
Sivajan-Jeyaseelan Nov 26, 2025
9d94e87
created app/blogs/page.tsx
Sivajan-Jeyaseelan Nov 27, 2025
196bd54
created SingleBlogPage
Sivajan-Jeyaseelan Nov 28, 2025
6441b76
partially implemented blogs animation
Sivajan-Jeyaseelan Nov 29, 2025
c238f25
final of blog listing page
Sivajan-Jeyaseelan Dec 1, 2025
355884a
created single blog page
Sivajan-Jeyaseelan Dec 1, 2025
f92b660
pulled from dev
Sivajan-Jeyaseelan Dec 1, 2025
357784d
solving some issue
Sivajan-Jeyaseelan Dec 1, 2025
05b1881
revied some errores and fixed that
Sivajan-Jeyaseelan Dec 1, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions app/blogs/[id]/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
"use client";

import { SingleBlog } from "../../components/sections/SingleBlog";
import { getBlogById, type Blog } from "@/sanity/lib/getBlogs";
import { useState,useEffect } from "react";



export default function BlogDetailPage() {
return (
<main className="flex flex-col">
<SingleBlog />;
</main>
);
}
146 changes: 11 additions & 135 deletions app/blogs/page.tsx
Original file line number Diff line number Diff line change
@@ -1,143 +1,19 @@
"use client";
import { BlogListing } from "../components/sections/BlogListing";
import {DynamicButtons} from "../components/sections/DynamicButtons";

import Link from "next/link";
import { client } from "@/sanity/lib/client";
import { useState, useEffect } from "react";

type Blog = {
_id: string;
title: string;
slug: { current: string };
mainImage?: { asset: { url: string } };
author?: { name: string };
excerpt?: string;
publishedAt?: string;
category?: string;
export const metadata = {
title: "Blogs",
description: "CSSL GenZ Chapter of UCSC",
keywords: "",
};

async function getBlogs(): Promise<Blog[]> {
const query = `*[_type=="blog"]|order(publishedAt desc)[0...50]{
_id,
title,
slug,
"mainImage": mainImage.asset->{url},
"author": author-> { name },
excerpt,
publishedAt,
category
}`;
return client.fetch(query);
}

export default function BlogsPage() {
const [blogs, setBlogs] = useState<Blog[]>([]);
const [visibleCount, setVisibleCount] = useState(9);
const [activeCategory, setActiveCategory] = useState("All");

//const categories = ["All", "Tutorials", "News", "Updates"];

const categories = ["All", "Events", "Workshops", "Competitions", "Announcements"];


useEffect(() => {
getBlogs().then(setBlogs);
}, []);

const filteredBlogs =
activeCategory === "All"
? blogs
: blogs.filter((b) => b.category === activeCategory);

export default function ContactUsPage() {
return (
<main className="mx-auto max-w-6xl px-4 py-10">
{/* Header */}
<section className="text-center mb-12">
<img
src="/images/blog-header.jpg"
alt="Blog Header"
className="mx-auto mb-6 w-full max-h-64 object-cover rounded-lg shadow-sm"
/>
<h1 className="text-4xl font-bold">Blogs</h1>
<p className="mt-4 text-gray-600">
Stay updated with the latest events, workshops, and announcements
</p>
</section>

{/* Filter Buttons */}
<section className="flex justify-center mb-10 space-x-3">
{categories.map((cat) => (
<button
key={cat}
onClick={() => setActiveCategory(cat)}
className={`px-4 py-2 rounded-lg transition ${
activeCategory === cat
? "bg-blue-600 text-white"
: "bg-gray-100 text-gray-700 hover:bg-blue-600 hover:text-white"
}`}
>
{cat}
</button>
))}
</section>

{/* Blog Grid */}
{filteredBlogs.length === 0 ? (
<p className="text-center text-gray-500">No blogs yet.</p>
) : (
<section className="grid gap-8 sm:grid-cols-2 lg:grid-cols-3">
{filteredBlogs.slice(0, visibleCount).map((blog) => (
<article
key={blog._id}
className="border rounded-lg overflow-hidden shadow-sm hover:shadow-md transition-shadow duration-200 flex flex-col"
>
{blog.mainImage?.asset?.url && (
<img
src={blog.mainImage.asset.url}
alt={blog.title}
className="w-full h-56 object-cover"
/>
)}
<div className="p-4 flex flex-col flex-1 justify-between">
<div>
<Link
href={`/blogs/${blog.slug.current}`}
className="text-xl font-semibold hover:underline"
>
{blog.title}
</Link>
{blog.author?.name && (
<p className="text-sm text-gray-500 mt-1">
By {blog.author.name}
</p>
)}
{blog.excerpt && (
<p className="mt-2 text-gray-700 line-clamp-3">
{blog.excerpt}
</p>
)}
</div>
{blog.publishedAt && (
<p className="mt-3 text-sm text-gray-400">
{new Date(blog.publishedAt).toLocaleDateString()}
</p>
)}
</div>
</article>
))}
</section>
)}

{/* Load More */}
{visibleCount < filteredBlogs.length && (
<div className="flex justify-center mt-12">
<button
onClick={() => setVisibleCount((prev) => prev + 9)}
className="px-6 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition"
>
Load More
</button>
</div>
)}
<main className="flex flex-col">

<BlogListing />

</main>
);
}
2 changes: 1 addition & 1 deletion app/components/elements/Footer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -195,4 +195,4 @@ const FooterContent = () => {
</div>
</div>
);
};
};
2 changes: 1 addition & 1 deletion app/components/elements/MemberCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -68,4 +68,4 @@ export const MemberCardItem = ({ member }: { member: MemberCardProps }) => {
</Link>
</motion.div>
);
};
};
2 changes: 1 addition & 1 deletion app/components/elements/NavBar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -249,4 +249,4 @@ export const Navbar = () => {
</Container>
</motion.header>
);
};
};
2 changes: 1 addition & 1 deletion app/components/elements/TeamGroupPhoto.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -45,4 +45,4 @@ export const TeamGroupPhoto = ({
</motion.div>
</div>
);
};
};
2 changes: 1 addition & 1 deletion app/components/elements/Trail.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -192,4 +192,4 @@ export const Trail = ({
/>
</div>
);
};
};
2 changes: 1 addition & 1 deletion app/components/sections/About.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -148,4 +148,4 @@ export const About = () => {
</Container>
</section>
);
};
};
120 changes: 120 additions & 0 deletions app/components/sections/BlogDescription.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
"use client";

import { useState, useEffect } from "react";
import { usePathname } from "next/navigation";
import { getBlogById, type Blog } from "@/sanity/lib/getBlogs";
import { urlFor } from "@/sanity/lib/image";

export const BlogDescription = () => {

const pathname = usePathname();

const [blogId, setBlogId] = useState<string | null>(null);
const [blog, setBlog] = useState<Blog | null>(null);


useEffect(() => {
if (pathname) {
const segments = pathname.split("/");
const id = segments[2];
setBlogId(id);
}
}, [pathname]);

useEffect(() => {
if (blogId) {
getBlogById(blogId)
.then((data) => setBlog(data))
.catch((err) => console.error(err));
}
}, [blogId]);

if (!blog) return <p>Loading...</p>;

const contentParagraphs = blog.content
? blog.content.split("\n").filter(Boolean)
: [];

const subtopicParagraphs = blog.subtopicDescription
? blog.subtopicDescription.split("\n").filter(Boolean)
: [];

return (
<div className="py-8 pl-23 border border-red-500">
{/* Content paragraphs */}
{contentParagraphs.length > 0 ? (
contentParagraphs.map((p, i) => (
<p
key={i}
className={`my-2 ${
i === 0 ? "text-orange-500 font-semibold" : "text-[#9AA0A6]"
}`}
>
{p}
</p>
))
) : (
<p className="text-white">No content</p>
)}

{/* Subtopic section */}
{subtopicParagraphs.length > 0 ? (
<div>
<h5 className="text-[#84B5FF] mt-6 mb-2">Sub Topic</h5>

{/* First subtopic */}
<p className="text-[#9AA0A6] my-1">{subtopicParagraphs[0]}</p>

{/* Image if exists */}
{blog?.mainImage?.asset && (
<img
src={urlFor(blog.mainImage).width(1200).url()}
alt={blog.title}
className="w-[693px] h-[490px] object-cover lg:-left-[33px] lg:-top-[35px] lg:relative"
/>
)}

{/* Rest of subtopics (optional) */}
{subtopicParagraphs.slice(1).map((sub, i) => (
<p key={i} className="text-[#9AA0A6] my-1">
{sub}
</p>
))}

<div className="flex flex-col md:flex-row justify-between items-center gap-0 text-sm text-gray-400 mt-6">
{/* Last Updated */}
<p>
Last Updated{" "}
<span className="text-blue-500 font-medium">
{new Date(blog.publishedAt).toLocaleDateString("en-GB", {
day: "2-digit",
month: "short",
year: "numeric",
})}
</span>
</p>

{/* Category */}
{blog.category && (
<p>
Category{" "}
<span className="text-blue-500 font-medium -ml-30">{blog.category}</span>
</p>
)}
</div>
</div>
) : (
<p className="text-white">No subtopic description</p>
)}





</div>




);
};
50 changes: 50 additions & 0 deletions app/components/sections/BlogListing.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
"use client";

import { useState,useEffect } from "react";
import { motion } from "motion/react";
import { h1 } from "motion/react-client";
import { client } from "@/sanity/lib/client";
import Image from "next/image";
import Link from "next/link";
import { Button } from "../shared/Button";
import { PageTitle } from "../shared/PageTitle";
import { Container } from "../shared/Container";
import { getBlogs, Blog } from "@/sanity/lib/getBlogs";
import { DisplayBlogs } from "./DisplayBlogs";
import { BlogsAnimation } from "./BlogsAnimations";







export const BlogListing = () => {

return (
<section className="h- flex items-start justify-center bg-black text-white sm:pt-30 pt-20">
<Container className="h-full pb-20">
<div className="lg:-mb-790 w-full h-full flex flex-col sm:items-stretch ">
<PageTitle
text="BLOGS"
className="lg:text-[213px] md:text-[125px] sm:text-[100px] text-[60px]"
/>
<div className="flex px-2.5 justify-between items-start self-stretch flex-1">
<motion.p
initial={{ opacity: 0, filter: "blur(8px)" }}
animate={{ opacity: 1, filter: "blur(0px)" }}
transition={{ duration: 0.3, ease: "easeOut", delay: 0.15 }}
className="text-[#afafaf] font-[Poppins] sm:text-[16px] xl:mb-800 text-[12px] not-italic font-medium sm:leading-[23px] leading-4 sm:w-[474px] w-[200px]"
>
Exploring trends, ideas, and success stories that shape the future of community and connection.
</motion.p>
</div>
</div>

<BlogsAnimation />

<DisplayBlogs />
</Container>
</section>
);
}
2 changes: 1 addition & 1 deletion app/components/sections/Blogs.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -368,4 +368,4 @@ export const Blogs = () => {
</Container>
</section>
);
};
};
Loading