From 11549a07c312778a9848b794672f410e3412c3d3 Mon Sep 17 00:00:00 2001 From: glax Date: Sat, 17 May 2025 19:25:31 +0200 Subject: [PATCH] MangaPopup Drawer --- tranga-website/src/App.tsx | 4 +- tranga-website/src/Components/Manga.tsx | 114 +++---------------- tranga-website/src/Components/MangaPopup.tsx | 110 ++++++++++++++++++ tranga-website/src/api/Manga.tsx | 2 +- 4 files changed, 131 insertions(+), 99 deletions(-) create mode 100644 tranga-website/src/Components/MangaPopup.tsx diff --git a/tranga-website/src/App.tsx b/tranga-website/src/App.tsx index ee7745c..398e582 100644 --- a/tranga-website/src/App.tsx +++ b/tranga-website/src/App.tsx @@ -38,7 +38,7 @@ export default function App () { setShowSearch(true)} sx={{height:"fit-content",width:"fit-content"}}> - + - + Search diff --git a/tranga-website/src/Components/Manga.tsx b/tranga-website/src/Components/Manga.tsx index ab4d4b2..fcc3110 100644 --- a/tranga-website/src/Components/Manga.tsx +++ b/tranga-website/src/Components/Manga.tsx @@ -2,25 +2,16 @@ import { Badge, Box, Card, - CardActions, CardContent, CardCover, - Chip, CircularProgress, - Input, Link, - Skeleton, - Stack, - Typography } from "@mui/joy"; import IManga, {DefaultManga} from "../api/types/IManga.ts"; import {CSSProperties, ReactElement, useCallback, useContext, useEffect, useRef, useState} from "react"; -import {GetLatestChapterAvailable, GetMangaById, GetMangaCoverImageUrl, SetIgnoreThreshold} from "../api/Manga.tsx"; +import {GetMangaById, GetMangaCoverImageUrl} from "../api/Manga.tsx"; import {ApiUriContext, getData} from "../api/fetchApi.tsx"; -import AuthorTag from "./AuthorTag.tsx"; -import LinkTag from "./LinkTag.tsx"; import {ReleaseStatusToPalette} from "../api/types/EnumMangaReleaseStatus.ts"; -import IChapter from "../api/types/IChapter.ts"; -import MarkdownPreview from "@uiw/react-markdown-preview"; import {SxProps} from "@mui/joy/styles/types"; +import MangaPopup from "./MangaPopup.tsx"; export function MangaFromId({mangaId, children} : { mangaId: string, children?: ReactElement | ReactElement[] | undefined }){ const [manga, setManga] = useState(DefaultManga); @@ -37,45 +28,31 @@ export function MangaFromId({mangaId, children} : { mangaId: string, children?: loadManga(); }, []); - return + return ( + <> + {loading ? <> : } + + ); } export const CardWidth = 190; export const CardHeight = 300; -export function Manga({manga, children, loading} : { manga: IManga | undefined, children?: ReactElement | ReactElement[] | undefined, loading?: boolean}) { - const useManga = manga ?? DefaultManga; - loading = loading ?? false; +export function Manga({manga: manga, children} : { manga: IManga, children?: ReactElement | ReactElement[] | undefined}) { const CoverRef = useRef(null); const apiUri = useContext(ApiUriContext); const [expanded, setExpanded] = useState(false); - const [mangaMaxChapter, setMangaMaxChapter] = useState(); - const [maxChapterLoading, setMaxChapterLoading] = useState(true); - const LoadMaxChapter = useCallback(() => { - setMaxChapterLoading(true); - GetLatestChapterAvailable(apiUri, useManga.mangaId) - .then(setMangaMaxChapter) - .finally(() => setMaxChapterLoading(false)); - }, [useManga, apiUri]); - - const [updatingThreshold, setUpdatingThreshold] = useState(false); - const updateIgnoreThreshhold = useCallback((value: number) => { - setUpdatingThreshold(true); - SetIgnoreThreshold(apiUri, useManga.mangaId, value).finally(() => setUpdatingThreshold(false)); - },[useManga, apiUri]) - useEffect(() => { - LoadMaxChapter(); LoadMangaCover(); - }, [useManga]); + }, [manga]); const LoadMangaCover = useCallback(() => { if(CoverRef.current == null) return; - const coverUrl = GetMangaCoverImageUrl(apiUri, useManga.mangaId, CoverRef.current); + const coverUrl = GetMangaCoverImageUrl(apiUri, manga.mangaId, CoverRef.current); if(CoverRef.current.src == coverUrl) return; @@ -83,7 +60,7 @@ export function Manga({manga, children, loading} : { manga: IManga | undefined, getData(coverUrl).then(() => { if(CoverRef.current) CoverRef.current.src = coverUrl; }); - }, [useManga, apiUri]) + }, [manga, apiUri]) const coverSx : SxProps = { height: CardHeight + "px", @@ -91,12 +68,6 @@ export function Manga({manga, children, loading} : { manga: IManga | undefined, position: "relative", } - const descriptionSx : SxProps = { - height: CardHeight + "px", - width: CardWidth * 2 + "px", - position: "relative" - } - const coverCss : CSSProperties = { maxHeight: "calc("+CardHeight+"px + 2rem)", maxWidth: "calc("+CardWidth+"px + 2rem)", @@ -104,17 +75,17 @@ export function Manga({manga, children, loading} : { manga: IManga | undefined, const interactiveElements = ["button", "input", "textarea", "a", "select", "option", "li"]; - const mangaName = useManga.name.length > 30 ? useManga.name.substring(0, 27) + "..." : useManga.name; + const mangaName = manga.name.length > 30 ? manga.name.substring(0, 27) + "..." : manga.name; return ( - + { const target = e.target as HTMLElement; if(interactiveElements.find(x => x == target.localName) == undefined) setExpanded(!expanded)} }> - Manga Cover @@ -124,61 +95,12 @@ export function Manga({manga, children, loading} : { manga: IManga | undefined, }}/> - - - {mangaName} - - + + {mangaName} + - { - expanded ? - - - - {useManga.authors?.map(author => )} - {useManga.mangaTags?.map(tag => {tag.tag})} - {useManga.links?.map(link => )} - - - - - - - : null - } - { - expanded ? - - - - { - updatingThreshold ? - - : Ch. - } - - } - endDecorator={ - - - /{mangaMaxChapter?.chapterNumber??"Load Failed"} - - - } - sx={{width:"min-content"}} - size={"md"} - onChange={(e) => updateIgnoreThreshhold(e.currentTarget.valueAsNumber)} - /> - {children} - - - : null - } + {children} ); diff --git a/tranga-website/src/Components/MangaPopup.tsx b/tranga-website/src/Components/MangaPopup.tsx new file mode 100644 index 0000000..e086751 --- /dev/null +++ b/tranga-website/src/Components/MangaPopup.tsx @@ -0,0 +1,110 @@ +import IManga from "../api/types/IManga.ts"; +import {Badge, Box, Chip, CircularProgress, Drawer, Input, Skeleton, Stack, Typography} from "@mui/joy"; +import {ReactElement, useCallback, useContext, useEffect, useRef, useState} from "react"; +import {GetLatestChapterAvailable, GetMangaCoverImageUrl, SetIgnoreThreshold} from "../api/Manga.tsx"; +import {ApiUriContext, getData} from "../api/fetchApi.tsx"; +import AuthorTag from "./AuthorTag.tsx"; +import LinkTag from "./LinkTag.tsx"; +import MarkdownPreview from "@uiw/react-markdown-preview"; +import {CardHeight} from "./Manga.tsx"; +import IChapter from "../api/types/IChapter.ts"; +import {MangaReleaseStatus, ReleaseStatusToPalette} from "../api/types/EnumMangaReleaseStatus.ts"; + + +export default function MangaPopup({manga, open, children} : {manga: IManga | null, open: boolean, children?: ReactElement | ReactElement[] | undefined}) { + + const apiUri = useContext(ApiUriContext); + + const CoverRef = useRef(null); + + const LoadMangaCover = useCallback(() => { + if(CoverRef.current == null || manga == null) + return; + const coverUrl = GetMangaCoverImageUrl(apiUri, manga.mangaId, CoverRef.current); + if(CoverRef.current.src == coverUrl) + return; + + //Check if we can fetch the image exists (by fetching it), only then update + getData(coverUrl).then(() => { + if(CoverRef.current) CoverRef.current.src = coverUrl; + }); + }, [manga, apiUri]) + + useEffect(() => { + if(!open) + return; + LoadMaxChapter(); + LoadMangaCover(); + }, [open]); + + const [mangaMaxChapter, setMangaMaxChapter] = useState(); + const [maxChapterLoading, setMaxChapterLoading] = useState(true); + const LoadMaxChapter = useCallback(() => { + if(manga == null) + return; + setMaxChapterLoading(true); + GetLatestChapterAvailable(apiUri, manga.mangaId) + .then(setMangaMaxChapter) + .finally(() => setMaxChapterLoading(false)); + }, [manga, apiUri]); + + const [updatingThreshold, setUpdatingThreshold] = useState(false); + const updateIgnoreThreshhold = useCallback((value: number) => { + if(manga == null) + return; + setUpdatingThreshold(true); + SetIgnoreThreshold(apiUri, manga.mangaId, value).finally(() => setUpdatingThreshold(false)); + },[manga, apiUri]) + + return ( + + + { /* Cover and Description */ } + + + Manga Cover + + + {manga?.name} + + {manga?.authors?.map(author => )} + {manga?.mangaTags?.map(tag => {tag.tag})} + {manga?.links?.map(link => )} + + + + + + { /* Actions */ } + + + { + updatingThreshold ? + + : Ch. + } + + } + endDecorator={ + + + /{mangaMaxChapter?.chapterNumber??"-"} + + + } + sx={{width:"min-content"}} + size={"md"} + onChange={(e) => updateIgnoreThreshhold(e.currentTarget.valueAsNumber)} + /> + {children} + + + + ); +} \ No newline at end of file diff --git a/tranga-website/src/api/Manga.tsx b/tranga-website/src/api/Manga.tsx index 2a6d7bf..7940198 100644 --- a/tranga-website/src/api/Manga.tsx +++ b/tranga-website/src/api/Manga.tsx @@ -24,7 +24,7 @@ export const DeleteManga = async (apiUri: string, mangaId: string) : Promise { +export const GetMangaCoverImageUrl = (apiUri: string, mangaId: string, ref: HTMLImageElement | undefined | null) : string => { if(ref == null || ref == undefined) return `${apiUri}/v2/Manga/${mangaId}/Cover?width=64&height=64`; return `${apiUri}/v2/Manga/${mangaId}/Cover?width=${ref.clientWidth}&height=${ref.clientHeight}`;