Filter functionality

Removed textbox in top bar and added filter icon that opens up a box where you can search or select a connector/status and combination to filter by. Appearance and behavior needs to be refined.
This commit is contained in:
db-2001 2024-02-06 22:23:19 -05:00
parent 1ba49ddf08
commit 148af6abaa
4 changed files with 337 additions and 42 deletions

View File

@ -9,17 +9,44 @@
</head> </head>
<body> <body>
<wrapper> <wrapper>
<topbar> <topbar>
<titlebox> <titlebox>
<img alt="website image is Blahaj" src="media/blahaj.png"> <img alt="website image is Blahaj" src="media/blahaj.png">
<span>Tranga</span> <span>Tranga</span>
</titlebox> </titlebox>
<spacer></spacer> <spacer></spacer>
<searchdiv> <img id="filterFunnel" src="media/filter-funnel.svg" height="50%" alt="filterFunnel">
<label for="searchbox"></label><input id="searchbox" placeholder="Filter" type="text">
</searchdiv>
<img id="settingscog" src="media/settings-cogwheel.svg" height="100%" alt="settingscog"> <img id="settingscog" src="media/settings-cogwheel.svg" height="100%" alt="settingscog">
</topbar> </topbar>
<filter-box id="filterBox">
<border-bar>
<popup-title>Filter by: </popup-title>
<popup-close onclick="filterBox.classList.toggle('animate')" >&times</popup-close>
</border-bar>
<popup-content>
<div class="popup-section">
NAME:
<div class="section-content">
<label for="searchbox"></label><input id="searchbox" placeholder="Title" type="text">
</div>
</div>
<div class = "popup-section">
CONNECTOR:
<div class="section-content" id="connectorFilterBox">
</div>
</div>
<div class = "popup-section">
STATUS:
<div class="section-content" id="statusFilterBox">
</div>
</div>
</popup-content>
<border-bar-button onclick="ClearFilter()" class="clearFilter">Clear Filter</border-bar-button>
</filter-box>
<viewport> <viewport>
<div id="loaderdiv"> <div id="loaderdiv">
<blur-background></blur-background> <blur-background></blur-background>
@ -54,8 +81,7 @@
</popup> </popup>
<popup id="settingsPopup"> <popup id="settingsPopup">
<blur-background id="blurBackgroundSettingsPopup" onclick=" <blur-background id="blurBackgroundSettingsPopup" onclick="settingsPopup.style.display = 'none';"></blur-background>
settingsPopup.style.display = 'none';"></blur-background>
<popup-window> <popup-window>
<border-bar> <border-bar>
<popup-title>Settings</popup-title> <popup-title>Settings</popup-title>

View File

@ -5,10 +5,18 @@ let notificationConnectorTypes = [];
let libraryConnectorTypes = []; let libraryConnectorTypes = [];
let selectedManga; let selectedManga;
let selectedJob; let selectedJob;
let searchMatch;
let connectorMatch = [];
let connectorNameMatch;
let statusMatch = [];
let statusNameMatch = [];
const searchBox = document.querySelector("#searchbox"); const searchBox = document.querySelector("#searchbox");
const settingsPopup = document.querySelector("#settingsPopup"); const settingsPopup = document.querySelector("#settingsPopup");
const filterBox = document.querySelector("#filterBox");
const settingsCog = document.querySelector("#settingscog"); const settingsCog = document.querySelector("#settingscog");
const filterFunnel = document.querySelector("#filterFunnel");
const tasksContent = document.querySelector("content"); const tasksContent = document.querySelector("content");
const createMonitorTaskButton = document.querySelector("#createMonitoJobButton"); const createMonitorTaskButton = document.querySelector("#createMonitoJobButton");
const createDownloadChapterTaskButton = document.querySelector("#createDownloadChapterJobButton"); const createDownloadChapterTaskButton = document.querySelector("#createDownloadChapterJobButton");
@ -75,14 +83,41 @@ function Setup(){
GetAvailableControllers().then((json) => { GetAvailableControllers().then((json) => {
//console.log(json); //console.log(json);
newMangaConnector.replaceChildren(); newMangaConnector.replaceChildren();
connectorFilterBox = document.querySelector("#connectorFilterBox");
json.forEach(connector => { json.forEach(connector => {
//Add the connector to the New Manga dropdown
var option = document.createElement('option'); var option = document.createElement('option');
option.value = connector; option.value = connector;
option.innerText = connector; option.innerText = connector;
newMangaConnector.appendChild(option); 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");
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(); ResetContent();
UpdateJobs(); UpdateJobs();
GetSettings().then((json) => { GetSettings().then((json) => {
@ -102,9 +137,48 @@ function Setup(){
UpdateJobs(); UpdateJobs();
}, 1000); }, 1000);
}); });
//Clear the previous values if any exist.
searchBox.value = "";
connectorMatch.length = 0;
statusMatch.length = 0;
} }
Setup(); Setup();
function ToggleFilterConnector(connector) {
//console.log("Initial Array:");
//console.log(connectorMatch);
if (connectorMatch.includes(connector)) {
idx = connectorMatch.indexOf(connector);
connectorMatch.splice(idx, 1);
} else {
connectorMatch.push(connector);
}
//console.log("Final Array");
//console.log(connectorMatch);
FilterResults();
}
function ToggleFilterStatus(status) {
//console.log("Initial Array:");
//console.log(statusMatch);
if (statusMatch.includes(status)) {
idx = statusMatch.indexOf(status);
statusMatch.splice(idx, 1);
} else {
statusMatch.push(status);
}
//console.log("Final Array");
//console.log(statusMatch);
FilterResults();
}
function ClearFilter() {
searchBox.value = "";
statusMatch.length = 0;
connectorMatch.length = 0;
FilterResults();
}
function updateCSS(){ function updateCSS(){
if (document.getElementById("mangaHoverCheckbox").checked == true){ if (document.getElementById("mangaHoverCheckbox").checked == true){
ChangeStyleSheet('hover') ChangeStyleSheet('hover')
@ -300,25 +374,72 @@ function HidePublicationPopup(){
searchBox.addEventListener("keyup", () => FilterResults()); searchBox.addEventListener("keyup", () => FilterResults());
//Filter shown jobs //Filter shown jobs
function FilterResults(){ function FilterResults(){
if(searchBox.value.length > 0){ //For each publication
tasksContent.childNodes.forEach(publication => { tasksContent.childNodes.forEach(publication => {
publication.childNodes.forEach(item => { //If the search box isn't empty check that the title contains the searchbox content. If it does then
if(item.nodeName.toLowerCase() == "publication-information"){ //'searchMatch' is true and the manga is shown. If the search box is empty, then consider this field
item.childNodes.forEach(information => { //to be true anyways.
if(information.nodeName.toLowerCase() == "publication-name"){ if (searchBox.value.length > 0) {
if(!information.textContent.toLowerCase().includes(searchBox.value.toLowerCase())){ publication.childNodes.forEach(item => {
publication.style.display = "none"; if (item.nodeName.toLowerCase() == "publication-information"){
}else{ item.childNodes.forEach(information => {
publication.style.display = "initial"; if (information.nodeName.toLowerCase() == "publication-name") {
} if (information.textContent.toLowerCase().includes(searchBox.value.toLowerCase())){
} searchMatch = 1;
}); } else {
} searchMatch = 0;
}); }
}); }
}else{ });
tasksContent.childNodes.forEach(publication => publication.style.display = "initial"); }
});
} 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", () => { settingsCog.addEventListener("click", () => {
@ -326,6 +447,10 @@ settingsCog.addEventListener("click", () => {
settingsPopup.style.display = "flex"; settingsPopup.style.display = "flex";
}); });
filterFunnel.addEventListener("click", () => {
filterBox.classList.toggle("animate");
});
settingKomgaUrl.addEventListener("keypress", (event) => { { if(event.key === "Enter") UpdateSettings(); } }); settingKomgaUrl.addEventListener("keypress", (event) => { { if(event.key === "Enter") UpdateSettings(); } });
settingKomgaUser.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(); }); settingKomgaPass.addEventListener("keypress", (event) => { if(event.key === "Enter") UpdateSettings(); });
@ -430,7 +555,7 @@ function ClearKomga(){
settingKomgaUrl.value = ""; settingKomgaUrl.value = "";
settingKomgaUser.value = ""; settingKomgaUser.value = "";
settingKomgaPass.value = ""; settingKomgaPass.value = "";
settingKomgaConfigured.setAttribute("configuration", "Connector Not Configured"); settingKomgaConfigured.setAttribute("configuration", "Not Configured");
ResetKomga(); ResetKomga();
} }
@ -438,27 +563,27 @@ function ClearKavita(){
settingKavitaUrl.value = ""; settingKavitaUrl.value = "";
settingKavitaUser.value = ""; settingKavitaUser.value = "";
settingKavitaPass.value = ""; settingKavitaPass.value = "";
settingKavitaConfigured.setAttribute("configuration", "Connector Not Configured"); settingKavitaConfigured.setAttribute("configuration", "Not Configured");
ResetKavita(); ResetKavita();
} }
function ClearGotify(){ function ClearGotify(){
settingGotifyUrl.value = ""; settingGotifyUrl.value = "";
settingGotifyAppToken.value = "" settingGotifyAppToken.value = ""
settingGotifyConfigured.setAttribute("configuration", "Connector Not Configured"); settingGotifyConfigured.setAttribute("configuration", "Not Configured");
ResetGotify(); ResetGotify();
} }
function ClearLunasea(){ function ClearLunasea(){
settingLunaseaWebhook.value = ""; settingLunaseaWebhook.value = "";
settingLunaseaConfigured.setAttribute("configuration", "Connector Not Configured"); settingLunaseaConfigured.setAttribute("configuration", "Not Configured");
ResetLunaSea(); ResetLunaSea();
} }
function ClearNtfy(){ function ClearNtfy(){
settingNtfyEndpoint.value = ""; settingNtfyEndpoint.value = "";
settingNtfyAuth.value = ""; settingNtfyAuth.value = "";
settingNtfyConfigured.setAttribute("configuration", "Connector Not Configured"); settingNtfyConfigured.setAttribute("configuration", "Not Configured");
ResetNtfy(); ResetNtfy();
} }

View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="iso-8859-1"?>
<!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg fill="#000000" version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
width="800px" height="800px" viewBox="0 0 971.986 971.986"
xml:space="preserve">
<g>
<path d="M370.216,459.3c10.2,11.1,15.8,25.6,15.8,40.6v442c0,26.601,32.1,40.101,51.1,21.4l123.3-141.3
c16.5-19.8,25.6-29.601,25.6-49.2V500c0-15,5.7-29.5,15.8-40.601L955.615,75.5c26.5-28.8,6.101-75.5-33.1-75.5h-873
c-39.2,0-59.7,46.6-33.1,75.5L370.216,459.3z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 714 B

View File

@ -69,7 +69,6 @@ titlebox span{
titlebox img { titlebox img {
height: 100%; height: 100%;
margin-right: 10px;
cursor: grab; cursor: grab;
} }
@ -77,22 +76,156 @@ spacer{
flex-grow: 1; flex-grow: 1;
} }
searchdiv{ 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: 400px;
}
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; display: block;
margin: 0 10px 0 0; 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 { #searchbox {
padding: 3px 10px; display: flex;
border: 0; padding: 3px 5px;
border-radius: 4px; margin: 5px;
font-size: 14pt; border-style: solid;
width: 250px; 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 { #settingscog {
cursor: pointer; cursor: pointer;
margin: 0px 30px; 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%; height: 50%;
filter: invert(100%) sepia(0%) saturate(7465%) hue-rotate(115deg) brightness(116%) contrast(101%); filter: invert(100%) sepia(0%) saturate(7465%) hue-rotate(115deg) brightness(116%) contrast(101%);
} }
@ -179,6 +312,7 @@ border-bar {
margin:0; margin:0;
align-items: center; align-items: center;
position: relative; position: relative;
width: 100%;
} }
popup-title { popup-title {
@ -198,7 +332,7 @@ popup-close {
display: flex; display: flex;
cursor: pointer; cursor: pointer;
margin-left: auto; margin-left: auto;
margin-right: 5; margin-right: 15px;
height: 32px; height: 32px;
width: 32px; width: 32px;
border-radius: 16px; border-radius: 16px;
@ -268,7 +402,7 @@ popup popup-window {
overflow: hidden; overflow: hidden;
} }
popup popup-window popup-content{ popup-content{
display: flex; display: flex;
flex-direction: column; flex-direction: column;
align-items: left; align-items: left;
@ -288,7 +422,7 @@ popup-content > .popup-section {
border-top-style: solid; border-top-style: solid;
border-top-width: 1px; border-top-width: 1px;
border-top-color: lightgray; border-top-color: lightgray;
width: 100%; width: calc(100%-10px);
padding: 10px; padding: 10px;
} }
@ -377,8 +511,6 @@ popup-content > .popup-section {
background-color: gray; background-color: gray;
} }
.section-item > input { .section-item > input {
margin: 2px; margin: 2px;
padding: 2px; padding: 2px;