Created standardized Popup-Window
Moved Update-functions for Queue-Status and Monitoring-list to their respective modules
This commit is contained in:
parent
1304bc750a
commit
fcc1ff392c
@ -1,10 +1,11 @@
|
|||||||
import React, {EventHandler, useEffect} from 'react';
|
import React, {useEffect, useState} from 'react';
|
||||||
import Footer from "./modules/Footer";
|
import Footer from "./modules/Footer";
|
||||||
import Search from "./modules/Search";
|
import Search from "./modules/Search";
|
||||||
import Header from "./modules/Header";
|
import Header from "./modules/Header";
|
||||||
import MonitorJobsList from "./modules/MonitorJobsList";
|
import MonitorJobsList from "./modules/MonitorJobsList";
|
||||||
import './styles/index.css'
|
import './styles/index.css'
|
||||||
import QueuePopUp from "./modules/QueuePopUp";
|
import {Job} from "./modules/Job";
|
||||||
|
import IFrontendSettings from "./modules/interfaces/IFrontendSettings";
|
||||||
|
|
||||||
export default function App(){
|
export default function App(){
|
||||||
const [connected, setConnected] = React.useState(false);
|
const [connected, setConnected] = React.useState(false);
|
||||||
@ -15,35 +16,14 @@ export default function App(){
|
|||||||
const [joblistUpdateInterval, setJoblistUpdateInterval] = React.useState<number>();
|
const [joblistUpdateInterval, setJoblistUpdateInterval] = React.useState<number>();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
checkConnection();
|
checkConnection().then(res => setConnected(res)).catch(() => setConnected(false));
|
||||||
setInterval(() => {
|
setInterval(() => {
|
||||||
checkConnection();
|
checkConnection().then(res => setConnected(res)).catch(() => setConnected(false));
|
||||||
}, 500);
|
}, 500);
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const checkConnection = () =>{
|
function CreateJob(internalId: string, jobType: string){
|
||||||
getData('http://127.0.0.1:6531/v2/Ping').then((result) => {
|
Job.CreateJobDateInterval(internalId, jobType, frontendSettings.jobInterval);
|
||||||
setConnected(result != null);
|
|
||||||
}).catch(() => setConnected(false));
|
|
||||||
}
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if(connected){
|
|
||||||
setLastJobListUpdate(new Date());
|
|
||||||
setJoblistUpdateInterval(setInterval(() => {
|
|
||||||
setLastJobListUpdate(new Date());
|
|
||||||
}, 5000));
|
|
||||||
}else{
|
|
||||||
clearInterval(joblistUpdateInterval);
|
|
||||||
setJoblistUpdateInterval(undefined);
|
|
||||||
}
|
|
||||||
}, [connected]);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const JobsChanged : EventHandler<any> = () => {
|
|
||||||
setLastMangaListUpdate(new Date());
|
|
||||||
setLastJobListUpdate(new Date());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return(<div>
|
return(<div>
|
||||||
@ -52,18 +32,14 @@ export default function App(){
|
|||||||
? <>
|
? <>
|
||||||
{showSearch
|
{showSearch
|
||||||
? <>
|
? <>
|
||||||
<Search onJobsChanged={JobsChanged} closeSearch={() => setShowSearch(false)} />
|
<Search createJob={CreateJob} closeSearch={() => setShowSearch(false)} />
|
||||||
<hr/>
|
<hr/>
|
||||||
</>
|
</>
|
||||||
: <></>}
|
: <></>}
|
||||||
{showQueue
|
<MonitorJobsList onStartSearch={() => setShowSearch(true)} onJobsChanged={() => console.info("jobsChanged")} connectedToBackend={connected} />
|
||||||
? <QueuePopUp closeQueue={() => setShowQueue(false)} />
|
|
||||||
: <></>
|
|
||||||
}
|
|
||||||
<MonitorJobsList onStartSearch={() => setShowSearch(true)} onJobsChanged={JobsChanged} key={lastMangaListUpdate.getTime()}/>
|
|
||||||
</>
|
</>
|
||||||
: <h1>No connection to backend</h1>}
|
: <h1>No connection to backend</h1>}
|
||||||
<Footer key={lastJobListUpdate.getTime()} showQueue={() => setShowQueue(true)}/>
|
<Footer connectedToBackend={connected} />
|
||||||
</div>)
|
</div>)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -133,4 +109,10 @@ export function isValidUri(uri: string) : boolean{
|
|||||||
} catch (err) {
|
} catch (err) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const checkConnection = async (): Promise<boolean> =>{
|
||||||
|
return getData('http://127.0.0.1:6531/v2/Ping').then((result) => {
|
||||||
|
return result != null;
|
||||||
|
}).catch(() => Promise.reject());
|
||||||
}
|
}
|
@ -3,12 +3,14 @@ import '../styles/footer.css';
|
|||||||
import {Job} from './Job';
|
import {Job} from './Job';
|
||||||
import Icon from '@mdi/react';
|
import Icon from '@mdi/react';
|
||||||
import { mdiRun, mdiCounter, mdiEyeCheck, mdiTrayFull } from '@mdi/js';
|
import { mdiRun, mdiCounter, mdiEyeCheck, mdiTrayFull } from '@mdi/js';
|
||||||
|
import QueuePopUp from "./QueuePopUp";
|
||||||
|
|
||||||
export default function Footer({showQueue} : {showQueue(): void}){
|
export default function Footer({connectedToBackend} : {connectedToBackend: boolean}) {
|
||||||
const [MonitoringJobsCount, setMonitoringJobsCount] = React.useState(0);
|
const [MonitoringJobsCount, setMonitoringJobsCount] = React.useState(0);
|
||||||
const [AllJobsCount, setAllJobsCount] = React.useState(0);
|
const [AllJobsCount, setAllJobsCount] = React.useState(0);
|
||||||
const [RunningJobsCount, setRunningJobsCount] = React.useState(0);
|
const [RunningJobsCount, setRunningJobsCount] = React.useState(0);
|
||||||
const [StandbyJobsCount, setStandbyJobsCount] = React.useState(0);
|
const [StandbyJobsCount, setStandbyJobsCount] = React.useState(0);
|
||||||
|
const [countUpdateInterval, setcountUpdateInterval] = React.useState<number>();
|
||||||
|
|
||||||
function UpdateBackendState(){
|
function UpdateBackendState(){
|
||||||
Job.GetMonitoringJobs().then((jobs) => setMonitoringJobsCount(jobs.length));
|
Job.GetMonitoringJobs().then((jobs) => setMonitoringJobsCount(jobs.length));
|
||||||
@ -18,15 +20,25 @@ export default function Footer({showQueue} : {showQueue(): void}){
|
|||||||
}
|
}
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
UpdateBackendState();
|
if(connectedToBackend){
|
||||||
}, []);
|
UpdateBackendState();
|
||||||
|
setcountUpdateInterval(setInterval(() => {
|
||||||
|
UpdateBackendState();
|
||||||
|
}, 2000));
|
||||||
|
}else{
|
||||||
|
clearInterval(countUpdateInterval);
|
||||||
|
setcountUpdateInterval(undefined);
|
||||||
|
}
|
||||||
|
}, [connectedToBackend]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<footer>
|
<footer>
|
||||||
<div><Icon path={mdiEyeCheck} size={1}/> <span>{MonitoringJobsCount}</span></div>
|
<div className="statusBadge"><Icon path={mdiEyeCheck} size={1}/> <span>{MonitoringJobsCount}</span></div>
|
||||||
<div onClick={showQueue} className="hoverHand"><Icon path={mdiTrayFull} size={1}/> <span>{StandbyJobsCount}</span></div>
|
<QueuePopUp>
|
||||||
<div onClick={showQueue} className="hoverHand"><Icon path={mdiRun} size={1}/> <span>{RunningJobsCount}</span></div>
|
<div className="statusBadge hoverHand"><Icon path={mdiTrayFull} size={1}/> <span>{StandbyJobsCount}</span></div>
|
||||||
<div><Icon path={mdiCounter} size={1}/> <span>{AllJobsCount}</span></div>
|
<div className="statusBadge hoverHand"><Icon path={mdiRun} size={1}/> <span>{RunningJobsCount}</span></div>
|
||||||
|
</QueuePopUp>
|
||||||
|
<div className="statusBadge"><Icon path={mdiCounter} size={1}/> <span>{AllJobsCount}</span></div>
|
||||||
<p id="madeWith">Made with Blåhaj 🦈</p>
|
<p id="madeWith">Made with Blåhaj 🦈</p>
|
||||||
</footer>)
|
</footer>)
|
||||||
}
|
}
|
@ -4,6 +4,10 @@ import IProgressToken from "./interfaces/IProgressToken";
|
|||||||
|
|
||||||
export class Job
|
export class Job
|
||||||
{
|
{
|
||||||
|
static IntervalStringFromDate(date: Date) : string {
|
||||||
|
return `${date.getDay()}.${date.getHours()}:${date.getMinutes()}:${date.getSeconds()}`;
|
||||||
|
}
|
||||||
|
|
||||||
static async GetAllJobs(): Promise<string[]> {
|
static async GetAllJobs(): Promise<string[]> {
|
||||||
console.info("Getting all Jobs");
|
console.info("Getting all Jobs");
|
||||||
return getData("http://127.0.0.1:6531/v2/Jobs")
|
return getData("http://127.0.0.1:6531/v2/Jobs")
|
||||||
@ -101,9 +105,18 @@ export class Job
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static async CreateJobDateInterval(internalId: string, jobType: string, interval: Date) : Promise<null> {
|
||||||
|
return this.CreateJob(internalId, jobType, this.IntervalStringFromDate(interval));
|
||||||
|
}
|
||||||
|
|
||||||
static async CreateJob(internalId: string, jobType: string, interval: string): Promise<null> {
|
static async CreateJob(internalId: string, jobType: string, interval: string): Promise<null> {
|
||||||
|
const validate = /(?:[0-9]{1,2}\.)?[0-9]{1,2}:[0-9]{1,2}(?::[0-9]{1,2})?/
|
||||||
console.info(`Creating Job for Manga ${internalId} at ${interval} interval`);
|
console.info(`Creating Job for Manga ${internalId} at ${interval} interval`);
|
||||||
let data = {
|
if(!validate.test(interval)){
|
||||||
|
console.error("Interval was in incorrect format.");
|
||||||
|
return Promise.reject();
|
||||||
|
}
|
||||||
|
const data = {
|
||||||
internalId: internalId,
|
internalId: internalId,
|
||||||
interval: interval
|
interval: interval
|
||||||
};
|
};
|
||||||
|
@ -8,9 +8,10 @@ import '../styles/MangaCoverCard.css'
|
|||||||
import Icon from '@mdi/react';
|
import Icon from '@mdi/react';
|
||||||
import { mdiTrashCanOutline, mdiPlayBoxOutline } from '@mdi/js';
|
import { mdiTrashCanOutline, mdiPlayBoxOutline } from '@mdi/js';
|
||||||
|
|
||||||
export default function MonitorJobsList({onStartSearch, onJobsChanged} : {onStartSearch() : void, onJobsChanged: EventHandler<any>}) {
|
export default function MonitorJobsList({onStartSearch, onJobsChanged, connectedToBackend} : {onStartSearch() : void, onJobsChanged: EventHandler<any>, connectedToBackend: boolean}) {
|
||||||
const [MonitoringJobs, setMonitoringJobs] = useState<IJob[]>([]);
|
const [MonitoringJobs, setMonitoringJobs] = useState<IJob[]>([]);
|
||||||
const [AllManga, setAllManga] = useState<IManga[]>([]);
|
const [AllManga, setAllManga] = useState<IManga[]>([]);
|
||||||
|
const [joblistUpdateInterval, setJoblistUpdateInterval] = React.useState<number>();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
console.debug("Updating display list.");
|
console.debug("Updating display list.");
|
||||||
@ -28,8 +29,16 @@ export default function MonitorJobsList({onStartSearch, onJobsChanged} : {onStar
|
|||||||
}, [MonitoringJobs]);
|
}, [MonitoringJobs]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
UpdateMonitoringJobsList();
|
if(connectedToBackend){
|
||||||
}, []);
|
UpdateMonitoringJobsList();
|
||||||
|
setJoblistUpdateInterval(setInterval(() => {
|
||||||
|
UpdateMonitoringJobsList();
|
||||||
|
}, 1000));
|
||||||
|
}else{
|
||||||
|
clearInterval(joblistUpdateInterval);
|
||||||
|
setJoblistUpdateInterval(undefined);
|
||||||
|
}
|
||||||
|
}, [connectedToBackend]);
|
||||||
|
|
||||||
function UpdateMonitoringJobsList(){
|
function UpdateMonitoringJobsList(){
|
||||||
console.debug("Updating MonitoringJobsList");
|
console.debug("Updating MonitoringJobsList");
|
||||||
|
@ -1,16 +1,18 @@
|
|||||||
import React, {ReactElement, useEffect} from 'react';
|
import React, {useEffect, useState} from 'react';
|
||||||
import IJob, {JobTypeFromNumber} from "./interfaces/IJob";
|
import IJob, {JobTypeFromNumber} from "./interfaces/IJob";
|
||||||
import '../styles/queuePopUp.css';
|
import '../styles/queuePopUp.css';
|
||||||
|
import '../styles/popup.css';
|
||||||
import {Job} from "./Job";
|
import {Job} from "./Job";
|
||||||
import IManga from "./interfaces/IManga";
|
import IManga from "./interfaces/IManga";
|
||||||
import {Manga} from "./Manga";
|
import {Manga} from "./Manga";
|
||||||
|
|
||||||
export default function QueuePopUp({closeQueue} : {closeQueue(): void}){
|
export default function QueuePopUp({children} : {children: JSX.Element[]}) {
|
||||||
|
|
||||||
const [StandbyJobs, setStandbyJobs] = React.useState<IJob[]>([]);
|
const [StandbyJobs, setStandbyJobs] = React.useState<IJob[]>([]);
|
||||||
const [StandbyJobsManga, setStandbyJobsManga] = React.useState<IManga[]>([]);
|
const [StandbyJobsManga, setStandbyJobsManga] = React.useState<IManga[]>([]);
|
||||||
const [RunningJobs, setRunningJobs] = React.useState<IJob[]>([]);
|
const [RunningJobs, setRunningJobs] = React.useState<IJob[]>([]);
|
||||||
const [RunningJobsManga, setRunningJobsManga] = React.useState<IManga[]>([]);
|
const [RunningJobsManga, setRunningJobsManga] = React.useState<IManga[]>([]);
|
||||||
|
const [showQueuePopup, setShowQueuePopup] = useState<boolean>(false);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
Job.GetStandbyJobs()
|
Job.GetStandbyJobs()
|
||||||
@ -56,45 +58,54 @@ export default function QueuePopUp({closeQueue} : {closeQueue(): void}){
|
|||||||
.then(setRunningJobsManga);
|
.then(setRunningJobsManga);
|
||||||
}, [RunningJobs]);
|
}, [RunningJobs]);
|
||||||
|
|
||||||
return (
|
return (<>
|
||||||
<div id="QueuePopUp">
|
<div onClick={() => setShowQueuePopup(true)}>
|
||||||
<div id="QueuePopUpHeader">
|
{children}
|
||||||
<h1>Queue Status</h1>
|
|
||||||
<img alt="Close Search" id="closeSearch" src="../media/close-x.svg" onClick={closeQueue}/>
|
|
||||||
</div>
|
</div>
|
||||||
<div id="QueuePopUpBody">
|
{showQueuePopup
|
||||||
<div id="RunningJobQueue">
|
? <div className="popup" id="QueuePopUp">
|
||||||
<h1>Running</h1>
|
<div className="popupHeader">
|
||||||
<div className="JobQueue">
|
<h1>Queue Status {showQueuePopup ? "true" : "false"}</h1>
|
||||||
{RunningJobs.map((job: IJob) => {
|
<img alt="Close Search" className="close" src="../media/close-x.svg"
|
||||||
const manga = RunningJobsManga.find(manga => manga.internalId == job.mangaInternalId || manga.internalId == job.chapter?.parentManga.internalId);
|
onClick={() => setShowQueuePopup(false)}/>
|
||||||
if (manga === undefined || manga === null)
|
</div>
|
||||||
return <div key={"QueueJob-" + job.id}>Error. Could not find matching manga for {job.id}</div>
|
<div id="QueuePopUpBody" className="popupBody">
|
||||||
return <div className="QueueJob" key={"QueueJob-" + job.id}>
|
<div id="RunningJobQueue">
|
||||||
<img src={Manga.GetMangaCoverUrl(manga.internalId)} />
|
<h1>Running</h1>
|
||||||
<p>{JobTypeFromNumber(job.jobType)}</p>
|
<div className="JobQueue">
|
||||||
</div>;
|
{RunningJobs.map((job: IJob) => {
|
||||||
})}
|
const manga = RunningJobsManga.find(manga => manga.internalId == job.mangaInternalId || manga.internalId == job.chapter?.parentManga.internalId);
|
||||||
|
if (manga === undefined || manga === null)
|
||||||
|
return <div key={"QueueJob-" + job.id}>Error. Could not find matching manga
|
||||||
|
for {job.id}</div>
|
||||||
|
return <div className="QueueJob" key={"QueueJob-" + job.id}>
|
||||||
|
<img src={Manga.GetMangaCoverUrl(manga.internalId)}/>
|
||||||
|
<p>{JobTypeFromNumber(job.jobType)}</p>
|
||||||
|
</div>;
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div id="WaitingJobQueue">
|
||||||
|
<h1>Standby</h1>
|
||||||
|
<div className="JobQueue">
|
||||||
|
{StandbyJobs.map((job: IJob) => {
|
||||||
|
const manga = StandbyJobsManga.find(manga => manga.internalId == job.mangaInternalId || manga.internalId == job.chapter?.parentManga.internalId);
|
||||||
|
if (manga === undefined || manga === null)
|
||||||
|
return <div key={"QueueJob-" + job.id}>Error. Could not find matching manga
|
||||||
|
for {job.id}</div>
|
||||||
|
return <div className="QueueJob" key={"QueueJob-" + job.id}>
|
||||||
|
<img src={Manga.GetMangaCoverUrl(manga.internalId)}/>
|
||||||
|
<p className="QueueJob-Name">{manga.sortName}</p>
|
||||||
|
<p className="QueueJob-JobType">{JobTypeFromNumber(job.jobType)}</p>
|
||||||
|
<p className="QueueJob-additional">{job.jobType == 0 ? `Vol.${job.chapter?.volumeNumber} Ch.${job.chapter?.chapterNumber}` : ""}</p>
|
||||||
|
</div>;
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div id="WaitingJobQueue">
|
: <></>
|
||||||
<h1>Standby</h1>
|
}
|
||||||
<div className="JobQueue">
|
</>
|
||||||
{StandbyJobs.map((job: IJob) => {
|
|
||||||
const manga = StandbyJobsManga.find(manga => manga.internalId == job.mangaInternalId || manga.internalId == job.chapter?.parentManga.internalId);
|
|
||||||
if (manga === undefined || manga === null)
|
|
||||||
return <div key={"QueueJob-" + job.id}>Error. Could not find matching manga
|
|
||||||
for {job.id}</div>
|
|
||||||
return <div className="QueueJob" key={"QueueJob-" + job.id}>
|
|
||||||
<img src={Manga.GetMangaCoverUrl(manga.internalId)}/>
|
|
||||||
<p className="QueueJob-Name">{manga.sortName}</p>
|
|
||||||
<p className="QueueJob-JobType">{JobTypeFromNumber(job.jobType)}</p>
|
|
||||||
<p className="QueueJob-additional">{job.jobType == 0 ? `Vol.${job.chapter?.volumeNumber} Ch.${job.chapter?.chapterNumber}` : ""}</p>
|
|
||||||
</div>;
|
|
||||||
})}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
@ -6,7 +6,7 @@ import IManga, {SearchResult} from "./interfaces/IManga";
|
|||||||
import '../styles/search.css';
|
import '../styles/search.css';
|
||||||
import '../styles/MangaSearchResult.css'
|
import '../styles/MangaSearchResult.css'
|
||||||
|
|
||||||
export default function Search({onJobsChanged, closeSearch} : {onJobsChanged: EventHandler<any>, closeSearch(): void}) {
|
export default function Search({createJob, closeSearch} : {createJob: (internalId: string, type: string) => void, closeSearch(): void}) {
|
||||||
const [mangaConnectors, setConnectors] = useState<IMangaConnector[]>();
|
const [mangaConnectors, setConnectors] = useState<IMangaConnector[]>();
|
||||||
const [selectedConnector, setSelectedConnector] = useState<IMangaConnector>();
|
const [selectedConnector, setSelectedConnector] = useState<IMangaConnector>();
|
||||||
const [selectedLanguage, setSelectedLanguage] = useState<string>();
|
const [selectedLanguage, setSelectedLanguage] = useState<string>();
|
||||||
@ -98,8 +98,7 @@ export default function Search({onJobsChanged, closeSearch} : {onJobsChanged: Ev
|
|||||||
<select id="Searchbox-language" onChange={changeSelectedLanguage} value={selectedLanguage === null ? "" : selectedLanguage}>
|
<select id="Searchbox-language" onChange={changeSelectedLanguage} value={selectedLanguage === null ? "" : selectedLanguage}>
|
||||||
{selectedConnector === undefined
|
{selectedConnector === undefined
|
||||||
? <option value="" disabled hidden>Select Connector</option>
|
? <option value="" disabled hidden>Select Connector</option>
|
||||||
: selectedConnector.SupportedLanguages.map(language => <option value={language}
|
: selectedConnector.SupportedLanguages.map(language => <option value={language} key={language}>{language}</option>)}
|
||||||
key={language}>{language}</option>)}
|
|
||||||
</select>
|
</select>
|
||||||
<button id="Searchbox-button" type="submit" onClick={ExecuteSearch}>Search</button>
|
<button id="Searchbox-button" type="submit" onClick={ExecuteSearch}>Search</button>
|
||||||
</div>
|
</div>
|
||||||
@ -107,7 +106,7 @@ export default function Search({onJobsChanged, closeSearch} : {onJobsChanged: Ev
|
|||||||
<div id="SearchResults">
|
<div id="SearchResults">
|
||||||
{searchResults === undefined
|
{searchResults === undefined
|
||||||
? <p></p>
|
? <p></p>
|
||||||
: searchResults.map(result => SearchResult(result, onJobsChanged))}
|
: searchResults.map(result => SearchResult(result, createJob))}
|
||||||
</div>
|
</div>
|
||||||
</div>)
|
</div>)
|
||||||
}
|
}
|
@ -52,7 +52,7 @@ export function CoverCard(manga: IManga) : ReactElement {
|
|||||||
</div>);
|
</div>);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function SearchResult(manga: IManga, jobsChanged: EventHandler<any>) : ReactElement {
|
export function SearchResult(manga: IManga, createJob: (internalId: string, type: string) => void) : ReactElement {
|
||||||
return(
|
return(
|
||||||
<div className="SearchResult" key={manga.internalId}>
|
<div className="SearchResult" key={manga.internalId}>
|
||||||
<img src={Manga.GetMangaCoverUrl(manga.internalId)}></img>
|
<img src={Manga.GetMangaCoverUrl(manga.internalId)}></img>
|
||||||
@ -65,7 +65,7 @@ export function SearchResult(manga: IManga, jobsChanged: EventHandler<any>) : Re
|
|||||||
</div>
|
</div>
|
||||||
<MarkdownPreview className="Manga-description" source={manga.description} style={{ backgroundColor: "transparent", color: "black" }} />
|
<MarkdownPreview className="Manga-description" source={manga.description} style={{ backgroundColor: "transparent", color: "black" }} />
|
||||||
<button className="Manga-AddButton" onClick={(e) => {
|
<button className="Manga-AddButton" onClick={(e) => {
|
||||||
Job.CreateJob(manga.internalId, "MonitorManga", "03:00:00").then(() => jobsChanged(manga.internalId));
|
createJob(manga.internalId, "MonitorManga")
|
||||||
}}>Monitor
|
}}>Monitor
|
||||||
</button>
|
</button>
|
||||||
</div>);
|
</div>);
|
||||||
|
@ -11,6 +11,7 @@ footer {
|
|||||||
position: fixed;
|
position: fixed;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
color: white;
|
color: white;
|
||||||
|
z-index: 10;
|
||||||
}
|
}
|
||||||
|
|
||||||
#madeWith {
|
#madeWith {
|
||||||
@ -20,19 +21,20 @@ footer {
|
|||||||
cursor: url("Website/media/blahaj.png"), grab;
|
cursor: url("Website/media/blahaj.png"), grab;
|
||||||
}
|
}
|
||||||
|
|
||||||
footer div {
|
footer .statusBadge {
|
||||||
margin: 0 10px;
|
margin: 0 10px;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-items: center;
|
justify-items: center;
|
||||||
background-color: rgba(255,255,255, 0.3);
|
background-color: rgba(255,255,255, 0.3);
|
||||||
border-radius: 10px;
|
border-radius: 10px;
|
||||||
padding: 0 5px;
|
padding: 2px 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
footer div > * {
|
footer > div {
|
||||||
margin: 0 2px;
|
display: flex;
|
||||||
padding: 3px 0;
|
align-items: center;
|
||||||
|
justify-items: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
footer .hoverHand {
|
footer .hoverHand {
|
||||||
|
43
Website/styles/popup.css
Normal file
43
Website/styles/popup.css
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
.popup {
|
||||||
|
position: fixed;
|
||||||
|
left: 10%;
|
||||||
|
top: 7.5%;
|
||||||
|
width: 80%;
|
||||||
|
height: 80%;
|
||||||
|
margin: auto;
|
||||||
|
z-index: 100;
|
||||||
|
background-color: var(--second-background-color);
|
||||||
|
border-radius: 10px;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.popup .popupHeader {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
height: 40px;
|
||||||
|
width: 100%;
|
||||||
|
background-color: var(--primary-color);
|
||||||
|
color: var(--accent-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.popup .popupHeader h1 {
|
||||||
|
margin: 4px 10px;
|
||||||
|
font-size: 20pt;
|
||||||
|
}
|
||||||
|
|
||||||
|
.popup .close {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
right: 0;
|
||||||
|
height: 100%;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.popup .popupBody {
|
||||||
|
position: absolute;
|
||||||
|
top: 40px;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: calc(100% - 40px);
|
||||||
|
}
|
@ -1,44 +1,4 @@
|
|||||||
#QueuePopUp {
|
|
||||||
position: absolute;
|
|
||||||
left: 10%;
|
|
||||||
top: 7.5%;
|
|
||||||
width: 80%;
|
|
||||||
height: 80%;
|
|
||||||
margin: auto;
|
|
||||||
z-index: 100;
|
|
||||||
background-color: var(--second-background-color);
|
|
||||||
border-radius: 10px;
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
#QueuePopUp #QueuePopUpHeader {
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
height: 40px;
|
|
||||||
width: 100%;
|
|
||||||
background-color: var(--primary-color);
|
|
||||||
color: var(--accent-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
#QueuePopUp #QueuePopUpHeader h1 {
|
|
||||||
margin: 4px 10px;
|
|
||||||
font-size: 20pt;
|
|
||||||
}
|
|
||||||
|
|
||||||
#QueuePopUp #closeSearch {
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
right: 0;
|
|
||||||
height: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
#QueuePopUp #QueuePopUpBody {
|
#QueuePopUp #QueuePopUpBody {
|
||||||
position: absolute;
|
|
||||||
top: 40px;
|
|
||||||
left: 0;
|
|
||||||
width: 100%;
|
|
||||||
height: calc(100% - 40px);
|
|
||||||
display: flex;
|
display: flex;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user