Skip to content

Commit c94001d

Browse files
committed
css blur transition for thumbnails
1 parent c8bae90 commit c94001d

File tree

3 files changed

+32
-4
lines changed

3 files changed

+32
-4
lines changed

docs/working-notes/todo4.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,8 @@ image 100% width and height, fills container that controls size // must do it li
9494
src="image-1200w.jpg"
9595
alt="A responsive image example" />
9696

97+
blur preloader makes no sense for thumbnails, better css blur transition
98+
ImageBlurPreloader should support srcset or picture tag
9799

98100
```
99101

src/components/react/ImageBlurPreloader.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ const ImageBlurPreloader: FC<Props> = ({
4343
setHasLoaded(true);
4444
onSrcLoaded?.();
4545
};
46+
// src important dependency
4647
}, [src, setHasLoaded]);
4748

4849
const imageSrc = hasLoaded ? src : blurSrc;

src/components/react/NewGallery.tsx

Lines changed: 29 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { useEffect, useRef, useState } from 'react';
1+
import { useEffect, useMemo, useRef, useState } from 'react';
22

33
import PhotoSwipeLightbox from 'photoswipe/lightbox';
44

@@ -8,11 +8,14 @@ import type { FC } from 'react';
88
import 'photoswipe/style.css';
99

1010
import { GALLERY_ID } from '@/constants/gallery';
11+
import { cn } from '@/utils/styles';
1112

1213
interface Props {
1314
images: ImageProps[];
1415
}
1516

17+
type LoadedStates = Record<string, boolean>;
18+
1619
// step
1720
const PAGE_SIZE = 3 as const; // Todo: make it responsive
1821
// page dependency in useEffect is more important
@@ -28,6 +31,14 @@ const NewGallery: FC<Props> = ({ images }) => {
2831
const [page, setPage] = useState<number>(INITIAL_PAGE);
2932
const observerTarget = useRef(null);
3033

34+
const [loadedStates, setLoadedStates] = useState<LoadedStates>({});
35+
// calculate if new page is loaded on scroll
36+
// not for blur transition
37+
const isAllImagesLoaded = useMemo(
38+
() => Object.values(loadedStates).every(Boolean),
39+
[loadedStates, loadedImages.length]
40+
);
41+
3142
const isEnd = loadedImages.length === images.length;
3243

3344
// converts page to loaded images
@@ -39,8 +50,8 @@ const NewGallery: FC<Props> = ({ images }) => {
3950
// sets only page
4051
useEffect(() => {
4152
const callback: IntersectionObserverCallback = (entries) => {
42-
// Todo: must wait here for images to load
43-
if (!isEnd && entries[0].isIntersecting) {
53+
// must wait here for images to load
54+
if (!isEnd && isAllImagesLoaded && entries[0].isIntersecting) {
4455
setPage((prevPage) => prevPage + 1);
4556
}
4657
};
@@ -72,6 +83,10 @@ const NewGallery: FC<Props> = ({ images }) => {
7283
};
7384
}, []);
7485

86+
const handleLoad = (src: string) => {
87+
setLoadedStates((prev) => ({ ...prev, [src]: true }));
88+
};
89+
7590
return (
7691
<>
7792
<div
@@ -87,7 +102,17 @@ const NewGallery: FC<Props> = ({ images }) => {
87102
target="_blank"
88103
rel="noreferrer"
89104
>
90-
<img src={image.xs.src} alt="Gallery image" className="w-full" />
105+
<img
106+
src={image.xs.src}
107+
onLoad={() => handleLoad(image.xs.src)}
108+
alt="Gallery image"
109+
className={cn(
110+
'w-full transition-all duration-[2s] ease-in-out',
111+
loadedStates[image.xs.src]
112+
? 'opacity-100 blur-0 grayscale-0'
113+
: 'opacity-75 blur-sm grayscale'
114+
)}
115+
/>
91116
</a>
92117
))}
93118
</div>

0 commit comments

Comments
 (0)