diff --git a/src/web/components/BackgroundImage.tsx b/src/web/components/BackgroundImage.tsx
index ce951aa..a6f3cdf 100644
--- a/src/web/components/BackgroundImage.tsx
+++ b/src/web/components/BackgroundImage.tsx
@@ -4,11 +4,13 @@ import useAsyncEffect from 'use-async-effect';
import InspiratContext from 'web/contexts/Inspirat';
import {
+ BACKGROUND_ANIMATION_INITIAL_SCALE,
BACKGROUND_TRANSITION_DURATION,
BACKGROUND_TRANSITION_FUNCTION,
BACKGROUND_RULE_OVERRIDES
} from 'web/etc/constants';
-import { preloadImage } from 'web/lib/utils';
+import log from 'web/lib/log';
+// import { preloadImage } from 'web/lib/utils';
import classes, { keyframes } from './BackgroundImage.css';
@@ -61,28 +63,35 @@ export default function BackgroundImage(props: BackgroundImageProps) {
const photoUrls = buildPhotoUrls(photo);
- void Promise.race([
- preloadImage(photoUrls.lowQuality),
- preloadImage(photoUrls.highQuality)
- ]).then(() => {
- if (!isMounted()) return;
- setAnyImageReady(true);
- setAnimationName(keyframes.zoomOut);
- setStyleOverrides(BACKGROUND_RULE_OVERRIDES[photo.id] ?? {});
- });
+ // void Promise.race([
+ // preloadImage(photoUrls.lowQuality),
+ // preloadImage(photoUrls.highQuality)
+ // ]).then(() => {
+ // if (!isMounted()) return;
+ // setAnyImageReady(true);
+ // setAnimationName(keyframes.zoomOut);
+ // setStyleOverrides(BACKGROUND_RULE_OVERRIDES[photo.id] ?? {});
+ // });
+
+ // TODO: Testing out not waiting to preload images.
+ setAnyImageReady(true);
+ setAnimationName(keyframes.zoomOut);
+ setStyleOverrides(BACKGROUND_RULE_OVERRIDES[photo.id] ?? {});
setLowQualityUrl(photoUrls.lowQuality);
setFullQualityUrl(photoUrls.highQuality);
}, () => {
// DO NOT CLEAR THIS, IT RESETS PHOTO ZOOM AT THE START OF A TRANSITION.
// setAnimationName('none');
- }, [photo?.id, isActive]);
+ }, [photo?.id]);
const srcSet = lowQualityUrl && fullQualityUrl ? [
`${lowQualityUrl} ${Math.round(window.screen.width / 2)}w`,
- fullQualityUrl
+ `${fullQualityUrl} ${Math.round(window.screen.width * 2 * BACKGROUND_ANIMATION_INITIAL_SCALE)}w`
].join(', ') : undefined;
+ // if (srcSet) log.debug('srcSet', srcSet);
+
return (
diff --git a/src/web/components/Greeting.css.ts b/src/web/components/Greeting.css.ts
index 4d994f5..e608d99 100644
--- a/src/web/components/Greeting.css.ts
+++ b/src/web/components/Greeting.css.ts
@@ -34,7 +34,8 @@ const classes = {
borderRadius: '24px',
backgroundColor: 'rgba(80, 80, 80, 0.12)',
backdropFilter: 'blur(12px)',
- boxShadow: '0px 0px 24px rgba(0, 0, 0, 0.12)'
+ boxShadow: '0px 0px 24px rgba(0, 0, 0, 0.12)',
+ userSelect: 'none'
})
};
diff --git a/src/web/components/dev-tools/DevTools.tsx b/src/web/components/dev-tools/DevTools.tsx
index 23ebb65..3ad7c2a 100644
--- a/src/web/components/dev-tools/DevTools.tsx
+++ b/src/web/components/dev-tools/DevTools.tsx
@@ -94,18 +94,12 @@ export const DevTools = () => {
getCurrentPhotoFromCollection({ offset: dayOffset + 1 }).then(photo => {
if (!photo) return;
const { lowQuality, highQuality } = buildPhotoUrls(photo);
- return Promise.all([
- preloadImage(lowQuality),
- preloadImage(highQuality)
- ]);
+ return Promise.all([preloadImage(lowQuality), preloadImage(highQuality)]);
}),
getCurrentPhotoFromCollection({ offset: dayOffset - 1 }).then(photo => {
if (!photo) return;
const { lowQuality, highQuality } = buildPhotoUrls(photo);
- return Promise.all([
- preloadImage(lowQuality),
- preloadImage(highQuality)
- ]);
+ return Promise.all([preloadImage(lowQuality), preloadImage(highQuality)]);
})
]);
}, [showDevTools, dayOffset]);
diff --git a/src/web/contexts/Inspirat.tsx b/src/web/contexts/Inspirat.tsx
index 848da35..521d7bd 100644
--- a/src/web/contexts/Inspirat.tsx
+++ b/src/web/contexts/Inspirat.tsx
@@ -188,7 +188,11 @@ export function InspiratProvider(props: React.PropsWithChildren) {
// This is where IMGIX configuration for low and high quality versions of
// photos is defined.
return buildPhotoUrlSrcSet(photo.urls.full, {
- // blend: 'FA653D80',
+ q: 100,
+ w: Math.round(window.screen.width / 2),
+ h: Math.round(window.screen.height / 2)
+ // Adds a color overlay. Can be useful for debugging.
+ // blend: 'FA653D',
// blendMode: 'overlay'
}, {
w: Math.round(window.screen.width * 2 * BACKGROUND_ANIMATION_INITIAL_SCALE),
diff --git a/src/web/lib/utils.ts b/src/web/lib/utils.ts
index 6c24ea4..cf10a3b 100644
--- a/src/web/lib/utils.ts
+++ b/src/web/lib/utils.ts
@@ -167,8 +167,12 @@ export function onClickAndHold(interval: number, cb: (e: React.MouseEvent | Reac
return handler;
}
+type PreloadImageCacheValue = {
+ promise: Promise
;
+ state: 'LOADING' | 'SUCCESS' | 'ERROR';
+};
-const preloadImageCache = new Map();
+const preloadImageCache = new Map();
/**
@@ -177,26 +181,28 @@ const preloadImageCache = new Map();
*/
export async function preloadImage(imgUrl: string) {
if (!preloadImageCache.has(imgUrl)) {
- preloadImageCache.set(imgUrl, 'LOADING');
- }
-
- return new Promise((resolve, reject) => {
- const img = new Image();
-
- img.addEventListener('load', () => {
- preloadImageCache.set(imgUrl, 'SUCCESS');
- resolve(imgUrl);
+ const imagePromise = new Promise((resolve, reject) => {
+ const img = new Image();
+
+ img.addEventListener('load', () => {
+ preloadImageCache.set(imgUrl, { promise: imagePromise, state: 'SUCCESS' });
+ resolve(imgUrl);
+ });
+
+ img.addEventListener('error', event => {
+ preloadImageCache.set(imgUrl, { promise: imagePromise, state: 'ERROR' });
+ const message = event.error?.message ?? 'Unknown Error';
+ reject(new Error(`[preloadImage] Failed to load image: ${message}`, { cause: event.error }));
+ });
+
+ // N.B. Setting this property will cause the browser to fetch the image.
+ img.src = imgUrl;
});
- img.addEventListener('error', event => {
- preloadImageCache.set(imgUrl, 'ERROR');
- const message = event.error?.message ?? 'Unknown Error';
- reject(new Error(`[preloadImage] Failed to load image: ${message}`, { cause: event.error }));
- });
+ preloadImageCache.set(imgUrl, { promise: imagePromise, state: 'LOADING' });
+ }
- // N.B. Setting this property will cause the browser to fetch the image.
- img.src = imgUrl;
- });
+ return preloadImageCache.get(imgUrl)?.promise;
}
/**
@@ -204,8 +210,8 @@ export async function preloadImage(imgUrl: string) {
* currently preloading.
*/
preloadImage.isLoadingImages = () => {
- const states = new Set(preloadImageCache.values());
- return states.has('LOADING');
+ const states = [...preloadImageCache.values()].map(cacheValue => cacheValue.state);
+ return states.includes('LOADING');
};
/**
@@ -293,11 +299,6 @@ export function buildPhotoUrlSrcSet(url: string, lqOptions ={}, fullOptions = {}
return {
lowQuality: updateImgixQueryParams(url, {
q: QUALITY_LQIP,
- w: Math.round(window.screen.width / 2),
- h: Math.round(window.screen.height / 2),
- // Adds a color overlay. Can be useful for debugging.
- // blend: 'FA653D',
- // blendMode: 'overlay',
...lqOptions
}),
highQuality: updateImgixQueryParams(url, {