diff options
author | Wolfgang Müller | 2025-02-19 15:39:48 +0100 |
---|---|---|
committer | Wolfgang Müller | 2025-02-19 15:39:48 +0100 |
commit | 6bc3ca7032c78c77a6e2b316789938221d686d8b (patch) | |
tree | b70bdd334a825b1fe6d14603e214b993ed2ce08b | |
parent | 2177d004c88d1daccc9ae4808dc75b66eb0f2d3a (diff) | |
download | hircine-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.
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> |