Show manga placeholder thumbnail while loading
This commit is contained in:
@@ -9,7 +9,7 @@
|
|||||||
import FavoriteIcon from '@mui/icons-material/Favorite';
|
import FavoriteIcon from '@mui/icons-material/Favorite';
|
||||||
import FavoriteBorderIcon from '@mui/icons-material/FavoriteBorder';
|
import FavoriteBorderIcon from '@mui/icons-material/FavoriteBorder';
|
||||||
import { styled, useTheme } from '@mui/material/styles';
|
import { styled, useTheme } from '@mui/material/styles';
|
||||||
import { ComponentProps, useEffect, useMemo, useState } from 'react';
|
import { ComponentProps, useCallback, useEffect, useMemo, useState } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { t as translate } from 'i18next';
|
import { t as translate } from 'i18next';
|
||||||
import Link from '@mui/material/Link';
|
import Link from '@mui/material/Link';
|
||||||
@@ -36,6 +36,7 @@ import { Metadata as BaseMetadata } from '@/components/atoms/Metadata.tsx';
|
|||||||
import { defaultPromiseErrorHandler } from '@/util/defaultPromiseErrorHandler.ts';
|
import { defaultPromiseErrorHandler } from '@/util/defaultPromiseErrorHandler.ts';
|
||||||
import { MangaType, SourceType } from '@/lib/graphql/generated/graphql.ts';
|
import { MangaType, SourceType } from '@/lib/graphql/generated/graphql.ts';
|
||||||
import { useLocalStorage } from '@/util/useStorage.tsx';
|
import { useLocalStorage } from '@/util/useStorage.tsx';
|
||||||
|
import { useResizeObserver } from '@/util/useResizeObserver.tsx';
|
||||||
|
|
||||||
const DetailsWrapper = styled('div')(({ theme }) => ({
|
const DetailsWrapper = styled('div')(({ theme }) => ({
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
@@ -103,43 +104,43 @@ const Thumbnail = ({ manga }: { manga: Partial<MangaThumbnailInfo> }) => {
|
|||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
|
|
||||||
const popupState = usePopupState({ variant: 'popover', popupId: 'manga-thumbnail-fullscreen' });
|
const popupState = usePopupState({ variant: 'popover', popupId: 'manga-thumbnail-fullscreen' });
|
||||||
|
|
||||||
|
const [imageHeight, setImageHeight] = useState<number>();
|
||||||
|
const [imageElement, setImageElement] = useState<HTMLImageElement | null>(null);
|
||||||
|
useResizeObserver(
|
||||||
|
imageElement,
|
||||||
|
useCallback(() => setImageHeight(imageElement?.clientHeight), [imageElement]),
|
||||||
|
);
|
||||||
|
|
||||||
const [isImageReady, setIsImageReady] = useState(false);
|
const [isImageReady, setIsImageReady] = useState(false);
|
||||||
|
const isImageHeightReady = isImageReady && !!imageHeight;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Stack
|
<Stack
|
||||||
sx={{
|
sx={{
|
||||||
position: 'relative',
|
position: 'relative',
|
||||||
'& img': {
|
borderRadius: 1,
|
||||||
borderRadius: 0.5,
|
overflow: 'hidden',
|
||||||
width: '150px',
|
backgroundColor: 'background.paper',
|
||||||
height: 'auto',
|
width: '150px',
|
||||||
[theme.breakpoints.up('lg')]: {
|
height: `${isImageHeightReady ? imageHeight : 225}px`,
|
||||||
width: '200px',
|
flexShrink: 0,
|
||||||
},
|
[theme.breakpoints.up('lg')]: {
|
||||||
[theme.breakpoints.up('xl')]: {
|
width: '200px',
|
||||||
width: '300px',
|
height: `${isImageHeightReady ? imageHeight : 300}px`,
|
||||||
},
|
},
|
||||||
|
[theme.breakpoints.up('xl')]: {
|
||||||
|
width: '300px',
|
||||||
|
height: `${isImageHeightReady ? imageHeight : 450}px`,
|
||||||
},
|
},
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<SpinnerImage
|
<SpinnerImage
|
||||||
|
ref={setImageElement}
|
||||||
src={Mangas.getThumbnailUrl(manga)}
|
src={Mangas.getThumbnailUrl(manga)}
|
||||||
alt="Manga Thumbnail"
|
alt="Manga Thumbnail"
|
||||||
onImageLoad={() => setIsImageReady(true)}
|
onImageLoad={() => setIsImageReady(true)}
|
||||||
spinnerStyle={{
|
|
||||||
borderRadius: 0.5,
|
|
||||||
width: '150px',
|
|
||||||
height: '225px',
|
|
||||||
[theme.breakpoints.up('lg')]: {
|
|
||||||
width: '200px',
|
|
||||||
height: '300px',
|
|
||||||
},
|
|
||||||
[theme.breakpoints.up('xl')]: {
|
|
||||||
width: '300px',
|
|
||||||
height: '450px',
|
|
||||||
},
|
|
||||||
}}
|
|
||||||
/>
|
/>
|
||||||
{isImageReady && (
|
{isImageReady && (
|
||||||
<Stack
|
<Stack
|
||||||
|
|||||||
@@ -103,7 +103,7 @@ export const SpinnerImage = forwardRef((props: IProps, imgRef: ForwardedRef<HTML
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{(isLoading || hasError) && (
|
{(isLoading || hasError) && (
|
||||||
<Box sx={spinnerStyle}>
|
<Box sx={{ height: '100%', ...spinnerStyle }}>
|
||||||
<Stack
|
<Stack
|
||||||
sx={{
|
sx={{
|
||||||
height: '100%',
|
height: '100%',
|
||||||
|
|||||||
Reference in New Issue
Block a user