Skip to content

Commit e651765

Browse files
committed
infinite scroll works
1 parent e9a63ca commit e651765

File tree

4 files changed

+83
-4
lines changed

4 files changed

+83
-4
lines changed

docs/working-notes/todo4.md

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,20 @@ http://localhost:3000/_image?href=/@fs/home/username/Desktop/nemanjam.github.io/
8080
// in prod
8181
http://localhost:3000/_astro/focus1.CEdGhKb3_nVk9T.webp
8282

83-
image 100% width and height, fills container that controls size
83+
image 100% width and height, fills container that controls size // must do it like this for server component
84+
// explain in chatgpt
85+
<img
86+
srcset="
87+
image-480w.jpg 480w,
88+
image-768w.jpg 768w,
89+
image-1200w.jpg 1200w"
90+
sizes="
91+
(max-width: 480px) 100vw,
92+
(max-width: 768px) 50vw,
93+
33vw"
94+
src="image-1200w.jpg"
95+
alt="A responsive image example" />
96+
8497

8598
```
8699

src/components/Gallery.astro

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
---
22
import ReactGallery from '@/components/react/Gallery';
3+
import NewReactGallery from '@/components/react/NewGallery';
4+
import { getImagesProps } from '@/libs/gallery/images';
35
import { sliceToMod4 } from '@/utils/array';
46
import { allImagesMetadata, imageMetadataToReactImageProps } from '@/utils/image';
57
import { randomizeArray } from '@/utils/objects';
@@ -9,9 +11,10 @@ export interface Props extends astroHTML.JSX.HTMLAttributes {}
911
1012
const allImagesMetadataMod4 = sliceToMod4(allImagesMetadata);
1113
12-
const reactImages = await Promise.all(
14+
const _reactImages = await Promise.all(
1315
allImagesMetadataMod4.map((metadata) => imageMetadataToReactImageProps(metadata))
1416
);
17+
const reactImages = await getImagesProps();
1518
1619
const randomizedReactImages = randomizeArray(reactImages);
1720
@@ -21,5 +24,6 @@ const { class: className } = Astro.props;
2124
---
2225

2326
<div class={cn('', className)}>
24-
<ReactGallery client:only="react" images={randomizedReactImages} />
27+
<!-- <ReactGallery client:only="react" images={randomizedReactImages} /> -->
28+
<NewReactGallery client:only="react" images={randomizedReactImages} />
2529
</div>

src/components/react/NewGallery.tsx

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
import { useEffect, useRef, useState } from 'react';
2+
3+
import type { ImageProps } from '@/libs/gallery/transform';
4+
import type { FC } from 'react';
5+
6+
interface Props {
7+
images: ImageProps[];
8+
}
9+
10+
const PAGE_SIZE = 4 as const;
11+
const INITIAL_PAGE = 1 as const;
12+
13+
const fetchImagesUpToPage = (images: ImageProps[], nextPage: number): ImageProps[] => {
14+
const endIndex = nextPage * PAGE_SIZE;
15+
return images.slice(0, endIndex);
16+
};
17+
18+
const NewGallery: FC<Props> = ({ images }) => {
19+
const [loadedImages, setLoadedImages] = useState<ImageProps[]>([]);
20+
const [page, setPage] = useState<number>(INITIAL_PAGE);
21+
const observerTarget = useRef(null);
22+
23+
// converts page to loaded images
24+
useEffect(() => {
25+
const upToPageImages = fetchImagesUpToPage(images, page);
26+
setLoadedImages(upToPageImages);
27+
}, [page, images]);
28+
29+
// sets only page
30+
useEffect(() => {
31+
const callback: IntersectionObserverCallback = (entries) => {
32+
if (entries[0].isIntersecting) {
33+
setPage((prevPage) => prevPage + 1);
34+
}
35+
};
36+
const options: IntersectionObserverInit = { threshold: 1 };
37+
const observer = new IntersectionObserver(callback, options);
38+
39+
const observerRef = observerTarget.current;
40+
41+
if (observerRef) observer.observe(observerRef);
42+
43+
return () => {
44+
if (observerRef) observer.unobserve(observerRef);
45+
};
46+
// page dependency is important for initial load to work for all resolutions
47+
}, [observerTarget, page]);
48+
49+
return (
50+
<>
51+
<div className="grid grid-cols-1 gap-1 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-4">
52+
{loadedImages.map((image) => (
53+
<img key={image.xs.src} src={image.xs.src} alt="thumbnail image" className="" />
54+
))}
55+
</div>
56+
{/* control threshold with margin-top */}
57+
<div ref={observerTarget} className="h-8 border border-red-500 mt-0"></div>
58+
</>
59+
);
60+
};
61+
62+
export default NewGallery;

src/libs/gallery/images.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { EXCLUDE_IMAGES } from '@/constants/gallery';
22
import { imageMetadataToImageProps } from '@/libs/gallery/transform';
33

4-
import type { GalleryImageProps, HeroImageProps, ImageProps } from '@/libs/gallery/transform';
4+
import type { ImageProps } from '@/libs/gallery/transform';
55
import type { ImageMetadata } from 'astro';
66

77
// no need for API route, image server already exists, it will only rewrite url

0 commit comments

Comments
 (0)