summaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
authorWolfgang Müller2025-02-13 19:04:12 +0100
committerWolfgang Müller2025-02-13 19:04:12 +0100
commit618f72b31d57ac17f475dbe983a31627cff3b96e (patch)
tree21cc384917ad64fe726d6356d3616df4b7507927
parent341fc19d4b7e9d8fb8b9a9d72377cf36565f2f2e (diff)
downloadhircine-618f72b31d57ac17f475dbe983a31627cff3b96e.tar.gz
frontend: Allow control-clicking to open the quick filter
This makes hircine's behaviour more consistent with standard browser behaviour (that would also open a new tab when control-clicking).
-rw-r--r--frontend/src/lib/Navigation.ts6
-rw-r--r--frontend/src/lib/components/Cardlet.svelte19
-rw-r--r--frontend/src/lib/selection/Selectable.svelte36
-rw-r--r--frontend/src/routes/artists/+page.svelte9
-rw-r--r--frontend/src/routes/characters/+page.svelte9
-rw-r--r--frontend/src/routes/circles/+page.svelte9
-rw-r--r--frontend/src/routes/namespaces/+page.svelte9
-rw-r--r--frontend/src/routes/tags/+page.svelte9
-rw-r--r--frontend/src/routes/worlds/+page.svelte9
9 files changed, 72 insertions, 43 deletions
diff --git a/frontend/src/lib/Navigation.ts b/frontend/src/lib/Navigation.ts
index f3bc413..4dcb998 100644
--- a/frontend/src/lib/Navigation.ts
+++ b/frontend/src/lib/Navigation.ts
@@ -1,5 +1,5 @@
import { goto as svelteGoto } from '$app/navigation';
-import { SortDirection } from '$gql/graphql';
+import { SortDirection, type ComicFilter } from '$gql/graphql';
import JsonURL from '@jsonurl/jsonurl';
import { toastError } from './Toasts';
import type { Key } from './Utils';
@@ -120,3 +120,7 @@ export function navigate(params: NavigationParameters<object>, current?: URLSear
export function href<T>(base: string, params: NavigationParameters<T>) {
return `/${base}/?${parametersFrom(params).toString()}`;
}
+
+export function quickComicFilter(id: number | string, filter: keyof ComicFilter) {
+ window.open(href('comics', { filter: { include: { [filter]: { all: [id] } } } }));
+}
diff --git a/frontend/src/lib/components/Cardlet.svelte b/frontend/src/lib/components/Cardlet.svelte
index d249cc8..d0c0509 100644
--- a/frontend/src/lib/components/Cardlet.svelte
+++ b/frontend/src/lib/components/Cardlet.svelte
@@ -1,30 +1,15 @@
<script lang="ts">
- import type { ComicFilter } from '$gql/graphql';
- import { href } from '$lib/Navigation';
import type { Snippet } from 'svelte';
interface Props {
name: string;
title?: string | null;
- filter?: keyof ComicFilter;
- id?: number | string;
overlay?: Snippet;
onclick: (event: MouseEvent) => void;
+ onauxclick?: (event: MouseEvent) => void;
}
- let {
- name,
- title = undefined,
- filter = undefined,
- id = undefined,
- overlay,
- onclick
- }: Props = $props();
-
- const onauxclick = (e: MouseEvent) => {
- if (filter === undefined || id === undefined || e.button !== 1) return;
- window.open(href('comics', { filter: { include: { [filter]: { all: [id] } } } }));
- };
+ let { name, title = undefined, overlay, onclick, onauxclick = undefined }: Props = $props();
</script>
<button
diff --git a/frontend/src/lib/selection/Selectable.svelte b/frontend/src/lib/selection/Selectable.svelte
index 4705f44..439d6b7 100644
--- a/frontend/src/lib/selection/Selectable.svelte
+++ b/frontend/src/lib/selection/Selectable.svelte
@@ -2,25 +2,47 @@
import type { Snippet } from 'svelte';
import { getSelectionContext } from './Selection.svelte';
+ interface SnippetProps {
+ onclick: (event: MouseEvent) => void;
+ onauxclick: (event: MouseEvent) => void;
+ selected: boolean;
+ }
+
interface Props {
id: number;
index: number;
- edit?: ((id: number) => void) | undefined;
- children?: Snippet<[{ onclick: (event: MouseEvent) => void; selected: boolean }]>;
+ onclick?: (id: number) => void;
+ onauxclick?: (id: number) => void;
+ children?: Snippet<[SnippetProps]>;
}
- let { id, index, edit = undefined, children }: Props = $props();
+ let {
+ id,
+ index,
+ onclick: onclick = undefined,
+ onauxclick = undefined,
+ children
+ }: Props = $props();
+
let selection = getSelectionContext();
- const onclick = (event: MouseEvent) => {
+ const click = (event: MouseEvent) => {
if (selection.active) {
selection.update(index, event.shiftKey);
event.preventDefault();
- } else if (edit) {
- edit(id);
+ } else if (event.ctrlKey && onauxclick) {
+ onauxclick(id);
+ } else if (onclick) {
+ onclick(id);
event.preventDefault();
}
};
+
+ const auxclick = (event: MouseEvent) => {
+ if (event.button === 1 && onauxclick) {
+ onauxclick(id);
+ }
+ };
</script>
-{@render children?.({ onclick, selected: selection.contains(id) })}
+{@render children?.({ onclick: click, onauxclick: auxclick, selected: selection.contains(id) })}
diff --git a/frontend/src/routes/artists/+page.svelte b/frontend/src/routes/artists/+page.svelte
index c907470..9f0d893 100644
--- a/frontend/src/routes/artists/+page.svelte
+++ b/frontend/src/routes/artists/+page.svelte
@@ -4,6 +4,7 @@
import type { Artist } from '$gql/graphql';
import { ArtistSortLabel } from '$lib/Enums';
import { BasicFilterContext } from '$lib/Filter.svelte';
+ import { quickComicFilter } from '$lib/Navigation';
import { toastFinally } from '$lib/Toasts';
import AddButton from '$lib/components/AddButton.svelte';
import Cardlet from '$lib/components/Cardlet.svelte';
@@ -53,6 +54,8 @@
.then((artist) => modals.open(EditArtist, { artist }))
.catch(toastFinally);
};
+
+ const quickFilter = (id: number) => quickComicFilter(id, 'artists');
</script>
<Head section="artists" />
@@ -78,9 +81,9 @@
<main>
<Cardlets>
{#each artists.edges as { id, name }, index (id)}
- <Selectable {index} {id} {edit}>
- {#snippet children({ onclick, selected })}
- <Cardlet {name} {onclick} filter="artists" {id}>
+ <Selectable {index} {id} onclick={edit} onauxclick={quickFilter}>
+ {#snippet children({ onclick, onauxclick, selected })}
+ <Cardlet {name} {onclick} {onauxclick}>
{#snippet overlay()}
<SelectionOverlay position="right" centered {selected} />
{/snippet}
diff --git a/frontend/src/routes/characters/+page.svelte b/frontend/src/routes/characters/+page.svelte
index 04c72cb..3a4b737 100644
--- a/frontend/src/routes/characters/+page.svelte
+++ b/frontend/src/routes/characters/+page.svelte
@@ -4,6 +4,7 @@
import type { Character } from '$gql/graphql';
import { CharacterSortLabel } from '$lib/Enums';
import { BasicFilterContext } from '$lib/Filter.svelte';
+ import { quickComicFilter } from '$lib/Navigation';
import { toastFinally } from '$lib/Toasts';
import AddButton from '$lib/components/AddButton.svelte';
import Cardlet from '$lib/components/Cardlet.svelte';
@@ -53,6 +54,8 @@
.then((character) => modals.open(EditCharacter, { character }))
.catch(toastFinally);
};
+
+ const quickFilter = (id: number) => quickComicFilter(id, 'characters');
</script>
<Head section="characters" />
@@ -78,9 +81,9 @@
<main>
<Cardlets>
{#each characters.edges as { id, name }, index (id)}
- <Selectable {index} {id} {edit}>
- {#snippet children({ onclick, selected })}
- <Cardlet {name} {onclick} filter="characters" {id}>
+ <Selectable {index} {id} onclick={edit} onauxclick={quickFilter}>
+ {#snippet children({ onclick, onauxclick, selected })}
+ <Cardlet {name} {onclick} {onauxclick}>
{#snippet overlay()}
<SelectionOverlay position="right" centered {selected} />
{/snippet}
diff --git a/frontend/src/routes/circles/+page.svelte b/frontend/src/routes/circles/+page.svelte
index 57520f8..8bac7ed 100644
--- a/frontend/src/routes/circles/+page.svelte
+++ b/frontend/src/routes/circles/+page.svelte
@@ -4,6 +4,7 @@
import type { Circle } from '$gql/graphql';
import { CircleSortLabel } from '$lib/Enums';
import { BasicFilterContext } from '$lib/Filter.svelte';
+ import { quickComicFilter } from '$lib/Navigation';
import { toastFinally } from '$lib/Toasts';
import AddButton from '$lib/components/AddButton.svelte';
import Cardlet from '$lib/components/Cardlet.svelte';
@@ -53,6 +54,8 @@
.then((circle) => modals.open(EditCircle, { circle }))
.catch(toastFinally);
};
+
+ const quickFilter = (id: number) => quickComicFilter(id, 'circles');
</script>
<Head section="circles" />
@@ -78,9 +81,9 @@
<main>
<Cardlets>
{#each circles.edges as { id, name }, index (id)}
- <Selectable {index} {id} {edit}>
- {#snippet children({ onclick, selected })}
- <Cardlet {name} {onclick} filter="circles" {id}>
+ <Selectable {index} {id} onclick={edit} onauxclick={quickFilter}>
+ {#snippet children({ onclick, onauxclick, selected })}
+ <Cardlet {name} {onclick} {onauxclick}>
{#snippet overlay()}
<SelectionOverlay position="right" centered {selected} />
{/snippet}
diff --git a/frontend/src/routes/namespaces/+page.svelte b/frontend/src/routes/namespaces/+page.svelte
index 04f7737..d8e728d 100644
--- a/frontend/src/routes/namespaces/+page.svelte
+++ b/frontend/src/routes/namespaces/+page.svelte
@@ -4,6 +4,7 @@
import type { Namespace } from '$gql/graphql';
import { NamespaceSortLabel } from '$lib/Enums';
import { BasicFilterContext } from '$lib/Filter.svelte';
+ import { quickComicFilter } from '$lib/Navigation';
import { toastFinally } from '$lib/Toasts';
import AddButton from '$lib/components/AddButton.svelte';
import Cardlet from '$lib/components/Cardlet.svelte';
@@ -53,6 +54,8 @@
.then((namespace) => modals.open(EditNamespace, { namespace }))
.catch(toastFinally);
};
+
+ const quickFilter = (id: number) => quickComicFilter(`${id}:`, 'tags');
</script>
<Head section="Namespaces" />
@@ -78,9 +81,9 @@
<main>
<Cardlets>
{#each namespaces.edges as { id, name }, index (id)}
- <Selectable {index} {id} {edit}>
- {#snippet children({ onclick, selected })}
- <Cardlet {name} {onclick} filter="tags" id={`${id}:`}>
+ <Selectable {index} {id} onclick={edit} onauxclick={quickFilter}>
+ {#snippet children({ onclick, onauxclick, selected })}
+ <Cardlet {name} {onclick} {onauxclick}>
{#snippet overlay()}
<SelectionOverlay position="right" centered {selected} />
{/snippet}
diff --git a/frontend/src/routes/tags/+page.svelte b/frontend/src/routes/tags/+page.svelte
index 30554c7..f71267f 100644
--- a/frontend/src/routes/tags/+page.svelte
+++ b/frontend/src/routes/tags/+page.svelte
@@ -4,6 +4,7 @@
import { type Tag } from '$gql/graphql';
import { TagSortLabel } from '$lib/Enums';
import { TagFilterContext } from '$lib/Filter.svelte';
+ import { quickComicFilter } from '$lib/Navigation';
import { toastFinally } from '$lib/Toasts';
import AddButton from '$lib/components/AddButton.svelte';
import Cardlet from '$lib/components/Cardlet.svelte';
@@ -58,6 +59,8 @@
.then((tag) => modals.open(EditTag, { tag }))
.catch(toastFinally);
};
+
+ const quickFilter = (id: number) => quickComicFilter(`:${id}`, 'tags');
</script>
<Head section="Tags" />
@@ -88,9 +91,9 @@
<main>
<Cardlets>
{#each tags.edges as { id, name, description }, index (id)}
- <Selectable {index} {id} {edit}>
- {#snippet children({ onclick, selected })}
- <Cardlet {name} title={description} {onclick} filter="tags" id={`:${id}`}>
+ <Selectable {index} {id} onclick={edit} onauxclick={quickFilter}>
+ {#snippet children({ onclick, onauxclick, selected })}
+ <Cardlet {name} title={description} {onclick} {onauxclick}>
{#snippet overlay()}
<SelectionOverlay position="right" centered {selected} />
{/snippet}
diff --git a/frontend/src/routes/worlds/+page.svelte b/frontend/src/routes/worlds/+page.svelte
index f223a61..6b95142 100644
--- a/frontend/src/routes/worlds/+page.svelte
+++ b/frontend/src/routes/worlds/+page.svelte
@@ -4,6 +4,7 @@
import type { World } from '$gql/graphql';
import { WorldSortLabel } from '$lib/Enums';
import { BasicFilterContext } from '$lib/Filter.svelte';
+ import { quickComicFilter } from '$lib/Navigation';
import { toastFinally } from '$lib/Toasts';
import AddButton from '$lib/components/AddButton.svelte';
import Cardlet from '$lib/components/Cardlet.svelte';
@@ -53,6 +54,8 @@
.then((world) => modals.open(EditWorld, { world }))
.catch(toastFinally);
};
+
+ const quickFilter = (id: number) => quickComicFilter(id, 'worlds');
</script>
<Head section="worlds" />
@@ -78,9 +81,9 @@
<main>
<Cardlets>
{#each worlds.edges as { id, name }, index (id)}
- <Selectable {index} {id} {edit}>
- {#snippet children({ onclick, selected })}
- <Cardlet {name} {onclick} filter="worlds" {id}>
+ <Selectable {index} {id} onclick={edit} onauxclick={quickFilter}>
+ {#snippet children({ onclick, onauxclick, selected })}
+ <Cardlet {name} {onclick} {onauxclick}>
{#snippet overlay()}
<SelectionOverlay position="right" centered {selected} />
{/snippet}