add nsfw; save show type and nsfw mode to local storage

This commit is contained in:
Daniel Bulant 2022-12-10 19:12:37 +01:00
parent 8056f1a1c3
commit c6c3cf57f0
6 changed files with 159 additions and 32 deletions

View file

@ -1,5 +1,6 @@
<script lang="ts">
import SvelteMarkdown from "svelte-markdown";
import { showNsfw } from "./showNsfwChooser.svelte";
import { showType } from "./showTypeChooser.svelte";
export var r18: boolean = false;
@ -18,15 +19,13 @@
</script>
<div on:click class="item" class:grid={$showType == "grid"} class:comfortable={$showType == "comfortable"} class:coverOnly={$showType == "cover-only"} class:list={$showType == "list"}>
<div class="flex" class:r18>
<div class="flex" class:r18={r18 && $showNsfw !== "show"}>
{#if cover}
<div class="cover-container" width={coverWidth} height={coverHeight}>
<img class="cover" style="{coverColor ? "--box-shadow-color: " + coverColor : ""}" draggable="false" src="{cover}" alt="{title}" {title} width={coverWidth} height={coverHeight}>
{#if $showType == "grid"}
<div class="over">
{title}
</div>
{/if}
<div class="over" class:hidden={$showType !== "grid"}>
{title}
</div>
</div>
{:else}
Broken art
@ -47,11 +46,9 @@
{/if}
</div>
</div>
{#if $showType == "comfortable"}
<div>
{title}
</div>
{/if}
<div class="comfortable-div" class:hidden={$showType !== "comfortable"}>
{title}
</div>
</div>
<style>
@ -113,6 +110,27 @@
color: white;
padding: 1.5rem 0.5rem 0.5rem 0.5rem;
border-radius: 5px;
user-select: initial;
opacity: 1;
transition: .3s opacity;
}
.comfortable-div {
user-select: initial;
opacity: 1;
transition: .3s opacity;
line-height: 1.5rem;
display: -webkit-box;
max-height: calc(2rem + 3*1.4rem);
overflow: hidden;
text-overflow: ellipsis;
-webkit-line-clamp: 3;
-webkit-box-orient: vertical;
transition: max-height .3s;
}
.hidden {
opacity: 0;
user-select: none;
max-height: 0;
}
.item img {
--box-shadow-color: white;
@ -121,10 +139,10 @@
width: auto;
max-width: 100%;
box-shadow: 0 0 0 var(--box-shadow-color);
transition: .4s box-shadow, .3s height, .4s filter;
transition: .4s box-shadow, .3s max-height, .4s filter;
}
.item.list img.cover {
height: 8rem;
max-height: 8rem;
}
.item:hover img {
box-shadow: 0 0 20px var(--box-shadow-color);

View file

@ -0,0 +1,34 @@
<script lang="ts" context="module">
import type { Writable } from "svelte/store";
import { storedWritable } from "../util/storedWritable";
export const showNsfw: Writable<"hide" | "blur" | "show"> = storedWritable("nsfw-mode", "blur");
</script>
<div>
<button on:click={() => $showNsfw = "hide"} class:active={$showNsfw == "hide"}>Hide</button><!--
--><button on:click={() => $showNsfw = "blur"} class:active={$showNsfw == "blur"}>Blur</button><!--
--><button on:click={() => $showNsfw = "show"} class:active={$showNsfw == "show"}>Show</button>
</div>
<style>
div {
width: max-content;
user-select: none;
}
button {
border-radius: 0;
margin: 0;
}
button:first-child {
border-top-left-radius: 5px;
border-bottom-left-radius: 5px;
}
button:last-child {
border-top-right-radius: 5px;
border-bottom-right-radius: 5px;
}
button.active {
background: rgb(202, 202, 202);
}
</style>

View file

@ -1,7 +1,8 @@
<script context="module" lang="ts">
import { writable, type Writable } from "svelte/store";
import { storedWritable } from "$lib/util/storedWritable";
import type { Writable } from "svelte/store";
export var showType: Writable<"grid" | "comfortable" | "list" | "cover-only"> = writable("grid");
export var showType: Writable<"grid" | "comfortable" | "list" | "cover-only"> = storedWritable("show-mode", "grid");
</script>
<div>
@ -15,6 +16,7 @@
div {
margin-left: auto;
width: max-content;
user-select: none;
}
button {
border-radius: 0;

View file

@ -0,0 +1,74 @@
import {writable as internal, get, type Writable} from 'svelte/store'
declare type Updater<T> = (value: T) => T;
declare type StoreDict<T> = { [key: string]: Writable<T> }
/* eslint-disable @typescript-eslint/no-explicit-any */
const stores: StoreDict<any> = {}
interface Serializer<T> {
parse(text: string): T
stringify(object: T): string
}
type StorageType = 'local' | 'session'
interface Options<T> {
serializer?: Serializer<T>
storage?: StorageType
}
function getStorage(type: StorageType) {
return type === 'local' ? localStorage : sessionStorage
}
export function storedWritable<T>(key: string, initialValue: T, options?: Options<T>): Writable<T> {
const serializer = options?.serializer ?? JSON
const storageType = options?.storage ?? 'local'
const browser = typeof(window) !== 'undefined' && typeof(document) !== 'undefined'
function updateStorage(key: string, value: T) {
if (!browser) return
getStorage(storageType).setItem(key, serializer.stringify(value))
}
if (!stores[key]) {
const store = internal(initialValue, (set) => {
const json = browser ? getStorage(storageType).getItem(key) : null
if (json) {
set(<T>serializer.parse(json))
}
if (browser) {
const handleStorage = (event: StorageEvent) => {
if (event.key === key)
set(event.newValue ? serializer.parse(event.newValue) : null)
}
window.addEventListener("storage", handleStorage)
return () => window.removeEventListener("storage", handleStorage)
}
})
const {subscribe, set} = store
stores[key] = {
set(value: T) {
updateStorage(key, value)
set(value)
},
update(updater: Updater<T>) {
const value = updater(get(store))
updateStorage(key, value)
set(value)
},
subscribe
}
}
return stores[key]
}

View file

@ -9,6 +9,7 @@
import type { load } from "./+page";
import Navbar from "$lib/components/navbar.svelte";
import ShowNsfwChooser, { showNsfw } from "$lib/components/showNsfwChooser.svelte";
export var data: Awaited<ReturnType<typeof load>>;
var name: string = typeof window === "undefined" ? "" : data.url.searchParams.get("search") || "";
@ -18,8 +19,6 @@
history.replaceState(history.state, "", url.toString());
}
var allowNSFW = false;
const filters = {
contentRating: ["safe", "suggestive"],
demographic: [],
@ -28,7 +27,7 @@
sortValue: "desc"
};
filters.contentRating = allowNSFW ? [] : ["safe", "suggestive"];
filters.contentRating = $showNsfw !== "hide" ? ["safe", "suggestive", "erotica", "pornographic"] : ["safe", "suggestive"];
/**
* Searches for results
@ -109,7 +108,7 @@
$: if(userDetails) {
userDetails.then(data => {
if(data.data.User.options.nsfwContent) {
allowNSFW = true;
$showNsfw = "show";
}
})
}
@ -130,10 +129,7 @@
<div class="flex" style="margin-top: 1rem;">
<div>
<div class="nsfw">
<input id="nsfw" type="checkbox" bind:checked={allowNSFW}>
<label for="nsfw">
Allow NSFW
</label>
<ShowNsfwChooser />
</div>
<a href="https://discord.gg/XKPbz5xRuK">Made by TechmandanCZ#3372</a>
</div>
@ -170,20 +166,12 @@
</main>
<style lang="postcss">
.nsfw > input, .nsfw > label {
display: inline-block;
width: auto;
}
.flex {
display: flex;
justify-content: space-between;
width: 100%;
align-items: center;
}
input {
width: 100%;
margin-bottom: 5px;
}
a:not(.button) {
color: rgb(86, 139, 255);
text-decoration: underline;

View file

@ -1,5 +1,6 @@
<script lang="ts">
import Item from "$lib/components/item.svelte";
import ShowNsfwChooser, { showNsfw } from "$lib/components/showNsfwChooser.svelte";
import ShowTypeChooser, { showType } from "$lib/components/showTypeChooser.svelte";
import request, { imageproxy } from "$lib/util/request";
import { createEventDispatcher, tick } from "svelte";
@ -86,11 +87,16 @@
$: {
$showType;
$showNsfw;
setTimeout(() => dispatch("slideToClosest"), 100);
}
</script>
<ShowTypeChooser />
<div class="flex">
<ShowNsfwChooser />
<ShowTypeChooser />
</div>
<div class="grid" class:list={$showType == "list"}>
{#each mangaRelations.filter(t => $showNsfw !== "hide" || ["safe", "suggestive"].includes(t.attributes.contentRating)) as manga (manga.id)}
@ -109,6 +115,11 @@
</div>
<style>
.flex {
display: flex;
justify-content: space-between;
align-items: center;
}
.grid {
display: grid;
grid-template-columns: repeat(auto-fill, 11rem);