mirror of
https://github.com/danbulant/Mangades
synced 2026-06-14 03:41:13 +00:00
use filters
This commit is contained in:
parent
e1d90cc5f5
commit
dcd831cecc
4 changed files with 162 additions and 8 deletions
62
src/components/multiSelect.svelte
Normal file
62
src/components/multiSelect.svelte
Normal 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>
|
||||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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());
|
||||
|
|
|
|||
Loading…
Reference in a new issue