fix: action selector

update dependencies
This commit is contained in:
2025-12-18 15:35:33 +01:00
parent e08dda40d9
commit 9f65b4bb6c
18 changed files with 712 additions and 611 deletions

19
src/lib/assets/layouts/layout.d.ts vendored Normal file
View File

@@ -0,0 +1,19 @@
export interface CompiledLayout {
name: string;
size: [number, number];
keys: CompiledLayoutKey[];
}
export interface CompiledLayoutKey {
id: number;
shape: "quarter-circle" | "square";
cornerRadius: number;
size: [number, number];
pos: [number, number];
rotate: number;
}
declare module "*.layout.yml" {
const layout: CompiledLayout;
export default layout;
}

View File

@@ -32,6 +32,9 @@
onMount(() => {
search();
if (autofocus) {
searchBox.focus();
}
});
const index = new FlexSearch.Index({ tokenize: "full" });
@@ -122,7 +125,6 @@
<!-- svelte-ignore a11y_autofocus -->
<input
type="search"
{autofocus}
bind:this={searchBox}
oninput={search}
onkeypress={keyboardNavigation}
@@ -175,16 +177,19 @@
<button
class="action-item"
draggable="true"
ondragstart={(event) => {
if (!event.dataTransfer) return;
event.stopPropagation();
event.dataTransfer.dropEffect = "copy";
event.dataTransfer.clearData();
event.dataTransfer.setData(
"text/plain",
actionToValue(action.code),
);
}}
onclick={() => select(action.code)}
ondragstart={onselect === undefined
? (event) => {
if (!event.dataTransfer) return;
event.stopPropagation();
event.dataTransfer.dropEffect = "copy";
event.dataTransfer.clearData();
event.dataTransfer.setData(
"text/plain",
actionToValue(action.code),
);
}
: undefined}
>
<Action {action} display="verbose"></Action>
</button>

View File

@@ -1,9 +1,4 @@
<script lang="ts">
import { compileLayout } from "$lib/serialization/visual-layout";
import type {
VisualLayout,
CompiledLayoutKey,
} from "$lib/serialization/visual-layout";
import { deviceLayout } from "$lib/serial/connection";
import { dev } from "$app/environment";
import ActionSelector from "$lib/components/layout/ActionSelector.svelte";
@@ -15,6 +10,10 @@
import { fly } from "svelte/transition";
import { expoOut } from "svelte/easing";
import { activeLayer, activeProfile } from "$lib/serial/connection";
import type {
CompiledLayout,
CompiledLayoutKey,
} from "$lib/assets/layouts/layout.d.ts";
const { scale, margin, strokeWidth, fontSize, iconFontSize } =
getContext<VisualLayoutConfig>("visual-layout-config");
@@ -29,8 +28,7 @@
console.assert(iconFontSize % 1 === 0, "Icon font size must be an integer");
}
let { visualLayout }: { visualLayout: VisualLayout } = $props();
let layoutInfo = $state(compileLayout(visualLayout));
let { layoutInfo }: { layout: CompiledLayout } = $props();
function getCenter(key: CompiledLayoutKey): [x: number, y: number] {
return [key.pos[0] + key.size[0] / 2, key.pos[1] + key.size[1] / 2];

View File

@@ -3,49 +3,49 @@
import { action } from "$lib/title";
import GenericLayout from "$lib/components/layout/GenericLayout.svelte";
import { activeProfile, activeLayer } from "$lib/serial/connection";
import type { VisualLayout } from "$lib/serialization/visual-layout";
import { fade, fly } from "svelte/transition";
import { restoreFromFile } from "$lib/backup/backup";
import type { CompiledLayout } from "$lib/assets/layouts/layout.d.ts";
const layouts = {
ONE: () =>
import("$lib/assets/layouts/one.yml").then(
(it) => it.default as VisualLayout,
import("$lib/assets/layouts/one.layout.yml").then(
(it) => it.default as CompiledLayout,
),
TWO: () =>
import("$lib/assets/layouts/one.yml").then(
(it) => it.default as VisualLayout,
import("$lib/assets/layouts/one.layout.yml").then(
(it) => it.default as CompiledLayout,
),
LITE: () =>
import("$lib/assets/layouts/lite.yml").then(
(it) => it.default as VisualLayout,
import("$lib/assets/layouts/lite.layout.yml").then(
(it) => it.default as CompiledLayout,
),
X: () =>
import("$lib/assets/layouts/generic/103-key.yml").then(
(it) => it.default as VisualLayout,
import("$lib/assets/layouts/103-key.layout.yml").then(
(it) => it.default as CompiledLayout,
),
ZERO: () =>
import("$lib/assets/layouts/generic/103-key.yml").then(
(it) => it.default as VisualLayout,
import("$lib/assets/layouts/103-key.layout.yml").then(
(it) => it.default as CompiledLayout,
),
M4G: () =>
import("$lib/assets/layouts/m4g.yml").then(
(it) => it.default as VisualLayout,
import("$lib/assets/layouts/m4g.layout.yml").then(
(it) => it.default as CompiledLayout,
),
M4GR: () =>
import("$lib/assets/layouts/m4gr.yml").then(
(it) => it.default as VisualLayout,
import("$lib/assets/layouts/m4gr.layout.yml").then(
(it) => it.default as CompiledLayout,
),
T4G: () =>
import("$lib/assets/layouts/t4g.yml").then(
(it) => it.default as VisualLayout,
import("$lib/assets/layouts/t4g.layout.yml").then(
(it) => it.default as CompiledLayout,
),
};
</script>
<div class="container">
{#if $serialPort}
{#await layouts[$serialPort.device]() then visualLayout}
{#await layouts[$serialPort.device]() then layoutInfo}
<fieldset transition:fade>
<div class="layers">
{#each Array.from({ length: $serialPort.layerCount }, (_, i) => i) as layer}
@@ -75,7 +75,7 @@
{/if}
</fieldset>
<GenericLayout {visualLayout} />
<GenericLayout {layoutInfo} />
{/await}
{/if}
</div>

View File

@@ -1,111 +0,0 @@
export interface VisualLayout {
name: string;
col: VisualLayoutRow[];
}
interface Positionable {
offset: [number, number];
rotate: number;
}
export interface VisualLayoutRow extends Positionable {
row: Array<VisualLayoutKey | VisualLayoutSwitch>;
}
export interface VisualLayoutKey extends Positionable {
key: number;
size?: [number, number];
}
export interface VisualLayoutSwitch extends Positionable {
switch: {
n: number;
e: number;
w: number;
s: number;
d: number;
};
}
export interface CompiledLayout {
name: string;
size: [number, number];
keys: CompiledLayoutKey[];
}
export interface CompiledLayoutKey {
id: number;
shape: "quarter-circle" | "square";
cornerRadius: number;
size: [number, number];
pos: [number, number];
rotate: number;
}
export function compileLayout(layout: VisualLayout): CompiledLayout {
const compiled: CompiledLayout = {
name: layout.name,
size: [0, 0],
keys: [],
};
let y = 0;
for (const { row, offset } of layout.col) {
let x = offset?.[0] ?? 0;
y += offset?.[1] ?? 0;
let maxHeight = 0;
for (const info of row) {
const [ox, oy] = info.offset || [0, 0];
const rotate = info.rotate || 0;
if ("key" in info) {
const [width, height] = info.size ?? [1, 1];
compiled.keys.push({
id: info.key,
shape: "square",
size: [width, height],
pos: [x + ox, y + oy],
cornerRadius: 0.1,
rotate,
});
x += width + ox;
maxHeight = Math.max(maxHeight, height + oy);
} else if ("switch" in info) {
const cx = x + ox + 1;
const cy = y + oy + 1;
for (const [i, id] of [
info.switch.s,
info.switch.w,
info.switch.n,
info.switch.e,
].entries()) {
compiled.keys.push({
id,
shape: "quarter-circle",
cornerRadius: 0,
size: [2, 0.6],
pos: [cx, cy],
rotate: 90 * i + 45,
});
}
compiled.keys.push({
id: info.switch.d,
shape: "square",
cornerRadius: 0.5,
size: [0.8, 0.8],
pos: [x + 0.6 + ox, y + 0.6 + oy],
rotate: 0,
});
x += 2 + ox;
maxHeight = Math.max(maxHeight, 2 + oy);
}
}
y += maxHeight;
compiled.size[0] = Math.max(compiled.size[0], x);
}
compiled.size[1] = y;
return compiled;
}