summaryrefslogtreecommitdiffstatshomepage
path: root/frontend
diff options
context:
space:
mode:
authorWolfgang Müller2025-02-20 16:09:08 +0100
committerWolfgang Müller2025-02-21 12:12:48 +0100
commit000a1e8a33ac3f1dea00ca21aac0f1771a0325f0 (patch)
tree66a9679a3f2d8f2833afa62101fb58e92adf4e6e /frontend
parent18c8719b74b1510ad82b686333071bcc10d68e30 (diff)
downloadhircine-000a1e8a33ac3f1dea00ca21aac0f1771a0325f0.tar.gz
frontend: Rework and improve accelerators
This commit switches around a couple of existing accelerators to make them easier to activate with just the left hand on the keyboard and more easily allow the addition of accelerators for all filter fields.
Diffstat (limited to 'frontend')
-rw-r--r--frontend/src/lib/Shortcuts.ts2
-rw-r--r--frontend/src/lib/filter/ComicFilterForm.svelte43
-rw-r--r--frontend/src/lib/filter/TagFilterForm.svelte7
-rw-r--r--frontend/src/lib/filter/components/Filter.svelte6
-rw-r--r--frontend/src/lib/toolbar/FilterOrganized.svelte2
-rw-r--r--frontend/src/lib/toolbar/Search.svelte2
-rw-r--r--frontend/src/lib/toolbar/ToggleAdvancedFilters.svelte3
7 files changed, 39 insertions, 26 deletions
diff --git a/frontend/src/lib/Shortcuts.ts b/frontend/src/lib/Shortcuts.ts
index 1ff7679..82f19ac 100644
--- a/frontend/src/lib/Shortcuts.ts
+++ b/frontend/src/lib/Shortcuts.ts
@@ -31,7 +31,7 @@ type UppercaseLetter = Uppercase<LowercaseLetter>;
type Letter = LowercaseLetter | UppercaseLetter;
type Special = '?' | 'Enter' | 'Escape' | 'Delete';
-const modeSwitches = ['n', 'g', 'i'] as const;
+const modeSwitches = ['n', 'g', 'i', 'e'] as const;
type ModeSwitch = (typeof modeSwitches)[number];
function isModeSwitch(s: string): s is ModeSwitch {
diff --git a/frontend/src/lib/filter/ComicFilterForm.svelte b/frontend/src/lib/filter/ComicFilterForm.svelte
index 331d571..4c6e2d2 100644
--- a/frontend/src/lib/filter/ComicFilterForm.svelte
+++ b/frontend/src/lib/filter/ComicFilterForm.svelte
@@ -2,6 +2,7 @@
import { artistList, characterList, circleList, comicTagList, worldList } from '$gql/Queries';
import { categories, censorships, languages, ratings } from '$lib/Enums';
import { ComicFilterContext } from '$lib/Filter.svelte';
+ import { accelerator } from '$lib/Shortcuts';
import { getContextClient } from '@urql/svelte';
import Filter from './components/Filter.svelte';
import FilterForm from './components/FilterForm.svelte';
@@ -21,38 +22,42 @@
let characters = $derived($charactersQuery.data?.characters.edges);
let circles = $derived($circlesQuery.data?.circles.edges);
let worlds = $derived($worldsQuery.data?.worlds.edges);
+
+ let inc = $derived(filter.include);
+ let exc = $derived(filter.exclude);
</script>
<FilterForm type="grid" apply={filter.apply}>
{#snippet include(type)}
- <Filter {type} wide title="Tags" options={tags} filter={filter.include.tags} />
- <Filter {type} title="Artists" options={artists} filter={filter.include.artists} />
- <Filter {type} title="Circles" options={circles} filter={filter.include.circles} />
- <Filter {type} title="Characters" options={characters} filter={filter.include.characters} />
- <Filter {type} title="Worlds" options={worlds} filter={filter.include.worlds} />
- <Filter {type} title="Categories" options={categories} filter={filter.include.categories} />
- <Filter {type} title="Ratings" options={ratings} filter={filter.include.ratings} />
- <Filter {type} title="Censorship" options={censorships} filter={filter.include.censorships} />
- <Filter {type} title="Languages" options={languages} filter={filter.include.languages} />
+ <Filter {type} wide title="Tags" options={tags} filter={inc.tags} accel="it" />
+ <Filter {type} title="Artists" options={artists} filter={inc.artists} accel="ia" />
+ <Filter {type} title="Circles" options={circles} filter={inc.circles} accel="ii" />
+ <Filter {type} title="Characters" options={characters} filter={inc.characters} accel="ih" />
+ <Filter {type} title="Worlds" options={worlds} filter={inc.worlds} accel="iw" />
+ <Filter {type} title="Categories" options={categories} filter={inc.categories} accel="ig" />
+ <Filter {type} title="Ratings" options={ratings} filter={inc.ratings} accel="ir" />
+ <Filter {type} title="Censorship" options={censorships} filter={inc.censorships} accel="is" />
+ <Filter {type} title="Languages" options={languages} filter={inc.languages} accel="il" />
<div class="flex flex-col">
<label for="include-url">URL</label>
<input
+ use:accelerator={'iu'}
id="include-url"
class="h-full"
placeholder="Search..."
- bind:value={filter.include.url.contains}
+ bind:value={inc.url.contains}
/>
</div>
{/snippet}
{#snippet exclude(type)}
- <Filter {type} wide title="Tags" options={tags} filter={filter.exclude.tags} />
- <Filter {type} title="Artists" options={artists} filter={filter.exclude.artists} />
- <Filter {type} title="Circles" options={circles} filter={filter.exclude.circles} />
- <Filter {type} title="Characters" options={characters} filter={filter.exclude.characters} />
- <Filter {type} title="Worlds" options={worlds} filter={filter.exclude.worlds} />
- <Filter {type} title="Categories" options={categories} filter={filter.exclude.categories} />
- <Filter {type} title="Ratings" options={ratings} filter={filter.exclude.ratings} />
- <Filter {type} title="Censorship" options={censorships} filter={filter.exclude.censorships} />
- <Filter {type} title="Languages" options={languages} filter={filter.exclude.languages} />
+ <Filter {type} wide title="Tags" options={tags} filter={exc.tags} accel="et" />
+ <Filter {type} title="Artists" options={artists} filter={exc.artists} accel="ea" />
+ <Filter {type} title="Circles" options={circles} filter={exc.circles} accel="ei" />
+ <Filter {type} title="Characters" options={characters} filter={exc.characters} accel="eh" />
+ <Filter {type} title="Worlds" options={worlds} filter={exc.worlds} accel="ew" />
+ <Filter {type} title="Categories" options={categories} filter={exc.categories} accel="eg" />
+ <Filter {type} title="Ratings" options={ratings} filter={exc.ratings} accel="er" />
+ <Filter {type} title="Censorship" options={censorships} filter={exc.censorships} accel="es" />
+ <Filter {type} title="Languages" options={languages} filter={exc.languages} accel="el" />
{/snippet}
</FilterForm>
diff --git a/frontend/src/lib/filter/TagFilterForm.svelte b/frontend/src/lib/filter/TagFilterForm.svelte
index 1ca1a2d..c514163 100644
--- a/frontend/src/lib/filter/TagFilterForm.svelte
+++ b/frontend/src/lib/filter/TagFilterForm.svelte
@@ -11,13 +11,16 @@
let namespaceQuery = $derived(namespaceList(client));
let namespaces = $derived($namespaceQuery.data?.namespaces.edges);
+
+ let inc = $derived(filter.include);
+ let exc = $derived(filter.exclude);
</script>
<FilterForm apply={filter.apply}>
{#snippet include(type)}
- <Filter {type} title="Namespaces" options={namespaces} filter={filter.include.namespaces} />
+ <Filter {type} title="Namespaces" options={namespaces} filter={inc.namespaces} accel="in" />
{/snippet}
{#snippet exclude(type)}
- <Filter {type} title="Namespaces" options={namespaces} filter={filter.exclude.namespaces} />
+ <Filter {type} title="Namespaces" options={namespaces} filter={exc.namespaces} accel="en" />
{/snippet}
</FilterForm>
diff --git a/frontend/src/lib/filter/components/Filter.svelte b/frontend/src/lib/filter/components/Filter.svelte
index 832ac19..4ebbd7f 100644
--- a/frontend/src/lib/filter/components/Filter.svelte
+++ b/frontend/src/lib/filter/components/Filter.svelte
@@ -1,5 +1,6 @@
<script lang="ts">
import { Association, Enum, type FilterType } from '$lib/Filter.svelte';
+ import { accelerator, type Shortcut } from '$lib/Shortcuts';
import type { ListItem } from '$lib/Utils';
import Select from '$lib/components/Select.svelte';
@@ -8,10 +9,11 @@
type: FilterType;
options: ListItem[] | undefined;
filter: Association<string> | Enum<string>;
+ accel: Shortcut;
wide?: boolean;
}
- let { title, type, options, filter, wide = false }: Props = $props();
+ let { title, type, options, filter, accel, wide = false }: Props = $props();
let exclude = $derived(type === 'exclude');
const id = `${type}-${title.toLowerCase()}`;
@@ -19,7 +21,7 @@
<div class:exclude class:wide class="[&.wide]:col-span-2">
<div class="flex gap-2">
- <label for={id}>{title}</label>
+ <label use:accelerator={accel} for={id}>{title}</label>
<div class="ml-auto flex items-center gap-1 self-center text-xs">
{#if filter instanceof Association}
<button
diff --git a/frontend/src/lib/toolbar/FilterOrganized.svelte b/frontend/src/lib/toolbar/FilterOrganized.svelte
index 0f95e5f..9fc9d21 100644
--- a/frontend/src/lib/toolbar/FilterOrganized.svelte
+++ b/frontend/src/lib/toolbar/FilterOrganized.svelte
@@ -24,7 +24,7 @@
class="btn-slate"
title="Filter organized"
onclick={toggle}
- use:accelerator={'o'}
+ use:accelerator={'z'}
>
<Organized tristate {organized} />
</button>
diff --git a/frontend/src/lib/toolbar/Search.svelte b/frontend/src/lib/toolbar/Search.svelte
index 4806971..d5971bc 100644
--- a/frontend/src/lib/toolbar/Search.svelte
+++ b/frontend/src/lib/toolbar/Search.svelte
@@ -19,5 +19,5 @@
placeholder="Search {name}..."
bind:value={field}
use:debounce={{ callback: () => filter.apply(page.url.searchParams) }}
- use:accelerator={'F'}
+ use:accelerator={'q'}
/>
diff --git a/frontend/src/lib/toolbar/ToggleAdvancedFilters.svelte b/frontend/src/lib/toolbar/ToggleAdvancedFilters.svelte
index ee07902..2ef63f4 100644
--- a/frontend/src/lib/toolbar/ToggleAdvancedFilters.svelte
+++ b/frontend/src/lib/toolbar/ToggleAdvancedFilters.svelte
@@ -1,6 +1,7 @@
<script lang="ts">
import { page } from '$app/state';
import { navigate } from '$lib/Navigation';
+ import { accelerator } from '$lib/Shortcuts';
import { slideXFast } from '$lib/Transitions';
import Badge from '$lib/components/Badge.svelte';
import { slide } from 'svelte/transition';
@@ -19,6 +20,7 @@
class="btn-slate relative"
title={`${expanded ? 'Hide' : 'Show'} filters`}
onclick={toggle}
+ use:accelerator={'F'}
>
{#if expanded}
<span class="icon-base icon-[material-symbols--filter-alt]"></span>
@@ -34,6 +36,7 @@
transition:slide={slideXFast}
title="Reset filters"
aria-label="Reset filters"
+ use:accelerator={'X'}
>
<div class="flex">
<span class="icon-base icon-[material-symbols--filter-alt-off]"></span>