From 4e7758682105819328cfad7ce5cb9886027d6766 Mon Sep 17 00:00:00 2001 From: monoid Date: Wed, 31 Aug 2022 04:52:59 +0900 Subject: [PATCH] feat: lazy image load --- src/client/component/contentinfo.tsx | 7 ++-- src/client/page/reader/reader.tsx | 53 +++++++++++++++++++++++++--- src/client/page/reader/thumbnail.css | 15 ++++++++ 3 files changed, 66 insertions(+), 9 deletions(-) create mode 100644 src/client/page/reader/thumbnail.css diff --git a/src/client/component/contentinfo.tsx b/src/client/component/contentinfo.tsx index 4d9a1a8..82d021e 100644 --- a/src/client/component/contentinfo.tsx +++ b/src/client/component/contentinfo.tsx @@ -93,6 +93,7 @@ export const ContentInfo = (props: { const url = props.gallery === undefined ? makeContentReaderUrl(document.id) : makeContentInfoUrl(document.id); return ( {document.deleted_at === null ? - () + () : (Deleted)} diff --git a/src/client/page/reader/reader.tsx b/src/client/page/reader/reader.tsx index 3e81f82..a1f3245 100644 --- a/src/client/page/reader/reader.tsx +++ b/src/client/page/reader/reader.tsx @@ -1,4 +1,4 @@ -import { Typography } from '@mui/material'; +import { Typography, styled } from '@mui/material'; import React from 'react'; import { Document, makeThumbnailUrl } from '../../accessor/document'; import {ComicReader} from './comic'; @@ -21,15 +21,60 @@ export const getPresenter = (content:Document):PagePresenter => { } return ()=>Not implemented reader; } +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(options?: IntersectionObserverInit) { + const elementRef = useRef(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:{ content:Document, className?:string, - style?:React.CSSProperties, }){ + const {elementRef, isVisible} = useIsElementInViewport({}); + const [loaded, setLoaded] = useState(false); + useEffect(()=>{ + if(isVisible){ + setLoaded(true); + } + },[isVisible]) + const style = { + maxHeight: '400px', + maxWidth: 'min(400px, 100vw)', + }; const thumbnailurl = makeThumbnailUrl(props.content); if(props.content.content_type === "video"){ - return () + return () } - else return () + else return ( + {loaded && } + ) } \ No newline at end of file diff --git a/src/client/page/reader/thumbnail.css b/src/client/page/reader/thumbnail.css new file mode 100644 index 0000000..ae26df8 --- /dev/null +++ b/src/client/page/reader/thumbnail.css @@ -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; + } +} \ No newline at end of file