feat: lazy image load

This commit is contained in:
monoid 2022-08-31 04:52:59 +09:00
parent e889f98530
commit 4e77586821
3 changed files with 66 additions and 9 deletions

View File

@ -93,6 +93,7 @@ export const ContentInfo = (props: {
const url = props.gallery === undefined ? makeContentReaderUrl(document.id) : makeContentInfoUrl(document.id); const url = props.gallery === undefined ? makeContentReaderUrl(document.id) : makeContentInfoUrl(document.id);
return (<Paper sx={{ return (<Paper sx={{
display: "flex", display: "flex",
height: "400px",
[theme.breakpoints.down("sm")]: { [theme.breakpoints.down("sm")]: {
flexDirection: "column", flexDirection: "column",
alignItems: "center", alignItems: "center",
@ -102,11 +103,7 @@ export const ContentInfo = (props: {
pathname: makeContentReaderUrl(document.id) pathname: makeContentReaderUrl(document.id)
}}> }}>
{document.deleted_at === null ? {document.deleted_at === null ?
(<ThumbnailContainer content={document} (<ThumbnailContainer content={document}/>)
style={{
maxHeight: '400px',
maxWidth: 'min(400px, 100vw)',
}}/>)
: (<Typography/* className={propclasses.thumbnail_content ?? thumbnail_content} */ variant='h4'>Deleted</Typography>)} : (<Typography/* className={propclasses.thumbnail_content ?? thumbnail_content} */ variant='h4'>Deleted</Typography>)}
</Link> </Link>
<Box /*className={propclasses.infoContainer ?? classes.infoContainer}*/> <Box /*className={propclasses.infoContainer ?? classes.infoContainer}*/>

View File

@ -1,4 +1,4 @@
import { Typography } from '@mui/material'; import { Typography, styled } from '@mui/material';
import React from 'react'; import React from 'react';
import { Document, makeThumbnailUrl } from '../../accessor/document'; import { Document, makeThumbnailUrl } from '../../accessor/document';
import {ComicReader} from './comic'; import {ComicReader} from './comic';
@ -21,15 +21,60 @@ export const getPresenter = (content:Document):PagePresenter => {
} }
return ()=><Typography variant='h2'>Not implemented reader</Typography>; return ()=><Typography variant='h2'>Not implemented reader</Typography>;
} }
const BackgroundDiv = styled("div")({
height: '400px',
width:'300px',
backgroundColor:"#272733",
display:"flex",
alignItems:"center",
justifyContent:"center"}
);
import { useRef, useState, useEffect } from 'react';
import "./thumbnail.css"
export function useIsElementInViewport<T extends HTMLElement>(options?: IntersectionObserverInit) {
const elementRef = useRef<T>(null);
const [isVisible, setIsVisible] = useState(false);
const callback = (entries: IntersectionObserverEntry[]) => {
const [entry] = entries;
setIsVisible(entry.isIntersecting);
};
useEffect(() => {
const observer = new IntersectionObserver(callback, options);
elementRef.current && observer.observe(elementRef.current);
return () => observer.disconnect();
}, [elementRef, options]);
return { elementRef, isVisible };
};
export function ThumbnailContainer(props:{ export function ThumbnailContainer(props:{
content:Document, content:Document,
className?:string, className?:string,
style?:React.CSSProperties,
}){ }){
const {elementRef, isVisible} = useIsElementInViewport<HTMLDivElement>({});
const [loaded, setLoaded] = useState(false);
useEffect(()=>{
if(isVisible){
setLoaded(true);
}
},[isVisible])
const style = {
maxHeight: '400px',
maxWidth: 'min(400px, 100vw)',
};
const thumbnailurl = makeThumbnailUrl(props.content); const thumbnailurl = makeThumbnailUrl(props.content);
if(props.content.content_type === "video"){ if(props.content.content_type === "video"){
return (<video src={thumbnailurl} muted autoPlay loop className={props.className} style={props.style} loading="lazy"></video>) return (<video src={thumbnailurl} muted autoPlay loop className={props.className} style={style}></video>)
} }
else return (<img src={thumbnailurl} className={props.className} style={props.style} loading="lazy"></img>) else return (<BackgroundDiv ref={elementRef}>
{loaded && <img src={thumbnailurl}
className={props.className + " thumbnail_img"}
loading="lazy"></img>}
</BackgroundDiv>)
} }

View File

@ -0,0 +1,15 @@
.thumbnail_img{
max-width: 100%;
max-height: 100%;
animation: slideop 0.4s ease;
}
@keyframes slideop {
from {
opacity: 0;
}
to {
opacity: 1;
}
}