Skip to content
Open
Changes from 2 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
178 changes: 112 additions & 66 deletions pages/blog/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import React, { useContext, useEffect, useState } from 'react';

import Empty from '@/components/illustrations/Empty';
import GenericLayout from '@/components/layout/GenericLayout';
import Loader from '@/components/Loader';
import BlogPostItem from '@/components/navigation/BlogPostItem';
import Filter from '@/components/navigation/Filter';
import Heading from '@/components/typography/Heading';
Expand All @@ -14,127 +13,174 @@ import type { IBlogPost } from '@/types/post';
import { HeadingLevel, HeadingTypeStyle } from '@/types/typography/Heading';
import { ParagraphTypeStyle } from '@/types/typography/Paragraph';

/**
* @description The BlogIndexPage is the blog index page of the website.
*/
export default function BlogIndexPage() {
const router = useRouter();
const { navItems } = useContext(BlogContext);

// Sorting featured + date
const [posts, setPosts] = useState<IBlogPost[]>(
navItems
? navItems.sort((i1: IBlogPost, i2: IBlogPost) => {
const i1Date = new Date(i1.date);
const i2Date = new Date(i2.date);
const i1Date = new Date(i1.date);
const i2Date = new Date(i2.date);

if (i1.featured && !i2.featured) return -1;
if (!i1.featured && i2.featured) return 1;
if (i1.featured && !i2.featured) return -1;
if (!i1.featured && i2.featured) return 1;

return i2Date.getTime() - i1Date.getTime();
})
return i2Date.getTime() - i1Date.getTime();
})
: []
);
const [isClient, setIsClient] = useState(false);

const onFilter = (data: IBlogPost[]) => setPosts(data);
const [currentPage, setCurrentPage] = useState(1);
const postsPerPage = 6;

const indexOfLastPost = currentPage * postsPerPage;
const indexOfFirstPost = indexOfLastPost - postsPerPage;
const currentPosts = posts.slice(indexOfFirstPost, indexOfLastPost);

const totalPages = Math.ceil(posts.length / postsPerPage);

const onFilter = (data: IBlogPost[]) => {
setPosts(data);
setCurrentPage(1);
};

const toFilter = [
{
name: 'type'
},
{
name: 'authors',
unique: 'name'
},
{
name: 'tags'
}
{ name: 'type' },
{ name: 'authors', unique: 'name' },
{ name: 'tags' },
];

const clearFilters = () => {
router.push(`${router.pathname}`, undefined, {
shallow: true
});
router.push(`${router.pathname}`, undefined, { shallow: true });
};

const showClearFilters = Object.keys(router.query).length > 0;

const description = 'Find the latest and greatest stories from our community';
const image = '/img/social/blog.webp';

useEffect(() => {
setIsClient(true);
}, []);

return (
<GenericLayout title='Blog' description={description} image={image} wide>
<div className='relative px-4 pb-20 pt-8 sm:px-6 lg:px-8 lg:pb-28 lg:pt-12' id='main-content'>
<div className='absolute inset-0'>
<div className='h-1/3 bg-white sm:h-2/3'></div>
<GenericLayout title="Blog" description={description} image={image} wide>
<div
className="relative px-4 pb-20 pt-8 sm:px-6 lg:px-8 lg:pb-28 lg:pt-12"
id="main-content"
>
<div className="absolute inset-0">
<div className="h-1/3 bg-white sm:h-2/3"></div>
</div>
<div className='relative mx-auto max-w-7xl'>
<div className='text-center'>

<div className="relative mx-auto max-w-7xl">
<div className="text-center">
<Heading level={HeadingLevel.h1} typeStyle={HeadingTypeStyle.lg}>
Welcome to our blog!
</Heading>
<Paragraph className='mx-auto mt-3 max-w-2xl sm:mt-4'>
<Paragraph className="mx-auto mt-3 max-w-2xl sm:mt-4">
Find the latest and greatest stories from our community
</Paragraph>
<Paragraph typeStyle={ParagraphTypeStyle.md} className='mx-auto mt-4 max-w-2xl'>
<Paragraph
typeStyle={ParagraphTypeStyle.md}
className="mx-auto mt-4 max-w-2xl"
>
Want to publish a blog post? We love community stories.{' '}
<TextLink href='https://github.com/asyncapi/website/issues/new?template=blog.md' target='_blank'>
<TextLink
href="https://github.com/asyncapi/website/issues/new?template=blog.md"
target="_blank"
>
Submit yours!
</TextLink>
</Paragraph>
<Paragraph typeStyle={ParagraphTypeStyle.md} className='mx-auto mt-1 max-w-2xl'>
<Paragraph
typeStyle={ParagraphTypeStyle.md}
className="mx-auto mt-1 max-w-2xl"
>
We have an
<img
className='ml-1 text-primary-500 hover:text-primary-300'
className="ml-1 text-primary-500 hover:text-primary-300"
style={{ display: 'inline' }}
src='/img/logos/rss.svg'
alt='RSS feed'
height='18px'
width='18px'
src="/img/logos/rss.svg"
alt="RSS feed"
height="18px"
width="18px"
/>
<TextLink href='/rss.xml'> RSS Feed</TextLink>, too!
<TextLink href="/rss.xml"> RSS Feed</TextLink>, too!
</Paragraph>
</div>
<div className='mx:64 mt-12 md:flex md:justify-center lg:justify-center'>

{/* Filter Controls */}
<div className="mx:64 mt-12 md:flex md:justify-center lg:justify-center">
<Filter
data={navItems || []}
onFilter={onFilter}
className='md: mx-px mt-1 w-full md:mt-0 md:w-1/5 md:text-sm'
className="md: mx-px mt-1 w-full md:mt-0 md:w-1/5 md:text-sm"
checks={toFilter}
/>
{showClearFilters && (
<button
type='button'
className='bg-none text-md mt-1 rounded-md border border-gray-200 px-4 py-2 font-semibold tracking-heading text-gray-800 shadow-none transition-all duration-500 ease-in-out hover:text-gray-700 md:mt-0 md:py-0'
type="button"
className="bg-none text-md mt-1 rounded-md border border-gray-200 px-4 py-2 font-semibold tracking-heading text-gray-800 shadow-none transition-all duration-500 ease-in-out hover:text-gray-700 md:mt-0 md:py-0"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Fix formatting issues flagged by the linter.

This line has multiple formatting issues: it exceeds the 120-character limit and uses double quotes instead of single quotes in JSX attributes.

Apply this diff to fix the formatting:

-                className="bg-none text-md mt-1 rounded-md border border-gray-200 px-4 py-2 font-semibold tracking-heading text-gray-800 shadow-none transition-all duration-500 ease-in-out hover:text-gray-700 md:mt-0 md:py-0"
+                className='bg-none text-md mt-1 rounded-md border border-gray-200 px-4 py-2 font-semibold tracking-heading text-gray-800 shadow-none transition-all duration-500 ease-in-out hover:text-gray-700 md:mt-0 md:py-0'

Alternatively, break the className into multiple lines for better readability:

                 className='bg-none text-md mt-1 rounded-md border border-gray-200 px-4 py-2 
-                  font-semibold tracking-heading text-gray-800 shadow-none transition-all 
-                  duration-500 ease-in-out hover:text-gray-700 md:mt-0 md:py-0'
+                  font-semibold tracking-heading text-gray-800 shadow-none 
+                  transition-all duration-500 ease-in-out hover:text-gray-700 md:mt-0 md:py-0'
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
className="bg-none text-md mt-1 rounded-md border border-gray-200 px-4 py-2 font-semibold tracking-heading text-gray-800 shadow-none transition-all duration-500 ease-in-out hover:text-gray-700 md:mt-0 md:py-0"
className='bg-none text-md mt-1 rounded-md border border-gray-200 px-4 py-2 font-semibold tracking-heading text-gray-800 shadow-none transition-all duration-500 ease-in-out hover:text-gray-700 md:mt-0 md:py-0'
🧰 Tools
🪛 GitHub Actions: PR testing - if Node project

[error] 122-122: Line exceeds maximum length of 120. Consider breaking into multiple lines. (max-len)


[error] 122-122: JSX quotes style violation. Use single quotes. (jsx-quotes)

🤖 Prompt for AI Agents
In pages/blog/index.tsx around line 122, the JSX attribute uses double quotes
and the line exceeds the 120-character limit; change the attribute to use single
quotes and break the className string across multiple lines (or split into
template literal concatenation) so no output line exceeds 120 chars and each JSX
attribute uses single quotes; ensure indentation remains consistent and the
resulting lines preserve the same class order and spacing.

onClick={clearFilters}
>
<span className='inline-block'>Clear filters</span>
<span className="inline-block">Clear filters</span>
</button>
)}
</div>

{/* Blog List and Pagination */}
<div>
{Object.keys(posts).length === 0 && (
<div className='mt-16 flex flex-col items-center justify-center'>
{posts.length === 0 ? (
<div className="mt-16 flex flex-col items-center justify-center">
<Empty />
<p className='mx-auto mt-3 max-w-2xl text-xl leading-7 text-gray-500'>No post matches your filter</p>
</div>
)}
{Object.keys(posts).length > 0 && isClient && (
<ul className='mx-auto mt-12 grid max-w-lg gap-5 lg:max-w-none lg:grid-cols-3'>
{posts.map((post, index) => (
<BlogPostItem key={index} post={post} />
))}
</ul>
)}
{Object.keys(posts).length > 0 && !isClient && (
<div className='h-screen w-full'>
<Loader loaderText='Loading Blogs' className='mx-auto my-60' pulsating />
<p className="mx-auto mt-3 max-w-2xl text-xl leading-7 text-gray-500">
No post matches your filter
</p>
</div>
) : (
<>
<ul className="mx-auto mt-12 grid max-w-lg gap-5 lg:max-w-none lg:grid-cols-3">
{currentPosts.map((post) => (
<BlogPostItem
key={post.slug || post.id || post.title}
post={post}
/>
))}
</ul>

{totalPages > 1 && (
<div className="mt-10 flex justify-center items-center space-x-4">
<button
onClick={() =>
setCurrentPage((prev) => Math.max(prev - 1, 1))
}
disabled={currentPage === 1}
className="rounded-md border border-gray-300 px-3 py-1 text-gray-700 hover:bg-gray-100 disabled:opacity-50"
>
Previous
</button>

<span className="text-gray-700">
Page {currentPage} of {totalPages}
</span>

<button
onClick={() =>
setCurrentPage((prev) =>
Math.min(prev + 1, totalPages)
)
}
disabled={currentPage === totalPages}
className="rounded-md border border-gray-300 px-3 py-1 text-gray-700 hover:bg-gray-100 disabled:opacity-50"
>
Next
</button>
</div>
)}
</>
)}
</div>
</div>
</div>
</GenericLayout>
);
}
}
Loading