@@ -5,6 +5,7 @@ import Actions from "@/components/Actions";
55import ImageItem from "@/components/ImageItem" ;
66import { LoaderCircle } from "lucide-react" ;
77import Link from "next/link" ;
8+ import { Masonry } from "react-plock" ;
89
910export interface ImageType {
1011 id : string ;
@@ -26,46 +27,34 @@ export type ImagesListType = { code: number; message: string } | ImageType[];
2627export default function Home ( ) {
2728 const [ data , setData ] = useState < ImageType [ ] > ( [ ] ) ;
2829 const [ page , setPage ] = useState ( 1 ) ;
29- const [ loading , setLoading ] = useState ( true ) ; // first page load
30- const [ bottomLoading , setBottomLoading ] = useState ( false ) ; // scroll load
31- const [ hasMore , setHasMore ] = useState ( true ) ; // stop when no more images
30+ const [ loading , setLoading ] = useState ( true ) ;
31+ const [ bottomLoading , setBottomLoading ] = useState ( false ) ;
32+ const [ hasMore , setHasMore ] = useState ( true ) ;
3233
3334 const LIMIT = 10 ;
3435
3536 const fetchImages = useCallback ( async ( ) => {
3637 try {
37- if ( page === 1 ) {
38- setLoading ( true ) ;
39- } else {
40- setBottomLoading ( true ) ;
41- }
38+ if ( page === 1 ) setLoading ( true ) ;
39+ else setBottomLoading ( true ) ;
4240
4341 const res = await fetch (
4442 `${ process . env . NEXT_PUBLIC_BACKEND_URL } /images?page=${ page } &limit=${ LIMIT } ` ,
4543 { cache : "no-cache" }
4644 ) ;
4745 const json = await res . json ( ) ;
4846
49- // Error handling
5047 if ( ! json ?. data || ! Array . isArray ( json . data ) ) {
5148 setHasMore ( false ) ;
52- if ( page === 1 ) {
53- setData ( [ ] ) ;
54- }
49+ if ( page === 1 ) setData ( [ ] ) ;
5550 return ;
5651 }
5752
58- // No more data check
59- if ( json . data . length < LIMIT ) {
60- setHasMore ( false ) ;
61- }
62-
53+ if ( json . data . length < LIMIT ) setHasMore ( false ) ;
6354 setData ( ( prev ) => [ ...prev , ...json . data ] ) ;
6455 } catch ( err ) {
6556 console . error ( err ) ;
66- if ( page === 1 ) {
67- setData ( [ ] ) ;
68- }
57+ if ( page === 1 ) setData ( [ ] ) ;
6958 } finally {
7059 setLoading ( false ) ;
7160 setBottomLoading ( false ) ;
@@ -111,12 +100,16 @@ export default function Home() {
111100
112101 return (
113102 < div className = "flex flex-col" >
114- < div className = "w-full exs:columns-2 md:columns-3 lg:columns-4 exs:gap-2 sm:gap-5" >
115- { data . map ( ( image ) => (
116- < div
117- key = { image . id }
118- className = "exs:mb-3 sm:mb-5 break-inside-avoid flex flex-col gap-2"
119- >
103+ < Masonry
104+ items = { data }
105+ config = { {
106+ columns : [ 2 , 3 , 4 ] ,
107+ gap : [ 8 , 20 , 20 ] ,
108+ media : [ 480 , 768 , 1024 ] ,
109+ useBalancedLayout : true ,
110+ } }
111+ render = { ( image ) => (
112+ < div key = { image . id } className = "flex flex-col gap-2" >
120113 < Link href = { `/image/${ image . id } ` } >
121114 < ImageItem image = { image } />
122115 </ Link >
@@ -132,9 +125,10 @@ export default function Home() {
132125 />
133126 </ div >
134127 </ div >
135- ) ) }
136- </ div >
128+ ) }
129+ / >
137130
131+ { /* Infinite scroll indicators */ }
138132 { bottomLoading && (
139133 < div className = "grid place-items-center h-[100px] text-[#ffffff90]" >
140134 < LoaderCircle className = "animate-spin" size = { 32 } />
0 commit comments