Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
5 changes: 1 addition & 4 deletions app/(landing)/blog/page.tsx
Original file line number Diff line number Diff line change
@@ -1,20 +1,17 @@
import React from 'react';
import { Metadata } from 'next';
import { generatePageMetadata } from '@/lib/metadata';
import BlogHero from '@/components/landing-page/blog/BlogHero';
import BlogGrid from '@/components/landing-page/blog/BlogGrid';
import { getAllBlogPosts } from '@/lib/data/blog';

export const metadata: Metadata = generatePageMetadata('blog');

const BlogPage = async () => {
const posts = await getAllBlogPosts();
const otherPosts = posts.slice(1);

return (
<div className='min-h-screen bg-[#030303]'>
<BlogHero />
<BlogGrid posts={otherPosts} showLoadMore={false} />
<BlogGrid posts={posts} showLoadMore={true} />
</div>
);
};
Expand Down
49 changes: 20 additions & 29 deletions components/landing-page/blog/BlogCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,54 +7,45 @@ import {
import Link from 'next/link';
import Image from 'next/image';
import React from 'react';
import { BlogPost } from '@/lib/data/blog';

type Blog = {
id: number;
title: string;
excerpt: string;
image: string;
date: string;
slug: string;
category: string;
};

const BlogCard = ({ blog }: { blog: Blog }) => {
const BlogCard = ({ post }: { post: BlogPost }) => {
return (
<Card
key={blog.id}
key={post.id}
className='max-w-noneflex h-full w-full flex-col gap-0 overflow-hidden rounded-[8px] border-[#1B1B1B] bg-[#101010] p-0 transition-colors duration-300 hover:border-[#2A2A2A]'
>
<CardHeader className='relative p-0 !pb-0'>
<div className='h-[214px] w-full'>
<div className='h-[250px] w-full'>
<Image
src={blog.image}
alt={blog.title}
width={397}
height={214}
src={post.image}
alt={post.title}
width={500}
height={250}
className='h-full w-full object-cover'
/>
</div>
</CardHeader>

<CardContent className='flex-1 border-b border-[#2B2B2B] px-4 pt-4 pb-5'>
<div className='mb-3 flex items-center justify-between text-xs leading-[145%] text-[#b5b5b5] sm:text-sm'>
<span className='inline-block rounded-[8px] bg-[#A7F95014] px-2.5 py-1 text-sm font-medium text-[#A7F950]'>
{blog.category}
<CardContent className='flex-1 border-b border-[#2B2B2B] px-6 pt-6 pb-6'>
<div className='mb-4 flex items-center justify-between text-sm leading-[145%] text-[#b5b5b5]'>
<span className='inline-block rounded-[8px] bg-[#A7F95014] px-3 py-1.5 text-sm font-medium text-[#A7F950]'>
{post.category}
</span>
<span className='font-normal'>{blog.date}</span>
<span className='font-normal'>{post.date}</span>
</div>
<h2 className='line-clamp-2 text-[16px] leading-[145%] font-semibold text-white sm:text-base'>
{blog.title}
<h2 className='line-clamp-2 text-lg leading-[145%] font-semibold text-white'>
{post.title}
</h2>
<p className='mt-3 line-clamp-3 text-sm leading-[145%] font-normal tracking-[-0.48px] text-[#B5B5B5] sm:text-base'>
{blog.excerpt}
<p className='mt-4 line-clamp-3 text-base leading-[145%] font-normal tracking-[-0.48px] text-[#B5B5B5]'>
{post.excerpt}
</p>
</CardContent>

<CardFooter className='mt-auto px-5 pt-5 pb-4'>
<CardFooter className='mt-auto px-6 pt-6 pb-6'>
<Link
href={`/blog/${blog.slug}`}
className='flex w-full items-center justify-end gap-2 text-right text-sm font-medium text-[#A7F950]'
href={`/blog/${post.slug}`}
className='flex w-full items-center justify-end gap-2 text-right text-base font-medium text-[#A7F950]'
>
Continue reading
<Image
Expand Down
131 changes: 126 additions & 5 deletions components/landing-page/blog/BlogGrid.tsx
Comment thread
0xDeon marked this conversation as resolved.
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
/* eslint-disable @typescript-eslint/no-unused-vars */
'use client';

import React from 'react';
import React, { useState, useCallback } from 'react';
import { BlogPost } from '@/lib/data/blog';
import BlogCard from './BlogCard';
import { Search, Loader2 } from 'lucide-react';
import { Input } from '@/components/ui/input';

interface BlogGridProps {
posts: BlogPost[];
Expand All @@ -12,12 +14,131 @@ interface BlogGridProps {

const BlogGrid: React.FC<BlogGridProps> = ({
posts,
showLoadMore = false,
showLoadMore = true,
maxPosts,
}) => {
const displayPosts = maxPosts ? posts.slice(0, maxPosts) : posts;
const [visiblePosts, setVisiblePosts] = useState(maxPosts || 12);
const [selectedCategory, setSelectedCategory] = useState('Latest');
const [isLoading, setIsLoading] = useState(false);

return <section className=''></section>;
// Get posts to display (no filtering)
const displayPosts = posts.slice(0, visiblePosts);
const hasMorePosts = visiblePosts < posts.length;

// Load more handler
const handleLoadMore = useCallback(() => {
if (isLoading || !hasMorePosts) return;

setIsLoading(true);

// Simulate loading delay for better UX
setTimeout(() => {
setVisiblePosts(prev => prev + 12);
setIsLoading(false);
}, 500);
}, [isLoading, hasMorePosts]);

const handleCategoryChange = (category: string) => {
setSelectedCategory(category);
// UI only - no filtering functionality
};

return (
<div className='min-h-screen bg-[#030303]'>
{/* Header Navigation */}
<div>
<div className='mx-auto max-w-6xl px-6 py-8'>
<div className='flex flex-col gap-4 md:flex-row md:items-center md:justify-between'>
{/* Category Buttons */}
<div className='flex items-center gap-3'>
<button
onClick={() => handleCategoryChange('Latest')}
className={`flex items-center gap-2 rounded-lg px-4 py-2 text-sm font-medium transition-colors ${
selectedCategory === 'Latest'
? 'border border-white/20 text-white'
: 'border border-white/10 text-white hover:bg-[#2A2A2A]'
}`}
>
<svg
className='h-4 w-4'
fill='currentColor'
viewBox='0 0 20 20'
>
<path
fillRule='evenodd'
d='M3 4a1 1 0 011-1h12a1 1 0 110 2H4a1 1 0 01-1-1zm0 4a1 1 0 011-1h12a1 1 0 110 2H4a1 1 0 01-1-1zm0 4a1 1 0 011-1h12a1 1 0 110 2H4a1 1 0 01-1-1zm0 4a1 1 0 011-1h12a1 1 0 110 2H4a1 1 0 01-1-1z'
clipRule='evenodd'
/>
</svg>
Latest
</button>
<button
onClick={() => handleCategoryChange('Category')}
className={`flex items-center gap-2 rounded-lg px-4 py-2 text-sm font-medium transition-colors ${
selectedCategory === 'Category'
? 'border border-white/20 text-white'
: 'border border-white/10 text-white hover:bg-[#2A2A2A]'
}`}
>
Category
</button>
</div>

{/* Search Bar */}
<div className='relative w-full md:w-auto md:min-w-[300px]'>
<Search className='absolute top-1/2 left-3 h-4 w-4 -translate-y-1/2 text-white' />
<Input
type='text'
placeholder='Search article'
className='w-full rounded-lg border border-white/10 bg-[#101010] py-2 pr-4 pl-10 text-white placeholder:text-[#B5B5B5] focus:border-white/20 focus:ring-white/20'
readOnly
/>
</div>
</div>
</div>
</div>

{/* Blog Grid */}
<div className='mx-auto max-w-6xl px-6 py-12'>
<div className='grid grid-cols-1 gap-6 sm:grid-cols-2 lg:grid-cols-2 xl:grid-cols-3'>
{displayPosts.map(post => (
<div key={post.id} className='w-full'>
<BlogCard post={post} />
</div>
))}
</div>

{/* View More Button */}
{showLoadMore && hasMorePosts && !isLoading && (
<div className='mt-12 flex justify-center'>
<button
onClick={handleLoadMore}
className='flex items-center gap-2 rounded-lg border border-[#2B2B2B] bg-[#1A1A1A] px-6 py-3 text-white transition-colors hover:bg-[#2A2A2A] hover:text-white focus:ring-2 focus:ring-[#A7F950] focus:outline-none'
>
View More
</button>
</div>
)}

{/* Loading indicator */}
{isLoading && (
<div className='mt-12 flex justify-center'>
<div className='flex items-center gap-2 text-[#B5B5B5]'>
<Loader2 className='h-5 w-5 animate-spin' />
<span>Loading more posts...</span>
</div>
</div>
)}

{/* No more posts message */}
{!hasMorePosts && posts.length > 0 && !isLoading && (
<div className='mt-12 text-center text-[#B5B5B5]'>
<p>You've reached the end of the blog posts!</p>
</div>
)}
</div>
</div>
);
};

export default BlogGrid;
7 changes: 0 additions & 7 deletions components/landing-page/blog/BlogHero.tsx

This file was deleted.

Loading
Loading