105 lines
2.7 KiB
Svelte
105 lines
2.7 KiB
Svelte
<script lang="ts">
|
|
import { tick } from "svelte";
|
|
import { chats } from "#lib/stores/chats.svelte.js";
|
|
import { search } from "#lib/stores/search.svelte.js";
|
|
import { ui } from "#lib/stores/ui.svelte.js";
|
|
import { goto } from "$app/navigation";
|
|
import { page } from "$app/state";
|
|
|
|
const EDITABLE = "input, textarea, select, [contenteditable='true']";
|
|
const LAYERS = "[role='dialog'], [role='alertdialog'], [role='menu']";
|
|
|
|
const chatId = $derived(
|
|
page.params.chatId ? Number(page.params.chatId) : null
|
|
);
|
|
|
|
async function focusIn(selector: string) {
|
|
await tick();
|
|
document.querySelector<HTMLInputElement>(selector)?.focus();
|
|
}
|
|
|
|
async function focusSearch() {
|
|
if (ui.leftView === "settings") {
|
|
ui.closeSettings();
|
|
}
|
|
await focusIn("#LeftColumn .left-header input");
|
|
}
|
|
|
|
function stepChat(step: number) {
|
|
const { list } = chats;
|
|
const index = list.findIndex((chat) => chat.chat_id === chatId);
|
|
if (index === -1 && step < 0) {
|
|
return;
|
|
}
|
|
const target = index === -1 ? list[0] : list[index + step];
|
|
if (target) {
|
|
goto(`/app/${target.chat_id}`);
|
|
}
|
|
}
|
|
|
|
function closeTop(editable: HTMLElement | null) {
|
|
if (editable) {
|
|
if (editable.closest("#LeftColumn .left-header")) {
|
|
search.close();
|
|
}
|
|
editable.blur();
|
|
} else if (ui.rightPanel !== null) {
|
|
ui.closePanel();
|
|
} else if (ui.leftView === "settings") {
|
|
ui.closeSettings();
|
|
} else if (chatId !== null) {
|
|
goto("/app");
|
|
}
|
|
}
|
|
|
|
function onCommand(event: KeyboardEvent): boolean {
|
|
const key = event.key.toLowerCase();
|
|
if (key === "k") {
|
|
focusSearch();
|
|
return true;
|
|
}
|
|
if (key === "f" && chatId !== null) {
|
|
ui.openPanel("search");
|
|
focusIn("#RightColumn input");
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
function onPlain(event: KeyboardEvent): boolean {
|
|
if (event.key === "/" && !event.altKey) {
|
|
focusSearch();
|
|
return true;
|
|
}
|
|
if (
|
|
event.altKey &&
|
|
(event.key === "ArrowUp" || event.key === "ArrowDown")
|
|
) {
|
|
stepChat(event.key === "ArrowUp" ? -1 : 1);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
function onkeydown(event: KeyboardEvent) {
|
|
if (event.defaultPrevented || document.querySelector(LAYERS)) {
|
|
return;
|
|
}
|
|
const target = event.target as HTMLElement | null;
|
|
const editable = target?.closest<HTMLElement>(EDITABLE) ?? null;
|
|
const modified = event.ctrlKey || event.metaKey;
|
|
if (event.key === "Escape") {
|
|
closeTop(editable);
|
|
return;
|
|
}
|
|
const handled = modified
|
|
? !event.altKey && onCommand(event)
|
|
: editable === null && onPlain(event);
|
|
if (handled) {
|
|
event.preventDefault();
|
|
}
|
|
}
|
|
</script>
|
|
|
|
<svelte:window {onkeydown} />
|