From ebf7d73d205825c6b502be0c1daad808dd94e95b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thea=20Sch=C3=B6bl?= Date: Tue, 14 Nov 2023 20:19:01 +0100 Subject: [PATCH] feat: new blocking progress bar, fixes #18 feat: change cloud icon to history, fixes #15 fix: action search items overlap, fixes #16 feat: show tooltips immediately --- icons.config.ts | 2 + package.json | 5 +- src/i18n/de/index.ts | 31 +++- src/i18n/en/index.ts | 33 +++- src/lib/assets/keymaps/scancode.yml | 124 ++++++++++++++ src/lib/components/Action.svelte | 39 +++++ src/lib/components/ActionListItem.svelte | 5 + src/lib/components/ActionString.svelte | 11 ++ src/lib/components/action-extension.ts | 8 - src/lib/{ => dialogs}/ConfirmDialog.svelte | 11 +- src/lib/dialogs/Dialog.svelte | 32 ++++ src/lib/dialogs/PickChangesDialog.svelte | 161 ++++++++++++++++++ src/lib/{ => dialogs}/confirm-dialog.ts | 2 +- src/lib/os-layout.ts | 39 +++++ src/lib/serial/connection.ts | 22 ++- .../style/form/_checkbox.scss} | 0 src/lib/style/theme.scss | 1 + src/lib/title.ts | 1 - src/routes/+layout.svelte | 16 +- src/routes/EditActions.svelte | 29 +++- src/routes/Footer.svelte | 120 ++++++++++++- src/routes/Navigation.svelte | 93 +++------- src/routes/PageTransition.svelte | 51 ++++++ src/routes/Profile.svelte | 116 ------------- src/routes/SyncOverlay.svelte | 68 ++++++++ .../config/chords/ChordActionEdit.svelte | 18 +- .../config/chords/ChordPhraseEdit.svelte | 20 +-- 27 files changed, 790 insertions(+), 268 deletions(-) create mode 100644 src/lib/components/Action.svelte create mode 100644 src/lib/components/ActionString.svelte delete mode 100644 src/lib/components/action-extension.ts rename src/lib/{ => dialogs}/ConfirmDialog.svelte (89%) create mode 100644 src/lib/dialogs/Dialog.svelte create mode 100644 src/lib/dialogs/PickChangesDialog.svelte rename src/lib/{ => dialogs}/confirm-dialog.ts (91%) create mode 100644 src/lib/os-layout.ts rename src/{routes/stats/+page.svelte => lib/style/form/_checkbox.scss} (100%) create mode 100644 src/routes/PageTransition.svelte delete mode 100644 src/routes/Profile.svelte create mode 100644 src/routes/SyncOverlay.svelte diff --git a/icons.config.ts b/icons.config.ts index 89f04a84..ae35ae17 100644 --- a/icons.config.ts +++ b/icons.config.ts @@ -72,6 +72,8 @@ const config: IconsConfig = { "navigate_next", "print", "restore_from_trash", + "history", + "history_toggle_off", ], codePoints: { speed: "e9e4", diff --git a/package.json b/package.json index c5d20dcb..ab82ed65 100644 --- a/package.json +++ b/package.json @@ -44,9 +44,6 @@ "@sveltejs/vite-plugin-svelte": "^2.4.5", "@tauri-apps/api": "^1.4.0", "@tauri-apps/cli": "^1.4.0", - "@tiptap/core": "^2.1.12", - "@tiptap/pm": "^2.1.12", - "@tiptap/starter-kit": "^2.1.12", "@theaninova/prettier-config": "^1.0.0", "@types/dom-view-transitions": "^1.0.1", "@types/flexsearch": "^0.7.3", @@ -84,4 +81,4 @@ "vitest": "^0.34.4" }, "type": "module" -} \ No newline at end of file +} diff --git a/src/i18n/de/index.ts b/src/i18n/de/index.ts index c8df7f99..3adbc2df 100644 --- a/src/i18n/de/index.ts +++ b/src/i18n/de/index.ts @@ -9,6 +9,12 @@ const de = { APPLY: "Anwenden", SAVE: "Änderungen auf das Gerät schreiben", }, + sync: { + TITLE_READ: "Neueste Änderungen werden abgerufen", + TITLE_WRITE: "Änderungen werden gebrannt", + DISCLAIMER_WRITE: + "Das Brennen von Änderungen ist nur für Layouts und Einstellungen erforderlich wenn diese Neustarts überdauern sollen. Bei Akkorden passiert das brennen automatisch beim anwenden.", + }, backup: { TITLE: "Sicherungskopie", DISCLAIMER: @@ -28,9 +34,13 @@ const de = { }, }, share: { + TITLE: "Teilen", URL_COPIED: "Teilbare URL kopiert!", EXTRA_DOWNLOAD: "Als Datei herunterladen", }, + print: { + TITLE: "Drucken", + }, profile: { TITLE: "Profil", LANGUAGE: "Sprache", @@ -67,12 +77,21 @@ const de = { DOWNLOAD_APP: "Desktop-app herunterladen", }, changes: { - TITLE: "Änderungen anwenden", - CHORD_ADD: "{0} Akkord{{|e}} hinzugefügt", - CHORD_EDIT: "{0} Akkord{{|e}} bearbeitet", - CHORD_DELETE: "{0} Akkord{{|e}} entfernt", - SETTING_CHANGE: "{0} Einstellung{{|en}} geändert", - LAYOUT_CHANGE: "{0} Layout-belegung{{|en}} geändert", + TITLE: "Änderungen importieren", + ALL_CHANGES: "Alle Änderungen", + layout: { + TITLE: "{0} veränderte Belegung{{:|en}}", + LAYER: "{changes} Belegung{{changes:|en}} in Ebene {layer} ändern", + }, + settings: { + TITLE: "{0} Einstellung{{|en}} anpassen", + }, + chords: { + TITLE: "{0} Akkorde", + NEW_CHORDS: "{0} neue Akkord{{|e}} hinzufügen", + CHANGED_CHORDS: "{0} Akkord{{|e}} ersetzen", + DELETED_CHORDS: "{0} Akkord{{|e}} zum löschen markieren", + }, }, configure: { chords: { diff --git a/src/i18n/en/index.ts b/src/i18n/en/index.ts index c6c55431..50cf4beb 100644 --- a/src/i18n/en/index.ts +++ b/src/i18n/en/index.ts @@ -7,7 +7,7 @@ const en = { UNDO: "Undo (hold shift to undo all changes)", REDO: "Redo", APPLY: "Apply", - SAVE: "Write changes to your device", + SAVE: "Burn changes to your device", }, backup: { TITLE: "Local Backup", @@ -15,6 +15,12 @@ const en = { DOWNLOAD: "Download Backup", RESTORE: "Restore", }, + sync: { + TITLE_READ: "Reading latest changes", + TITLE_WRITE: "Burning changes to device", + DISCLAIMER_WRITE: + "Burning is only necessary if you want your layout or settings to persist across reboots. Chords always persist automatically on apply.", + }, modal: { CLOSE: "Close", }, @@ -27,9 +33,13 @@ const en = { }, }, share: { + TITLE: "Share", URL_COPIED: "Sharable URL copied!", EXTRA_DOWNLOAD: "Download as file", }, + print: { + TITLE: "Print", + }, profile: { TITLE: "Profile", LANGUAGE: "Language", @@ -65,12 +75,21 @@ const en = { DOWNLOAD_APP: "Download the desktop app", }, changes: { - TITLE: "Apply changes", - CHORD_ADD: "{0} chord{{|s}} added", - CHORD_EDIT: "{0} chord{{|s}} edited", - CHORD_DELETE: "{0} chord{{|s}} deleted", - SETTING_CHANGE: "{0} setting{{|s}} changed", - LAYOUT_CHANGE: "{0} layout key{{|s}} changed", + TITLE: "Import changes", + ALL_CHANGES: "All changes", + layout: { + TITLE: "{0} layout change{{|s}}", + LAYER: "Update {changes} key{{changes:|s}} in layer {layer}", + }, + settings: { + TITLE: "Update {0} setting{{|s}}", + }, + chords: { + TITLE: "{0} chords", + NEW_CHORDS: "Add {0} new chord{{|s}}", + CHANGED_CHORDS: "Replace {0} chord{{|s}}", + DELETED_CHORDS: "Mark {0} chord{{|s}} for deletion", + }, }, configure: { chords: { diff --git a/src/lib/assets/keymaps/scancode.yml b/src/lib/assets/keymaps/scancode.yml index a0afe6f2..9420c151 100644 --- a/src/lib/assets/keymaps/scancode.yml +++ b/src/lib/assets/keymaps/scancode.yml @@ -15,311 +15,408 @@ actions: title: Keyboard Error Undefined 260: id: "KEY_A" + keyCode: "KeyA" title: Keyboard a and A (US English) description: Non US English keyboard users may prefer these Raw Scancodes 261: id: "KEY_B" + keyCode: "KeyB" title: Keyboard b and B (US English) 262: id: "KEY_C" + keyCode: "KeyC" title: Keyboard c and C (US English) 263: id: "KEY_D" + keyCode: "KeyD" title: Keyboard d and D (US English) 264: id: "KEY_E" + keyCode: "KeyE" title: Keyboard e and E (US English) 265: id: "KEY_F" + keyCode: "KeyF" title: Keyboard f and F (US English) 266: id: "KEY_G" + keyCode: "KeyG" title: Keyboard g and G (US English) 267: id: "KEY_H" + keyCode: "KeyH" title: Keyboard h and H (US English) 268: id: "KEY_I" + keyCode: "KeyI" title: Keyboard i and I (US English) 269: id: "KEY_J" + keyCode: "KeyJ" title: Keyboard j and J (US English) 270: id: "KEY_K" + keyCode: "KeyK" title: Keyboard k and K (US English) 271: id: "KEY_L" + keyCode: "KeyL" title: Keyboard l and L (US English) 272: id: "KEY_M" + keyCode: "KeyM" title: Keyboard m and M (US English) 273: id: "KEY_N" + keyCode: "KeyN" title: Keyboard n and N (US English) 274: id: "KEY_O" + keyCode: "KeyO" title: Keyboard o and O (US English) 275: id: "KEY_P" + keyCode: "KeyP" title: Keyboard p and P (US English) 276: id: "KEY_Q" + keyCode: "KeyQ" title: Keyboard q and Q (US English) 277: id: "KEY_R" + keyCode: "KeyR" title: Keyboard r and R (US English) 278: id: "KEY_S" + keyCode: "KeyS" title: Keyboard s and S (US English) 279: id: "KEY_T" + keyCode: "KeyT" title: Keyboard t and T (US English) 280: id: "KEY_U" + keyCode: "KeyU" title: Keyboard u and U (US English) 281: id: "KEY_V" + keyCode: "KeyV" title: Keyboard v and V (US English) 282: id: "KEY_W" + keyCode: "KeyW" title: Keyboard w and W (US English) 283: id: "KEY_X" + keyCode: "KeyX" title: Keyboard x and X (US English) 284: id: "KEY_Y" + keyCode: "KeyY" title: Keyboard y and Y (US English) 285: id: "KEY_Z" + keyCode: "KeyZ" title: Keyboard z and Z (US English) 286: id: "KEY_1" + keyCode: "Digit1" title: Keyboard 1 and ! (US English) 287: id: "KEY_2" + keyCode: "Digit2" title: Keyboard 2 and @ (US English) 288: id: "KEY_3" + keyCode: "Digit3" title: Keyboard 3 and # (US English) 289: id: "KEY_4" + keyCode: "Digit4" title: Keyboard 4 and $ (US English) 290: id: "KEY_5" + keyCode: "Digit5" title: Keyboard 5 and % (US English) 291: id: "KEY_6" + keyCode: "Digit6" title: Keyboard 6 and ^ (US English) 292: id: "KEY_7" + keyCode: "Digit7" title: Keyboard 7 and & (US English) 293: id: "KEY_8" + keyCode: "Digit8" title: Keyboard 8 and * (US English) 294: id: "KEY_9" + keyCode: "Digit9" title: Keyboard 9 and ( (US English) 295: id: "KEY_0" + keyCode: "Digit0" title: Keyboard 0 and ) (US English) 296: id: "ENTER" + keyCode: "Enter" title: Keyboard Return (US English) icon: keyboard_return 297: id: "ESC" + keyCode: "Escape" title: Keyboard Escape (US English) 298: id: "BKSP" + keyCode: "Backspace" title: Keyboard Backspace (US English) icon: backspace 299: id: "TAB" + keyCode: "Tab" title: Keyboard Tab (US English) icon: keyboard_tab 300: id: "KSC_2C" + keyCode: "Space" title: Keyboard Space (US English) description: | The ASCII space is preferred over this raw scancode for the space bar. icon: space_bar 301: id: "KSC_2D" + keyCode: "Minus" title: Keyboard - and _ (US English) 302: id: "KSC_2E" + keyCode: "Equal" title: Keyboard = and + (US English) 303: id: "KSC_2F" + keyCode: "BracketLeft" title: Keyboard [ and { (US English) 304: id: "KSC_30" + keyCode: "BracketRight" title: Keyboard ] and } (US English) 305: id: "KSC_31" + keyCode: "Backslash" title: Keyboard \ and | (US English) 306: id: "KSC_32" + # TODO: also backslash? title: Keyboard Non-US \# and ~ (US English) 307: id: "KSC_33" + keyCode: "Semicolon" title: "Keyboard ; and : (US English)" 308: id: "KSC_34" + keyCode: "Quote" title: Keyboard ' and " (US English) 309: id: "KSC_35" + keyCode: "Backquote" title: Keyboard ` and ~ (US English) 310: id: "KSC_36" + keyCode: "Comma" title: Keyboard , and < (US English) 311: id: "KSC_37" + keyCode: "Period" title: Keyboard . and > (US English) 312: id: "KSC_38" + keyCode: "Slash" title: Keyboard / and ? (US English) 313: id: "CAPSLOCK" + keyCode: "CapsLock" title: Keyboard Caps Lock icon: shift_lock 314: id: "F1" + keyCode: "F1" title: Keyboard F1 315: id: "F2" + keyCode: "F2" title: Keyboard F2 316: id: "F3" + keyCode: "F3" title: Keyboard F3 317: id: "F4" + keyCode: "F4" title: Keyboard F4 318: id: "F5" + keyCode: "F5" title: Keyboard F5 319: id: "F6" + keyCode: "F6" title: Keyboard F6 320: id: "F7" + keyCode: "F7" title: Keyboard F7 321: id: "F8" + keyCode: "F8" title: Keyboard F8 322: id: "F9" + keyCode: "F9" title: Keyboard F9 323: id: "F10" + keyCode: "F10" title: Keyboard F10 324: id: "F11" + keyCode: "F11" title: Keyboard F11 325: id: "F12" + keyCode: "F12" title: Keyboard F12 326: id: "PRTSCN" + keyCode: "PrintScreen" title: Keyboard Print Screen icon: screenshot_monitor 327: id: "SCRLK" + keyCode: "ScrollLock" title: Keyboard Scroll Lock 328: id: "PAUSE" + keyCode: "Pause" title: Keyboard Pause 329: id: "INSERT" + keyCode: "Insert" title: Keyboard Insert icon: insert_text 330: id: "HOME" + keyCode: "Home" title: Keyboard Home icon: home 331: id: "PGUP" + keyCode: "PageUp" title: Keyboard Page Up icon: move_up 332: id: "DELETE" + keyCode: "Delete" title: Keyboard Delete Forward 333: id: "END" + keyCode: "End" title: Keyboard End 334: id: "PGDN" + keyCode: "PageDown" title: Keyboard Page Down icon: move_down 335: id: "ARROW_RT" + keyCode: "ArrowRight" title: Keyboard Right Arrow icon: keyboard_arrow_right 336: id: "ARROW_LF" + keyCode: "ArrowLeft" title: Keyboard Left Arrow icon: keyboard_arrow_left 337: id: "ARROW_DN" + keyCode: "ArrowDown" title: Keyboard Down Arrow icon: keyboard_arrow_down 338: id: "ARROW_UP" + keyCode: "ArrowUp" title: Keyboard Up Arrow icon: keyboard_arrow_up 339: id: "NUMLOCK" + keyCode: "NumLock" title: Keyboard Num Lock and Clear 340: id: "KP_SLASH" + keyCode: "NumpadDivide" title: Keypad / 341: id: "KP_ASTER" + keyCode: "NumpadStar" title: Keypad * 342: id: "KP_MINUS" + keyCode: "NumpadSubtract" title: Keypad - 343: id: "KP_PLUS" + keyCode: "NumpadAdd" title: Keypad + 344: id: "KP_ENTER" + keyCode: "NumpadEnter" title: Keypad Enter 345: id: "KP_1" + keyCode: "Numpad1" title: Keypad 1 and End 346: id: "KP_2" + keyCode: "Numpad2" title: Keypad 2 and Down Arrow 347: id: "KP_3" + keyCode: "Numpad3" title: Keypad 3 and Page Down 348: id: "KP_4" + keyCode: "Numpad4" title: Keypad 4 and Left Arrow 349: id: "KP_5" + keyCode: "Numpad5" title: Keypad 5 350: id: "KP_6" + keyCode: "Numpad6" title: Keypad 6 and Rigth Arrow 351: id: "KP_7" + keyCode: "Numpad7" title: Keypad 7 and Home 352: id: "KP_8" + keyCode: "Numpad8" title: Keypad 8 and Up Arrow 353: id: "KP_9" + keyCode: "Numpad9" title: Keypad 9 and Page Up 354: id: "KP_0" + keyCode: "Numpad0" title: Keypad 0 and Insert 355: id: "KP_DOT" + keyCode: "NumpadDecimal" title: Keypad . and Delete 356: id: "KSC_64" + keyCode: "IntlBackslash" title: Keyboard Non-US \ and | (US English) 357: id: "COMPOSE" @@ -327,10 +424,12 @@ actions: description: Officially supported by Win, Unix, and Boot 358: id: "POWER" + keyCode: "Power" title: Keyboard Power description: Only officially supported by Mac and Unix 359: id: "KP_EQUAL" + keyCode: "NumpadEqual" title: Keypad = description: Only officially supported by Mac 360: @@ -787,10 +886,12 @@ actions: description: Not required to be supported by any OS 472: id: "KSC_D8" + keyCode: "NumpadClear" title: Keypad Clear description: Not required to be supported by any OS 473: id: "KSC_D9" + keyCode: "NumpadClearEntry" title: Keypad Clear Entry description: Not required to be supported by any OS 474: @@ -817,58 +918,74 @@ actions: description: Not required to be supported by any OS 480: id: "KSC_E0" + keyCode: "ControlLeft" title: Keyboard Left Control 481: id: "KSC_E1" + keyCode: "ShiftLeft" title: Keyboard Left Shift 482: id: "KSC_E2" + keyCode: "AltLeft" title: Keyboard Left Alt 483: id: "KSC_E3" + keyCode: "MetaLeft" title: Keyboard Left GUI 484: id: "KSC_E4" + keyCode: "ControlRight" title: Keyboard Right Control 485: id: "KSC_E5" + keyCode: "ShiftRight" title: Keyboard Right Shift 486: id: "KSC_E6" + keyCode: "AltRight" title: Keyboard Right Alt 487: id: "KSC_E7" + keyCode: "MetaRight" title: Keyboard Right GUI 488: id: "KSC_E8" + keyCode: "MediaPlayPause" title: Media Play Pause description: Not required to be supported by any OS. Possibly deprecated. 489: id: "KSC_E9" + keyCode: "MediaStop" title: Media Stop CD description: Not required to be supported by any OS. Possibly deprecated. 490: id: "KSC_EA" + keyCode: "MediaTrackPrevious" title: Media Previous Song description: Not required to be supported by any OS. Possibly deprecated. 491: id: "KSC_EB" + keyCode: "MediaTrackNext" title: Media Next Song description: Not required to be supported by any OS. Possibly deprecated. 492: id: "KSC_EC" + keyCode: "Eject" title: Media Eject CD description: Not required to be supported by any OS. Possibly deprecated. 493: id: "KSC_ED" + keyCode: "AudioVolumeUp" title: Media Volume Up description: Not required to be supported by any OS. Possibly deprecated. 494: id: "KSC_EE" + keyCode: "AudioVolumeDown" title: Media Volume Down description: Not required to be supported by any OS. Possibly deprecated. 495: id: "KSC_EF" + keyCode: "AudioVolumeMute" title: Media Mute description: Not required to be supported by any OS. Possibly deprecated. 496: @@ -877,18 +994,22 @@ actions: description: Not required to be supported by any OS. Possibly deprecated. 497: id: "KSC_F1" + keyCode: "BrowserBack" title: Media Back description: Not required to be supported by any OS. Possibly deprecated. 498: id: "KSC_F2" + keyCode: "BrowserForward" title: Media Forward description: Not required to be supported by any OS. Possibly deprecated. 499: id: "KSC_F3" + keyCode: "BrowserStop" title: Media Stop description: Not required to be supported by any OS. Possibly deprecated. 500: id: "KSC_F4" + keyCode: "BrowserSearch" title: Media Find description: Not required to be supported by any OS. Possibly deprecated. 501: @@ -905,14 +1026,17 @@ actions: description: Not required to be supported by any OS. Possibly deprecated. 504: id: "KSC_F8" + keyCode: "Sleep" title: Media Sleep description: Not required to be supported by any OS. Possibly deprecated. 505: id: "KSC_F9" + keyCode: "WakeUp" title: Media Coffee description: Not required to be supported by any OS. Possibly deprecated. 506: id: "KSC_FA" + keyCode: "BrowserRefresh" title: Media Refresh description: Not required to be supported by any OS. Possibly deprecated. 507: diff --git a/src/lib/components/Action.svelte b/src/lib/components/Action.svelte new file mode 100644 index 00000000..d7de36aa --- /dev/null +++ b/src/lib/components/Action.svelte @@ -0,0 +1,39 @@ + + +{#if display === "keys"} + + {info.icon ?? info.id ?? `0x${info.code.toString(16)}`} + +{:else if display === "inline-keys"} + {#if !info.icon && info.id?.length === 1} + {info.id} + {:else} + {info.icon ?? info.id ?? `0x${info.code.toString(16)}`} + {/if} +{/if} + + diff --git a/src/lib/components/ActionListItem.svelte b/src/lib/components/ActionListItem.svelte index b9973c8a..a3446013 100644 --- a/src/lib/components/ActionListItem.svelte +++ b/src/lib/components/ActionListItem.svelte @@ -35,6 +35,7 @@ align-items: center; width: 100%; + height: auto; margin: 0; padding: 8px; @@ -61,4 +62,8 @@ text-align: start; } + + kbd { + height: 24px; + } diff --git a/src/lib/components/ActionString.svelte b/src/lib/components/ActionString.svelte new file mode 100644 index 00000000..d24df087 --- /dev/null +++ b/src/lib/components/ActionString.svelte @@ -0,0 +1,11 @@ + + +{#each actions as action, i (`${typeof action === "number" ? action : action.code}:${i}`)} + +{/each} diff --git a/src/lib/components/action-extension.ts b/src/lib/components/action-extension.ts deleted file mode 100644 index da403250..00000000 --- a/src/lib/components/action-extension.ts +++ /dev/null @@ -1,8 +0,0 @@ -import {Extension, Node} from "@tiptap/core" - -const CharaAction = Node.create({ - name: "Action", - renderHTML({HTMLAttributes}) { - return ["kbd", HTMLAttributes, 0] - }, -}) diff --git a/src/lib/ConfirmDialog.svelte b/src/lib/dialogs/ConfirmDialog.svelte similarity index 89% rename from src/lib/ConfirmDialog.svelte rename to src/lib/dialogs/ConfirmDialog.svelte index b6066556..31967f7e 100644 --- a/src/lib/ConfirmDialog.svelte +++ b/src/lib/dialogs/ConfirmDialog.svelte @@ -1,5 +1,6 @@ - +

{@html title}

{#if message}

{@html message}

@@ -24,7 +19,7 @@ -
+
diff --git a/src/lib/dialogs/PickChangesDialog.svelte b/src/lib/dialogs/PickChangesDialog.svelte new file mode 100644 index 00000000..36cbc055 --- /dev/null +++ b/src/lib/dialogs/PickChangesDialog.svelte @@ -0,0 +1,161 @@ + + + +

{$LL.changes.TITLE()}

+

+ +

+
    + {#if layoutChanges.some(it => it.length > 0)} +
  • +

    + +

    +
      + {#each layoutChanges + .map((it, i) => /** @type {const} */ ([it, i + 1])) + .filter(([it]) => it.length > 0) as [changes, layer]} +
    • +

      + +

      +
    • + {/each} +
    +
  • + {/if} + {#if settingChanges.length > 0} +
  • +

    + +

    +
  • + {/if} + {#if totalChordChanges > 0} +
  • +

    + +

    +
      + {#each Object.entries(chordChanges) as [category, changes]} + {#if changes.length > 0} +
    • +

      + +

      +
        + {#each changes as change} +
      • + +
      • + {/each} +
      +
    • + {/if} + {/each} +
    +
  • + {/if} +
+
+ + diff --git a/src/lib/confirm-dialog.ts b/src/lib/dialogs/confirm-dialog.ts similarity index 91% rename from src/lib/confirm-dialog.ts rename to src/lib/dialogs/confirm-dialog.ts index 5bc2e439..f1f3597e 100644 --- a/src/lib/confirm-dialog.ts +++ b/src/lib/dialogs/confirm-dialog.ts @@ -1,4 +1,4 @@ -import ConfirmDialog from "$lib/ConfirmDialog.svelte" +import ConfirmDialog from "$lib/dialogs/ConfirmDialog.svelte" export async function askForConfirmation( title: string, diff --git a/src/lib/os-layout.ts b/src/lib/os-layout.ts new file mode 100644 index 00000000..a8feb4a5 --- /dev/null +++ b/src/lib/os-layout.ts @@ -0,0 +1,39 @@ +import {persistentWritable} from "$lib/storage" +import {get} from "svelte/store" + +export const osLayout = persistentWritable>("os-layout", {}) + +const keysCurrentlyDown = new Set() + +function keydown({code, key}: KeyboardEvent) { + const keys = [...keysCurrentlyDown] + keysCurrentlyDown.add(code) + + const keyString = JSON.stringify([...keys.sort(), code]) + if (keyString in get(osLayout) || get(osLayout)[JSON.stringify([code])] === key) return + + osLayout.update(layout => { + layout[keyString] = key + return layout + }) +} + +function keyup({code}: KeyboardEvent) { + keysCurrentlyDown.delete(code) +} + +export function runLayoutDetection() { + if ("keyboard" in navigator) { + ;(navigator.keyboard as any).getLayoutMap().then((layout: Map) => { + osLayout.update(osLayout => { + Object.assign( + osLayout, + Object.fromEntries([...layout.entries()].map(([key, value]) => [JSON.stringify([key]), value])), + ) + return osLayout + }) + }) + } + window.addEventListener("keydown", keydown) + window.addEventListener("keyup", keyup) +} diff --git a/src/lib/serial/connection.ts b/src/lib/serial/connection.ts index bbb670ba..f9f6eb90 100644 --- a/src/lib/serial/connection.ts +++ b/src/lib/serial/connection.ts @@ -45,17 +45,33 @@ export const deviceSettings = persistentWritable( export const syncStatus: Writable<"done" | "error" | "downloading" | "uploading"> = writable("done") +export interface ProgressInfo { + max: number + current: number +} +export const syncProgress = writable(undefined) + export async function initSerial(manual = false) { const device = get(serialPort) ?? new CharaDevice() await device.init(manual) serialPort.set(device) - + const chordCount = await device.getChordCount() syncStatus.set("downloading") + + const max = Object.keys(settingInfo.settings).length + device.keyCount * 3 + chordCount + let current = 0 + syncProgress.set({max, current}) + function progressTick() { + current++ + syncProgress.set({max, current}) + } + const parsedSettings: number[] = [] for (const key in settingInfo.settings) { try { parsedSettings[Number.parseInt(key)] = await device.getSetting(Number.parseInt(key)) } catch {} + progressTick() } deviceSettings.set(parsedSettings) @@ -63,15 +79,17 @@ export async function initSerial(manual = false) { for (let layer = 1; layer <= 3; layer++) { for (let i = 0; i < device.keyCount; i++) { parsedLayout[layer - 1][i] = await device.getLayoutKey(layer, i) + progressTick() } } deviceLayout.set(parsedLayout) - const chordCount = await device.getChordCount() const chordInfo = [] for (let i = 0; i < chordCount; i++) { chordInfo.push(await device.getChord(i)) + progressTick() } deviceChords.set(chordInfo) syncStatus.set("done") + syncProgress.set(undefined) } diff --git a/src/routes/stats/+page.svelte b/src/lib/style/form/_checkbox.scss similarity index 100% rename from src/routes/stats/+page.svelte rename to src/lib/style/form/_checkbox.scss diff --git a/src/lib/style/theme.scss b/src/lib/style/theme.scss index d99d1f3b..8f8df775 100644 --- a/src/lib/style/theme.scss +++ b/src/lib/style/theme.scss @@ -1,5 +1,6 @@ @import "./form/button"; @import "./form/toggle"; +@import "./form/checkbox"; @import "./kbd"; @import "./print"; diff --git a/src/lib/title.ts b/src/lib/title.ts index dbc1764b..b8d399e2 100644 --- a/src/lib/title.ts +++ b/src/lib/title.ts @@ -13,7 +13,6 @@ export const action: Action = arrow: false, theme: "tooltip", animation: "fade", - delay: [500, 0], onShow(instance) { component ??= new Tooltip({ target: instance.popper.querySelector(".tippy-content") as HTMLElement, diff --git a/src/routes/+layout.svelte b/src/routes/+layout.svelte index 6c5036b7..b0e72dd5 100644 --- a/src/routes/+layout.svelte +++ b/src/routes/+layout.svelte @@ -9,7 +9,7 @@ import Navigation from "./Navigation.svelte" import {canAutoConnect} from "$lib/serial/device" import {initSerial} from "$lib/serial/connection" - import type {LayoutServerData} from "./$types" + import type {LayoutData} from "./$types" import {browser} from "$app/environment" import BrowserWarning from "./BrowserWarning.svelte" import "tippy.js/animations/shift-away.css" @@ -21,12 +21,16 @@ import {detectLocale} from "../i18n/i18n-util" import type {Locales} from "../i18n/i18n-types" import Footer from "./Footer.svelte" + import {runLayoutDetection} from "$lib/os-layout.js" + import PageTransition from "./PageTransition.svelte" + import SyncOverlay from "./SyncOverlay.svelte" const locale = ((browser && localStorage.getItem("locale")) as Locales) || detectLocale() loadLocale(locale) setLocale(locale) if (browser) { + runLayoutDetection() tippy.setDefaultProps({ animation: "shift-away", theme: "surface-variant", @@ -37,7 +41,7 @@ }) } - export let data: LayoutServerData + export let data: LayoutData onMount(async () => { theme.subscribe(it => { @@ -63,11 +67,15 @@ + + -
+ + + -
+