feat: lazy image load
This commit is contained in:
parent
e889f98530
commit
4e77586821
@ -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}*/>
|
||||||
|
@ -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>)
|
||||||
}
|
}
|
15
src/client/page/reader/thumbnail.css
Normal file
15
src/client/page/reader/thumbnail.css
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user