mirror of
https://github.com/CharaChorder/DeviceManager.git
synced 2026-02-05 00:32:41 +00:00
@@ -4,11 +4,12 @@
|
||||
import LL from "../../../i18n/i18n-svelte"
|
||||
import {action} from "$lib/title"
|
||||
import {onDestroy, onMount, setContext} from "svelte"
|
||||
import {chords} from "$lib/undo-redo"
|
||||
import {changes, ChangeType, 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"
|
||||
import ChordActionEdit from "./ChordActionEdit.svelte"
|
||||
|
||||
const resultSize = 38
|
||||
let results: HTMLElement
|
||||
@@ -46,12 +47,27 @@
|
||||
searchFilter.set(query && searchIndex ? searchIndex.search(query) : undefined)
|
||||
}
|
||||
|
||||
function insertChord(actions: number[]) {
|
||||
changes.update(changes => {
|
||||
changes.push({
|
||||
type: ChangeType.Chord,
|
||||
id: actions,
|
||||
actions,
|
||||
phrase: [],
|
||||
})
|
||||
return changes
|
||||
})
|
||||
}
|
||||
|
||||
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)
|
||||
const lastPage = derived(
|
||||
[items, pageSize],
|
||||
([items, pageSize]) => Math.ceil((items.length + 1) / pageSize) - 1,
|
||||
)
|
||||
|
||||
setContext("cursor-crossfade", crossfade({}))
|
||||
|
||||
@@ -91,8 +107,11 @@
|
||||
|
||||
<section bind:this={results}>
|
||||
<table>
|
||||
{#if page === 0}
|
||||
<tr><th><ChordActionEdit on:submit={({detail}) => insertChord(detail)} /></th><td /><td /></tr>
|
||||
{/if}
|
||||
{#if $lastPage !== -1}
|
||||
{#each $items.slice(page * $pageSize, (page + 1) * $pageSize) as [chord] (chord.id)}
|
||||
{#each $items.slice(page * $pageSize - (page === 0 ? 0 : 1), (page + 1) * $pageSize - 1) as [chord] (JSON.stringify(chord.id))}
|
||||
<tr>
|
||||
<ChordEdit {chord} />
|
||||
</tr>
|
||||
|
||||
@@ -2,8 +2,12 @@
|
||||
import {KEYMAP_CODES, KEYMAP_IDS} from "$lib/serial/keymap-codes"
|
||||
import type {ChordInfo} from "$lib/undo-redo"
|
||||
import {changes, ChangeType} from "$lib/undo-redo"
|
||||
import {createEventDispatcher} from "svelte"
|
||||
import LL from "../../../i18n/i18n-svelte"
|
||||
|
||||
export let chord: ChordInfo
|
||||
export let chord: ChordInfo | undefined = undefined
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
|
||||
let pressedKeys = new Set<number>()
|
||||
let editing = false
|
||||
@@ -24,12 +28,13 @@
|
||||
if (!editing) return
|
||||
editing = false
|
||||
if (pressedKeys.size < 2) return
|
||||
if (!chord) return dispatch("submit", [...pressedKeys])
|
||||
changes.update(changes => {
|
||||
changes.push({
|
||||
type: ChangeType.Chord,
|
||||
id: chord.id,
|
||||
id: chord!.id,
|
||||
actions: [...pressedKeys],
|
||||
phrase: chord.phrase,
|
||||
phrase: chord!.phrase,
|
||||
})
|
||||
return changes
|
||||
})
|
||||
@@ -37,16 +42,18 @@
|
||||
</script>
|
||||
|
||||
<button
|
||||
class:deleted={chord.phrase.length === 0}
|
||||
class:edited={chord.actionsChanged}
|
||||
class:deleted={chord && chord.phrase.length === 0}
|
||||
class:edited={chord && chord.actionsChanged}
|
||||
on:click={edit}
|
||||
on:keydown={keydown}
|
||||
on:keyup={keyup}
|
||||
>
|
||||
{#if editing && pressedKeys.size === 0}
|
||||
<span>Press keys</span>
|
||||
<span>{$LL.configure.chords.HOLD_KEYS()}</span>
|
||||
{:else if !editing && !chord}
|
||||
<span>{$LL.configure.chords.NEW_CHORD()}</span>
|
||||
{/if}
|
||||
{#each editing ? [...pressedKeys].sort() : chord.actions as actionId}
|
||||
{#each editing ? [...pressedKeys].sort() : chord?.actions ?? [] as actionId}
|
||||
{@const {icon, id, code} = KEYMAP_CODES[actionId] ?? {code: actionId}}
|
||||
<kbd class:icon={!!icon}>
|
||||
{icon ?? id ?? `0x${code.toString(16)}`}
|
||||
@@ -92,9 +99,10 @@
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
transform-origin: center left;
|
||||
translate: -6px 0;
|
||||
scale: 0 1;
|
||||
|
||||
width: calc(100% - 16px);
|
||||
width: calc(100% - 32px);
|
||||
height: 1px;
|
||||
|
||||
background: currentcolor;
|
||||
|
||||
@@ -31,10 +31,10 @@
|
||||
<ChordPhraseEdit {chord} />
|
||||
</td>
|
||||
<td class="table-buttons">
|
||||
{#if chord.phrase.length === 0}
|
||||
<button transition:slide class="icon compact" on:click={restore}>restore_from_trash</button>
|
||||
{:else}
|
||||
{#if chord.phrase.length !== 0}
|
||||
<button transition:slide class="icon compact" on:click={remove}>delete</button>
|
||||
{:else if chord.phraseChanged}
|
||||
<button transition:slide class="icon compact" on:click={restore}>restore_from_trash</button>
|
||||
{/if}
|
||||
<button class="icon compact" class:disabled={chord.isApplied} on:click={restore}>undo</button>
|
||||
<div class="separator" />
|
||||
|
||||
@@ -135,7 +135,7 @@
|
||||
role="textbox"
|
||||
tabindex="0"
|
||||
bind:this={box}
|
||||
class:edited={chord.phraseChanged}
|
||||
class:edited={chord.phrase.length !== 0 && chord.phraseChanged}
|
||||
on:focusin={() => (hasFocus = true)}
|
||||
on:focusout={event => {
|
||||
if (event.relatedTarget !== button) hasFocus = false
|
||||
@@ -236,12 +236,13 @@
|
||||
background: currentcolor;
|
||||
|
||||
transition:
|
||||
opacity 250ms ease,
|
||||
opacity 150ms ease,
|
||||
scale 250ms ease;
|
||||
}
|
||||
|
||||
&::after {
|
||||
scale: 0 1;
|
||||
transition-duration: 250ms;
|
||||
}
|
||||
|
||||
&:hover::before {
|
||||
|
||||
Reference in New Issue
Block a user