diff options
author | Wolfgang Müller | 2025-02-13 17:52:16 +0100 |
---|---|---|
committer | Wolfgang Müller | 2025-02-13 17:52:16 +0100 |
commit | dc4db405d2991d3ec6a114f3b08d3fccd057d3ee (patch) | |
tree | 2c620c9af2062ba09fa591f8b3ed961664adab58 /frontend/src/lib/tabs | |
parent | 4df870d793123be95c8af031a340a39b5b8402ac (diff) | |
download | hircine-dc4db405d2991d3ec6a114f3b08d3fccd057d3ee.tar.gz |
frontend: Migrate to Svelte 5
Diffstat (limited to 'frontend/src/lib/tabs')
-rw-r--r-- | frontend/src/lib/tabs/AddOverlay.svelte | 21 | ||||
-rw-r--r-- | frontend/src/lib/tabs/ArchiveDelete.svelte | 4 | ||||
-rw-r--r-- | frontend/src/lib/tabs/ArchiveDetails.svelte | 2 | ||||
-rw-r--r-- | frontend/src/lib/tabs/ArchiveEdit.svelte | 22 | ||||
-rw-r--r-- | frontend/src/lib/tabs/ComicDelete.svelte | 6 | ||||
-rw-r--r-- | frontend/src/lib/tabs/ComicDetails.svelte | 20 | ||||
-rw-r--r-- | frontend/src/lib/tabs/DetailsHeader.svelte | 6 | ||||
-rw-r--r-- | frontend/src/lib/tabs/DetailsSection.svelte | 6 | ||||
-rw-r--r-- | frontend/src/lib/tabs/Tab.svelte | 22 | ||||
-rw-r--r-- | frontend/src/lib/tabs/Tabs.svelte | 38 |
10 files changed, 102 insertions, 45 deletions
diff --git a/frontend/src/lib/tabs/AddOverlay.svelte b/frontend/src/lib/tabs/AddOverlay.svelte index b1c98bf..329b259 100644 --- a/frontend/src/lib/tabs/AddOverlay.svelte +++ b/frontend/src/lib/tabs/AddOverlay.svelte @@ -1,7 +1,7 @@ <script lang="ts"> - import { updateComics } from '$gql/Mutations'; import { UpdateMode } from '$gql/graphql'; - import { getSelectionContext } from '$lib/Selection'; + import { updateComics } from '$gql/Mutations'; + import { getSelectionContext } from '$lib/selection/Selection.svelte'; import { toastFinally } from '$lib/Toasts'; import { fadeDefault } from '$lib/Transitions'; import { getContextClient } from '@urql/svelte'; @@ -10,27 +10,30 @@ const client = getContextClient(); const selection = getSelectionContext(); - export let id: number; + let { id }: { id: number } = $props(); + + function onclick(event: MouseEvent) { + event.preventDefault(); - function addPages() { updateComics(client, { ids: id, - input: { pages: { ids: $selection.ids, options: { mode: UpdateMode.Add } } } + input: { pages: { ids: selection.ids, options: { mode: UpdateMode.Add } } } }) - .then(() => ($selection = $selection.none())) + .then(() => selection.none()) .catch(toastFinally); } </script> -{#if $selection.size > 0} +{#if selection.size > 0} <div class="absolute left-1 top-1" transition:fade={fadeDefault}> <button type="button" class="btn-blue rounded-full shadow-sm shadow-black" title="Add to this comic" - on:click|preventDefault={addPages} + aria-label="Add to this comic" + {onclick} > - <span class="icon-base icon-[material-symbols--note-add]" /> + <span class="icon-base icon-[material-symbols--note-add]"></span> </button> </div> {/if} diff --git a/frontend/src/lib/tabs/ArchiveDelete.svelte b/frontend/src/lib/tabs/ArchiveDelete.svelte index b0e3c58..50a99c2 100644 --- a/frontend/src/lib/tabs/ArchiveDelete.svelte +++ b/frontend/src/lib/tabs/ArchiveDelete.svelte @@ -9,7 +9,7 @@ const client = getContextClient(); - export let archive: FullArchiveFragment; + let { archive }: { archive: FullArchiveFragment } = $props(); function deleteArchive() { confirmDeletion('Archive', archive.name, () => { @@ -37,6 +37,6 @@ <p class="mt-2 font-medium">This action is irrevocable.</p> </div> <div class="flex"> - <DeleteButton prominent on:click={deleteArchive} /> + <DeleteButton prominent onclick={deleteArchive} /> </div> </div> diff --git a/frontend/src/lib/tabs/ArchiveDetails.svelte b/frontend/src/lib/tabs/ArchiveDetails.svelte index 9554557..b3d570f 100644 --- a/frontend/src/lib/tabs/ArchiveDetails.svelte +++ b/frontend/src/lib/tabs/ArchiveDetails.svelte @@ -8,7 +8,7 @@ import Header from './DetailsHeader.svelte'; import Section from './DetailsSection.svelte'; - export let archive: FullArchiveFragment; + let { archive }: { archive: FullArchiveFragment } = $props(); const now = Date.now(); const modifiedDate = new Date(archive.mtime); diff --git a/frontend/src/lib/tabs/ArchiveEdit.svelte b/frontend/src/lib/tabs/ArchiveEdit.svelte index 80efaed..83a492b 100644 --- a/frontend/src/lib/tabs/ArchiveEdit.svelte +++ b/frontend/src/lib/tabs/ArchiveEdit.svelte @@ -1,12 +1,12 @@ <script lang="ts"> import { addComic, updateArchives } from '$gql/Mutations'; import { type FullArchiveFragment } from '$gql/graphql'; - import { getSelectionContext } from '$lib/Selection'; import { toastFinally } from '$lib/Toasts'; import AddButton from '$lib/components/AddButton.svelte'; import Card, { comicCard } from '$lib/components/Card.svelte'; import OrganizedButton from '$lib/components/OrganizedButton.svelte'; import ComicPills from '$lib/pills/ComicPills.svelte'; + import { getSelectionContext } from '$lib/selection/Selection.svelte'; import SelectionControls from '$lib/toolbar/SelectionControls.svelte'; import { getContextClient } from '@urql/svelte'; import AddOverlay from './AddOverlay.svelte'; @@ -14,23 +14,23 @@ const client = getContextClient(); const selection = getSelectionContext(); - export let archive: FullArchiveFragment; + let { archive }: { archive: FullArchiveFragment } = $props(); function addNew() { addComic(client, { input: { archive: { id: archive.id }, title: archive.name, - pages: { ids: $selection.ids }, - cover: { id: archive.pages[$selection.indices.toSorted((a, b) => a - b)[0]].id } + pages: { ids: selection.ids }, + cover: { id: archive.pages[selection.indices.toSorted((a, b) => a - b)[0]].id } } }) .then((mutatation) => { const data = mutatation.addComic; if (data.__typename === 'AddComicSuccess' && !data.archivePagesRemaining) { - $selection = $selection.clear(); + selection.clear(); } else { - $selection = $selection.none(); + selection.none(); } }) .catch(toastFinally); @@ -46,10 +46,10 @@ <div class="flex flex-col gap-4"> <div class="flex gap-2 text-sm"> <SelectionControls page> - <AddButton title="Add Comic from selected" on:click={addNew} /> + <AddButton title="Add Comic from selected" onclick={addNew} /> </SelectionControls> - <div class="grow" /> - <OrganizedButton organized={archive.organized} on:click={toggleOrganized} /> + <div class="grow"></div> + <OrganizedButton organized={archive.organized} onclick={toggleOrganized} /> </div> {#if archive.comics.length > 0} @@ -58,7 +58,9 @@ <div class="flex shrink-0 flex-col gap-4"> {#each archive.comics as comic} <Card compact {...comicCard(comic)}> - <AddOverlay slot="overlay" id={comic.id} /> + {#snippet overlay()} + <AddOverlay id={comic.id} /> + {/snippet} <ComicPills {comic} /> </Card> {/each} diff --git a/frontend/src/lib/tabs/ComicDelete.svelte b/frontend/src/lib/tabs/ComicDelete.svelte index a10f6b2..3ae924c 100644 --- a/frontend/src/lib/tabs/ComicDelete.svelte +++ b/frontend/src/lib/tabs/ComicDelete.svelte @@ -9,9 +9,9 @@ const client = getContextClient(); - export let comic: FullComicFragment; + let { comic }: { comic: FullComicFragment } = $props(); - function deleteComic() { + function onclick() { confirmDeletion('Comic', comic.title, () => { deleteComics(client, { ids: comic.id }) .then(() => goto('/comics/')) @@ -29,6 +29,6 @@ <p class="mt-2 font-medium">This action is irrevocable.</p> </div> <div class="flex"> - <DeleteButton prominent on:click={deleteComic} /> + <DeleteButton prominent {onclick} /> </div> </div> diff --git a/frontend/src/lib/tabs/ComicDetails.svelte b/frontend/src/lib/tabs/ComicDetails.svelte index 0a131af..121f068 100644 --- a/frontend/src/lib/tabs/ComicDetails.svelte +++ b/frontend/src/lib/tabs/ComicDetails.svelte @@ -28,12 +28,24 @@ <div class="flex flex-col gap-4 text-sm"> <Header {title}> {#if comic.url} - <a href={comic.url} target="_blank" rel="noreferrer" class="btn-slate" title="Open URL"> - <span class="icon-base icon-[material-symbols--link]" /> + <a + href={comic.url} + target="_blank" + rel="noreferrer" + class="btn-slate" + title="Open URL" + aria-label="Open URL" + > + <span class="icon-base icon-[material-symbols--link]"></span> </a> {/if} - <a href={`/archives/${comic.archive.id}`} class="btn-slate" title="Go to Archive"> - <span class="icon-base icon-[material-symbols--folder-zip]" /> + <a + href={`/archives/${comic.archive.id}`} + class="btn-slate" + title="Go to Archive" + aria-label="Go to Archive" + > + <span class="icon-base icon-[material-symbols--folder-zip]"></span> </a> </Header> diff --git a/frontend/src/lib/tabs/DetailsHeader.svelte b/frontend/src/lib/tabs/DetailsHeader.svelte index f980f75..ee5fa23 100644 --- a/frontend/src/lib/tabs/DetailsHeader.svelte +++ b/frontend/src/lib/tabs/DetailsHeader.svelte @@ -1,5 +1,7 @@ <script lang="ts"> - export let title: string; + import type { Snippet } from 'svelte'; + + let { title, children }: { title: string; children?: Snippet } = $props(); </script> <div class="flex items-center gap-2"> @@ -7,5 +9,5 @@ {title} </h2> <div class="grow"></div> - <slot /> + {@render children?.()} </div> diff --git a/frontend/src/lib/tabs/DetailsSection.svelte b/frontend/src/lib/tabs/DetailsSection.svelte index 9a6ad51..5514aa3 100644 --- a/frontend/src/lib/tabs/DetailsSection.svelte +++ b/frontend/src/lib/tabs/DetailsSection.svelte @@ -1,10 +1,12 @@ <script lang="ts"> - export let title: string; + import type { Snippet } from 'svelte'; + + let { title, children }: { title: string; children?: Snippet } = $props(); </script> <section class="flex flex-col gap-1"> <h2 class="text-base font-medium">{title}</h2> <div class="flex flex-wrap gap-1 text-gray-300"> - <slot /> + {@render children?.()} </div> </section> diff --git a/frontend/src/lib/tabs/Tab.svelte b/frontend/src/lib/tabs/Tab.svelte index cddd072..f8dc67c 100644 --- a/frontend/src/lib/tabs/Tab.svelte +++ b/frontend/src/lib/tabs/Tab.svelte @@ -1,14 +1,28 @@ <script lang="ts"> - import { getTabContext } from '$lib/Tabs'; import { fadeDefault } from '$lib/Transitions'; + import type { Snippet } from 'svelte'; import { fade } from 'svelte/transition'; + import { getTabContext } from './Tabs.svelte'; + + interface Props { + id: string; + title: string; + initial?: boolean; + children: Snippet; + } + + let { id, title, initial = false, children }: Props = $props(); const context = getTabContext(); - export let id: string; + + context.tabs = { ...context.tabs, [id]: { title } }; + if (initial) { + context.current = id; + } </script> -{#if $context.current === id} +{#if context.current === id} <div class="h-full overflow-auto py-2 pe-3 ps-1" in:fade={fadeDefault}> - <slot /> + {@render children?.()} </div> {/if} diff --git a/frontend/src/lib/tabs/Tabs.svelte b/frontend/src/lib/tabs/Tabs.svelte index fd5d08e..1ae7c32 100644 --- a/frontend/src/lib/tabs/Tabs.svelte +++ b/frontend/src/lib/tabs/Tabs.svelte @@ -1,28 +1,50 @@ +<script lang="ts" module> + import { getContext, setContext } from 'svelte'; + + type Tab = string; + type Tabs = Record<Tab, { title: string }>; + + class TabContext { + tabs: Tabs = $state({}); + current: Tab = $state(''); + } + + export function getTabContext() { + return getContext<TabContext>('tabs'); + } + + function initTabContext() { + return setContext('tabs', new TabContext()); + } +</script> + <script lang="ts"> - import { getTabContext } from '$lib/Tabs'; import { fadeFast } from '$lib/Transitions'; + import type { Snippet } from 'svelte'; import { fade } from 'svelte/transition'; - const context = getTabContext(); + let { badges = {}, children }: { badges?: Record<Tab, boolean>; children?: Snippet } = $props(); + + const context = initTabContext(); </script> <div class="flex h-full max-h-full flex-col"> <nav> <ul class="me-3 ms-1 flex border-b-2 border-slate-700 text-sm"> - {#each Object.entries($context.tabs) as [id, { title, badge }]} + {#each Object.entries(context.tabs) as [id, { title }]} <li class="-mb-0.5"> <button type="button" - class:active={$context.current === id} + class:active={context.current === id} class="focus-background relative flex gap-1 p-1 px-3 hover:border-b-2 hover:border-slate-200" - on:click={() => ($context.current = id)} + onclick={() => (context.current = id)} > - {#if badge} + {#if badges[id]} <div class="absolute right-0 top-1 h-2 w-2 rounded-full bg-emerald-400" title="There are pending changes" transition:fade={fadeFast} - /> + ></div> {/if} <span>{title}</span> </button> @@ -30,7 +52,7 @@ {/each} </ul> </nav> - <slot /> + {@render children?.()} </div> <style lang="postcss"> |