mirror of
https://github.com/C9Glax/tranga-website.git
synced 2025-06-15 16:27:54 +02:00
Single Style for Manga
This commit is contained in:
@ -6,7 +6,10 @@ export default interface IAuthor {
|
||||
authorName: string;
|
||||
}
|
||||
|
||||
export function AuthorElement({apiUri, authorId} : {apiUri: string, authorId: string}) : ReactElement{
|
||||
export function AuthorElement({apiUri, authorId} : {apiUri: string, authorId: string | null}) : ReactElement{
|
||||
if(authorId === null)
|
||||
return (<p className="Manga-Author-Name">Author</p>);
|
||||
|
||||
let [name, setName] = React.useState<string>(authorId);
|
||||
|
||||
useEffect(()=> {
|
||||
@ -17,5 +20,5 @@ export function AuthorElement({apiUri, authorId} : {apiUri: string, authorId: st
|
||||
});
|
||||
}, [])
|
||||
|
||||
return (<span>{name}</span>);
|
||||
return (<p className="Manga-Author-Name">{name}</p>);
|
||||
}
|
@ -1,10 +0,0 @@
|
||||
export default interface IChapter{
|
||||
chapterId: string;
|
||||
volumeNumber: number;
|
||||
chapterNumber: string;
|
||||
url: string;
|
||||
title: string | undefined;
|
||||
archiveFileName: string;
|
||||
downloaded: boolean;
|
||||
parentMangaId: string;
|
||||
}
|
48
Website/modules/interfaces/IChapter.tsx
Normal file
48
Website/modules/interfaces/IChapter.tsx
Normal file
@ -0,0 +1,48 @@
|
||||
import React, {ReactElement, ReactEventHandler, useEffect, useState} from "react";
|
||||
import Manga from "../Manga";
|
||||
import IManga from "./IManga";
|
||||
import Chapter from "../Chapter";
|
||||
|
||||
export default interface IChapter{
|
||||
chapterId: string;
|
||||
volumeNumber: number;
|
||||
chapterNumber: string;
|
||||
url: string;
|
||||
title: string | undefined;
|
||||
archiveFileName: string;
|
||||
downloaded: boolean;
|
||||
parentMangaId: string;
|
||||
}
|
||||
|
||||
export function ChapterItem({apiUri, chapterId} : {apiUri: string, chapterId: string}) : ReactElement {
|
||||
const setCoverItem : ReactEventHandler<HTMLImageElement> = (e) => {
|
||||
setMangaCoverHtmlImageItem(e.currentTarget);
|
||||
}
|
||||
|
||||
let [chapter, setChapter] = useState<IChapter | null>(null);
|
||||
let [manga, setManga] = useState<IManga | null>(null);
|
||||
let [mangaCoverUrl, setMangaCoverUrl] = useState<string>("../../media/blahaj.png");
|
||||
let [mangaCoverHtmlImageItem, setMangaCoverHtmlImageItem] = useState<HTMLImageElement | null>(null);
|
||||
useEffect(() => {
|
||||
Chapter.GetChapterFromId(apiUri, chapterId).then(setChapter);
|
||||
}, []);
|
||||
useEffect(() => {
|
||||
if(chapter === null)
|
||||
manga = null;
|
||||
else
|
||||
Manga.GetMangaById(apiUri, chapter.parentMangaId).then(setManga);
|
||||
}, [chapter]);
|
||||
useEffect(() => {
|
||||
if(chapter != null && mangaCoverHtmlImageItem != null)
|
||||
setMangaCoverUrl(Manga.GetMangaCoverImageUrl(apiUri, chapter.parentMangaId, mangaCoverHtmlImageItem));
|
||||
}, [chapter, mangaCoverHtmlImageItem]);
|
||||
|
||||
return (<div className="ChapterItem" key={chapterId}>
|
||||
<img className="ChapterItem-Cover" src={mangaCoverUrl} alt="Manga Cover" onLoad={setCoverItem} onResize={setCoverItem}></img>
|
||||
<p className="ChapterItem-MangaName">{manga ? manga.name : "Manga-Name"}</p>
|
||||
<p className="ChapterItem-ChapterName">{chapter ? chapter.title : "Chapter-Title"}</p>
|
||||
<p className="ChapterItem-Volume">Vol.{chapter ? chapter.volumeNumber : "VolNum"}</p>
|
||||
<p className="ChapterItem-Chapter">Ch.{chapter ? chapter.chapterNumber : "ChNum"}</p>
|
||||
<a className="ChapterItem-Website" href={chapter ? chapter.url : "#"}><img src="../../media/link.svg" alt="Link"/></a>
|
||||
</div>)
|
||||
}
|
@ -1,6 +1,5 @@
|
||||
import React, {ReactElement, useEffect} from "react";
|
||||
import {getData} from "../../App";
|
||||
import IAuthor from "./IAuthor";
|
||||
|
||||
export default interface ILink {
|
||||
linkId: string;
|
||||
@ -8,7 +7,10 @@ export default interface ILink {
|
||||
linkUrl: string;
|
||||
}
|
||||
|
||||
export function LinkElement({apiUri, linkId} : {apiUri: string, linkId: string}) : ReactElement{
|
||||
export function LinkElement({apiUri, linkId} : {apiUri: string, linkId: string | null}) : ReactElement{
|
||||
if(linkId === null)
|
||||
return (<a className="Manga-Link-Value" href="#">Link</a>);
|
||||
|
||||
let [provider, setProvider] = React.useState<string>(linkId);
|
||||
let [linkUrl, setLinkUrl] = React.useState<string>("");
|
||||
|
||||
@ -21,5 +23,5 @@ export function LinkElement({apiUri, linkId} : {apiUri: string, linkId: string})
|
||||
});
|
||||
}, [])
|
||||
|
||||
return (<a href={linkUrl}>{provider}</a>);
|
||||
return (<a className="Manga-Link-Value" href={linkUrl}>{provider}</a>);
|
||||
}
|
@ -1,17 +1,14 @@
|
||||
import Manga from "../Manga";
|
||||
import React, {ReactElement, ReactEventHandler, useEffect} from "react";
|
||||
import React, {Children, ReactElement, ReactEventHandler, useEffect, useState} from "react";
|
||||
import Icon from '@mdi/react';
|
||||
import { mdiTagTextOutline, mdiAccountEdit, mdiLinkVariant } from '@mdi/js';
|
||||
import MarkdownPreview from '@uiw/react-markdown-preview';
|
||||
import {AuthorElement} from "./IAuthor";
|
||||
import {LinkElement} from "./ILink";
|
||||
import DownloadSingleChapterJob from "./Jobs/DownloadSingleChapterJob";
|
||||
import IChapter from "./IChapter";
|
||||
import Chapter from "../Chapter";
|
||||
|
||||
export default interface IManga{
|
||||
mangaId: string;
|
||||
connectorId: string;
|
||||
idOnConnectorSite: string;
|
||||
name: string;
|
||||
description: string;
|
||||
websiteUrl: string;
|
||||
@ -35,128 +32,65 @@ export enum MangaReleaseStatus {
|
||||
Unreleased = "Unreleased",
|
||||
}
|
||||
|
||||
export const defaultManga: IManga = {
|
||||
altTitleIds: [],
|
||||
authorIds: [],
|
||||
connectorId: "",
|
||||
description: "",
|
||||
folderName: "",
|
||||
ignoreChapterBefore: 0,
|
||||
linkIds: [],
|
||||
mangaConnectorId: "",
|
||||
name: "",
|
||||
originalLanguage: "",
|
||||
releaseStatus: MangaReleaseStatus.Unreleased,
|
||||
tags: [],
|
||||
websiteUrl: "",
|
||||
year: 0,
|
||||
mangaId: ""
|
||||
}
|
||||
|
||||
export function CoverCard({apiUri, mangaId} : {apiUri: string, mangaId: string}) : ReactElement {
|
||||
let [manga, setContent] = React.useState<IManga>(defaultManga);
|
||||
let [extendedInfo, setExtendedInfo] = React.useState(false);
|
||||
export function MangaItem({apiUri, mangaId, children} : {apiUri: string, mangaId: string, children?: (string | ReactElement)[]}) : ReactElement {
|
||||
const LoadMangaCover : ReactEventHandler<HTMLImageElement> = (e) => {
|
||||
if(e.currentTarget.src != Manga.GetMangaCoverImageUrl(apiUri, mangaId, e.currentTarget))
|
||||
e.currentTarget.src = Manga.GetMangaCoverImageUrl(apiUri, mangaId, e.currentTarget);
|
||||
}
|
||||
|
||||
let [manga, setManga] = useState<IManga | null>(null);
|
||||
let [clicked, setClicked] = useState<boolean>(false);
|
||||
useEffect(() => {
|
||||
Manga.GetMangaById(apiUri, mangaId).then(setContent);
|
||||
Manga.GetMangaById(apiUri, mangaId).then(setManga);
|
||||
}, []);
|
||||
|
||||
const MangaCover : ReactEventHandler<HTMLImageElement> = (e) => {
|
||||
if(e.currentTarget.src != Manga.GetMangaCoverImageUrl(apiUri, manga.mangaId, e.currentTarget))
|
||||
e.currentTarget.src = Manga.GetMangaCoverImageUrl(apiUri, manga.mangaId, e.currentTarget);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="Manga" key={manga.mangaId} onClick={(e) => {
|
||||
setExtendedInfo(!extendedInfo);
|
||||
}}>
|
||||
<img src={Manga.GetMangaCoverImageUrl(apiUri, manga.mangaId, undefined)} alt="Manga Cover" onLoad={MangaCover} onResize={MangaCover}></img>
|
||||
<div className="SimpleCover">
|
||||
<p className="pill connector-name">{manga.mangaConnectorId}</p>
|
||||
<div className="Manga-status" release-status={manga.releaseStatus}></div>
|
||||
<p className="Manga-name">{manga.name}</p>
|
||||
</div>
|
||||
{extendedInfo ? <div extended-info={extendedInfo ? "yes" : "no"}>
|
||||
<ExtendedInfo apiUri={apiUri} manga={manga} actions={[
|
||||
<button className="Manga-DeleteButton" onClick={() => {
|
||||
Manga.DeleteManga(apiUri, manga.mangaId);
|
||||
}}>Delete</button>
|
||||
]} />
|
||||
</div> : null}
|
||||
</div>);
|
||||
}
|
||||
|
||||
export function ExtendedInfo({apiUri, manga, actions} : {apiUri: string, manga: IManga, actions: ReactElement[]}) : ReactElement {
|
||||
const MangaCover : ReactEventHandler<HTMLImageElement> = (e) => {
|
||||
if(e.currentTarget.src != Manga.GetMangaCoverImageUrl(apiUri, manga.mangaId, e.currentTarget))
|
||||
e.currentTarget.src = Manga.GetMangaCoverImageUrl(apiUri, manga.mangaId, e.currentTarget);
|
||||
}
|
||||
|
||||
return(
|
||||
<div className="SearchResult" key={manga.mangaId}>
|
||||
<img src={Manga.GetMangaCoverImageUrl(apiUri, manga.mangaId, undefined)} alt="Manga Cover" onLoad={MangaCover} onResize={MangaCover}></img>
|
||||
<p className="connector-name">{manga.mangaConnectorId}</p>
|
||||
<div className="Manga-status" release-status={manga.releaseStatus}></div>
|
||||
<p className="Manga-name"><a href={manga.websiteUrl}>{manga.name}<img src="../../media/link.svg"
|
||||
alt=""/></a></p>
|
||||
<div className="Manga-tags">
|
||||
{manga.authorIds.map(authorId =>
|
||||
<p className="Manga-author" key={manga.mangaId + "-author-" + authorId} >
|
||||
<Icon path={mdiAccountEdit} size={0.5} />
|
||||
<AuthorElement apiUri={apiUri} authorId={authorId}></AuthorElement>
|
||||
</p>)}
|
||||
{manga.tags.map(tag =>
|
||||
<p className="Manga-tag" key={manga.mangaId + "-tag-" + tag}>
|
||||
<Icon path={mdiTagTextOutline} size={0.5}/>
|
||||
{tag}
|
||||
</p>)}
|
||||
{manga.linkIds.map(linkId =>
|
||||
<p className="Manga-link" key={manga.mangaId + "-link-" + linkId}>
|
||||
<Icon path={mdiLinkVariant} size={0.5}/>
|
||||
<LinkElement apiUri={apiUri} linkId={linkId}></LinkElement>
|
||||
</p>)}
|
||||
</div>
|
||||
<MarkdownPreview className="Manga-description" source={manga.description}
|
||||
style={{backgroundColor: "transparent", color: "black"}}/>
|
||||
<div className="Manga-actions">
|
||||
{actions.map((p, i) => <div key={i}>{p}</div>)}
|
||||
</div>
|
||||
</div>);
|
||||
}
|
||||
|
||||
export function ItemDownloadSingleChapterJob({apiUri, job} : {apiUri: string, job: DownloadSingleChapterJob}){
|
||||
const MangaCover : ReactEventHandler<HTMLImageElement> = (e) => {
|
||||
if(manga === null)
|
||||
return;
|
||||
if(e.currentTarget.src != Manga.GetMangaCoverImageUrl(apiUri, manga.mangaId, e.currentTarget))
|
||||
e.currentTarget.src = Manga.GetMangaCoverImageUrl(apiUri, manga.mangaId, e.currentTarget);
|
||||
}
|
||||
|
||||
let [chapter, setChapter] = React.useState<IChapter|null>(null);
|
||||
let [manga, setManga] = React.useState<IManga|null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
Chapter.GetChapterFromId(apiUri, job.chapterId).then(setChapter);
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
if(chapter === null){
|
||||
setManga(null);
|
||||
return;
|
||||
}
|
||||
Manga.GetMangaById(apiUri, chapter.parentMangaId).then(setManga);
|
||||
}, [chapter]);
|
||||
|
||||
return (
|
||||
<div className="DownloadSingleChapterJob" key={"DownloadSingleChapterJob-" + job.jobId}>
|
||||
<img src={manga ? Manga.GetMangaCoverImageUrl(apiUri, manga.mangaId, undefined) : ""} alt="Manga Cover" onLoad={MangaCover} onResize={MangaCover}></img>
|
||||
<p className="DownloadSingleChapterJob-Name">{manga ? manga.name : job.chapterId}</p>
|
||||
<p className="DownloadSingleChapterJob-Title">
|
||||
{chapter ? "Vol." + chapter.volumeNumber + " Ch." + chapter.chapterNumber + ": " + chapter.title : "loading"}
|
||||
<a href={chapter ? chapter.url : ""}>
|
||||
<img src="../../media/link.svg" alt=""/>
|
||||
</a>
|
||||
</p>
|
||||
return (<div className="MangaItem" key={mangaId} is-clicked={clicked ? "clicked" : "not-clicked"} onClick={()=>setClicked(!clicked)}>
|
||||
<img className="MangaItem-Cover" src={Manga.GetMangaCoverImageUrl(apiUri, mangaId, undefined)} alt="Manga Cover" onLoad={LoadMangaCover} onResize={LoadMangaCover}></img>
|
||||
<p className="MangaItem-Connector">{manga ? manga.mangaConnectorId : "Connector"}</p>
|
||||
<p className="MangaItem-Status" release-status={manga?.releaseStatus}></p>
|
||||
<p className="MangaItem-Name">{manga ? manga.name : "Name"}</p>
|
||||
<a className="MangaItem-Website" href={manga ? manga.websiteUrl : "#"}><img src="../../media/link.svg" alt="Link"/></a>
|
||||
<div className="MangaItem-Tags">
|
||||
{manga ? manga.authorIds.map(authorId =>
|
||||
<p className="MangaItem-Author" key={authorId} >
|
||||
<Icon path={mdiAccountEdit} size={0.5} />
|
||||
<AuthorElement apiUri={apiUri} authorId={authorId}></AuthorElement>
|
||||
</p>)
|
||||
:
|
||||
<p className="MangaItem-Author">
|
||||
<Icon path={mdiAccountEdit} size={0.5} />
|
||||
<AuthorElement apiUri={apiUri} authorId={null}></AuthorElement>
|
||||
</p>}
|
||||
{manga ? manga.tags.map(tag =>
|
||||
<p className="MangaItem-Tag" key={tag}>
|
||||
<Icon path={mdiTagTextOutline} size={0.5}/>
|
||||
<p className="MangaItem-Tag-Value">{tag}</p>
|
||||
</p>)
|
||||
:
|
||||
<p className="MangaItem-Tag">
|
||||
<Icon path={mdiTagTextOutline} size={0.5}/>
|
||||
<p className="MangaItem-Tag-Value">Tag</p>
|
||||
</p>
|
||||
}
|
||||
{manga ? manga.linkIds.map(linkId =>
|
||||
<p className="MangaItem-Link" key={linkId}>
|
||||
<Icon path={mdiLinkVariant} size={0.5}/>
|
||||
<LinkElement apiUri={apiUri} linkId={linkId} />
|
||||
</p>)
|
||||
:
|
||||
<p className="MangaItem-Link">
|
||||
<Icon path={mdiLinkVariant} size={0.5}/>
|
||||
<LinkElement apiUri={apiUri} linkId={null} />
|
||||
</p>}
|
||||
</div>
|
||||
);
|
||||
<MarkdownPreview className="MangaItem-Description" source={manga ? manga.description : "# Description"} />
|
||||
<div className="MangaItem-Props">
|
||||
{children ? children.map(c => {
|
||||
if(c instanceof Element)
|
||||
return c as ReactElement;
|
||||
else
|
||||
return <span>{c}</span>
|
||||
}) : null}
|
||||
</div>
|
||||
</div>)
|
||||
}
|
Reference in New Issue
Block a user