Skip to content

Commit

Permalink
feat: added fullscreen autoscroll
Browse files Browse the repository at this point in the history
  • Loading branch information
kurozenzen committed Feb 10, 2024
1 parent d5e363a commit c8da0cc
Show file tree
Hide file tree
Showing 36 changed files with 596 additions and 222 deletions.
2 changes: 1 addition & 1 deletion src/lib/components/kurosearch/button-tag/TagButton.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
export let icon: string;
</script>

<button {title} on:click>
<button type="button" {title} on:click>
<i class={icon} />
</button>

Expand Down
3 changes: 3 additions & 0 deletions src/lib/components/kurosearch/details/Summary.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
<Score value={post.score} />
<span class="divider" />
<button
type="button"
class="codicon codicon-link"
class:active={active === 'links'}
on:click={() => dispatch('links')}
Expand All @@ -25,6 +26,7 @@
</button>
{#if post.comment_count}
<button
type="button"
class="codicon codicon-comment"
class:active={active === 'comments'}
on:click={() => dispatch('comments')}
Expand All @@ -33,6 +35,7 @@
</button>
{/if}
<button
type="button"
class="codicon codicon-tag"
class:active={active === 'tags'}
on:click={() => dispatch('tags')}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
<section>
<h3>Create Supertag</h3>

<button class={`codicon codicon-close`} on:click={close} />
<button type="button" class="codicon codicon-close" on:click={close} />

<div>
<label for="supertag-name"> Name </label>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
<script lang="ts">
import { isEnter } from '$lib/logic/keyboard-utils';
export let value: number;
export let min: number;
export let max: number;
export let step: number;
let internalValue: number;
const blurOnEnter = (event: KeyboardEvent) =>
isEnter(event) && (event.target as HTMLElement)?.blur();
$: {
if (internalValue === undefined) {
internalValue = value;
}
let newValue = Number(internalValue);
if (!isNaN(newValue)) {
value = newValue;
}
}
</script>

<input type="number" {min} {max} {step} bind:value={internalValue} on:keyup={blurOnEnter} />

<style>
input[type='number'] {
height: var(--line-height);
box-sizing: border-box;
background-color: transparent;
border-radius: var(--border-radius);
padding-inline: var(--small-gap);
border: 2px solid var(--background-1);
width: 90px;
}
</style>
Original file line number Diff line number Diff line change
@@ -1,24 +1,9 @@
<script context="module" lang="ts">
export const RATING_OPTIONS = Object.freeze({
all: 'All',
safe: 'Safe',
questionable: 'Questionable',
explicit: 'Explicit'
});
const OPTIONS_SORT_PROPERTY = Object.freeze({
id: 'Uploaded',
score: 'Score',
updated: 'Updated',
random: 'Random'
});
const OPTIONS_SORT_DIRECTION = Object.freeze({
desc: 'codicon codicon-arrow-down',
asc: 'codicon codicon-arrow-up'
});
const OPTIONS_SCORE_COMPARATOR = Object.freeze({ '>=': '', '<=': '' });
</script>

<script lang="ts">
import NumberInput from './NumberInput.svelte';
import RadioGroup from './RadioGroup.svelte';
import sort from '$lib/store/sort-store';
Expand All @@ -29,6 +14,12 @@
import Select from '$lib/components/pure/select/Select.svelte';
import RotatingTextSelect from '$lib/components/pure/rotating-select/RotatingTextSelect.svelte';
import { isEnter } from '$lib/logic/keyboard-utils';
import {
LABELS_RATING,
LABELS_SCORE_COMPARATOR,
LABELS_SORT_DIRECTION,
LABELS_SORT_PROPERTY
} from '../sort-filter-config/sortfilter';
export let dialog: HTMLDialogElement;
Expand Down Expand Up @@ -61,8 +52,8 @@
<div>
<b>Sorting</b>
<div class="row">
<RotatingIconSelect bind:value={$sort.direction} options={OPTIONS_SORT_DIRECTION} />
<Select bind:value={$sort.property} options={OPTIONS_SORT_PROPERTY} />
<RotatingIconSelect bind:value={$sort.direction} options={LABELS_SORT_DIRECTION} />
<Select bind:value={$sort.property} options={LABELS_SORT_PROPERTY} />
</div>
</div>

Expand All @@ -71,23 +62,19 @@
<div class="row">
<RotatingTextSelect
bind:value={$filter.scoreComparator}
options={OPTIONS_SCORE_COMPARATOR}
/>
<input
type="number"
min={0}
max={100000}
step={1}
bind:value={internalScoreValue}
on:keyup={blurOnEnter}
options={LABELS_SCORE_COMPARATOR}
/>
<NumberInput bind:value={$filter.scoreValue} min={0} max={10000} step={1} />
</div>
</div>

<b>Filtering by Rating</b>
<RadioGroup name="rating" options={RATING_OPTIONS} bind:value={$filter.rating} />
<TextButton title="Return to searching." on:click={() => dialog.close()}>Done</TextButton>
<TextButton title="Reset sort and filter." type="secondary" on:click={reset}>Reset</TextButton>
<div>
<b>Rating</b>
<RadioGroup name="rating" options={LABELS_RATING} bind:value={$filter.rating} />
</div>

<TextButton title="Return to searching" on:click={() => dialog.close()}>Done</TextButton>
<TextButton title="Reset sort and filter" type="secondary" on:click={reset}>Reset</TextButton>
</div>
</Dialog>

Expand Down
177 changes: 177 additions & 0 deletions src/lib/components/kurosearch/fullscreen-post/FullscreenImage.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,177 @@
<script lang="ts">
import FullscreenProgress from './FullscreenProgress.svelte';
import autoplayFullscreenDelay from '$lib/store/autoplay-fullscreen-delay-store';
import LoadingAnimation from '$lib/components/pure/loading-animation/LoadingAnimation.svelte';
import { getGifSources } from '$lib/logic/media-utils';
import autoplayFullscreenEnabled from '$lib/store/autoplay-fullscreen-enabled-store';
import highResolutionEnabled from '$lib/store/high-resolution-enabled';
import { createEventDispatcher, onDestroy, onMount } from 'svelte';
import { browser } from '$app/environment';
const dispatch = createEventDispatcher();
export let post: kurosearch.Post;
export let postId = -1;
const getSources = (type: string, file_url: string, sample_url: string, preview_url: string) => {
if (type === 'gif') {
const gifSources = getGifSources(file_url, sample_url, preview_url);
return [gifSources.static, gifSources.animated];
}
return highResolutionEnabled ? [sample_url, file_url] : [preview_url, sample_url];
};
$: [previewSrc, fullSrc] = getSources(
post.type,
post.file_url,
post.sample_url,
post.preview_url
);
let currentTime = 0;
let lastFrameTime = Date.now();
let currentFrameTime = Date.now();
let difference: number;
let paused = true;
let animationHandle: number;
const updateSlider = () => {
// frame times
currentFrameTime = Date.now();
difference = currentFrameTime - lastFrameTime;
lastFrameTime = currentFrameTime;
if (!paused) {
currentTime += difference / 1000;
}
if (currentTime >= $autoplayFullscreenDelay) {
dispatch('ended');
currentTime = 0;
}
animationHandle = requestAnimationFrame(updateSlider);
};
const togglePaused = () => {
paused = !paused;
};
$: {
if (post.id !== postId) {
postId = post.id;
currentTime = 0;
}
}
const keybinds = (event: KeyboardEvent) => {
if (event.code === 'Space' || event.key === 'k') {
event.preventDefault();
event.stopPropagation();
paused = !paused;
}
};
const observer = browser
? new IntersectionObserver(
(entries) => {
for (const entry of entries) {
if (entry.target) {
paused = !entry.isIntersecting;
}
}
},
{ rootMargin: '0px', threshold: 0.5 }
)
: null;
const pauseoffscreen = (target: HTMLElement) => {
observer?.observe(target);
return {
destroy() {
observer?.unobserve(target);
}
};
};
onMount(() => {
if ($autoplayFullscreenEnabled) {
animationHandle = requestAnimationFrame(updateSlider);
document.addEventListener('keydown', keybinds);
}
});
onDestroy(() => {
cancelAnimationFrame(animationHandle);
document.removeEventListener('keydown', keybinds);
});
const preload = (src: string) => {
return new Promise((resolve) => {
paused = true;
let img = new Image();
img.onload = (e) => {
resolve(e);
paused = false;
};
img.src = src;
});
};
</script>

<!-- svelte-ignore a11y-no-noninteractive-element-interactions -->
<!-- svelte-ignore a11y-click-events-have-key-events -->

{#await preload(fullSrc)}
<img
src={previewSrc}
alt="[{post.type}] post #{post.id}"
title="[{post.type}] post #{post.id}"
on:contextmenu|preventDefault={() => {}}
on:click={togglePaused}
/>
<div>
<LoadingAnimation />
</div>
{:then _}
<img
src={fullSrc}
alt="[{post.type}] post #{post.id}"
title="[{post.type}] post #{post.id}"
on:contextmenu|preventDefault={() => {}}
on:click={togglePaused}
use:pauseoffscreen
/>
{/await}

{#if $autoplayFullscreenEnabled}
<FullscreenProgress bind:value={currentTime} max={$autoplayFullscreenDelay} />
{/if}

<style>
img {
display: flex;
width: 100vw;
height: 100vh;
object-fit: contain;
contain: paint;
scroll-snap-align: start;
scroll-snap-stop: always;
}
div {
position: absolute;
display: flex;
align-items: center;
justify-content: center;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background-color: #0008;
width: 48px;
height: 48px;
border-radius: 24px;
}
</style>
Loading

0 comments on commit c8da0cc

Please sign in to comment.