use filters

This commit is contained in:
Daniel Bulant 2021-05-26 08:40:46 +02:00
parent e1d90cc5f5
commit dcd831cecc
4 changed files with 162 additions and 8 deletions

View file

@ -0,0 +1,62 @@
<script>
export var value = [];
export var id;
export var name = id;
export var options;
/**
* @param {MouseEvent} e
* @param {string} name
*/
function select(e, name) {
if(value.includes(name)) {
value.splice(value.indexOf(name), 1);
value = value;
} else {
value.push(name);
value = value;
}
e.preventDefault();
/** @type {HTMLOptionElement} */
const opt = e.target;
opt.parentElement.focus();
return false;
}
/**
* @param {MouseEvent} e
* @param {string} name
*/
function dragSelect(e, name) {
if(!(e.buttons & 1)) {
return;
}
if(!value.includes(name)) {
value.push(name);
value = value;
}
}
</script>
<select multiple {name} {id} bind:value={value}>
{#each Object.entries(options) as [name, option]}
<option value={name} on:mousemove={e => dragSelect(e, name)} on:mousedown={(e) => select(e, name)}>{option}</option>
{/each}
</select>
<style>
select {
width: 100%;
margin-top: 5px;
overflow-y: auto;
padding: 0;
}
select option {
padding: 2px 5px;
}
select option:checked {
background-color: rgb(0, 38, 255);
color: white;
}
</style>

View file

@ -29,7 +29,7 @@
var progress = 0;
var state = "idle";
const defaultText = "Choose a chapter to view online or download EPUB";
const defaultText = "Choose a chapter to view online or download";
var text = defaultText;
var pagesDone = 0;
var totalPages = 0;

View file

@ -3,6 +3,7 @@
import request from "../util/request";
import ratelimit from "../util/ratelimit";
import { goto, url } from '@roxi/routify/runtime/helpers';
import MultiSelect from '../components/multiSelect.svelte';
var name = $params.search;
$: {
@ -15,10 +16,21 @@
* @param {string} title
* @returns {Promise<object>}
*/
async function search(title, offset=0) {
var query = "";
if(title) query += "title=" + encodeURIComponent(name) + "&";
query += "contentRating[]=safe&contentRating[]=suggestive&limit=100&offset=" + offset;
async function search(title, filters, offset=0) {
var query = new URLSearchParams();
if(title) query.set("title", title);
query.set("limit", 100);
query.set("offset", offset);
for(const rating of filters.contentRating) {
query.append("contentRating[]", rating);
}
for(const demographic of filters.demographic) {
query.append("demographic[]", demographic);
}
for(const status of filters.status) {
query.append("status[]", status);
}
query.set("order[" + filters.sort + "]", filters.sortValue);
const res = await request("manga", query);
for(const manga of res.results) {
for(const relation of manga.relationships) {
@ -30,7 +42,7 @@
return res;
}
$: result = ratelimit(search, name);
$: result = ratelimit(search, name, filters);
var scrollSearch = null;
/**
@ -40,7 +52,7 @@
if(scrollSearch !== null) return;
if(document.body.scrollHeight - window.scrollY - window.innerHeight < 300 && (await result).results.length < (await result).total) {
scrollSearch = name;
const res = await search(name, (await result).results.length);
const res = await search(name, filters, (await result).results.length);
if(scrollSearch === name && res.results.length) {
(await result).results.push(...res.results);
result = result; // trigger reload
@ -57,6 +69,35 @@
const res = await request("manga/random");
$goto("./" + res.data.id);
}
const filters = {
contentRating: ["safe", "suggestive"],
demographic: [],
status: [],
sort: "updatedAt",
sortValue: "desc"
};
const options = {
contentRating: {
safe: "Safe",
suggestive: "Suggestive",
erotica: "Erotica",
pornographic: "Pornographic"
},
demographic: {
shounen: "Shounen",
shoujo: "Shoujo",
josei: "Josei",
none: "None"
},
status: {
ongoing: "Ongoing",
completed: "Completed",
hiatus: "Hiatus - Paused",
cancelled: "Cancelled"
}
}
</script>
<svelte:window on:scroll={scroll} />
@ -71,6 +112,33 @@
<h1>MANGADEX</h1>
<input type="text" bind:value={name}>
<div class="filters">
<div class="grow">
<label for="content-rating">Content rating</label>
<MultiSelect id="content-rating" bind:value={filters.contentRating} options={options.contentRating} />
</div>
<div class="grow">
<label for="demographic">Demographic</label>
<MultiSelect id="demographic" bind:value={filters.demographic} options={options.demographic} />
</div>
<div class="grow">
<label for="status">Manga Status</label>
<MultiSelect id="status" bind:value={filters.status} options={options.status} />
</div>
<p style="margin: 0;"><i>Sorts currently don't work (mangadex shows the same results).</i></p>
<div class="flex">
<label for="sort">Sort by:</label>
<select name="sort" id="sort" class="flex-grow" bind:value={filters.sort}>
<option value="createdAt">Creation date</option>
<option value="updatedAt">Update date</option>
</select>
<select name="sort-type" id="sort-type" class="flex-grow" bind:value={filters.sortValue}>
<option value="asc">Ascending</option>
<option value="desc">Descending</option>
</select>
</div>
</div>
{#await result}
Loading...
{:then result}
@ -115,6 +183,30 @@
</main>
<style>
.filters {
display: flex;
justify-content: space-between;
flex-wrap: wrap;
}
.flex {
display: flex;
justify-content: space-between;
width: 100%;
align-items: center;
}
.flex select {
margin: 0;
}
.grow {
flex-grow: 1;
margin-left: 5px;
margin-right: 5px;
}
.flex select.flex-grow {
flex-grow: 1;
margin-left: 5px;
margin-right: 5px;
}
input {
width: 100%;
margin-bottom: 5px;

View file

@ -2,7 +2,7 @@ export const proxy = "https://cors-anywhere.danbulant.workers.dev/?";
export const base = proxy + "https://api.mangadex.org/";
function request(endpoint, query, type = "GET", body) {
return fetch(base + endpoint + (query ? "?" + query : ""), {
return fetch(base + endpoint + (query ? "?" + query.toString() : ""), {
method: type,
body: body ? JSON.stringify(body) : undefined
}).then(resp => resp.json());