summaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
authorWolfgang Müller2025-02-19 15:39:48 +0100
committerWolfgang Müller2025-02-19 15:39:48 +0100
commit6bc3ca7032c78c77a6e2b316789938221d686d8b (patch)
treeb70bdd334a825b1fe6d14603e214b993ed2ce08b
parent2177d004c88d1daccc9ae4808dc75b66eb0f2d3a (diff)
downloadhircine-6bc3ca7032c78c77a6e2b316789938221d686d8b.tar.gz
frontend: Implement a better page indicator
This replaces the very simplistic x/y page indicator with a visual bar at the bottom of the reader that allows the user quick access to any arbitrary page. At the margins it shows the current page number(s) and the total amount of pages.
-rw-r--r--frontend/src/lib/reader/PageView.svelte60
-rw-r--r--frontend/src/lib/reader/components/PageIndicator.svelte9
-rw-r--r--frontend/src/lib/reader/components/SliderMargin.svelte11
-rw-r--r--frontend/src/lib/reader/components/SliderTooltip.svelte17
4 files changed, 79 insertions, 18 deletions
diff --git a/frontend/src/lib/reader/PageView.svelte b/frontend/src/lib/reader/PageView.svelte
index 2f8def7..50c0873 100644
--- a/frontend/src/lib/reader/PageView.svelte
+++ b/frontend/src/lib/reader/PageView.svelte
@@ -1,10 +1,11 @@
<script lang="ts">
import { Direction, Layout, type PageFragment } from '$gql/graphql';
- import { getReaderContext, partition } from '$lib/Reader.svelte';
+ import { type Chunk, getReaderContext, partition } from '$lib/Reader.svelte';
import { binds } from '$lib/Shortcuts';
import { src } from '$lib/Utils';
- import PageIndicator from './components/PageIndicator.svelte';
import ReaderPage from './ReaderPage.svelte';
+ import SliderMargin from './components/SliderMargin.svelte';
+ import SliderTooltip from './components/SliderTooltip.svelte';
const reader = getReaderContext();
@@ -56,7 +57,10 @@
}
let [chunks, lookup] = $derived(partition(reader.pages, layout));
- let { main, secondary } = $derived(chunks[lookup[reader.page]]);
+ let currentChunk = $derived(chunks[lookup[reader.page]]);
+ let { main, secondary } = $derived(currentChunk);
+
+ let reverse = $derived(direction === Direction.RightToLeft);
</script>
<svelte:document
@@ -76,18 +80,56 @@
{#if !secondary}
<ReaderPage page={main} onclick={clickMain} --justify="center" />
-{:else if direction === Direction.LeftToRight}
- <ReaderPage page={main} onclick={prev} --justify="flex-end" />
- <ReaderPage page={secondary} onclick={next} --justify="flex-start" />
-{:else}
+{:else if reverse}
<ReaderPage page={secondary} onclick={next} --justify="flex-end" />
<ReaderPage page={main} onclick={prev} --justify="flex-start" />
+{:else}
+ <ReaderPage page={main} onclick={prev} --justify="flex-end" />
+ <ReaderPage page={secondary} onclick={next} --justify="flex-start" />
{/if}
-<div class="absolute right-0 bottom-0 z-10 flex p-1 text-lg">
- <PageIndicator />
+
+{#snippet pagesIn(chunk: Chunk)}
+ {#if chunk.secondary}
+ {chunk.index + 1} - {chunk.index + 2}
+ {:else}
+ {chunk.index + 1}
+ {/if}
+{/snippet}
+
+<div class="group/slider absolute bottom-0 z-1 flex w-full pt-20">
+ <div class:reverse class="flex h-1 w-full transition-[height] group-hover/slider:h-8">
+ <SliderMargin>
+ {@render pagesIn(currentChunk)}
+ </SliderMargin>
+ <div class:reverse class="flex w-full bg-gray-400/60 backdrop-blur-2xl">
+ {#each chunks as chunk, index}
+ <button
+ type="button"
+ class:read={index <= lookup[reader.page]}
+ class="group/page relative grow [&.read]:bg-blue-600/60"
+ onclick={() => reader.open(chunk.index)}
+ aria-label={`Open page ${chunk.index}`}
+ >
+ <SliderTooltip>
+ {@render pagesIn(chunk)}
+ </SliderTooltip>
+ </button>
+ {/each}
+ </div>
+ <SliderMargin>
+ {reader.pages.length}
+ </SliderMargin>
+ </div>
</div>
+
<div class="invisible absolute">
{#each pagesAround(reader.page) as page}
<img src={src(page.image, 'full')} alt="" />
{/each}
</div>
+
+<style>
+ .reverse {
+ flex-direction: row-reverse;
+ }
+</style>
diff --git a/frontend/src/lib/reader/components/PageIndicator.svelte b/frontend/src/lib/reader/components/PageIndicator.svelte
deleted file mode 100644
index d0a3d0c..0000000
--- a/frontend/src/lib/reader/components/PageIndicator.svelte
+++ /dev/null
@@ -1,9 +0,0 @@
-<script lang="ts">
- import { getReaderContext } from '$lib/Reader.svelte';
-
- const reader = getReaderContext();
-</script>
-
-<div class="floating p-2!">
- {reader.page + 1}/{reader.pages.length}
-</div>
diff --git a/frontend/src/lib/reader/components/SliderMargin.svelte b/frontend/src/lib/reader/components/SliderMargin.svelte
new file mode 100644
index 0000000..c2f9a55
--- /dev/null
+++ b/frontend/src/lib/reader/components/SliderMargin.svelte
@@ -0,0 +1,11 @@
+<script lang="ts">
+ import type { Snippet } from 'svelte';
+
+ let { children }: { children: Snippet } = $props();
+</script>
+
+<div
+ class="flex h-full w-22 items-center justify-center px-1 font-semibold text-white/0 transition-colors group-hover/slider:bg-black group-hover/slider:text-white"
+>
+ {@render children()}
+</div>
diff --git a/frontend/src/lib/reader/components/SliderTooltip.svelte b/frontend/src/lib/reader/components/SliderTooltip.svelte
new file mode 100644
index 0000000..9e0322d
--- /dev/null
+++ b/frontend/src/lib/reader/components/SliderTooltip.svelte
@@ -0,0 +1,17 @@
+<script lang="ts">
+ import type { Snippet } from 'svelte';
+
+ let { children }: { children: Snippet } = $props();
+</script>
+
+<div
+ class="invisible absolute bottom-10 w-20 rounded-xl bg-blue-500 p-1 font-semibold text-white drop-shadow-md group-hover/page:visible"
+>
+ {@render children()}
+</div>
+
+<style lang="postcss">
+ div {
+ left: calc(50% - 2.5rem);
+ }
+</style>