diff --git a/README.md b/README.md index fed1b32..3df7b89 100644 --- a/README.md +++ b/README.md @@ -57,7 +57,9 @@ This repo makes HTTP-requests to the [Tranga-API](https://github.com/C9Glax/tran ### Built With - nginx -- HTML, CSS, and barebones Javascript +- vite +- react +- typescript - 💙 Blåhaj 🦈

(back to top)

@@ -73,16 +75,6 @@ There is a single release: Download [docker-compose.yaml](https://github.com/C9Glax/tranga-website/blob/cuttingedge/docker-compose.yaml) and configure to your needs. The `docker-compose` also includes [Tranga](https://github.com/C9Glax/tranga) as backend. For its configuration refer to the repo README. - -## Roadmap - -- [ ] ❓ - -See the [open issues](https://github.com/C9Glax/tranga-website/issues) for a full list of proposed features (and known issues). - -

(back to top)

- - ## Contributing diff --git a/Screenshots/Screenshot 2023-09-08 at 20-03-13 Tranga.png b/Screenshots/Screenshot 2023-09-08 at 20-03-13 Tranga.png deleted file mode 100644 index c30b3a8..0000000 Binary files a/Screenshots/Screenshot 2023-09-08 at 20-03-13 Tranga.png and /dev/null differ diff --git a/Screenshots/Screenshot 2023-09-08 at 20-03-37 Tranga.png b/Screenshots/Screenshot 2023-09-08 at 20-03-37 Tranga.png deleted file mode 100644 index 670743c..0000000 Binary files a/Screenshots/Screenshot 2023-09-08 at 20-03-37 Tranga.png and /dev/null differ diff --git a/Screenshots/Screenshot 2023-09-08 at 20-03-45 Tranga.png b/Screenshots/Screenshot 2023-09-08 at 20-03-45 Tranga.png deleted file mode 100644 index 2f38769..0000000 Binary files a/Screenshots/Screenshot 2023-09-08 at 20-03-45 Tranga.png and /dev/null differ diff --git a/Screenshots/Screenshot 2023-09-08 at 20-03-58 Tranga.png b/Screenshots/Screenshot 2023-09-08 at 20-03-58 Tranga.png deleted file mode 100644 index a287f41..0000000 Binary files a/Screenshots/Screenshot 2023-09-08 at 20-03-58 Tranga.png and /dev/null differ diff --git a/Screenshots/Screenshot 2023-09-08 at 20-04-41 Tranga.png b/Screenshots/Screenshot 2023-09-08 at 20-04-41 Tranga.png deleted file mode 100644 index 68c191f..0000000 Binary files a/Screenshots/Screenshot 2023-09-08 at 20-04-41 Tranga.png and /dev/null differ diff --git a/Website/apiConnector.js b/Website/apiConnector.js deleted file mode 100644 index 64dca93..0000000 --- a/Website/apiConnector.js +++ /dev/null @@ -1,346 +0,0 @@ -let apiUri = `${window.location.protocol}//${window.location.host.split(':')[0]}:6531` - -if(getCookie("apiUri") != ""){ - apiUri = getCookie("apiUri"); -} -setCookie("apiUri", apiUri); - -function setCookie(cname, cvalue) { - const d = new Date(); - d.setTime(d.getTime() + (365*24*60*60*1000)); - let expires = "expires="+ d.toUTCString(); - document.cookie = cname + "=" + cvalue + ";" + expires + ";path=/;samesite=strict"; -} - -function getCookie(cname) { - let name = cname + "="; - let decodedCookie = decodeURIComponent(document.cookie); - let ca = decodedCookie.split(';'); - for(let i = 0; i < ca.length; i++) { - let c = ca[i]; - while (c.charAt(0) == ' ') { - c = c.substring(1); - } - if (c.indexOf(name) == 0) { - return c.substring(name.length, c.length); - } - } - return ""; -} - -async function GetData(uri){ - let request = await fetch(uri, { - method: 'GET', - headers: { - 'Accept': 'application/json' - } - }); - let json = await request.json(); - return json; -} - -async function PostData(uri){ - let request = await fetch(uri, { - method: 'POST' - }); - //console.log(request); -} - -function DeleteData(uri){ - fetch(uri, { - method: 'DELETE' - }); -} - -async function Ping(){ - let ret = await GetData(`${apiUri}/Ping`); - return ret; -} - -async function GetAvailableControllers(){ - var uri = apiUri + "/Connectors"; - let json = await GetData(uri); - return json; -} - -async function GetPublicationFromConnector(connector, title){ - var uri; - if(title.includes("http")){ - uri = `${apiUri}/Manga/FromConnector?connector=${connector}&url=${title}`; - }else{ - uri = `${apiUri}/Manga/FromConnector?connector=${connector}&title=${title}`; - } - let json = await GetData(uri); - return json; -} - -async function GetChapters(connector, internalId, language){ - var uri = `${apiUri}/Manga/Chapters?connector=${connector}&internalId=${internalId}&translatedLanguage=${language}`; - let json = await GetData(uri); - return json; -} - -function GetCoverUrl(internalId){ - return `${apiUri}/Manga/Cover?internalId=${internalId}`; -} - -async function GetAllJobs(){ - var uri = `${apiUri}/Jobs`; - let json = await GetData(uri); - return json; -} - -async function GetRunningJobs(){ - var uri = `${apiUri}/Jobs/Running`; - let json = await GetData(uri); - return json; -} - -async function GetWaitingJobs(){ - var uri = `${apiUri}/Jobs/Waiting`; - let json = await GetData(uri); - return json; -} - -async function GetMonitorJobs(){ - var uri = `${apiUri}/Jobs/MonitorJobs`; - let json = await GetData(uri); - return json; -} - -async function GetProgress(jobId){ - var uri = `${apiUri}/Jobs/Progress?jobId=${jobId}`; - let json = await GetData(uri); - return json; -} - -async function GetSettings(){ - var uri = `${apiUri}/Settings`; - let json = await GetData(uri); - return json; -} - -async function GetAvailableNotificationConnectors(){ - var uri = `${apiUri}/NotificationConnectors/Types`; - let json = await GetData(uri); - return json; -} - -async function GetNotificationConnectors(){ - var uri = `${apiUri}/NotificationConnectors`; - let json = await GetData(uri); - return json; -} - -async function GetAvailableLibraryConnectors(){ - var uri = `${apiUri}/LibraryConnectors/Types`; - let json = await GetData(uri); - return json; -} - -async function GetLibraryConnectors(){ - var uri = `${apiUri}/LibraryConnectors`; - let json = await GetData(uri); - return json; -} - -async function GetRateLimits() { - var uri = `${apiUri}/Settings/customRequestLimit` - let json = await GetData(uri); - return json; -} - -function CreateMonitorJob(connector, internalId, language){ - var uri = `${apiUri}/Jobs/MonitorManga?connector=${connector}&internalId=${internalId}&interval=03:00:00&translatedLanguage=${language}`; - PostData(uri); -} - -function CreateDownloadNewChaptersJob(connector, internalId, language){ - var uri = `${apiUri}/Jobs/DownloadNewChapters?connector=${connector}&internalId=${internalId}&translatedLanguage=${language}`; - PostData(uri); -} - -function StartJob(jobId){ - var uri = `${apiUri}/Jobs/StartNow?jobId=${jobId}`; - PostData(uri); -} - -function UpdateDownloadLocation(downloadLocation){ - var uri = `${apiUri}/Settings/UpdateDownloadLocation?downloadLocation=${downloadLocation}`; - PostData(uri); -} - -function RefreshLibraryMetadata() { - var uri = `${apiUri}/Jobs/UpdateMetadata`; - PostData(uri); -} - -async function DownloadLogs() { - var uri = `${apiUri}/LogFile`; - - //Below taken from https://developer.mozilla.org/en-US/docs/Web/API/ReadableStream - fetch(uri) - .then((response) => response.body) - .then((rb) => { - const reader = rb.getReader(); - - return new ReadableStream({ - start(controller) { - // The following function handles each data chunk - function push() { - // "done" is a Boolean and value a "Uint8Array" - reader.read().then(({ done, value }) => { - // If there is no more data to read - if (done) { - console.log("done", done); - controller.close(); - return; - } - // Get the data and send it to the browser via the controller - controller.enqueue(value); - // Check chunks by logging to the console - console.log(done, value); - push(); - }); - } - - push(); - }, - }); - }) - .then((stream) => - // Respond with our stream - new Response(stream, { headers: { "Content-Type": "text/html" } }).text(), - ) - .then((result) => { - // Do things with result - //console.log(result); - - //Below download taken from https://stackoverflow.com/questions/3665115/how-to-create-a-file-in-memory-for-user-to-download-but-not-through-server - var element = document.createElement('a'); - element.setAttribute('href', 'data:text/plain;charset-utf-8,' + encodeURIComponent(result)); - var newDate = new Date(); - var filename = "Tranga_Logs_" + newDate.today() + "_" + newDate.timeNow() + ".log"; - element.setAttribute('download', filename); - element.click(); - }); -} - -//Following date-time code taken from: https://stackoverflow.com/questions/10211145/getting-current-date-and-time-in-javascript -// For todays date; -Date.prototype.today = function () { - return ((this.getDate() < 10)?"0":"") + this.getDate() +"/"+(((this.getMonth()+1) < 10)?"0":"") + (this.getMonth()+1) +"/"+ this.getFullYear(); -} - -// For the time now -Date.prototype.timeNow = function () { - return ((this.getHours() < 10)?"0":"") + this.getHours() +"_"+ ((this.getMinutes() < 10)?"0":"") + this.getMinutes() +"_"+ ((this.getSeconds() < 10)?"0":"") + this.getSeconds(); -} - -//Komga -function UpdateKomga(komgaUrl, komgaAuth){ - var uri = `${apiUri}/LibraryConnectors/Update?libraryConnector=Komga&komgaUrl=${komgaUrl}&komgaAuth=${komgaAuth}`; - PostData(uri); -} - -function ResetKomga(){ - var uri = `${apiUri}/LibraryConnectors/Reset?libraryConnector=Komga`; - PostData(uri); -} - -function TestKomga(komgaUrl, komgaAuth){ - var uri = `${apiUri}/LibraryConnectors/Test?libraryConnector=Komga&komgaUrl=${komgaUrl}&komgaAuth=${komgaAuth}`; - PostData(uri); -} - - -//Kavita -function UpdateKavita(kavitaUrl, kavitaUsername, kavitaPassword){ - var uri = `${apiUri}/LibraryConnectors/Update?libraryConnector=Kavita&kavitaUrl=${kavitaUrl}&kavitaUsername=${kavitaUsername}&kavitaPassword=${kavitaPassword}`; - PostData(uri); -} - -function ResetKavita(){ - var uri = `${apiUri}/LibraryConnectors/Reset?libraryConnector=Kavita`; - PostData(uri); -} - -function TestKavita(kavitaUrl, kavitaUsername, kavitaPassword){ - var uri = `${apiUri}/LibraryConnectors/Test?libraryConnector=Kavita&kavitaUrl=${kavitaUrl}&kavitaUsername=${kavitaUsername}&kavitaPassword=${kavitaPassword}`; - PostData(uri); -} - -//Gotify -function UpdateGotify(gotifyUrl, gotifyAppToken){ - var uri = `${apiUri}/NotificationConnectors/Update?notificationConnector=Gotify&gotifyUrl=${gotifyUrl}&gotifyAppToken=${gotifyAppToken}`; - PostData(uri); -} - -function ResetGotify(){ - var uri = `${apiUri}/NotificationConnectors/Reset?notificationConnector=Gotify`; - PostData(uri); -} - -function TestGotify(gotifyUrl, gotifyAppToken){ - var uri = `${apiUri}/NotificationConnectors/Test?notificationConnector=Gotify&gotifyUrl=${gotifyUrl}&gotifyAppToken=${gotifyAppToken}`; - PostData(uri); -} - -//LunaSea -function UpdateLunaSea(lunaseaWebhook){ - var uri = `${apiUri}/NotificationConnectors/Update?notificationConnector=LunaSea&lunaseaWebhook=${lunaseaWebhook}`; - PostData(uri); -} - -function ResetLunaSea(){ - var uri = `${apiUri}/NotificationConnectors/Reset?notificationConnector=LunaSea`; - PostData(uri); -} - -function TestLunaSea(lunaseaWebhook){ - var uri = `${apiUri}/NotificationConnectors/Test?notificationConnector=LunaSea&lunaseaWebhook=${lunaseaWebhook}`; - PostData(uri); -} - -//Ntfy -function UpdateNtfy(ntfyEndpoint, ntfyAuth){ - var uri = `${apiUri}/NotificationConnectors/Update?notificationConnector=Ntfy&ntfyUrl=${ntfyEndpoint}&ntfyAuth=${ntfyAuth}`; - PostData(uri); -} - -function ResetNtfy(){ - var uri = `${apiUri}/NotificationConnectors/Reset?notificationConnector=Ntfy`; - PostData(uri); -} - -function TestNtfy(ntfyEndpoint, ntfyAuth){ - var uri = `${apiUri}/NotificationConnectors/Test?notificationConnector=Ntfy&ntfyUrl=${ntfyEndpoint}&ntfyAuth=${ntfyAuth}`; - PostData(uri); -} - -function UpdateUserAgent(userAgent){ - var uri = `${apiUri}/Settings/userAgent?userAgent=${userAgent}`; - PostData(uri); -} - -function UpdateRateLimit(byteValue, rateLimit) { - var uri = `${apiUri}/Settings/customRequestLimit?requestType=${byteValue}&requestsPerMinute=${rateLimit}`; - PostData(uri); -} - -function RemoveJob(jobId){ - var uri = `${apiUri}/Jobs?jobId=${jobId}`; - DeleteData(uri); -} - -function CancelJob(jobId){ - var uri = `${apiUri}/Jobs/Cancel?jobId=${jobId}`; - PostData(uri); -} - -async function GetLogmessages(count){ - var uri = `${apiUri}/LogMessages?count=${count}`; - let json = await GetData(uri); - console.log(json); - return json; -} \ No newline at end of file diff --git a/Website/favicon.ico b/Website/favicon.ico deleted file mode 100644 index ffb44eb..0000000 Binary files a/Website/favicon.ico and /dev/null differ diff --git a/Website/index.html b/Website/index.html deleted file mode 100644 index 1bb8c4c..0000000 --- a/Website/index.html +++ /dev/null @@ -1,301 +0,0 @@ - - - - - Tranga - - - - - - - - - - website image is Blahaj - Tranga - - - filterFunnel - settingscog - - - - - Filter by: - × - - - - - - - Clear Filter - - - - -
- -
-

Check your Settings > API-URI

-
- -
-

+

-
- - cover - - Sample - Best Manga there is - - -
- - - -
- - -
-
-
- - - - - - Settings - × - - - - - - - - - - - - - -
- Apply Settings -
-
- -
-
- - - - - cover - - Best Manga there is - A Manga - Glax - - An interesting description. The description is very intriguing, yet wholesome. - - - Start Job ▶️ - Cancel Job ❌ - Delete Job 🗑️ - Monitor ➕ - Download Chapter 📥 - - - - - - - - - - Jobs - × - - - - - - - - - - - - - - -
- - -
- - - - - \ No newline at end of file diff --git a/Website/interaction.js b/Website/interaction.js deleted file mode 100644 index 889ade9..0000000 --- a/Website/interaction.js +++ /dev/null @@ -1,885 +0,0 @@ -let monitoringJobsCount = 0; -let runningJobs = []; -let waitingJobs = []; -let notificationConnectorTypes = []; -let libraryConnectorTypes = []; -let selectedManga; -let selectedJob; -let searchMatch; - -let connectorMatch = []; -let connectorNameMatch; -let statusMatch = []; -let statusNameMatch = []; - -const searchBox = document.querySelector("#searchbox"); -const settingsPopup = document.querySelector("#settingsPopup"); -const filterBox = document.querySelector("#filterBox"); -const settingsCog = document.querySelector("#settingscog"); -const filterFunnel = document.querySelector("#filterFunnel"); -const tasksContent = document.querySelector("content"); -const createMonitorTaskButton = document.querySelector("#createMonitoJobButton"); -const createDownloadChapterTaskButton = document.querySelector("#createDownloadChapterJobButton"); -const startJobButton = document.querySelector("#startJobButton"); -const cancelJobButton = document.querySelector("#cancelJobButton"); -const deleteJobButton = document.querySelector("#deleteJobButton"); - -//Manga viewer popup -const mangaViewerPopup = document.querySelector("#publicationViewerPopup"); -const mangaViewerWindow = document.querySelector("publication-viewer"); -const mangaViewerDescription = document.querySelector("#publicationViewerDescription"); -const mangaViewerName = document.querySelector("#publicationViewerName"); -const mangaViewerTags = document.querySelector("#publicationViewerTags"); -const mangaViewerAuthor = document.querySelector("#publicationViewerAuthor"); -const mangaViewCover = document.querySelector("#pubviewcover"); - -//General Rate Limits -const defaultRL = document.querySelector("#defaultRL"); -const coverRL = document.querySelector("#coverRL"); -const imageRL = document.querySelector("#imageRL"); -const infoRL = document.querySelector("#infoRL"); - -//MangaDex Rate Limits -const mDexAuthorRL = document.querySelector("#mDexAuthorRL"); -const mDexFeedRL = document.querySelector("#mDexFeedRL"); -const mDexImageRL = document.querySelector("#mDexImageRL"); - -//Komga -const settingKomgaUrl = document.querySelector("#komgaUrl"); -const settingKomgaUser = document.querySelector("#komgaUsername"); -const settingKomgaPass = document.querySelector("#komgaPassword"); - -//Kavita -const settingKavitaUrl = document.querySelector("#kavitaUrl"); -const settingKavitaUser = document.querySelector("#kavitaUsername"); -const settingKavitaPass = document.querySelector("#kavitaPassword"); - -//Gotify -const settingGotifyUrl = document.querySelector("#gotifyUrl"); -const settingGotifyAppToken = document.querySelector("#gotifyAppToken"); - -//Lunasea -const settingLunaseaWebhook = document.querySelector("#lunaseaWebhook"); - -//Ntfy -const settingNtfyEndpoint = document.querySelector("#ntfyEndpoint"); -const settingNtfyAuth = document.querySelector("#ntfyAuth"); - -//Connector Configured -const settingKomgaConfigured = document.querySelector("#komgaConfigured"); -const settingKavitaConfigured = document.querySelector("#kavitaConfigured"); -const settingGotifyConfigured = document.querySelector("#gotifyConfigured"); -const settingLunaseaConfigured = document.querySelector("#lunaseaConfigured"); -const settingNtfyConfigured = document.querySelector("#ntfyConfigured"); - -const settingUserAgent = document.querySelector("#userAgent"); -const settingApiUri = document.querySelector("#settingApiUri"); -const settingCSSStyle = document.querySelector('#cssStyle'); -const newMangaPopup = document.querySelector("#newMangaPopup"); -const newMangaConnector = document.querySelector("#newMangaConnector"); -const newMangaTitle = document.querySelector("#newMangaTitle"); -const newMangaResult = document.querySelector("#newMangaResult"); -const newMangaTranslatedLanguage = document.querySelector("#newMangaTranslatedLanguage"); - -//Jobs -const jobsRunningTag = document.querySelector("#jobsRunningTag"); -const jobsQueuedTag = document.querySelector("#jobsQueuedTag"); -const loaderdiv = document.querySelector('#loaderdiv'); -const jobStatusView = document.querySelector("#jobStatusView"); -const jobStatusRunning = document.querySelector("#jobStatusRunning"); -const jobStatusWaiting = document.querySelector("#jobStatusWaiting"); - -function Setup(){ - Ping().then((ret) => { - loaderdiv.style.display = 'none'; - - GetAvailableNotificationConnectors().then((json) => { - //console.log(json); - json.forEach(connector => { - notificationConnectorTypes[connector.Key] = connector.Value; - }); - }); - - GetAvailableLibraryConnectors().then((json) => { - //console.log(json); - json.forEach(connector => { - libraryConnectorTypes[connector.Key] = connector.Value; - }); - }); - - GetAvailableControllers().then((json) => { - //console.log(json); - newMangaConnector.replaceChildren(); - connectorFilterBox = document.querySelector("#connectorFilterBox"); - connectorFilterBox.replaceChildren(); - json.forEach(connector => { - //Add the connector to the New Manga dropdown - var option = document.createElement('option'); - option.value = connector; - option.innerText = connector; - newMangaConnector.appendChild(option); - - //Add the connector to the filter box - connectorFilter = document.createElement('connector-name'); - connectorFilter.innerText = connector; - connectorFilter.className = "pill"; - connectorFilter.style.backgroundColor = stringToColour(connector); - - connectorFilter.addEventListener("click", (event) => { - ToggleFilterConnector(connector, event); - }); - connectorFilterBox.appendChild(connectorFilter); - }); - }); - - //Add the publication status options to the filter bar - publicationStatusOptions = ["Ongoing", "Completed", "On Hiatus", "Cancelled", "Upcoming", "Status Unavailable"]; - statusFilterBox = document.querySelector("#statusFilterBox"); - statusFilterBox.replaceChildren(); - publicationStatusOptions.forEach(publicationStatus => { - var releaseStatus = document.createElement('status-filter'); - releaseStatus.innerText = publicationStatus; - releaseStatus.setAttribute("release-status", publicationStatus); - releaseStatus.addEventListener("click", (event) => { - ToggleFilterStatus(publicationStatus, event); - }); - - statusFilterBox.appendChild(releaseStatus); - }); - - ResetContent(); - UpdateJobs(); - GetSettings().then((json) => { - //console.log(json); - settingApiUri.placeholder = apiUri; - }); - GetRateLimits().then((json) => { - defaultRL.placeholder = json.Default + ' Requests/Minute'; - coverRL.placeholder = json.MangaCover + ' Requests/Minute'; - imageRL.placeholder = json.MangaImage + ' Requests/Minute'; - infoRL.placeholder = json.MangaInfo + ' Requests/Minute'; - mDexAuthorRL.placeholder = json.MangaDexAuthor + ' Requests/Minute'; - mDexFeedRL.placeholder = json.MangaDexFeed + ' Requests/Minute'; - mDexImageRL.placeholder = json.MangaDexImage + ' Requests/Minute'; - }); - - //If the cssStyle key isn't in the local storage of the browser, then set the css style to the default and load the page - //Otherwise get the style key from storage and set it. - if (!localStorage.getItem('cssStyle')) { - localStorage.setItem('cssStyle', 'card_compact'); - document.getElementById('librarystyle').setAttribute('href', 'styles/' + localStorage.getItem('cssStyle') + '.css'); - document.getElementById('card_compact').selected = true; - } else { - css_style = localStorage.getItem('cssStyle'); - document.getElementById('librarystyle').setAttribute('href', 'styles/' + css_style + '.css'); - document.getElementById(css_style).selected = true; - } - setInterval(() => { - UpdateJobs(); - }, 1000); - }); - //Clear the previous values if any exist. - searchBox.value = ""; - connectorMatch.length = 0; - statusMatch.length = 0; -} -Setup(); - -function ToggleFilterConnector(connector, event) { - //console.log("Initial Array:"); - //console.log(connectorMatch); - if (connectorMatch.includes(connector)) { - idx = connectorMatch.indexOf(connector); - connectorMatch.splice(idx, 1); - event.target.style.outline = 'none'; - event.target.style.outlineOffset = "0px"; - } else { - connectorMatch.push(connector); - event.target.style.outline = '4px solid var(--secondary-color)'; - event.target.style.outlineOffset = '3px'; - } - //console.log("Final Array"); - //console.log(connectorMatch); - FilterResults(); -} - -function ToggleFilterStatus(status, event) { - //console.log("Initial Array:"); - //console.log(statusMatch); - if (statusMatch.includes(status)) { - idx = statusMatch.indexOf(status); - statusMatch.splice(idx, 1); - event.target.style.outline = 'none'; - event.target.style.outlineOffset = "0px"; - } else { - statusMatch.push(status); - event.target.style.outline = '4px solid var(--secondary-color)'; - event.target.style.outlineOffset = '3px'; - } - //console.log("Final Array"); - //console.log(statusMatch); - FilterResults(); -} - -function ClearFilter() { - searchBox.value = ""; - statusMatch.length = 0; - connectorMatch.length = 0; - FilterResults(); - - //Get rid of the outlines - connectorFilterBox = document.querySelector("#connectorFilterBox"); - connectorFilterBox.childNodes.forEach(connector => { - if (connector.nodeName.toLowerCase() == 'connector-name') { - connector.style.outline = 'none'; - connector.style.outlineOffset = "0px"; - } - }); - - statusFilterBox = document.querySelector("#statusFilterBox"); - statusFilterBox.childNodes.forEach(publicationStatus => { - if (publicationStatus.nodeName.toLowerCase() == 'status-filter') { - publicationStatus.style.outline = 'none'; - publicationStatus.style.outlineOffset = "0px"; - } - }); -} - -settingCSSStyle.addEventListener("change", (event) => { - localStorage.setItem('cssStyle', settingCSSStyle.value); - document.getElementById('librarystyle').setAttribute('href', 'styles/' + localStorage.getItem('cssStyle') + '.css'); -}); - -function ResetContent(){ - //Delete everything - tasksContent.replaceChildren(); - - //Add "Add new Task" Button - var add = document.createElement("div"); - add.setAttribute("id", "addPublication") - var plus = document.createElement("p"); - plus.innerText = "+"; - add.appendChild(plus); - add.addEventListener("click", () => ShowNewMangaSearch()); - tasksContent.appendChild(add); - - //Populate with the monitored mangas - GetMonitorJobs().then((json) => { - //console.log(json); - json.forEach(job => { - var mangaView = CreateManga(job.manga, job.mangaConnector.name); - mangaView.addEventListener("click", (event) => { - ShowMangaWindow(job, job.manga, event, false); - }); - tasksContent.appendChild(mangaView); - }); - monitoringJobsCount = json.length; - }); -} - -function ShowNewMangaSearch(){ - newMangaTitle.value = ""; - newMangaPopup.style.display = "block"; - newMangaResult.replaceChildren(); -} - -newMangaTitle.addEventListener("keypress", (event) => { if(event.key === "Enter") GetNewMangaItems();}); - - - - -function GetNewMangaItems(){ - if(newMangaTitle.value.length < 4) - return; - - newMangaResult.replaceChildren(); - newMangaConnector.disabled = true; - newMangaTitle.disabled = true; - newMangaTranslatedLanguage.disabled = true; - GetPublicationFromConnector(newMangaConnector.value, newMangaTitle.value).then((json) => { - //console.log(json); - if(json.length > 0) - newMangaResult.style.display = "flex"; - json.forEach(result => { - var mangaElement = CreateManga(result, newMangaConnector.value) - newMangaResult.appendChild(mangaElement); - mangaElement.addEventListener("click", (event) => { - ShowMangaWindow(null, result, event, true); - }); - }); - - newMangaConnector.disabled = false; - newMangaTitle.disabled = false; - newMangaTranslatedLanguage.disabled = false; - }); -} - -//Returns a new "Publication" Item to display in the jobs section -function CreateManga(manga, connector){ - //Create a new publication and set an internal ID - var mangaElement = document.createElement('publication'); - mangaElement.id = GetValidSelector(manga.internalId); - - //Append the cover image to the publication - var mangaImage = document.createElement('img'); - mangaImage.src = GetCoverUrl(manga.internalId); - mangaElement.appendChild(mangaImage); - -//Append the publication information to the publication - //console.log(manga); - var info = document.createElement('publication-information'); - var connectorName = document.createElement('connector-name'); - connectorName.innerText = connector; - connectorName.className = "pill"; - connectorName.style.backgroundColor = stringToColour(connector); - info.appendChild(connectorName); - - var mangaName = document.createElement('publication-name'); - mangaName.innerText = manga.sortName; - - //Create the publication status indicator - var releaseStatus = document.createElement('publication-status'); - releaseStatus.setAttribute("release-status", manga.releaseStatus); - switch(manga.releaseStatus){ - case 0: - releaseStatus.setAttribute("release-status", "Ongoing"); - break; - case 1: - releaseStatus.setAttribute("release-status", "Completed"); - break; - case 2: - releaseStatus.setAttribute("release-status", "On Hiatus"); - break; - case 3: - releaseStatus.setAttribute("release-status", "Cancelled"); - break; - case 4: - releaseStatus.setAttribute("release-status", "Upcoming"); - break; - default: - releaseStatus.setAttribute("release-status", "Status Unavailable"); - break; - } - - info.appendChild(mangaName); - mangaElement.appendChild(info); - mangaElement.appendChild(releaseStatus); //Append the release status indicator to the publication element - return mangaElement; -} - -createMonitorJobButton.addEventListener("click", () => { - CreateMonitorJob(newMangaConnector.value, selectedManga.internalId, newMangaTranslatedLanguage.value); - UpdateJobs(); - mangaViewerPopup.style.display = "none"; -}); -startJobButton.addEventListener("click", () => { - StartJob(selectedJob.id); - mangaViewerPopup.style.display = "none"; -}); -cancelJobButton.addEventListener("click", () => { - CancelJob(selectedJob.id); - mangaViewerPopup.style.display = "none"; -}); -deleteJobButton.addEventListener("click", () => { - RemoveJob(selectedJob.id); - UpdateJobs(); - mangaViewerPopup.style.display = "none"; -}); - -function ShowMangaWindow(job, manga, event, add){ - selectedManga = manga; - selectedJob = job; - //Show popup - mangaViewerPopup.style.display = "block"; - - //Set position to mouse-position - if(event.clientY < window.innerHeight - mangaViewerWindow.offsetHeight) - mangaViewerWindow.style.top = `${event.clientY}px`; - else - mangaViewerWindow.style.top = `${event.clientY - mangaViewerWindow.offsetHeight}px`; - - if(event.clientX < window.innerWidth - mangaViewerWindow.offsetWidth) - mangaViewerWindow.style.left = `${event.clientX}px`; - else - mangaViewerWindow.style.left = `${event.clientX - mangaViewerWindow.offsetWidth}px`; - - //Edit information inside the window - mangaViewerName.innerText = manga.sortName; - mangaViewerTags.innerText = manga.tags.join(", "); - mangaViewerDescription.innerText = manga.description; - mangaViewerAuthor.innerText = manga.authors.join(','); - mangaViewCover.src = GetCoverUrl(manga.internalId); - toEditId = manga.internalId; - - //Check what action should be listed - if(add){ - createMonitorJobButton.style.display = "initial"; - createDownloadChapterJobButton.style.display = "none"; - cancelJobButton.style.display = "none"; - startJobButton.style.display = "none"; - deleteJobButton.style.display = "none"; - } - else{ - createMonitorJobButton.style.display = "none"; - createDownloadChapterJobButton.style.display = "none"; - cancelJobButton.style.display = "initial"; - startJobButton.style.display = "initial"; - deleteJobButton.style.display = "initial"; - } -} - -function HidePublicationPopup(){ - publicationViewerPopup.style.display = "none"; -} - -searchBox.addEventListener("keyup", () => FilterResults()); -//Filter shown jobs -function FilterResults(){ - //For each publication - tasksContent.childNodes.forEach(publication => { - //If the search box isn't empty check that the title contains the searchbox content. If it does then - //'searchMatch' is true and the manga is shown. If the search box is empty, then consider this field - //to be true anyways. - if (searchBox.value.length > 0) { - publication.childNodes.forEach(item => { - if (item.nodeName.toLowerCase() == "publication-information"){ - item.childNodes.forEach(information => { - if (information.nodeName.toLowerCase() == "publication-name") { - if (information.textContent.toLowerCase().includes(searchBox.value.toLowerCase())){ - searchMatch = 1; - } else { - searchMatch = 0; - } - } - }); - } - }); - } else { - searchMatch = 1; - } - - //If the array connectorMatch isn't empty then check that the connector matches one of the ones - //in the array - if (connectorMatch.length > 0) { - publication.childNodes.forEach(item => { - if (item.nodeName.toLowerCase() == "publication-information"){ - item.childNodes.forEach(information => { - if (information.nodeName.toLowerCase() == "connector-name") { - if (connectorMatch.includes(information.textContent)){ - connectorNameMatch = 1; - } else { - connectorNameMatch = 0; - } - } - }); - } - }); - } else { - connectorNameMatch = 1; - } - - //If the array statusMatch isn't empty then check that the status matches one of the ones - //in the array - if (statusMatch.length > 0) { - publication.childNodes.forEach(item => { - if (item.nodeName.toLowerCase() == "publication-status"){ - if (statusMatch.includes(item.getAttribute('release-status'))) { - statusNameMatch = 1; - } else { - statusNameMatch = 0; - } - } - }); - } else { - statusNameMatch = 1; - } - - //If all of the filtering conditions are met then show the manga, otherwise hide it. - if (searchMatch && connectorNameMatch && statusNameMatch) { - publication.style.display = 'initial'; - } else { - publication.style.display = 'none'; - } - }); -} - -settingsCog.addEventListener("click", () => { - OpenSettings(); - settingsPopup.style.display = "flex"; -}); - -filterFunnel.addEventListener("click", () => { - filterBox.classList.toggle("animate"); -}); - -settingKomgaUrl.addEventListener("keypress", (event) => { if(event.key === "Enter") UpdateSettings(); }); -settingKomgaUser.addEventListener("keypress", (event) => { if(event.key === "Enter") UpdateSettings(); }); -settingKomgaPass.addEventListener("keypress", (event) => { if(event.key === "Enter") UpdateSettings(); }); -settingKavitaUrl.addEventListener("keypress", (event) => { if(event.key === "Enter") UpdateSettings(); }); -settingKavitaUser.addEventListener("keypress", (event) => { if(event.key === "Enter") UpdateSettings(); }); -settingKavitaPass.addEventListener("keypress", (event) => { if(event.key === "Enter") UpdateSettings(); }); -settingGotifyUrl.addEventListener("keypress", (event) => { if(event.key === "Enter") UpdateSettings(); }); -settingGotifyAppToken.addEventListener("keypress", (event) => { if(event.key === "Enter") UpdateSettings(); }); -settingLunaseaWebhook.addEventListener("keypress", (event) => { if(event.key === "Enter") UpdateSettings(); }); -settingNtfyEndpoint.addEventListener("keypress", (event) => { if(event.key === "Enter") UpdateSettings(); }); -settingNtfyAuth.addEventListener("keypress", (event) => { if(event.key === "Enter") UpdateSettings(); }); -settingUserAgent.addEventListener("keypress", (event) => { if(event.key === "Enter") UpdateSettings(); }); -settingApiUri.addEventListener("keypress", (event) => { if(event.key === "Enter") UpdateSettings(); }); - -defaultRL.addEventListener("keypress", (event) => { if(event.key === "Enter") UpdateSettings();}); -coverRL.addEventListener("keypress", (event) => { if(event.key === "Enter") UpdateSettings();}); -imageRL.addEventListener("keypress", (event) => { if(event.key === "Enter") UpdateSettings();}); -infoRL.addEventListener("keypress", (event) => { if(event.key === "Enter") UpdateSettings();}); -mDexAuthorRL.addEventListener("keypress", (event) => { if(event.key === "Enter") UpdateSettings();}); -mDexFeedRL.addEventListener("keypress", (event) => { if(event.key === "Enter") UpdateSettings();}); -mDexImageRL.addEventListener("keypress", (event) => { if(event.key === "Enter") UpdateSettings();}); - - -function OpenSettings(){ - settingGotifyConfigured.setAttribute("configuration", "Not Configured"); - settingLunaseaConfigured.setAttribute("configuration", "Not Configured"); - settingNtfyConfigured.setAttribute("configuration", "Not Configured"); - settingKavitaConfigured.setAttribute("configuration", "Not Configured"); - settingKomgaConfigured.setAttribute("configuration", "Not Configured"); - settingKomgaUrl.value = ""; - settingKomgaUser.value = ""; - settingKomgaPass.value = ""; - settingKavitaUrl.value = ""; - settingKavitaUser.value = ""; - settingKavitaPass.value = ""; - settingGotifyUrl.value = ""; - settingGotifyAppToken.value = ""; - settingLunaseaWebhook.value = ""; - settingNtfyAuth.value = ""; - settingNtfyEndpoint.value = ""; - settingUserAgent.value = ""; - settingApiUri.value = ""; - defaultRL.value = ""; - coverRL.value = ""; - imageRL.value = ""; - infoRL.value = ""; - mDexAuthorRL.value = ""; - mDexFeedRL.value = ""; - mDexImageRL.value = ""; - - GetSettings().then((json) => { - //console.log(json); - settingApiUri.value = apiUri; - settingUserAgent.value = json.userAgent; - //console.log(json.styleSheet); - }); - GetRateLimits().then((json) => { - defaultRL.placeholder = json.Default + ' Requests/Minute'; - coverRL.placeholder = json.MangaCover + ' Requests/Minute'; - imageRL.placeholder = json.MangaImage + ' Requests/Minute'; - infoRL.placeholder = json.MangaInfo + ' Requests/Minute'; - mDexAuthorRL.placeholder = json.MangaDexAuthor + ' Requests/Minute'; - mDexFeedRL.placeholder = json.MangaDexFeed + ' Requests/Minute'; - mDexImageRL.placeholder = json.MangaDexImage + ' Requests/Minute'; - }); - GetLibraryConnectors().then((json) => { - //console.log(json); - json.forEach(connector => { - switch(libraryConnectorTypes[connector.libraryType]){ - case "Kavita": - settingKavitaConfigured.setAttribute("configuration", "Active"); - settingKavitaUrl.value = connector.baseUrl; - settingKavitaUser.value = "***"; - settingKavitaPass.value = "***"; - break; - case "Komga": - settingKomgaConfigured.setAttribute("configuration", "Active"); - settingKomgaUrl.value = connector.baseUrl; - settingKomgaUser.value = "***"; - settingKomgaPass.value = "***"; - break; - default: - console.log("Unknown type"); - console.log(connector); - break; - } - }); - }); - GetNotificationConnectors().then((json) => { - json.forEach(connector => { - switch(notificationConnectorTypes[connector.notificationConnectorType]){ - case "Gotify": - settingGotifyUrl.value = connector.endpoint; - settingGotifyAppToken.value = "***"; - settingGotifyConfigured.setAttribute("configuration", "Active"); - break; - case "LunaSea": - settingLunaseaConfigured.setAttribute("configuration", "Active"); - settingLunaseaWebhook.value = connector.id; - break; - case "Ntfy": - settingNtfyConfigured.setAttribute("configuration", "Active"); - settingNtfyEndpoint.value = connector.endpoint; - settingNtfyAuth.value = "***"; - break; - default: - console.log("Unknown type"); - console.log(connector); - break; - } - }); - }); -} - -//Functions for clearing/resetting connectors in the settings pop-up -function ClearKomga(){ - settingKomgaUrl.value = ""; - settingKomgaUser.value = ""; - settingKomgaPass.value = ""; - settingKomgaConfigured.setAttribute("configuration", "Not Configured"); - ResetKomga(); -} - -function ClearKavita(){ - settingKavitaUrl.value = ""; - settingKavitaUser.value = ""; - settingKavitaPass.value = ""; - settingKavitaConfigured.setAttribute("configuration", "Not Configured"); - ResetKavita(); -} - -function ClearGotify(){ - settingGotifyUrl.value = ""; - settingGotifyAppToken.value = "" - settingGotifyConfigured.setAttribute("configuration", "Not Configured"); - ResetGotify(); -} - -function ClearLunasea(){ - settingLunaseaWebhook.value = ""; - settingLunaseaConfigured.setAttribute("configuration", "Not Configured"); - ResetLunaSea(); -} - -function ClearNtfy(){ - settingNtfyEndpoint.value = ""; - settingNtfyAuth.value = ""; - settingNtfyConfigured.setAttribute("configuration", "Not Configured"); - ResetNtfy(); -} - -function UpdateSettings(){ - if(settingApiUri.value != ""){ - apiUri = settingApiUri.value; - setCookie("apiUri", apiUri); - Setup(); - } - - if(settingKomgaUrl.value != "" && - settingKomgaUser.value != "" && - settingKomgaPass.value != ""){ - UpdateKomga(settingKomgaUrl.value, utf8_to_b64(`${settingKomgaUser.value}:${settingKomgaPass.value}`)); - } - - if(settingKavitaUrl.value != "" && - settingKavitaUser.value != "" && - settingKavitaPass.value != ""){ - UpdateKavita(settingKavitaUrl.value, settingKavitaUser.value, settingKavitaPass.value); - } - - if(settingGotifyUrl.value != "" && - settingGotifyAppToken.value != ""){ - UpdateGotify(settingGotifyUrl.value, settingGotifyAppToken.value); - } - - if(settingLunaseaWebhook.value != ""){ - UpdateLunaSea(settingLunaseaWebhook.value); - } - - if(settingNtfyEndpoint.value != "" && - settingNtfyAuth.value != ""){ - UpdateNtfy(settingNtfyEndpoint.value, settingNtfyAuth.value); - } - - if(settingUserAgent.value != ""){ - UpdateUserAgent(settingUserAgent.value); - } - - if (defaultRL.value != "") { - UpdateRateLimit(0, defaultRL.value); - } - - if (coverRL.value != "") { - UpdateRateLimit(3, coverRL.value); - } - - if (imageRL.value != "") { - UpdateRateLimit(2, imageRL.value); - } - - if (infoRL.value != "") { - UpdateRateLimit(6, infoRL.value); - } - - if (mDexAuthorRL.value != "") { - UpdateRateLimit(5, mDexAuthorRL.value); - } - - if (mDexFeedRL.value != "") { - UpdateRateLimit(1, mDexFeedRL.value); - } - - if (mDexImageRL.value != "") { - UpdateRateLimit(5, mDexImageRL.value); - } - - setTimeout(() => { - OpenSettings(); - Setup(); - }, 100) -} - -function utf8_to_b64(str) { - return window.btoa(unescape(encodeURIComponent( str ))); -} - -function UpdateJobs(){ - - GetMonitorJobs().then((json) => { - if(monitoringJobsCount != json.length){ - ResetContent(); - monitoringJobsCount = json.length; - } - }); - - //Get the jobs that are waiting in the queue - GetWaitingJobs().then((json) => { - jobsQueuedTag.innerText = json.length; - - var nowWaitingJobs = []; - - json.forEach(job => { - if(!waitingJobs.includes(GetValidSelector(job.id))){ - var jobDom = createJob(job); - jobStatusWaiting.appendChild(jobDom); - } - nowWaitingJobs.push(GetValidSelector(job.id)); - }); - waitingJobs = nowWaitingJobs; - }); - - jobStatusWaiting.childNodes.forEach(child => { - if(!waitingJobs.includes(child.id)) - jobStatusWaiting.removeChild(child); - }); - - //Get currently running jobs - GetRunningJobs().then((json) => { - jobsRunningTag.innerText = json.length; - - var nowRunningJobs = []; - - json.forEach(job => { - if(!runningJobs.includes(GetValidSelector(job.id))){ - var jobDom = createJob(job); - jobStatusRunning.appendChild(jobDom); - } - nowRunningJobs.push(GetValidSelector(job.id)); - UpdateJobProgress(job.id); - }); - - runningJobs = nowRunningJobs; - }); - - jobStatusRunning.childNodes.forEach(child => { - if(!runningJobs.includes(child.id)) - jobStatusRunning.removeChild(child); - }); -} - -function createJob(jobjson){ - var manga; - if(jobjson.chapter != null) - manga = jobjson.chapter.parentManga; - else if(jobjson.manga != null) - manga = jobjson.manga; - else return null; - - - var wrapper = document.createElement("div"); - wrapper.className = "section-item"; - wrapper.id = GetValidSelector(jobjson.id); - - var image = document.createElement("img"); - image.className = "jobImage"; - image.src = GetCoverUrl(manga.internalId); - wrapper.appendChild(image); - - var details = document.createElement("div"); - details.className = 'jobDetails'; - - var title = document.createElement("span"); - title.className = "jobTitle"; - if(jobjson.chapter != null) - title.innerText = `${manga.sortName} - ${jobjson.chapter.fileName}`; - else if(jobjson.manga != null) - title.innerText = manga.sortName; - details.appendChild(title); - - var progressBar = document.createElement("progress"); - progressBar.className = "jobProgressBar"; - progressBar.id = `jobProgressBar${GetValidSelector(jobjson.id)}`; - details.appendChild(progressBar); - - var progressSpan = document.createElement("span"); - progressSpan.className = "jobProgressSpan"; - progressSpan.id = `jobProgressSpan${GetValidSelector(jobjson.id)}`; - progressSpan.innerText = "Pending..."; - details.appendChild(progressSpan); - - var cancelSpan = document.createElement("span"); - cancelSpan.className = "jobCancel"; - cancelSpan.innerText = "Cancel"; - cancelSpan.addEventListener("click", () => CancelJob(jobjson.id)); - details.appendChild(cancelSpan); - - wrapper.appendChild(details); - - return wrapper; -} - -function ShowJobQueue(){ - jobStatusView.style.display = "initial"; -} - -function UpdateJobProgress(jobId){ - GetProgress(jobId).then((json) => { - var progressBar = document.querySelector(`#jobProgressBar${GetValidSelector(jobId)}`); - var progressSpan = document.querySelector(`#jobProgressSpan${GetValidSelector(jobId)}`); - if(progressBar != null && json.progress != 0){ - progressBar.value = json.progress; - } - if(progressSpan != null){ - var percentageStr = "0%"; - var timeleftStr = "00:00:00"; - if(json.progress != 0){ - percentageStr = Intl.NumberFormat("en-US", { style: "percent"}).format(json.progress); - timeleftStr = json.timeRemaining.split('.')[0]; - } - progressSpan.innerText = `${percentageStr} ${timeleftStr}`; - } - }); -} - -function GetValidSelector(str){ - var clean = [...str.matchAll(/[a-zA-Z0-9]*-*_*/g)]; - return clean.join(''); -} - -const stringToColour = (str) => { - let hash = 0; - str.split('').forEach(char => { - hash = char.charCodeAt(0) + ((hash << 5) - hash) - }) - let colour = '#' - for (let i = 0; i < 3; i++) { - const value = (hash >> (i * 8)) & 0xff - colour += value.toString(16).padStart(2, '0') - } - return colour -} \ No newline at end of file diff --git a/Website/styles/base.css b/Website/styles/base.css deleted file mode 100644 index ee80fc5..0000000 --- a/Website/styles/base.css +++ /dev/null @@ -1,960 +0,0 @@ -:root{ - --background-color: #030304; - --second-background-color: white; - --primary-color: #f5a9b8; - --secondary-color: #5bcefa; - --blur-background: rgba(245, 169, 184, 0.58); - --accent-color: #fff; - /* --primary-color: green; - --secondary-color: gold; - --blur-background: rgba(86, 131, 36, 0.8); - --accent-color: olive; */ - --topbar-height: 60px; - box-sizing: border-box; -} - -body{ - padding: 0; - margin: 0; - height: 100vh; - background-color: var(--background-color); - font-family: "Inter", sans-serif; - overflow-x: hidden; -} - -wrapper { - display: flex; - flex-flow: column; - flex-wrap: nowrap; - height: 100vh; -} - -background-placeholder{ - background-color: var(--second-background-color); - opacity: 1; - position: absolute; - width: 100%; - height: 100%; - border-radius: 0 0 5px 0; - z-index: -1; -} - -topbar { - display: flex; - align-items: center; - height: var(--topbar-height); - background-color: var(--secondary-color); - z-index: 100; - box-shadow: 0 0 20px black; -} - -titlebox { - position: relative; - display: flex; - margin: 0 0 0 40px; - height: 100%; - align-items:center; - justify-content:center; -} - -titlebox span{ - cursor: default; - font-size: 24pt; - font-weight: bold; - background: linear-gradient(150deg, var(--primary-color), var(--accent-color)); - -webkit-background-clip: text; - -webkit-text-fill-color: transparent; - margin-left: 20px; -} - -titlebox img { - height: 100%; - cursor: grab; -} - -spacer{ - flex-grow: 1; -} - -filter-box { - display: none; - align-self: center; - flex-direction: column; - position: relative; - - margin: 10px; - background-color: var(--second-background-color); - border-style: solid; - border-color: var(--primary-color); - border-width: 2px; - border-radius: 15px; - min-width: 300px; - width: 50%; - overflow: hidden; - max-height: 50%; - height: 600px; -} - -filter-box.animate { - display: flex; -} - -filter-box border-bar popup-title{ - font-size: 12pt; -} - -filter-box border-bar popup-close { - height: 20px; - width: 20px; - font-size: 12pt; - -webkit-user-select: none; /* Safari */ - -ms-user-select: none; /* IE 10 and IE 11 */ - user-select: none; /* Standard syntax */ -} - -border-bar-button.clearFilter{ - font-weight: bold; - margin: 0px 10px 10px 10px; - border-color: lightgray; - color: gray; - align-content: center; - justify-content: center; -} - -border-bar-button.clearFilter:hover { - background-color: red; - border-color: var(--second-background-color); - color: var(--second-background-color); -} - -status-filter { - display: block; - margin: 10px; - - /*Text Properties*/ - font-size:10pt; - font-weight:bold; - color:white; - text-align: center; - - /*Size*/ - padding: 3px 8px; - border-radius: 6px; - border: 0px; - background-color: inherit; - - cursor: pointer; - -webkit-user-select: none; /* Safari */ - -ms-user-select: none; /* IE 10 and IE 11 */ - user-select: none; /* Standard syntax */ -} - -status-filter[release-status="Ongoing"]{ - background-color: limegreen; -} - -status-filter[release-status="Completed"]{ - background-color: blueviolet; -} - -status-filter[release-status="On Hiatus"]{ - background-color: darkorange; -} - -status-filter[release-status="Cancelled"]{ - background-color: firebrick; -} - -status-filter[release-status="Upcoming"]{ - background-color: aqua; -} - -status-filter[release-status="Status Unavailable"]{ - background-color: gray; -} - - -searchdiv{ - display: flex; - width: 100%; -} - -#searchbox { - display: flex; - padding: 3px 5px; - margin: 5px; - border-style: solid; - border-width: 2px; - border-radius: 10px; - font-size: 12pt; - outline: none; - border-color: lightgray; - flex-grow: 1; - flex-shrink: 1; -} - -#searchbox:focus { - border-color: var(--secondary-color); -} - -.pill { - flex-grow: 0; - height: 14pt; - font-size: 12pt; - border-radius: 9pt; - background-color: var(--primary-color); - padding: 2pt 17px; - color: black; -} - -#connectorFilterBox .pill { - margin: 10px; - cursor: pointer; - -webkit-user-select: none; /* Safari */ - -ms-user-select: none; /* IE 10 and IE 11 */ - user-select: none; /* Standard syntax */ -} - -#settingscog { - cursor: pointer; - margin: 0px 30px; - margin-left: 15px; - height: 50%; - filter: invert(100%) sepia(0%) saturate(7465%) hue-rotate(115deg) brightness(116%) contrast(101%); -} - -#filterFunnel { - cursor: pointer; - margin: 0px 15px; - height: 50%; - filter: invert(100%) sepia(0%) saturate(7465%) hue-rotate(115deg) brightness(116%) contrast(101%); -} - -viewport { - position: relative; - display: flex; - flex-flow: row; - flex-wrap: nowrap; - flex-grow: 1; - height: 100%; - overflow-y: scroll; - scrollbar-color: var(--accent-color) var(--primary-color); - scrollbar-width: thin; -} - -footer { - display: flex; - flex-direction: row; - flex-wrap: nowrap; - width: 100%; - height: 40px; - align-items: center; - justify-content: center; - background-color: var(--primary-color); - align-content: center; -} - -footer > div { - height: 100%; - margin: 0 30px; - display: flex; - flex-direction: row; - flex-wrap: nowrap; - align-items: center; - cursor: pointer; -} - -footer > div > *{ - height: 40%; - margin: 0 5px; -} - -#madeWith { - flex-grow: 1; - text-align: right; - margin-right: 20px; - cursor: url("media/blahaj.png"), grab; -} - -content { - position: relative; - flex-grow: 1; - border-radius: 5px; - display: flex; - flex-direction: row; - flex-wrap: wrap; - justify-content: start; - align-content: start; -} - -#settingsPopup{ - z-index: 300; -} - -popup{ - display: none; - width: 100%; - min-height: 100%; - top: 0; - left: 0; - position: fixed; - z-index: 2; - flex-direction: column; -} - -border-bar { - display: flex; - flex-direction: row; - background-color: var(--primary-color); - color: var(--accent-color); - font-weight: bolder; - padding: 7px 5px; - margin:0; - align-items: center; - position: relative; - width: 100%; -} - -popup-title { - font-size: 14pt; - display: flex; - margin-top: 3px; - margin-left: 5px; - color: var(--second-background-color); -} - -popup-close { - border: none; - background-color: inherit; - color: var(--second-background-color);; - font-weight: inherit; - font-size: 27px; - font-family: 'Trebuchet MS', 'Lucida Sans Unicode', 'Lucida Grande', 'Lucida Sans', Arial, sans-serif; - display: flex; - cursor: pointer; - margin-left: auto; - margin-right: 15px; - height: 32px; - width: 32px; - border-radius: 16px; - align-content: center; - justify-content: center; -} - -popup-close:hover { - background-color: var(--secondary-color); -} - -border-bar > .button-container { - display: flex; - flex-direction: row; - align-items: center; - flex-wrap: wrap; - margin-right: 0; - margin-left: auto; -} - -border-bar-button { - border-style: solid; - border-width: 2px; - background-color: inherit; - color: var(--second-background-color); - font-weight: inherit; - font-size: inherit; - font-family: inherit; - display: flex; - cursor: pointer; - margin: 0px 5px; - padding: 5px 20px; - border-radius: 20px; - height: 20px; - align-items: center; - border-color: var(--accent-color); - -webkit-user-select: none; /* Safari */ - -ms-user-select: none; /* IE 10 and IE 11 */ - user-select: none; /* Standard syntax */ -} - -border-bar-button:hover { - border-color: var(--secondary-color); -} - -border-bar-button.primary { - background-color: var(--secondary-color); - color: var(--accent-color); - border-color: var(--primary-color); - margin-right: 10px; -} - -border-bar-button.primary:hover { - border-color: var(--accent-color); -} - -border-bar-button.section { - font-weight: bold; - color: darkgray; - border-color: darkgray; - text-align: center; - padding: 5px; - flex-grow: 1; - justify-content: center; -} - -border-bar-button.section:hover { - color: var(--secondary-color); - border-color: var(--secondary-color); -} - - -popup popup-window { - position: absolute; - z-index: 3; - left: 10%; - top: 10%; - height: 80%; - width: 80%; - display: flex; - flex-direction: column; - background-color: var(--second-background-color); - border-radius: 15px; - overflow: hidden; -} - -popup#jobStatusView popup-window { - left: 20%; - top: 20%; - height: 60%; - width: 60%; -} - -popup-content{ - display: flex; - flex-direction: column; - align-items: left; - height: calc(100% - 60px); - overflow-y: auto; - overflow-x: hidden; - scrollbar-width: thin; - scrollbar-color: var(--secondary-color) var(--second-background-color); -} - -popup-content > .popup-section { - margin: 5px; - margin-bottom: 10px; - font-size: 10pt; - font-weight: 100; - display: block; - border-top-style: solid; - border-top-width: 1px; - border-top-color: lightgray; - width: calc(100%-10px); - padding: 10px; -} - -.section-content { - display: flex; - flex-direction: row; - width: 100%; - flex-wrap: wrap; -} - -.section-item { - display: flex; - flex-direction: column; - width: 22%; - min-width: 300px; - height: auto; - border-radius: 10px; - border-style: solid; - border-width: 1px; - border-color: lightgray; - margin: 7px; - padding: 5px; -} - -.section-item.dyn-height { - height: fit-content; -} - -.section-item > .title { - font-weight: bold; - vertical-align: bottom; - line-height: 32px; - font-size: 12pt; - width: 100%; -} - -a:link { - color: inherit; - text-decoration: none; -} - -a:visited { - color: inherit; - text-decoration: none; -} - -a:hover { - color: inherit; - text-decoration: underline solid var(--secondary-color) 3px; -} - -a:active { - color: inherit; - text-decoration: none; -} - -.section-item > .title > img { - width: auto; - height: 32px; - margin: 5px; - vertical-align: middle; - border-radius: 5px; -} - -.section-item > .title > connector-configured { - display:block; - height: 10px; - width: 10px; - border-radius: 50%; - margin: 5px; - float: right; - top: 5px; - right: 5px; -} - -.section-item > .title > connector-configured::after { - display: block; - content: attr(configuration); - float: right; - width: max-content; - width: -webkit-max-content; - width: -mox-max-content; - width: intrinsic; - - visibility: hidden; - - /*Text Properties*/ - font-size:8pt; - font-weight:bold; - color:white; - text-align: right; - - /*Size*/ - padding: 0px 8px; - border-radius: 6px; - border: 0px; - background-color: inherit; -} - -.section-item > .title > connector-configured:hover::after{ - visibility:visible; -} - -.section-item > .title > connector-configured[configuration="Active"] { - background-color: limegreen; -} - -.section-item > .title > connector-configured[configuration="Not Configured"] { - background-color: gray; -} - -.section-item > input { - margin: 2px; - padding: 5px; - height: 20px; - border-radius: 10px; - border-style: solid; - outline: none; -} -.section-item > input:focus { - border-color: var(--secondary-color); -} - -.section-item > row { - width: calc(100%-20px); - display: flex; - flex-direction: row; - align-items: center; - margin-left: 5px; - margin-bottom: 5px; -} - -.section-item > row > input { - margin-left: auto; - margin-right: 2px; - padding: 5px; - height: 20px; - border-radius: 10px; - border-style: solid; - outline: none; - flex-grow: 0; - text-align: end; - float: right; - width: 200px; -} -.section-item > row > input:focus { - border-color: var(--secondary-color); -} - -.section-item > row > select { - margin-left: auto; - margin-right: 2px; - padding: 2px; - height: 30px; - border-radius: 10px; - border-style: solid; - outline: none; - flex-grow: 0; - text-align: end; - float: right; - width: 200px; -} - -.section-item > row > select:focus { - border-color: var(--secondary-color); -} - -.section-buttons-container { - display: flex; - flex-direction: row; - align-items: center; - position: relative; - margin-left: auto; - margin-top: auto; - margin-bottom: 0; - margin-right: 0; -} - -.section-buttons-container > .section-button { - font-size: 12px; - padding: 3px 10px; - margin: 3px; - border-radius: 5px; - border-style: solid; - border-width: 1px; - border-color: lightgray; - font-weight: bold; - color: gray; - cursor: pointer; - -webkit-user-select: none; /* Safari */ - -ms-user-select: none; /* IE 10 and IE 11 */ - user-select: none; /* Standard syntax */ -} - -.section-button#reset:hover { - color: red; - border-color: red; -} -.section-buttons-container > .section-button:hover { - border-color: var(--secondary-color); - color: var(--secondary-color); -} - -#newMangaPopup > div { - z-index: 3; - position: relative; -} - -#newMangaPopup > #newMangaPopupSelector { - width: 600px; - height: 40px; - margin: 80px auto 0; -} - -#newMangaPopup > div > #newMangaConnector, #newMangaTitle, #newMangaTranslatedLanguage { - margin: 0; - display: inline-block; - height: 40px; -} - -#newMangaPopup #newMangaConnector { - width: 100px; - padding: 0 0 0 5px; - border-radius: 5px 0 0 5px; - border: 0; - border-right: 1px solid darkgray; -} - -#newMangaPopup #newMangaTitle{ - width: 445px; - padding: 0 5px 0 5px; - border: 0; -} - -#newMangaPopup #newMangaTranslatedLanguage { - width: 45px; - border-radius: 0 5px 5px 0; - border: 0; - border-left: 1px solid darkgray; - margin-left: -5px; -} - -#newMangaResult { - display: none; - flex-direction: row; - justify-content: flex-start; - margin: 5px auto 0; - border-radius: 5px; - padding: 5px; - width: min-content; - max-width: 98%; - max-height: 400px; - overflow-x: scroll; - overflow-y: hidden; -} - -blur-background { - width: 100%; - height: 100%; - position: absolute; - left: 0; - background: var(--blur-background); - box-shadow: 0 4px 30px rgba(0, 0, 0, 0.1); - backdrop-filter: blur(4.5px); - -webkit-backdrop-filter: blur(4.5px); -} - -#publicationViewerPopup{ - z-index: 5; -} - -publication-viewer{ - display: block; - width: 460px; - position: absolute; - top: 200px; - left: 400px; - background-color: var(--accent-color); - border-radius: 5px; - overflow: hidden; - padding: 15px; -} - -publication-viewer::after{ - content: ''; - position: absolute; - left: 0; top: 0; - border-radius: 5px; - width: 100%; - height: 100%; - background: rgba(0,0,0,0.8); - backdrop-filter: blur(3px); -} - -publication-viewer img { - position: absolute; - left: 0; - top: 0; - height: 100%; - width: 100%; - object-fit: cover; - border-radius: 5px; - z-index: 0; -} - -publication-viewer publication-details > * { - margin: 5px 0; -} - -publication-viewer publication-details publication-name { - width: initial; - overflow-x: scroll; - white-space: nowrap; - scrollbar-width: none; -} - -publication-viewer publication-details publication-tags::before { - content: "Tags"; - display: block; - font-weight: bolder; -} - -publication-viewer publication-details publication-tags { - overflow-x: scroll; - white-space: nowrap; - scrollbar-width: none; -} - -publication-viewer publication-details publication-author::before { - content: "Author: "; - font-weight: bolder; -} - -publication-viewer publication-details publication-description::before { - content: "Description"; - display: block; - font-weight: bolder; -} - -publication-viewer publication-details publication-description { - font-size: 12pt; - margin: 5px 0; - height: 145px; - overflow-x: scroll; -} - -publication-viewer publication-details publication-interactions { - display: flex; - flex-direction: row; - justify-content: end; - align-items: start; - width: 100%; -} - -publication-viewer publication-details publication-interactions > * { - margin: 0 10px; - font-size: 16pt; - cursor: pointer; -} - -publication-viewer publication-details publication-interactions publication-starttask { - color: var(--secondary-color); -} - -publication-viewer publication-details publication-interactions publication-delete { - color: red; -} - -publication-view publication-details publication-interactions publication-canceltask { - color: yellow; -} - -publication-viewer publication-details publication-interactions publication-add { - color: limegreen; -} - -footer-tag-popup { - display: none; - padding: 2px 4px; - position: fixed; - bottom: 58px; - left: 20px; - background-color: var(--second-background-color); - z-index: 8; - border-radius: 5px; - max-height: 400px; -} - -footer-tag-content{ - position: relative; - max-height: 400px; - display: flex; - flex-direction: column; - flex-wrap: nowrap; - overflow-y: scroll; -} - -footer-tag-content > * { - margin: 2px 5px; -} - -footer-tag-popup::before{ - content: ""; - width: 0; - height: 0; - position: absolute; - border-right: 10px solid var(--second-background-color); - border-left: 10px solid transparent; - border-top: 10px solid var(--second-background-color); - border-bottom: 10px solid transparent; - left: 0; - bottom: -17px; - border-radius: 0 0 0 5px; -} - -#loaderdiv { - position: absolute; - top: 0px; - left: 0px; - width: 100%; - height: 100%; - z-index: 200; -} - -#loader { - border: 16px solid transparent; - border-top: 16px solid var(--secondary-color); - border-bottom: 16px solid var(--primary-color); - border-radius: 50%; - width: 120px; - height: 120px; - animation: spin 2s linear infinite; - position: absolute; - left: calc(50% - 60px); - top: calc(50% - 120px); - z-index: 201; -} - -#loaderText { - position: relative; - margin: 0 auto; - top: calc(50% + 80px); - z-index: 201; - text-align: center; - color: var(--second-background-color); - font-size: 20pt; -} - -@keyframes spin { - 0% { transform: rotate(0deg); } - 100% { transform: rotate(360deg); } -} - -#jobStatusRunning > .section-item { - flex-direction: row; - height: 150px; - padding: 0; - overflow: hidden; -} - -#jobStatusWaiting > .section-item { - flex-direction: row; - height: 150px; - padding: 0; - overflow: hidden; -} - -.section-item > .jobImage { - height: 100%; - width: auto; - left: 0; - top: 0; - border-radius: 10px; -} - -.jobDetails { - display: flex; - flex-direction: column; - height: 100%; - width: 100%; -} - -.section-item > .jobDetails > .jobTitle { - margin: 5px; - font-size: 11pt; - font-weight: bold; - text-wrap: wrap; -} - -.section-item > .jobDetails > .jobProgressBar { - margin: 5px; - height: 10px; - border-radius: 7px; -} - -.section-item > .jobDetails > .jobProgressSpan { - margin: 5px; - margin-left: auto; - margin-right: 5px; -} - -.section-item > .jobDetails > .jobCancel { - margin-top: auto; - margin-bottom: 5px; - margin-left: auto; - margin-right: 5px; - font-size: 12pt; - color: var(--secondary-color); - cursor: pointer; -} \ No newline at end of file diff --git a/Website/styles/card_compact.css b/Website/styles/card_compact.css deleted file mode 100644 index 74a6648..0000000 --- a/Website/styles/card_compact.css +++ /dev/null @@ -1,159 +0,0 @@ -#addPublication { - cursor: pointer; - background-color: var(--secondary-color); - width: 180px; - height: 300px; - border-radius: 5px; - margin: 10px 10px; - padding: 15px 20px; - position: relative; -} - -#addPublication p{ - width: 100%; - text-align: center; - font-size: 150pt; - vertical-align: middle; - line-height: 300px; - margin: 0; - color: var(--accent-color); -} - -.pill { - flex-grow: 0; - height: 14pt; - font-size: 12pt; - border-radius: 9pt; - background-color: var(--primary-color); - padding: 2pt 17px; - color: black; -} - -publication{ - cursor: pointer; - background-color: var(--secondary-color); - width: 180px; - height: 300px; - border-radius: 5px; - margin: 10px 10px; - padding: 15px 19px; - position: relative; - flex-shrink: 0; -} - -publication::after{ - content: ''; - position: absolute; - left: 0; top: 0; - border-radius: 5px; - width: 100%; height: 100%; - background: linear-gradient(rgba(0,0,0,0.8), rgba(0, 0, 0, 0.7),rgba(0, 0, 0, 0.2)); -} - -publication-information { - display: flex; - flex-direction: column; - justify-content: start; -} - -publication-details { - display: flex; - flex-direction: column; - justify-content: start; -} - -publication-information * { - z-index: 1; - color: var(--accent-color); -} - -publication-details * { - z-index: 1; - color: var(--accent-color); -} - -connector-name{ - width: fit-content; - margin: 10px 0; -} - -publication-name{ - width: fit-content; - font-size: 16pt; - font-weight: bold; - color: white; -} - -publication-status { - display:block; - height: 10px; - width: 10px; - border-radius: 50%; - margin: 5px; - position: absolute; - top: 5px; - right: 5px; - z-index: 2; - box-shadow: rgba(0, 0, 0, 0.16) 0px 1px 10px, rgb(51, 51, 51) 0px 0px 10px 3px; -} - -publication-status::after { - content: attr(release-status); - position: absolute; - top: 0; - right: 0; - - visibility: hidden; - - /*Text Properties*/ - font-size:10pt; - font-weight:bold; - color:white; - text-align: center; - - /*Size*/ - padding: 3px 8px; - border-radius: 6px; - border: 0px; - background-color: inherit; -} - -publication-status:hover::after{ - visibility:visible; -} - - -publication-status[release-status="Ongoing"]{ - background-color: limegreen; -} - -publication-status[release-status="Completed"]{ - background-color: blueviolet; -} - -publication-status[release-status="On Hiatus"]{ - background-color: darkorange; -} - -publication-status[release-status="Cancelled"]{ - background-color: firebrick; -} - -publication-status[release-status="Upcoming"]{ - background-color: aqua; -} - -publication-status[release-status="Status Unavailable"]{ - background-color: gray; -} - -publication img { - position: absolute; - top: 0; - left: 0; - width: 100%; - height: 100%; - object-fit: cover; - z-index: 0; - border-radius: 5px; -} \ No newline at end of file diff --git a/Website/styles/card_hover.css b/Website/styles/card_hover.css deleted file mode 100644 index 6d830ed..0000000 --- a/Website/styles/card_hover.css +++ /dev/null @@ -1,172 +0,0 @@ -#addPublication { - cursor: pointer; - background-color: var(--secondary-color); - width: 180px; - height: 300px; - border-radius: 5px; - margin: 10px 10px; - padding: 15px 20px; - position: relative; -} - -#addPublication p{ - width: 100%; - text-align: center; - font-size: 150pt; - vertical-align: middle; - line-height: 300px; - margin: 0; - color: var(--accent-color); -} - -.pill { - flex-grow: 0; - height: 14pt; - font-size: 12pt; - border-radius: 9pt; - background-color: var(--primary-color); - padding: 2pt 17px; - color: black; -} - -publication{ - cursor: pointer; - background-color: var(--secondary-color); - width: 180px; - height: 300px; - border-radius: 5px; - margin: 10px 10px; - padding: 15px 19px; - position: relative; - flex-shrink: 0; -} - -publication:hover { - background-color: black; -} - -publication:hover::after{ - background: linear-gradient(rgba(0,0,0,0.8), rgba(0, 0, 0, 0.7),rgba(0, 0, 0, 0.2)); -} - -publication:hover > publication-information { - display: flex; - opacity:1; -} - -publication::after{ - content: ''; - position: absolute; - left: 0; top: 0; - border-radius: 5px; - width: 100%; height: 100%; - background: none; -} - -publication-information { - display: none; - flex-direction: column; - justify-content: start; -} - -publication-information * { - z-index: 1; - color: white; -} - -connector-name{ - width: fit-content; - margin: 10px 0; -} - -publication-name{ - width: fit-content; - font-size: 16pt; - font-weight: bold; -} - -publication-status { - display:block; - height: 10px; - width: 10px; - border-radius: 50%; - margin: 5px; - position: absolute; - top: 5px; - right: 5px; - z-index: 2; - box-shadow: rgba(0, 0, 0, 0.16) 0px 1px 10px, rgb(51, 51, 51) 0px 0px 10px 3px; -} - -publication-status::after { - content: attr(release-status); - position: absolute; - top: 0; - right: 0; - - visibility: hidden; - - /*Text Properties*/ - font-size:10pt; - font-weight:bold; - color:white; - text-align: center; - - /*Size*/ - padding: 3px 8px; - border-radius: 6px; - border: 0px; - background-color: inherit; -} - -publication-status:hover::after{ - visibility:visible; -} - - -publication-status[release-status="Ongoing"]{ - background-color: limegreen; -} - -publication-status[release-status="Completed"]{ - background-color: blueviolet; -} - -publication-status[release-status="On Hiatus"]{ - background-color: darkorange; -} - -publication-status[release-status="Cancelled"]{ - background-color: firebrick; -} - -publication-status[release-status="Upcoming"]{ - background-color: aqua; -} - -publication-status[release-status="Status Unavailable"]{ - background-color: gray; -} - - -publication-details { - display: flex; - flex-direction: column; - justify-content: start; -} - -publication-details * { - z-index: 1; - color: var(--accent-color); -} - -publication img { - position: absolute; - top: 0; - left: 0; - width: 100%; - height: 100%; - object-fit: cover; - z-index: 0; - border-radius: 5px; -} \ No newline at end of file