summaryrefslogtreecommitdiffstatshomepage
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
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 '')
-rw-r--r--docs/usage/shortcuts.rst58
-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
8 files changed, 94 insertions, 29 deletions
diff --git a/docs/usage/shortcuts.rst b/docs/usage/shortcuts.rst
index 3f532e2..d261c00 100644
--- a/docs/usage/shortcuts.rst
+++ b/docs/usage/shortcuts.rst
@@ -92,16 +92,68 @@ Filtering
* - Shortcut
- Action
- * - ``F``
+ * - ``q``
- Focus search.
* - ``f``
- Toggle favourites.
* - ``b``
- Toggle bookmarked.
- * - ``o``
- - Toggle organized.
* - ``r``
- Toggle orphaned.
+ * - ``z``
+ - Toggle organized.
+
+.. _shortcut-advanced-filtering:
+
+Advanced Filtering
+------------------
+
+.. list-table::
+ :align: left
+ :header-rows: 1
+
+ * - Shortcut
+ - Action
+ * - ``F``
+ - Toggle advanced filters.
+ * - ``X``
+ - Reset filters.
+
+Focusing filter fields
+^^^^^^^^^^^^^^^^^^^^^^
+
+When the advanced filters are visible, each field may be focused by activating
+the following shortcuts prefixed by either ``i`` for an include field or ``e``
+for an exclude field. For example, to include an artist, hit ``ia``.
+
+.. list-table::
+ :align: left
+ :header-rows: 1
+
+ * - Shortcut
+ - Filters on...
+ * - ``n``
+ - Namespaces
+ * - ``t``
+ - Tags
+ * - ``a``
+ - Artists
+ * - ``i``
+ - Circles
+ * - ``h``
+ - Characters
+ * - ``w``
+ - Worlds
+ * - ``g``
+ - Categories
+ * - ``r``
+ - Ratings
+ * - ``s``
+ - Censorships
+ * - ``l``
+ - Languages
+ * - ``u``
+ - URLs
.. _shortcut-misc:
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>