summaryrefslogtreecommitdiffstatshomepage
path: root/frontend/src/routes/archives
diff options
context:
space:
mode:
authorWolfgang Müller2025-02-13 17:52:16 +0100
committerWolfgang Müller2025-02-13 17:52:16 +0100
commitdc4db405d2991d3ec6a114f3b08d3fccd057d3ee (patch)
tree2c620c9af2062ba09fa591f8b3ed961664adab58 /frontend/src/routes/archives
parent4df870d793123be95c8af031a340a39b5b8402ac (diff)
downloadhircine-dc4db405d2991d3ec6a114f3b08d3fccd057d3ee.tar.gz
frontend: Migrate to Svelte 5
Diffstat (limited to 'frontend/src/routes/archives')
-rw-r--r--frontend/src/routes/archives/+page.svelte131
-rw-r--r--frontend/src/routes/archives/[id]/+page.svelte65
2 files changed, 88 insertions, 108 deletions
diff --git a/frontend/src/routes/archives/+page.svelte b/frontend/src/routes/archives/+page.svelte
index 545058a..3fc4ed4 100644
--- a/frontend/src/routes/archives/+page.svelte
+++ b/frontend/src/routes/archives/+page.svelte
@@ -3,10 +3,7 @@
import { archivesQuery } from '$gql/Queries';
import type { ArchiveFragment } from '$gql/graphql';
import { ArchiveSortLabel } from '$lib/Enums';
- import { ArchiveFilterContext, initFilterContext } from '$lib/Filter';
- import { initPaginationContext } from '$lib/Pagination';
- import { initSelectionContext } from '$lib/Selection';
- import { initSortContext } from '$lib/Sort';
+ import { ArchiveFilterContext } from '$lib/Filter.svelte';
import Card from '$lib/components/Card.svelte';
import Empty from '$lib/components/Empty.svelte';
import Guard from '$lib/components/Guard.svelte';
@@ -17,6 +14,7 @@
import Pagination from '$lib/pagination/Pagination.svelte';
import Pill from '$lib/pills/Pill.svelte';
import Selectable from '$lib/selection/Selectable.svelte';
+ import { initSelectionContext } from '$lib/selection/Selection.svelte';
import SelectionOverlay from '$lib/selection/SelectionOverlay.svelte';
import DeleteSelection from '$lib/toolbar/DeleteSelection.svelte';
import FilterOrganized from '$lib/toolbar/FilterOrganized.svelte';
@@ -29,90 +27,91 @@
import Toolbar from '$lib/toolbar/Toolbar.svelte';
import { getContextClient } from '@urql/svelte';
import { filesize } from 'filesize';
- import type { PageData } from './$types';
+ import type { PageProps } from './$types';
- let client = getContextClient();
+ let { data }: PageProps = $props();
+ let pagination = $derived(data.pagination);
+ let sort = $derived(data.sort);
- export let data: PageData;
+ const client = getContextClient();
+ let result = $derived(archivesQuery(client, { ...data }));
+ let archives = $derived($result.data?.archives);
- $: result = archivesQuery(client, {
- pagination: data.pagination,
- filter: data.filter,
- sort: data.sort
+ let selection = initSelectionContext<ArchiveFragment>('Archive', (a) => a.name);
+ $effect(() => {
+ if (archives) {
+ selection.view = archives.edges;
+ }
});
- $: archives = $result.data?.archives;
-
- const selection = initSelectionContext<ArchiveFragment>('Archive', (a) => a.name);
- $: if (archives) {
- $selection.view = archives.edges;
- $pagination.total = archives.count;
- }
-
- const pagination = initPaginationContext();
- $: $pagination.update = data.pagination;
-
- const filter = initFilterContext<ArchiveFilterContext>();
- $: $filter = new ArchiveFilterContext(data.filter);
-
- const sort = initSortContext(data.sort, ArchiveSortLabel);
- $: $sort.update = data.sort;
-
- function refresh() {
- result.reexecute({ requestPolicy: 'network-only' });
- }
+ let filter = $state(new ArchiveFilterContext(data.filter));
+ $effect(() => {
+ filter = new ArchiveFilterContext(data.filter);
+ });
</script>
<Head section="Archives" />
<Column>
<Toolbar>
- <SelectionControls slot="start">
- <MarkSelection>
- <MarkOrganized mutation={updateArchives} />
- </MarkSelection>
- <DeleteSelection
- mutation={deleteArchives}
- warning="Deleting an archive will also delete its archive file on disk as well as all comics that belong to it."
- />
- </SelectionControls>
- <svelte:fragment slot="center">
- <Search name="Archives" bind:field={$filter.include.controls.path.contains} />
- <FilterOrganized />
- <SelectSort />
- <SelectItems />
- </svelte:fragment>
- <RefreshButton slot="end" on:click={refresh} />
+ {#snippet start()}
+ <SelectionControls>
+ <MarkSelection>
+ <MarkOrganized mutation={updateArchives} />
+ </MarkSelection>
+ <DeleteSelection
+ mutation={deleteArchives}
+ warning="Deleting an archive will also delete its archive file on disk as well as all comics that belong to it."
+ />
+ </SelectionControls>
+ {/snippet}
+ {#snippet center()}
+ <Search name="Archives" {filter} bind:field={filter.include.path.contains} />
+ <FilterOrganized {filter} />
+ <SelectSort {sort} labels={ArchiveSortLabel} />
+ <SelectItems {pagination} />
+ {/snippet}
+ {#snippet end()}
+ <RefreshButton onclick={() => result.reexecute({ requestPolicy: 'network-only' })} />
+ {/snippet}
</Toolbar>
{#if archives}
- <Pagination />
+ <Pagination {pagination} total={archives.count} />
<main>
<Cards>
{#each archives.edges as { id, name, cover, size, pageCount }, index (id)}
- <Selectable {index} {id} let:handle let:selected>
- <Card
- ellipsis={false}
- href={id.toString()}
- details={{ title: name, cover: cover }}
- on:click={handle}
- >
- <SelectionOverlay position="left" {selected} slot="overlay" />
- <div class="flex gap-1 text-xs">
- <Pill name={`${pageCount} pages`}>
- <span class="icon-[material-symbols--note] mr-0.5" slot="icon" />
- </Pill>
- <Pill name={filesize(size, { base: 2 })}>
- <span class="icon-[material-symbols--hard-drive] mr-0.5" slot="icon" />
- </Pill>
- </div>
- </Card>
+ <Selectable {index} {id}>
+ {#snippet children({ onclick, selected })}
+ <Card
+ ellipsis={false}
+ href={id.toString()}
+ details={{ title: name, cover }}
+ {onclick}
+ >
+ {#snippet overlay()}
+ <SelectionOverlay position="left" {selected} />
+ {/snippet}
+ <div class="flex gap-1 text-xs">
+ <Pill name={`${pageCount} pages`}>
+ {#snippet icon()}
+ <span class="icon-[material-symbols--note] mr-0.5"></span>
+ {/snippet}
+ </Pill>
+ <Pill name={filesize(size, { base: 2 })}>
+ {#snippet icon()}
+ <span class="icon-[material-symbols--hard-drive] mr-0.5"></span>
+ {/snippet}
+ </Pill>
+ </div>
+ </Card>
+ {/snippet}
</Selectable>
{:else}
<Empty />
{/each}
</Cards>
</main>
- <Pagination />
+ <Pagination {pagination} total={archives.count} />
{:else}
<Guard {result} />
{/if}
diff --git a/frontend/src/routes/archives/[id]/+page.svelte b/frontend/src/routes/archives/[id]/+page.svelte
index 50a2940..56c3273 100644
--- a/frontend/src/routes/archives/[id]/+page.svelte
+++ b/frontend/src/routes/archives/[id]/+page.svelte
@@ -2,9 +2,6 @@
import { updateArchives } from '$gql/Mutations';
import { archiveQuery } from '$gql/Queries';
import { Direction, Layout, type FullArchiveFragment, type PageFragment } from '$gql/graphql';
- import { initReaderContext } from '$lib/Reader';
- import { initSelectionContext } from '$lib/Selection';
- import { setTabContext } from '$lib/Tabs';
import { toastFinally } from '$lib/Toasts';
import Guard from '$lib/components/Guard.svelte';
import Head from '$lib/components/Head.svelte';
@@ -12,52 +9,40 @@
import Grid from '$lib/containers/Grid.svelte';
import Gallery from '$lib/gallery/Gallery.svelte';
import PageView from '$lib/reader/PageView.svelte';
- import Reader from '$lib/reader/Reader.svelte';
+ import Reader, { initReaderContext } from '$lib/reader/Reader.svelte';
+ import { initSelectionContext } from '$lib/selection/Selection.svelte';
import ArchiveDelete from '$lib/tabs/ArchiveDelete.svelte';
import ArchiveDetails from '$lib/tabs/ArchiveDetails.svelte';
import ArchiveEdit from '$lib/tabs/ArchiveEdit.svelte';
import Tab from '$lib/tabs/Tab.svelte';
import Tabs from '$lib/tabs/Tabs.svelte';
import { getContextClient } from '@urql/svelte';
- import type { PageData } from './$types';
+ import type { PageProps } from './$types';
- export let data: PageData;
+ let { data }: PageProps = $props();
const client = getContextClient();
const reader = initReaderContext();
- setTabContext({
- tabs: {
- details: { title: 'Details' },
- edit: { title: 'Edit' },
- deletion: { title: 'Delete' }
- },
- current: 'details'
- });
-
- $: result = archiveQuery(client, { id: data.id });
- function updateCover(event: CustomEvent<number>) {
- updateArchives(client, { ids: archive.id, input: { cover: { id: event.detail } } }).catch(
- toastFinally
- );
+ function updateCover(id: number) {
+ updateArchives(client, { ids: data.id, input: { cover: { id } } }).catch(toastFinally);
}
- let archive: FullArchiveFragment;
+ let selection = initSelectionContext<PageFragment>(
+ 'Page',
+ (p) => p.path,
+ (p) => p.comicId === null
+ );
- $: $result, update();
- function update() {
- if (!$result.stale && $result.data?.archive.__typename === 'FullArchive') {
- archive = structuredClone($result.data.archive);
+ let result = $derived(archiveQuery(client, { id: data.id }));
+ let archive: FullArchiveFragment | undefined = $state();
- $reader.pages = archive.pages;
+ $effect(() => {
+ if (!$result.stale && $result.data?.archive.__typename === 'FullArchive') {
+ archive = $result.data.archive;
+ reader.pages = $result.data.archive.pages;
+ selection.view = $result.data.archive.pages;
}
- }
-
- const selection = initSelectionContext<PageFragment>('Page', (p) => p.path);
- $selection.selectable = (p) => p.comicId === null;
-
- $: if (archive) {
- $selection.view = archive.pages;
- }
+ });
</script>
<Head section="Archive" title={archive?.name} />
@@ -70,24 +55,20 @@
<aside>
<Tabs>
- <Tab id="details">
+ <Tab initial id="details" title="Details">
<ArchiveDetails {archive} />
</Tab>
- <Tab id="edit">
+ <Tab id="edit" title="Edit">
<ArchiveEdit {archive} />
</Tab>
- <Tab id="deletion">
+ <Tab id="deletion" title="Delete">
<ArchiveDelete {archive} />
</Tab>
</Tabs>
</aside>
<main class="overflow-auto">
- <Gallery
- pages={archive.pages}
- on:open={(e) => ($reader = $reader.open(e.detail))}
- on:cover={updateCover}
- />
+ <Gallery pages={archive.pages} open={reader.open} {updateCover} />
</main>
</Grid>
{:else}