From 94cfaf40e5ef9236ce6c420f3cb4d170bcae4fef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thea=20Sch=C3=B6bl?= Date: Fri, 10 Nov 2023 01:17:36 +0100 Subject: [PATCH] feat: new chord editing feat: clear all changes with shift undo, fixes #7 --- icons.config.ts | 1 + src/i18n/de/index.ts | 2 +- src/i18n/en/index.ts | 2 +- src/lib/undo-redo.ts | 32 ++-- src/routes/EditActions.svelte | 10 +- src/routes/Navigation.svelte | 2 +- src/routes/config/chords/+page.svelte | 52 ++---- .../config/chords/ChordActionEdit.svelte | 84 ++++++++++ src/routes/config/chords/ChordEdit.svelte | 70 ++++++++ .../config/chords/ChordPhraseEdit.svelte} | 150 +++++++++++++----- 10 files changed, 306 insertions(+), 99 deletions(-) create mode 100644 src/routes/config/chords/ChordActionEdit.svelte create mode 100644 src/routes/config/chords/ChordEdit.svelte rename src/{lib/components/ActionStringEdit.svelte => routes/config/chords/ChordPhraseEdit.svelte} (62%) diff --git a/icons.config.ts b/icons.config.ts index 66b10e54..89f04a84 100644 --- a/icons.config.ts +++ b/icons.config.ts @@ -71,6 +71,7 @@ const config: IconsConfig = { "navigate_before", "navigate_next", "print", + "restore_from_trash", ], codePoints: { speed: "e9e4", diff --git a/src/i18n/de/index.ts b/src/i18n/de/index.ts index 8218b38a..0b7a6b28 100644 --- a/src/i18n/de/index.ts +++ b/src/i18n/de/index.ts @@ -4,7 +4,7 @@ const de = { TITLE: "CharaChorder Gerätemanager", DESCRIPTION: "Gerätemanager und Konfigurationstool für CharaChorder Geräte.", saveActions: { - UNDO: "Rückgängig", + UNDO: "Rückgängig (shift halten um alle Änderungen rückgängig zu machen)", REDO: "Wiederholen", APPLY: "Anwenden", SAVE: "Änderungen auf das Gerät schreiben", diff --git a/src/i18n/en/index.ts b/src/i18n/en/index.ts index 5540e582..36bc7222 100644 --- a/src/i18n/en/index.ts +++ b/src/i18n/en/index.ts @@ -4,7 +4,7 @@ const en = { TITLE: "CharaChorder Device Manager", DESCRIPTION: "The device manager and configuration tool for CharaChorder devices.", saveActions: { - UNDO: "Undo", + UNDO: "Undo (hold shift to undo all changes)", REDO: "Redo", APPLY: "Apply", SAVE: "Write changes to your device", diff --git a/src/lib/undo-redo.ts b/src/lib/undo-redo.ts index cc98f1cb..82804004 100644 --- a/src/lib/undo-redo.ts +++ b/src/lib/undo-redo.ts @@ -90,20 +90,22 @@ export const layout = derived([overlay, deviceLayout], ([overlay, layout]) => export type ChordInfo = Chord & ChangeInfo export const chords = derived([overlay, deviceChords], ([overlay, chords]) => - chords.map(chord => { - const key = serializeActions(chord.actions) - if (overlay.chords.has(key)) { - return { - actions: chord.actions, - phrase: overlay.chords.get(key)!, - isApplied: false, + chords + .map(chord => { + const key = serializeActions(chord.actions) + if (overlay.chords.has(key)) { + return { + actions: chord.actions, + phrase: overlay.chords.get(key)!, + isApplied: false, + } + } else { + return { + actions: chord.actions, + phrase: chord.phrase, + isApplied: true, + } } - } else { - return { - actions: chord.actions, - phrase: chord.phrase, - isApplied: true, - } - } - }), + }) + .sort((a, b) => (a.actions.some((it, i) => it > b.actions[i]) ? 1 : -1)), ) diff --git a/src/routes/EditActions.svelte b/src/routes/EditActions.svelte index 1b680d29..c0f1b4a8 100644 --- a/src/routes/EditActions.svelte +++ b/src/routes/EditActions.svelte @@ -7,9 +7,13 @@ import {deviceChords, deviceLayout, deviceSettings, serialPort, syncStatus} from "$lib/serial/connection" import {deserializeActions} from "$lib/serial/chord" - function undo() { - redoQueue = [$changes.pop()!, ...redoQueue] - changes.update(it => it) + function undo(event: MouseEvent) { + if (event.shiftKey) { + changes.set([]) + } else { + redoQueue = [$changes.pop()!, ...redoQueue] + changes.update(it => it) + } } function redo() { diff --git a/src/routes/Navigation.svelte b/src/routes/Navigation.svelte index e9170b3c..1907e084 100644 --- a/src/routes/Navigation.svelte +++ b/src/routes/Navigation.svelte @@ -92,7 +92,7 @@ content: ""; position: absolute; - top: 12px; + top: 20px; left: 50%; transform-origin: top; translate: -50% 0; diff --git a/src/routes/config/chords/+page.svelte b/src/routes/config/chords/+page.svelte index 4eee27c4..9693d496 100644 --- a/src/routes/config/chords/+page.svelte +++ b/src/routes/config/chords/+page.svelte @@ -3,11 +3,12 @@ import Index from "flexsearch" import LL from "../../../i18n/i18n-svelte" import {action} from "$lib/title" - import {onDestroy, onMount} from "svelte" - import ActionStringEdit from "$lib/components/ActionStringEdit.svelte" - import {changes, ChangeType, chords} from "$lib/undo-redo" + import {onDestroy, onMount, setContext} from "svelte" + import {chords} from "$lib/undo-redo" import type {ChordInfo} from "$lib/undo-redo" import {derived, writable} from "svelte/store" + import ChordEdit from "./ChordEdit.svelte" + import {crossfade} from "svelte/transition" const resultSize = 38 let results: HTMLElement @@ -45,13 +46,15 @@ searchFilter.set(query && searchIndex ? searchIndex.search(query) : undefined) } - const items = derived([searchFilter, chords], ([filter, chords]) => - (filter?.map(it => [chords[it], it] as const) ?? chords.map((it, i) => [it, i] as const)).filter( - ([{phrase}]) => phrase.length > 0, - ), + const items = derived( + [searchFilter, chords], + ([filter, chords]) => + filter?.map(it => [chords[it], it] as const) ?? chords.map((it, i) => [it, i] as const), ) const lastPage = derived([items, pageSize], ([items, pageSize]) => Math.ceil(items.length / pageSize) - 1) + setContext("cursor-crossfade", crossfade({})) + let page = 0 $: { $items @@ -89,26 +92,8 @@
{#if $lastPage !== -1} - {#each $items.slice(page * $pageSize, (page + 1) * $pageSize) as [{ actions, phrase, isApplied }]} - - - - - + {#each $items.slice(page * $pageSize, (page + 1) * $pageSize) as [chord], i (`${page}:${i}`)} + {/each} {:else} @@ -175,17 +160,4 @@ min-width: min(90vw, 16.5cm); transition: all 1s ease; } - - th { - text-align: start; - } - - .table-buttons { - opacity: 0; - transition: opacity 75ms ease; - } - - tr:hover > .table-buttons { - opacity: 1; - } diff --git a/src/routes/config/chords/ChordActionEdit.svelte b/src/routes/config/chords/ChordActionEdit.svelte new file mode 100644 index 00000000..9a3427cf --- /dev/null +++ b/src/routes/config/chords/ChordActionEdit.svelte @@ -0,0 +1,84 @@ + + + + + diff --git a/src/routes/config/chords/ChordEdit.svelte b/src/routes/config/chords/ChordEdit.svelte new file mode 100644 index 00000000..7cf1d365 --- /dev/null +++ b/src/routes/config/chords/ChordEdit.svelte @@ -0,0 +1,70 @@ + + + + + + + + + diff --git a/src/lib/components/ActionStringEdit.svelte b/src/routes/config/chords/ChordPhraseEdit.svelte similarity index 62% rename from src/lib/components/ActionStringEdit.svelte rename to src/routes/config/chords/ChordPhraseEdit.svelte index 2fbafa5e..15b712a5 100644 --- a/src/lib/components/ActionStringEdit.svelte +++ b/src/routes/config/chords/ChordPhraseEdit.svelte @@ -2,9 +2,12 @@ import {KEYMAP_CODES, KEYMAP_IDS, specialKeycodes} from "$lib/serial/keymap-codes" import {tick} from "svelte" import ActionSelector from "$lib/components/layout/ActionSelector.svelte" + import type {Chord} from "$lib/serial/chord" import {changes, ChangeType} from "$lib/undo-redo" + import {scale} from "svelte/transition" - export let actions: number[] + export let chord: Chord + export let edited: boolean function keypress(event: KeyboardEvent) { if (event.key === "ArrowUp") { @@ -28,17 +31,31 @@ } function moveCursor(to: number) { - cursorPosition = Math.max(0, Math.min(to, actions.length)) + cursorPosition = Math.max(0, Math.min(to, chord.phrase.length)) const item = box.children.item(cursorPosition) as HTMLElement cursorOffset = item.offsetLeft + item.offsetWidth } function deleteAction(at: number, count = 1) { - actions = actions.toSpliced(at, count) + changes.update(changes => { + changes.push({ + type: ChangeType.Chord, + actions: chord.actions, + phrase: chord.phrase.toSpliced(at, count), + }) + return changes + }) } function insertAction(at: number, action: number) { - actions = actions.toSpliced(at, 0, action) + changes.update(changes => { + changes.push({ + type: ChangeType.Chord, + actions: chord.actions, + phrase: chord.phrase.toSpliced(at, 0, action), + }) + return changes + }) } function clickCursor(event: unknown) { @@ -105,13 +122,29 @@ let box: HTMLDivElement let cursorPosition = 0 let cursorOffset = 0 + + let hasFocus = false -
-
- -
- {#each actions as actionId} +
(hasFocus = true)} + on:focusout={() => (hasFocus = false)} +> + {#if hasFocus} +
+ +
+ {:else} +
+ + {/if} + {#each chord.phrase as actionId, i (`${actionId}:${i}`)} {@const {icon, id, code} = KEYMAP_CODES[actionId] ?? {code: actionId}} {#if !icon && id?.length === 1} {id} @@ -119,11 +152,50 @@ {icon ?? id ?? `0x${code.toString(16)}`} {/if} {/each} +
- - - - - - -
No Results
+ + + + + {#if chord.phrase.length === 0} + + {:else} + + {/if} + +
+ +