Files
beaver-calendar/src/ui/shortcuts.svelte
T

106 lines
3.5 KiB
Svelte

<script lang="ts">
import { fade, fly } from "svelte/transition";
import { cubicOut } from "svelte/easing";
import { GROUPS, SHORTCUTS } from "../lib/keymap";
import type { Group } from "../lib/keymap";
import { useView } from "./context";
const view = useView();
const store = view.store;
function close(): void {
store.helpOpen = false;
}
function grab(node: HTMLElement) {
node.focus({ preventScroll: true });
return { destroy: () => view.focusRoot() };
}
function onkeydown(event: KeyboardEvent): void {
if (event.key !== "Escape" && event.key !== "?") return;
event.preventDefault();
event.stopPropagation();
close();
}
function rows(group: Group) {
return SHORTCUTS.filter((shortcut) => shortcut.group === group);
}
/**
* Only Moving needs the qualifier: it is the one group where the same key
* does two things. The other groups say their scope in the heading.
*/
function scope(shortcut: (typeof SHORTCUTS)[number]): string {
if (shortcut.group !== "Moving") return "";
if (shortcut.scopes.includes("task")) return "on a task";
if (shortcut.scopes.includes("day")) return "on a day";
return "";
}
</script>
<div
class="fixed inset-0 z-50 grid place-items-center bg-black/45 p-4 outline-none backdrop-blur-[2px]"
onclick={close}
{onkeydown}
role="presentation"
tabindex="-1"
transition:fade={{ duration: 120 }}
use:grab
>
<div
class="max-h-full w-full max-w-5xl overflow-y-auto rounded-xl border border-border bg-popover text-popover-foreground shadow-[0_24px_64px_-16px_rgb(0_0_0/55%)] @container"
onclick={(event) => event.stopPropagation()}
onkeydown={() => {}}
role="presentation"
transition:fly={{ duration: 180, easing: cubicOut, y: 8 }}
>
<div class="flex items-baseline gap-3 px-5 pt-4 pb-3">
<h2 class="font-semibold text-base">Keyboard</h2>
<p class="text-muted-foreground text-xs">
The vim block reads the physical key, so it answers on a Cyrillic layout too.
</p>
<button
class="ml-auto shrink-0 rounded-md px-2 py-1 text-muted-foreground text-xs outline-none transition-colors hover:bg-muted hover:text-foreground focus-visible:ring-2 focus-visible:ring-ring"
onclick={close}
type="button"
>
esc
</button>
</div>
<div class="gap-x-8 px-5 pb-5 @min-[34rem]:columns-2 @min-[58rem]:columns-3">
{#each GROUPS as group (group)}
<section class="mb-4 min-w-0 break-inside-avoid">
<h3
class="pb-1.5 font-semibold text-[10px] text-muted-foreground uppercase tracking-[0.09em]"
>
{group}
</h3>
<dl class="grid grid-cols-[1fr_auto] items-center gap-x-3">
{#each rows(group) as shortcut, index (`${shortcut.label}-${index}`)}
<dt
class="min-w-0 truncate border-border/40 border-t py-1 text-xs first:border-t-0"
title={shortcut.label}
>
{shortcut.label}
{#if scope(shortcut)}
<span class="text-muted-foreground/70">{scope(shortcut)}</span>
{/if}
</dt>
<dd
class="flex shrink-0 items-center gap-1 border-border/40 border-t py-1 [&:nth-child(2)]:border-t-0"
>
{#each shortcut.keys as key (key)}
<kbd class="kbd">{key}</kbd>
{/each}
</dd>
{/each}
</dl>
</section>
{/each}
</div>
</div>
</div>