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

View File

@@ -147,12 +147,25 @@ const config = {
"developer_board", "developer_board",
"developer_board_off", "developer_board_off",
"memory", "memory",
"gamepad_circle_up",
"gamepad_circle_left",
"gamepad_circle_down",
"gamepad_circle_right",
"trail_length_medium",
"blur_short",
"combine_columns",
"animation",
"text_select_move_back_word",
], ],
codePoints: { codePoints: {
speed: "e9e4", speed: "e9e4",
arrow_split: "e985", arrow_split: "e985",
arrow_circle_down: "f181", arrow_circle_down: "f181",
arrow_circle_up: "f182", arrow_circle_up: "f182",
gamepad_circle_up: "eecd",
gamepad_circle_right: "eece",
gamepad_circle_left: "eecf",
gamepad_circle_down: "eed0",
counter_1: "f784", counter_1: "f784",
counter_2: "f783", counter_2: "f783",
counter_3: "f782", counter_3: "f782",

View File

@@ -34,68 +34,69 @@
"typesafe-i18n": "typesafe-i18n" "typesafe-i18n": "typesafe-i18n"
}, },
"devDependencies": { "devDependencies": {
"@codemirror/autocomplete": "^6.18.6", "@codemirror/autocomplete": "^6.20.0",
"@codemirror/commands": "^6.8.1", "@codemirror/commands": "^6.10.1",
"@codemirror/lang-javascript": "^6.2.4", "@codemirror/lang-javascript": "^6.2.4",
"@codemirror/language": "^6.11.2", "@codemirror/language": "^6.11.3",
"@codemirror/merge": "^6.11.2", "@codemirror/merge": "^6.11.2",
"@codemirror/state": "^6.5.2", "@codemirror/state": "^6.5.2",
"@codemirror/view": "^6.38.1", "@codemirror/view": "^6.39.4",
"@fontsource-variable/material-symbols-rounded": "^5.2.17", "@fontsource-variable/material-symbols-rounded": "^5.2.30",
"@fontsource-variable/noto-sans-mono": "^5.2.7", "@fontsource-variable/noto-sans-mono": "^5.2.10",
"@lezer/common": "^1.4.0", "@lezer/common": "^1.4.0",
"@lezer/generator": "^1.8.0", "@lezer/generator": "^1.8.0",
"@lezer/highlight": "^1.2.1", "@lezer/highlight": "^1.2.3",
"@lezer/lr": "^1.4.5", "@lezer/lr": "^1.4.5",
"@material/material-color-utilities": "^0.3.0", "@material/material-color-utilities": "^0.3.0",
"@melt-ui/pp": "^0.3.2", "@melt-ui/pp": "^0.3.2",
"@melt-ui/svelte": "^0.86.6", "@melt-ui/svelte": "^0.86.6",
"@modyfi/vite-plugin-yaml": "^1.1.1", "@modyfi/vite-plugin-yaml": "^1.1.1",
"@sveltejs/adapter-static": "^3.0.8", "@sveltejs/adapter-static": "^3.0.10",
"@sveltejs/kit": "^2.26.1", "@sveltejs/kit": "^2.49.2",
"@sveltejs/vite-plugin-svelte": "^6.1.0", "@sveltejs/vite-plugin-svelte": "^6.2.1",
"@tauri-apps/api": "^1.6.0", "@tauri-apps/api": "^1.6.0",
"@tauri-apps/cli": "^1.6.0", "@tauri-apps/cli": "^1.6.0",
"@types/dom-view-transitions": "^1.0.6", "@types/dom-view-transitions": "^1.0.6",
"@types/semver": "^7.7.0", "@types/js-yaml": "^4.0.9",
"@types/semver": "^7.7.1",
"@types/w3c-web-serial": "^1.0.8", "@types/w3c-web-serial": "^1.0.8",
"@types/w3c-web-usb": "^1.0.10", "@types/w3c-web-usb": "^1.0.13",
"@types/wicg-file-system-access": "^2023.10.6", "@types/wicg-file-system-access": "^2023.10.7",
"@vite-pwa/sveltekit": "^1.0.0", "@vite-pwa/sveltekit": "^1.1.0",
"autoprefixer": "^10.4.21", "autoprefixer": "^10.4.23",
"codemirror": "^6.0.2", "codemirror": "^6.0.2",
"cypress": "^14.5.3", "cypress": "^14.5.3",
"d3": "^7.9.0", "d3": "^7.9.0",
"esptool-js": "^0.5.6", "esptool-js": "^0.5.7",
"flexsearch": "^0.8.205", "flexsearch": "^0.8.212",
"fontkit": "^2.0.4", "fontkit": "^2.0.4",
"glob": "^11.0.3", "glob": "^11.0.3",
"js-yaml": "^4.1.1",
"jsdom": "^26.1.0", "jsdom": "^26.1.0",
"matrix-js-sdk": "^37.12.0", "matrix-js-sdk": "^37.12.0",
"npm-run-all": "^4.1.5", "npm-run-all": "^4.1.5",
"prettier": "^3.6.2", "prettier": "^3.7.4",
"prettier-plugin-css-order": "^2.1.2", "prettier-plugin-css-order": "^2.1.2",
"prettier-plugin-svelte": "^3.4.0", "prettier-plugin-svelte": "^3.4.1",
"rxjs": "^7.8.2", "rxjs": "^7.8.2",
"sass": "^1.89.2", "sass": "^1.97.0",
"semver": "^7.7.2", "semver": "^7.7.3",
"socket.io-client": "^4.8.1", "socket.io-client": "^4.8.1",
"stylelint": "^16.23.0", "stylelint": "^16.26.1",
"stylelint-config-clean-order": "^7.0.0",
"stylelint-config-html": "^1.1.0", "stylelint-config-html": "^1.1.0",
"stylelint-config-prettier-scss": "^1.0.0", "stylelint-config-prettier-scss": "^1.0.0",
"stylelint-config-recommended-scss": "^15.0.1", "stylelint-config-recommended-scss": "^16.0.2",
"stylelint-config-standard-scss": "^15.0.1", "stylelint-config-standard-scss": "^16.0.0",
"svelte": "5.37.1", "svelte": "5.37.1",
"svelte-check": "^4.3.0", "svelte-check": "^4.3.4",
"svelte-preprocess": "^6.0.3", "svelte-preprocess": "^6.0.3",
"tippy.js": "^6.3.7", "tippy.js": "^6.3.7",
"typesafe-i18n": "^5.26.2", "typesafe-i18n": "^5.26.2",
"typescript": "^5.8.3", "typescript": "^5.8.3",
"vite": "^7.0.6", "vite": "^7.0.6",
"vite-plugin-mkcert": "^1.17.8", "vite-plugin-mkcert": "^1.17.9",
"vite-plugin-pwa": "^1.0.2", "vite-plugin-pwa": "^1.0.2",
"vitest": "^3.2.4", "vitest": "^4.0.16",
"web-serial-polyfill": "^1.0.15", "web-serial-polyfill": "^1.0.15",
"workbox-window": "^7.3.0" "workbox-window": "^7.3.0"
}, },

1090
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

2
pnpm-workspace.yaml Normal file
View File

@@ -0,0 +1,2 @@
onlyBuiltDependencies:
- svelte-preprocess

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

View File

@@ -1,9 +1,4 @@
<script lang="ts"> <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 { deviceLayout } from "$lib/serial/connection";
import { dev } from "$app/environment"; import { dev } from "$app/environment";
import ActionSelector from "$lib/components/layout/ActionSelector.svelte"; import ActionSelector from "$lib/components/layout/ActionSelector.svelte";
@@ -15,6 +10,10 @@
import { fly } from "svelte/transition"; import { fly } from "svelte/transition";
import { expoOut } from "svelte/easing"; import { expoOut } from "svelte/easing";
import { activeLayer, activeProfile } from "$lib/serial/connection"; import { activeLayer, activeProfile } from "$lib/serial/connection";
import type {
CompiledLayout,
CompiledLayoutKey,
} from "$lib/assets/layouts/layout.d.ts";
const { scale, margin, strokeWidth, fontSize, iconFontSize } = const { scale, margin, strokeWidth, fontSize, iconFontSize } =
getContext<VisualLayoutConfig>("visual-layout-config"); getContext<VisualLayoutConfig>("visual-layout-config");
@@ -29,8 +28,7 @@
console.assert(iconFontSize % 1 === 0, "Icon font size must be an integer"); console.assert(iconFontSize % 1 === 0, "Icon font size must be an integer");
} }
let { visualLayout }: { visualLayout: VisualLayout } = $props(); let { layoutInfo }: { layout: CompiledLayout } = $props();
let layoutInfo = $state(compileLayout(visualLayout));
function getCenter(key: CompiledLayoutKey): [x: number, y: number] { function getCenter(key: CompiledLayoutKey): [x: number, y: number] {
return [key.pos[0] + key.size[0] / 2, key.pos[1] + key.size[1] / 2]; 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 { action } from "$lib/title";
import GenericLayout from "$lib/components/layout/GenericLayout.svelte"; import GenericLayout from "$lib/components/layout/GenericLayout.svelte";
import { activeProfile, activeLayer } from "$lib/serial/connection"; import { activeProfile, activeLayer } from "$lib/serial/connection";
import type { VisualLayout } from "$lib/serialization/visual-layout";
import { fade, fly } from "svelte/transition"; import { fade, fly } from "svelte/transition";
import { restoreFromFile } from "$lib/backup/backup"; import { restoreFromFile } from "$lib/backup/backup";
import type { CompiledLayout } from "$lib/assets/layouts/layout.d.ts";
const layouts = { const layouts = {
ONE: () => ONE: () =>
import("$lib/assets/layouts/one.yml").then( import("$lib/assets/layouts/one.layout.yml").then(
(it) => it.default as VisualLayout, (it) => it.default as CompiledLayout,
), ),
TWO: () => TWO: () =>
import("$lib/assets/layouts/one.yml").then( import("$lib/assets/layouts/one.layout.yml").then(
(it) => it.default as VisualLayout, (it) => it.default as CompiledLayout,
), ),
LITE: () => LITE: () =>
import("$lib/assets/layouts/lite.yml").then( import("$lib/assets/layouts/lite.layout.yml").then(
(it) => it.default as VisualLayout, (it) => it.default as CompiledLayout,
), ),
X: () => X: () =>
import("$lib/assets/layouts/generic/103-key.yml").then( import("$lib/assets/layouts/103-key.layout.yml").then(
(it) => it.default as VisualLayout, (it) => it.default as CompiledLayout,
), ),
ZERO: () => ZERO: () =>
import("$lib/assets/layouts/generic/103-key.yml").then( import("$lib/assets/layouts/103-key.layout.yml").then(
(it) => it.default as VisualLayout, (it) => it.default as CompiledLayout,
), ),
M4G: () => M4G: () =>
import("$lib/assets/layouts/m4g.yml").then( import("$lib/assets/layouts/m4g.layout.yml").then(
(it) => it.default as VisualLayout, (it) => it.default as CompiledLayout,
), ),
M4GR: () => M4GR: () =>
import("$lib/assets/layouts/m4gr.yml").then( import("$lib/assets/layouts/m4gr.layout.yml").then(
(it) => it.default as VisualLayout, (it) => it.default as CompiledLayout,
), ),
T4G: () => T4G: () =>
import("$lib/assets/layouts/t4g.yml").then( import("$lib/assets/layouts/t4g.layout.yml").then(
(it) => it.default as VisualLayout, (it) => it.default as CompiledLayout,
), ),
}; };
</script> </script>
<div class="container"> <div class="container">
{#if $serialPort} {#if $serialPort}
{#await layouts[$serialPort.device]() then visualLayout} {#await layouts[$serialPort.device]() then layoutInfo}
<fieldset transition:fade> <fieldset transition:fade>
<div class="layers"> <div class="layers">
{#each Array.from({ length: $serialPort.layerCount }, (_, i) => i) as layer} {#each Array.from({ length: $serialPort.layerCount }, (_, i) => i) as layer}
@@ -75,7 +75,7 @@
{/if} {/if}
</fieldset> </fieldset>
<GenericLayout {visualLayout} /> <GenericLayout {layoutInfo} />
{/await} {/await}
{/if} {/if}
</div> </div>

View File

@@ -1,15 +1,13 @@
<script lang="ts"> <script lang="ts">
import { KEYMAP_CODES } from "$lib/serial/keymap-codes"; import { KEYMAP_CODES, KEYMAP_IDS } from "$lib/serial/keymap-codes";
import { onMount, tick } from "svelte"; import { onMount, tick } from "svelte";
import { changes, ChangeType } from "$lib/undo-redo"; import { changes, ChangeType } from "$lib/undo-redo";
import type { ChordInfo } from "$lib/undo-redo"; import type { ChordInfo } from "$lib/undo-redo";
import { scale } from "svelte/transition"; import { scale } from "svelte/transition";
import ActionString from "$lib/components/ActionString.svelte";
import { selectAction } from "./action-selector"; import { selectAction } from "./action-selector";
import { inputToAction } from "./input-converter"; import { inputToAction } from "./input-converter";
import { deviceMeta, serialPort } from "$lib/serial/connection"; import { deviceMeta, serialPort } from "$lib/serial/connection";
import { get } from "svelte/store"; import { get } from "svelte/store";
import { action, actionTooltip } from "$lib/title";
import semverGte from "semver/functions/gte"; import semverGte from "semver/functions/gte";
import Action from "$lib/components/Action.svelte"; import Action from "$lib/components/Action.svelte";
import AutospaceSelector from "$lib/chord-editor/AutospaceSelector.svelte"; import AutospaceSelector from "$lib/chord-editor/AutospaceSelector.svelte";
@@ -26,12 +24,16 @@
}); });
function keypress(event: KeyboardEvent) { function keypress(event: KeyboardEvent) {
console.log(event);
if (!event.shiftKey && event.key === "ArrowUp") { if (!event.shiftKey && event.key === "ArrowUp") {
addSpecial(event); addSpecial(event);
} else if (!event.shiftKey && event.key === "ArrowLeft") { } else if (!event.shiftKey && event.key === "ArrowLeft") {
moveCursor(cursorPosition - 1, true); moveCursor(cursorPosition - 1, true);
} else if (!event.shiftKey && event.key === "ArrowRight") { } else if (!event.shiftKey && event.key === "ArrowRight") {
moveCursor(cursorPosition + 1, true); moveCursor(cursorPosition + 1, true);
} else if (event.key === " " && $KEYMAP_IDS.has("HYPERSPACE")) {
insertAction(cursorPosition, $KEYMAP_IDS.get("HYPERSPACE")!.code);
tick().then(() => moveCursor(cursorPosition + 1));
} else if (event.key === "Backspace") { } else if (event.key === "Backspace") {
deleteAction(cursorPosition - 1, 1, true); deleteAction(cursorPosition - 1, 1, true);
moveCursor(cursorPosition - 1, true); moveCursor(cursorPosition - 1, true);

View File

@@ -67,13 +67,13 @@
<label><input type="checkbox" bind:checked={$showEdits} />Show edits</label> <label><input type="checkbox" bind:checked={$showEdits} />Show edits</label>
<div class="split"> <div class="split">
<ActionList />
<div <div
class="editor" class="editor"
class:hide-edits={!$showEdits} class:hide-edits={!$showEdits}
class:raw={$rawCode} class:raw={$rawCode}
bind:this={editor} bind:this={editor}
></div> ></div>
<ActionList />
</div> </div>
<style lang="scss"> <style lang="scss">
@@ -82,13 +82,12 @@
gap: 1rem; gap: 1rem;
height: 100%; height: 100%;
> :global(:last-child) { > :global(:first-child) {
max-width: 600px; max-width: 600px;
} }
} }
.editor:not(.raw) :global(.cm-line) { .editor:not(.raw) :global(.cm-line) {
margin-inline: auto;
width: fit-content; width: fit-content;
} }

View File

@@ -1,3 +1,7 @@
import type { Plugin, Rollup } from "vite";
import type { CompiledLayout } from "./src/lib/assets/layouts/layout.d.ts";
import yaml from "js-yaml";
export interface VisualLayout { export interface VisualLayout {
name: string; name: string;
col: VisualLayoutRow[]; col: VisualLayoutRow[];
@@ -27,19 +31,21 @@ export interface VisualLayoutSwitch extends Positionable {
}; };
} }
export interface CompiledLayout { const fileRegex = /\.(layout\.yml)$/;
name: string;
size: [number, number];
keys: CompiledLayoutKey[];
}
export interface CompiledLayoutKey { export function layoutPlugin() {
id: number; return {
shape: "quarter-circle" | "square"; name: "charachorder-layout",
cornerRadius: number; transform(code, id) {
size: [number, number]; if (fileRegex.test(id)) {
pos: [number, number]; return {
rotate: number; code: `const data = ${JSON.stringify(compileLayout(yaml.load(code) as VisualLayout))};\nexport default data;`,
map: null,
} satisfies Rollup.TransformResult;
}
return null;
},
} satisfies Plugin;
} }
export function compileLayout(layout: VisualLayout): CompiledLayout { export function compileLayout(layout: VisualLayout): CompiledLayout {
@@ -89,14 +95,16 @@ export function compileLayout(layout: VisualLayout): CompiledLayout {
rotate: 90 * i + 45, rotate: 90 * i + 45,
}); });
} }
compiled.keys.push({ if (info.switch.d !== undefined) {
id: info.switch.d, compiled.keys.push({
shape: "square", id: info.switch.d,
cornerRadius: 0.5, shape: "square",
size: [0.8, 0.8], cornerRadius: 0.5,
pos: [x + 0.6 + ox, y + 0.6 + oy], size: [0.8, 0.8],
rotate: 0, pos: [x + 0.6 + ox, y + 0.6 + oy],
}); rotate: 0,
});
}
x += 2 + ox; x += 2 + ox;
maxHeight = Math.max(maxHeight, 2 + oy); maxHeight = Math.max(maxHeight, 2 + oy);

View File

@@ -7,6 +7,7 @@ import ViteYaml from "@modyfi/vite-plugin-yaml";
import { readFile } from "fs/promises"; import { readFile } from "fs/promises";
import { fileURLToPath } from "url"; import { fileURLToPath } from "url";
import { lezerGrammarPlugin } from "./vite-plugin-lezer"; import { lezerGrammarPlugin } from "./vite-plugin-lezer";
import { layoutPlugin } from "./vite-plugin-layout";
const isTauri = "TAURI_FAMILY" in process.env; const isTauri = "TAURI_FAMILY" in process.env;
console.info(isTauri ? "Building for Tauri" : "Building for PWA"); console.info(isTauri ? "Building for Tauri" : "Building for PWA");
@@ -47,7 +48,8 @@ export default defineConfig({
}, },
envPrefix: ["TAURI_", "VITE_"], envPrefix: ["TAURI_", "VITE_"],
plugins: [ plugins: [
ViteYaml(), ViteYaml({ exclude: /\.layout\.yml$/ }),
layoutPlugin(),
sveltekit(), sveltekit(),
lezerGrammarPlugin(), lezerGrammarPlugin(),
...(isTauri ...(isTauri