Infinite Scroll Demo

PreviousNext

Demo showing infinite scroll component.

Docs
systaliko-uiblock

Preview

Loading preview…
registry/demo/ecommerce/infinite-scroll/index.tsx
'use client';
import { Skeleton } from '@/components/ui/skeleton';
import {
  InfiniteScroll,
  InfiniteScrollCell,
} from '@/components/systaliko-ui/ecommerce/infinite-scroll';
import { useEffect, useCallback, useState } from 'react';

interface Post {
  id: number;
  userId: number;
  title: string;
  body: string;
}

function CardSkelton() {
  return (
    <div className="flex flex-col space-y-6">
      <div className="flex items-center gap-2">
        <Skeleton className="size-8 rounded-full" />
        <Skeleton className="w-full h-6 rounded" />
      </div>
      <Skeleton className="w-full h-24 rounded" />
    </div>
  );
}
export function InfiniteScrollDemo() {
  const BASE_URL = 'https://jsonplaceholder.typicode.com/posts';
  const LIMIT = 6;

  const [posts, setPosts] = useState<Post[]>([]);
  const [page, setPage] = useState<number>(0);
  const [totalCount, setTotalCount] = useState<number | null>();
  const [isPending, setIsPending] = useState<boolean>(false);

  const fetchData = useCallback(async () => {
    if (isPending) return;

    setIsPending(true);
    const start = page * LIMIT;

    try {
      const response = await fetch(
        `${BASE_URL}?_start=${start}&_limit=${LIMIT}`,
      );
      const totalItems = response.headers.get('x-total-count');
      const data = await response.json();

      setTotalCount(Number(totalItems));
      setPosts((prevPosts) => [...prevPosts, ...data]);
      setPage((prevPage) => prevPage + 1);
    } catch (error) {
      console.error('Error fetching data:', error);
    } finally {
      setIsPending(false);
    }
  }, [page, isPending]);

  useEffect(() => {
    fetchData();
  }, []);
  return (
    <InfiniteScroll
      isPending={isPending}
      currentItemsLength={posts.length}
      allItemsCount={totalCount}
      loadMore={fetchData}
      className="grid grid-cols-[repeat(auto-fill,minmax(250px,1fr))] justify-center items-start gap-4 p-8"
    >
      {posts.map((post) => (
        <InfiniteScrollCell
          className="p-6 bg-card border border-border/50 rounded-xl shadow-2xs"
          key={post.id}
          amount={0.2}
          skelton={<CardSkelton />}
        >
          <div className="flex flex-col space-y-6 ">
            <div className="flex items-center gap-2">
              <div className="font-semibold text-sm text-muted-foreground">
                #{post.id}
              </div>
              <h2
                title={post.title}
                className="font-medium max-w-[15ch] capitalize line-clamp-1"
              >
                {post.title}
              </h2>
            </div>
            <p className="text-sm text-muted-foreground">{post.body}</p>
          </div>
        </InfiniteScrollCell>
      ))}
    </InfiniteScroll>
  );
}

Installation

npx shadcn@latest add @systaliko-ui/infinite-scroll-demo

Usage

import { InfiniteScrollDemo } from "@/components/infinite-scroll-demo"
<InfiniteScrollDemo />