mirror of
https://github.com/CharaChorder/DeviceManager.git
synced 2026-01-21 01:12:59 +00:00
refactor: update to Svelte 5 preview
feat: add charrecorder feat: dynamic os layouts for CC1
This commit is contained in:
@@ -5,13 +5,22 @@
|
||||
KEYMAP_IDS,
|
||||
} from "$lib/serial/keymap-codes";
|
||||
import FlexSearch from "flexsearch";
|
||||
import { createEventDispatcher, onMount } from "svelte";
|
||||
import { onMount } from "svelte";
|
||||
import ActionListItem from "$lib/components/ActionListItem.svelte";
|
||||
import LL from "$i18n/i18n-svelte";
|
||||
import { action } from "$lib/title";
|
||||
|
||||
export let currentAction: number | undefined = undefined;
|
||||
export let nextAction: number | undefined = undefined;
|
||||
let {
|
||||
currentAction = undefined,
|
||||
nextAction = undefined,
|
||||
onselect,
|
||||
onclose,
|
||||
}: {
|
||||
currentAction?: number;
|
||||
nextAction?: number;
|
||||
onselect: (id: number) => void;
|
||||
onclose: () => void;
|
||||
} = $props();
|
||||
|
||||
onMount(() => {
|
||||
searchBox.focus();
|
||||
@@ -39,13 +48,13 @@
|
||||
|
||||
function select(id?: number) {
|
||||
if (id !== undefined) {
|
||||
dispatch("select", id);
|
||||
onselect(id);
|
||||
}
|
||||
}
|
||||
|
||||
function keyboardNavigation(event: KeyboardEvent) {
|
||||
if (event.shiftKey && event.key === "Enter") {
|
||||
dispatch("select", exact);
|
||||
if (event.shiftKey && event.key === "Enter" && exact !== undefined) {
|
||||
onselect(exact);
|
||||
} else if (event.key === "ArrowDown") {
|
||||
const element =
|
||||
resultList.querySelector("li:focus-within")?.nextSibling ??
|
||||
@@ -67,40 +76,45 @@
|
||||
event.preventDefault();
|
||||
}
|
||||
|
||||
let results: number[] = [];
|
||||
let exact: number | undefined = undefined;
|
||||
let code: number = Number.NaN;
|
||||
let results: number[] = $state([]);
|
||||
let exact: number | undefined = $state(undefined);
|
||||
let code: number = $state(Number.NaN);
|
||||
|
||||
const dispatch = createEventDispatcher();
|
||||
let searchBox: HTMLInputElement;
|
||||
let resultList: HTMLUListElement;
|
||||
let filter: Set<number>;
|
||||
let filter = $state(new Set<number>());
|
||||
</script>
|
||||
|
||||
<svelte:window on:keydown={keyboardNavigation} />
|
||||
|
||||
<!-- svelte-ignore a11y-click-events-have-key-events a11y-no-noninteractive-element-interactions -->
|
||||
<dialog open on:click|self={() => dispatch("close")}>
|
||||
<!-- svelte-ignore a11y_click_events_have_key_events -->
|
||||
<!-- svelte-ignore a11y_no_noninteractive_element_interactions -->
|
||||
<dialog
|
||||
open
|
||||
onclick={(event) => {
|
||||
if (event.target === event.currentTarget) onclose();
|
||||
}}
|
||||
>
|
||||
<div class="content">
|
||||
<div class="search-row">
|
||||
<input
|
||||
type="search"
|
||||
bind:this={searchBox}
|
||||
on:input={search}
|
||||
on:keypress={(event) => {
|
||||
oninput={search}
|
||||
onkeypress={(event) => {
|
||||
if (event.key === "Enter") {
|
||||
select(exact);
|
||||
}
|
||||
}}
|
||||
placeholder={$LL.actionSearch.PLACEHOLDER()}
|
||||
/>
|
||||
<button on:click={() => select(0)} use:action={{ shortcut: "shift+esc" }}
|
||||
<button onclick={() => select(0)} use:action={{ shortcut: "shift+esc" }}
|
||||
>{$LL.actionSearch.DELETE()}</button
|
||||
>
|
||||
<button
|
||||
use:action={{ title: $LL.modal.CLOSE(), shortcut: "esc" }}
|
||||
class="icon"
|
||||
on:click={() => dispatch("close")}>close</button
|
||||
onclick={onclose}>close</button
|
||||
>
|
||||
</div>
|
||||
<fieldset class="filters">
|
||||
@@ -140,12 +154,12 @@
|
||||
{#if exact !== undefined}
|
||||
<li class="exact">
|
||||
<i>Exact match</i>
|
||||
<ActionListItem id={exact} on:click={() => select(exact)} />
|
||||
<ActionListItem id={exact} onclick={() => select(exact)} />
|
||||
</li>
|
||||
{/if}
|
||||
{#if !exact && code}
|
||||
{#if code >= 2 ** 5 && code < 2 ** 13}
|
||||
<li><button on:click={() => select(code)}>USE CODE</button></li>
|
||||
<li><button onclick={() => select(code)}>USE CODE</button></li>
|
||||
{:else}
|
||||
<li>Action code is out of range</li>
|
||||
{/if}
|
||||
@@ -156,7 +170,7 @@
|
||||
? Array.from(KEYMAP_CODES, ([it]) => it)
|
||||
: results}
|
||||
{#each filter ? resultValue.filter( (it) => filter.has(it), ) : resultValue as id (id)}
|
||||
<li><ActionListItem {id} on:click={() => select(id)} /></li>
|
||||
<li><ActionListItem {id} onclick={() => select(id)} /></li>
|
||||
{/each}
|
||||
{/if}
|
||||
</ul>
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
import { get } from "svelte/store";
|
||||
import type { Writable } from "svelte/store";
|
||||
import KeyboardKey from "$lib/components/layout/KeyboardKey.svelte";
|
||||
import { getContext } from "svelte";
|
||||
import { getContext, mount, unmount } from "svelte";
|
||||
import type { VisualLayoutConfig } from "./visual-layout.js";
|
||||
import { changes, ChangeType, layout } from "$lib/undo-redo";
|
||||
import { fly } from "svelte/transition";
|
||||
@@ -30,8 +30,8 @@
|
||||
console.assert(iconFontSize % 1 === 0, "Icon font size must be an integer");
|
||||
}
|
||||
|
||||
export let visualLayout: VisualLayout;
|
||||
$: layoutInfo = compileLayout(visualLayout);
|
||||
let { visualLayout }: { visualLayout: VisualLayout } = $props();
|
||||
let layoutInfo = $state(compileLayout(visualLayout));
|
||||
|
||||
function getCenter(key: CompiledLayoutKey): [x: number, y: number] {
|
||||
return [key.pos[0] + key.size[0] / 2, key.pos[1] + key.size[1] / 2];
|
||||
@@ -127,11 +127,26 @@
|
||||
const clickedGroup = groupParent.children.item(index) as SVGGElement;
|
||||
const nextAction = get(layout)[get(activeLayer)]?.[keyInfo.id];
|
||||
const currentAction = get(deviceLayout)[get(activeLayer)]?.[keyInfo.id];
|
||||
const component = new ActionSelector({
|
||||
const component = mount(ActionSelector, {
|
||||
target: document.body,
|
||||
props: {
|
||||
currentAction,
|
||||
nextAction: nextAction?.isApplied ? undefined : nextAction?.action,
|
||||
onclose() {
|
||||
closed();
|
||||
},
|
||||
onselect(action) {
|
||||
changes.update((changes) => {
|
||||
changes.push({
|
||||
type: ChangeType.Layout,
|
||||
id: keyInfo.id,
|
||||
layer: get(activeLayer),
|
||||
action,
|
||||
});
|
||||
return changes;
|
||||
});
|
||||
closed();
|
||||
},
|
||||
},
|
||||
});
|
||||
const dialog = document.querySelector("dialog > div") as HTMLDivElement;
|
||||
@@ -167,22 +182,8 @@
|
||||
|
||||
await dialogAnimation.finished;
|
||||
|
||||
component.$destroy();
|
||||
unmount(component);
|
||||
}
|
||||
|
||||
component.$on("close", closed);
|
||||
component.$on("select", ({ detail }) => {
|
||||
changes.update((changes) => {
|
||||
changes.push({
|
||||
type: ChangeType.Layout,
|
||||
id: keyInfo.id,
|
||||
layer: get(activeLayer),
|
||||
action: detail,
|
||||
});
|
||||
return changes;
|
||||
});
|
||||
closed();
|
||||
});
|
||||
}
|
||||
|
||||
let focusKey: CompiledLayoutKey;
|
||||
@@ -201,9 +202,9 @@
|
||||
<KeyboardKey
|
||||
{i}
|
||||
{key}
|
||||
on:focusin={() => (focusKey = key)}
|
||||
on:click={() => edit(i)}
|
||||
on:keypress={({ key }) => {
|
||||
onfocusin={() => (focusKey = key)}
|
||||
onclick={() => edit(i)}
|
||||
onkeypress={({ key }) => {
|
||||
if (key === "Enter") {
|
||||
edit(i);
|
||||
}
|
||||
|
||||
@@ -12,14 +12,21 @@
|
||||
getContext<VisualLayoutConfig>("visual-layout-config");
|
||||
const activeLayer = getContext<Writable<number>>("active-layer");
|
||||
|
||||
export let key: CompiledLayoutKey;
|
||||
export let fontSizeMultiplier = 1;
|
||||
|
||||
export let middle: [number, number];
|
||||
export let pos: [number, number];
|
||||
export let rotate: number;
|
||||
|
||||
export let positions: [[number, number], [number, number], [number, number]];
|
||||
let {
|
||||
key,
|
||||
fontSizeMultiplier = 1,
|
||||
middle,
|
||||
pos,
|
||||
rotate,
|
||||
positions,
|
||||
}: {
|
||||
key: CompiledLayoutKey;
|
||||
fontSizeMultiplier?: number;
|
||||
middle: [number, number];
|
||||
pos: [number, number];
|
||||
rotate: number;
|
||||
positions: [[number, number], [number, number], [number, number]];
|
||||
} = $props();
|
||||
</script>
|
||||
|
||||
{#each positions as position, layer}
|
||||
|
||||
@@ -3,24 +3,41 @@
|
||||
import { getContext } from "svelte";
|
||||
import type { VisualLayoutConfig } from "./visual-layout.js";
|
||||
import KeyText from "$lib/components/layout/KeyText.svelte";
|
||||
import type {
|
||||
FocusEventHandler,
|
||||
KeyboardEventHandler,
|
||||
MouseEventHandler,
|
||||
} from "svelte/elements";
|
||||
|
||||
const { scale, margin, strokeWidth } = getContext<VisualLayoutConfig>(
|
||||
"visual-layout-config",
|
||||
);
|
||||
export let i: number;
|
||||
export let key: CompiledLayoutKey;
|
||||
|
||||
$: posX = key.pos[0] * scale;
|
||||
$: posY = key.pos[1] * scale;
|
||||
$: sizeX = key.size[0] * scale;
|
||||
$: sizeY = key.size[1] * scale;
|
||||
let {
|
||||
i,
|
||||
key,
|
||||
onclick,
|
||||
onkeypress,
|
||||
onfocusin,
|
||||
}: {
|
||||
i: number;
|
||||
key: CompiledLayoutKey;
|
||||
onclick: MouseEventHandler<SVGGElement>;
|
||||
onkeypress: KeyboardEventHandler<SVGGElement>;
|
||||
onfocusin: FocusEventHandler<SVGGElement>;
|
||||
} = $props();
|
||||
|
||||
let posX = $derived(key.pos[0] * scale);
|
||||
let posY = $derived(key.pos[1] * scale);
|
||||
let sizeX = $derived(key.size[0] * scale);
|
||||
let sizeY = $derived(key.size[1] * scale);
|
||||
</script>
|
||||
|
||||
<g
|
||||
class="key-group"
|
||||
on:click
|
||||
on:keypress
|
||||
on:focusin
|
||||
{onclick}
|
||||
{onkeypress}
|
||||
{onfocusin}
|
||||
role="button"
|
||||
tabindex={i + 1}
|
||||
>
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
import type { VisualLayout } from "$lib/serialization/visual-layout";
|
||||
import { fade } from "svelte/transition";
|
||||
|
||||
$: device = $serialPort?.device;
|
||||
let device = $derived($serialPort?.device);
|
||||
const activeLayer = getContext<Writable<number>>("active-layer");
|
||||
|
||||
const layers = [
|
||||
@@ -48,7 +48,7 @@
|
||||
<button
|
||||
class="icon"
|
||||
use:action={{ title, shortcut: `alt+${value + 1}` }}
|
||||
on:click={() => ($activeLayer = value)}
|
||||
onclick={() => ($activeLayer = value)}
|
||||
class:active={$activeLayer === value}
|
||||
>
|
||||
{icon}
|
||||
|
||||
Reference in New Issue
Block a user