mirror of
https://github.com/CharaChorder/DeviceManager.git
synced 2026-02-27 19:42:04 +00:00
feat: update stuff
This commit is contained in:
@@ -131,8 +131,6 @@
|
||||
<div class="layout">
|
||||
<Sidebar />
|
||||
|
||||
<!-- <PickChangesDialog /> -->
|
||||
|
||||
<PageTransition>
|
||||
{#if children}
|
||||
{@render children()}
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
<script lang="ts">
|
||||
import { browser, version } from "$app/environment";
|
||||
import { action } from "$lib/title";
|
||||
import { actionTooltip } from "$lib/title";
|
||||
import LL, { setLocale } from "$i18n/i18n-svelte";
|
||||
import { theme } from "$lib/preferences.js";
|
||||
import type { Locales } from "$i18n/i18n-types";
|
||||
import { detectLocale, locales } from "$i18n/i18n-util";
|
||||
import { detectLocale } from "$i18n/i18n-util";
|
||||
import { loadLocaleAsync } from "$i18n/i18n-util.async";
|
||||
import { tick } from "svelte";
|
||||
import {
|
||||
@@ -54,15 +54,13 @@
|
||||
$serialPort = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
let languageSelect: HTMLSelectElement;
|
||||
</script>
|
||||
|
||||
<footer>
|
||||
<ul>
|
||||
<li>
|
||||
<a
|
||||
use:action={{ title: "Branch" }}
|
||||
{@attach actionTooltip("Branch")}
|
||||
href={import.meta.env.VITE_HOMEPAGE_URL}
|
||||
rel="noreferrer"
|
||||
target="_blank"><span class="icon">commit</span> v{version}</a
|
||||
@@ -71,7 +69,7 @@
|
||||
<li>
|
||||
<a
|
||||
href="/ccos/{currentDevice ? `${currentDevice}/` : ''}"
|
||||
use:action={{ title: "Updates" }}
|
||||
{@attach actionTooltip("Updates")}
|
||||
>
|
||||
CCOS {$serialPort?.version ?? "Updates"}
|
||||
</a>
|
||||
@@ -94,12 +92,13 @@
|
||||
<ConnectPopup />
|
||||
</div>
|
||||
{:else}
|
||||
{#snippet disconnectTooltip()}
|
||||
Disconnect<br /><kbd class="icon">shift</kbd> Sync
|
||||
{/snippet}
|
||||
<button
|
||||
transition:slide={{ axis: "x" }}
|
||||
onclick={disconnect}
|
||||
use:action={{
|
||||
title: "Disconnect<br><kbd class='icon'>shift</kbd> Sync",
|
||||
}}
|
||||
{@attach actionTooltip(disconnectTooltip)}
|
||||
><b
|
||||
>{$serialPort.company}
|
||||
{$serialPort.device}
|
||||
@@ -129,7 +128,7 @@
|
||||
</li>
|
||||
<li class="hide-forced-colors">
|
||||
<input
|
||||
use:action={{ title: $LL.profile.theme.COLOR_SCHEME() }}
|
||||
{@attach actionTooltip($LL.profile.theme.COLOR_SCHEME())}
|
||||
type="color"
|
||||
bind:value={$theme.color}
|
||||
/>
|
||||
@@ -137,7 +136,7 @@
|
||||
<li class="hide-forced-colors">
|
||||
{#if $theme.mode === "light"}
|
||||
<button
|
||||
use:action={{ title: $LL.profile.theme.DARK_MODE() }}
|
||||
{@attach actionTooltip($LL.profile.theme.DARK_MODE())}
|
||||
class="icon"
|
||||
onclick={switchTheme}
|
||||
>
|
||||
@@ -145,7 +144,7 @@
|
||||
</button>
|
||||
{:else if $theme.mode === "dark"}
|
||||
<button
|
||||
use:action={{ title: $LL.profile.theme.LIGHT_MODE() }}
|
||||
{@attach actionTooltip($LL.profile.theme.LIGHT_MODE())}
|
||||
class="icon"
|
||||
onclick={switchTheme}
|
||||
>
|
||||
@@ -153,22 +152,6 @@
|
||||
</button>
|
||||
{/if}
|
||||
</li>
|
||||
<!--<li>
|
||||
<div
|
||||
role="button"
|
||||
class="icon"
|
||||
use:action={{ title: $LL.profile.LANGUAGE() }}
|
||||
onclick={() => languageSelect.click()}
|
||||
>
|
||||
translate
|
||||
|
||||
<select bind:value={locale} bind:this={languageSelect}>
|
||||
{#each locales as code}
|
||||
<option value={code}>{code}</option>
|
||||
{/each}
|
||||
</select>
|
||||
</div>
|
||||
</li>-->
|
||||
</ul>
|
||||
</footer>
|
||||
|
||||
@@ -232,14 +215,6 @@
|
||||
background: var(--md-sys-color-primary);
|
||||
}
|
||||
|
||||
.warning {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
color: var(--md-sys-color-error);
|
||||
}
|
||||
|
||||
input[type="color"] {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
import {
|
||||
changes,
|
||||
ChangeType,
|
||||
chords,
|
||||
layout,
|
||||
overlay,
|
||||
settings,
|
||||
@@ -11,7 +10,7 @@
|
||||
} from "$lib/undo-redo";
|
||||
import type { Change, ChordChange } from "$lib/undo-redo";
|
||||
import { fly } from "svelte/transition";
|
||||
import { action, actionTooltip } from "$lib/title";
|
||||
import { actionTooltip } from "$lib/title";
|
||||
import {
|
||||
deviceChords,
|
||||
deviceLayout,
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
<script lang="ts">
|
||||
import { KEYMAP_CODES, type KeyInfo } from "$lib/serial/keymap-codes";
|
||||
import FlexSearch from "flexsearch";
|
||||
import FlexSearch, { type Index } from "flexsearch";
|
||||
import LL from "$i18n/i18n-svelte";
|
||||
import { action } from "$lib/title";
|
||||
import { actionTooltip } from "$lib/title";
|
||||
import { onDestroy, onMount, setContext, tick } from "svelte";
|
||||
import { changes, ChangeType, chords } from "$lib/undo-redo";
|
||||
import type { ChordChange, ChordInfo } from "$lib/undo-redo";
|
||||
@@ -38,7 +38,7 @@
|
||||
});
|
||||
|
||||
let index = new FlexSearch.Index();
|
||||
let searchIndex = writable<FlexSearch.Index | undefined>(undefined);
|
||||
let searchIndex = writable<Index | undefined>(undefined);
|
||||
$effect(() => {
|
||||
abortIndexing?.();
|
||||
progress = 0;
|
||||
@@ -129,7 +129,7 @@
|
||||
chords: ChordInfo[],
|
||||
osLayout: Map<string, string>,
|
||||
codes: Map<number, KeyInfo>,
|
||||
): Promise<FlexSearch.Index> {
|
||||
): Promise<Index> {
|
||||
if (chords.length === 0 || !browser) return index;
|
||||
|
||||
index = new FlexSearch.Index({
|
||||
@@ -185,7 +185,7 @@
|
||||
const searchFilter = writable<number[] | undefined>(undefined);
|
||||
let currentSearchQuery = $state("");
|
||||
|
||||
async function search(index: FlexSearch.Index, event: Event) {
|
||||
async function search(index: Index, event: Event) {
|
||||
const query = (event.target as HTMLInputElement).value;
|
||||
currentSearchQuery = query;
|
||||
searchFilter.set(
|
||||
@@ -296,12 +296,12 @@
|
||||
<button
|
||||
class="icon"
|
||||
onclick={() => (page = Math.max(page - 1, 0))}
|
||||
use:action={{ shortcut: "ctrl+left" }}>navigate_before</button
|
||||
{@attach actionTooltip("", "ctrl+left")}>navigate_before</button
|
||||
>
|
||||
<button
|
||||
class="icon"
|
||||
onclick={() => (page = Math.min(page + 1, $lastPage))}
|
||||
use:action={{ shortcut: "ctrl+right" }}>navigate_next</button
|
||||
{@attach actionTooltip("", "ctrl+right")}>navigate_next</button
|
||||
>
|
||||
</div>
|
||||
|
||||
@@ -370,10 +370,6 @@
|
||||
min-width: 8ch;
|
||||
}
|
||||
|
||||
.new-chord :global(.add) {
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
.sidebar {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
@@ -82,6 +82,7 @@
|
||||
function addSpecial(event: MouseEvent) {
|
||||
event.stopPropagation();
|
||||
selectAction(event, (action) => {
|
||||
if (!chord) return onsubmit([action]);
|
||||
changes.update((changes) => {
|
||||
changes.push([
|
||||
{
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
<div class="table-buttons">
|
||||
{#if !chord.deleted}
|
||||
<button transition:slide class="icon compact" onclick={remove}
|
||||
>delete</button
|
||||
>
|
||||
{:else}
|
||||
<button transition:slide class="icon compact" onclick={restore}
|
||||
>restore_from_trash</button
|
||||
>
|
||||
{/if}
|
||||
<button disabled={chord.deleted} class="icon compact" onclick={duplicate}
|
||||
>content_copy</button
|
||||
>
|
||||
<button
|
||||
class="icon compact"
|
||||
class:disabled={chord.isApplied}
|
||||
onclick={restore}>undo</button
|
||||
>
|
||||
<div class="separator"></div>
|
||||
<button class="icon compact" onclick={share}>share</button>
|
||||
</div>
|
||||
@@ -1,71 +0,0 @@
|
||||
<script lang="ts">
|
||||
import Action from "$lib/components/Action.svelte";
|
||||
import type { ChordInfo } from "$lib/undo-redo";
|
||||
import { onMount, tick } from "svelte";
|
||||
|
||||
let { chord }: { chord: ChordInfo } = $props();
|
||||
|
||||
let actualElements: HTMLDivElement | undefined = $state(undefined);
|
||||
let pseudoElements: HTMLDivElement | undefined = $state(undefined);
|
||||
|
||||
let widths: number[] = $state([]);
|
||||
|
||||
onMount(async () => {
|
||||
for (const letter of chord.phrase) {
|
||||
const span = document.createElement("span");
|
||||
span.textContent = String.fromCodePoint(letter);
|
||||
pseudoElements?.appendChild(span);
|
||||
}
|
||||
|
||||
await tick();
|
||||
await tick();
|
||||
await tick();
|
||||
await tick();
|
||||
|
||||
update();
|
||||
});
|
||||
|
||||
function update() {
|
||||
console.log(document.getSelection());
|
||||
pseudoElements?.childNodes.forEach((node, index) => {
|
||||
if (node instanceof HTMLElement) {
|
||||
const range = document.createRange();
|
||||
const actual = actualElements?.childNodes[index];
|
||||
range.setStartBefore(actual);
|
||||
range.setEndAfter(actual);
|
||||
const rect = range.getBoundingClientRect();
|
||||
console.log(rect);
|
||||
node.style.width = rect.width + "px";
|
||||
}
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="editor">
|
||||
<div class="visual" bind:this={actualElements}>
|
||||
{#each chord.phrase as action, index}
|
||||
<Action {action} display="inline-keys" />
|
||||
{/each}
|
||||
</div>
|
||||
<div contenteditable="true" bind:this={pseudoElements}></div>
|
||||
</div>
|
||||
|
||||
<style lang="scss">
|
||||
.editor {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
[contenteditable="true"] {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
|
||||
> :global(span) {
|
||||
display: inline-block;
|
||||
background: red;
|
||||
|
||||
&:nth-child(even) {
|
||||
background: blue;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1,34 +0,0 @@
|
||||
<script lang="ts">
|
||||
import type { Snippet } from "svelte";
|
||||
|
||||
let {
|
||||
children,
|
||||
onofferdropbefore,
|
||||
onofferdropafter,
|
||||
onofferreplace,
|
||||
}: {
|
||||
children: Snippet;
|
||||
onofferdropbefore: () => void;
|
||||
onofferdropafter: () => void;
|
||||
onofferreplace: () => void;
|
||||
} = $props();
|
||||
|
||||
let element: HTMLSpanElement | undefined = $state(undefined);
|
||||
|
||||
</script>
|
||||
|
||||
<span
|
||||
class="droptarget"
|
||||
bind:this={element}
|
||||
{ondrop}
|
||||
{ondragenter}
|
||||
{ondragleave}
|
||||
>
|
||||
{@render children()}
|
||||
</span>
|
||||
|
||||
<style lang="scss">
|
||||
.droptarget {
|
||||
position: relative;
|
||||
}
|
||||
</style>
|
||||
@@ -7,6 +7,7 @@
|
||||
import SharePopup from "../SharePopup.svelte";
|
||||
import type { VisualLayoutConfig } from "$lib/components/layout/visual-layout";
|
||||
import { layout } from "$lib/undo-redo";
|
||||
import { activeProfile } from "$lib/serial/connection";
|
||||
|
||||
async function shareLayout(event: Event) {
|
||||
const url = new URL(window.location.href);
|
||||
@@ -16,11 +17,9 @@
|
||||
charaVersion: 1,
|
||||
type: "layout",
|
||||
device: "one",
|
||||
layout: $layout.map((it) => it.map((it) => it.action)) as [
|
||||
number[],
|
||||
number[],
|
||||
number[],
|
||||
],
|
||||
layout: $layout[$activeProfile]?.map((it) =>
|
||||
it.map((it) => it.action),
|
||||
) as [number[], number[], number[]],
|
||||
}),
|
||||
);
|
||||
await navigator.clipboard.writeText(url.toString());
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
<script lang="ts">
|
||||
import Action from "$lib/components/Action.svelte";
|
||||
import { popup } from "$lib/popup";
|
||||
import { deviceMeta, serialPort } from "$lib/serial/connection";
|
||||
import { setting } from "$lib/setting";
|
||||
import ResetPopup from "./ResetPopup.svelte";
|
||||
@@ -14,8 +12,7 @@
|
||||
restoreBackup,
|
||||
restoreFromFile,
|
||||
} from "$lib/backup/backup";
|
||||
import { preference } from "$lib/preferences";
|
||||
import { action } from "$lib/title";
|
||||
import { actionTooltip } from "$lib/title";
|
||||
import { fly } from "svelte/transition";
|
||||
import type { SettingsItemMeta } from "$lib/meta/types/meta";
|
||||
|
||||
@@ -96,7 +93,9 @@
|
||||
/>{item.unit}
|
||||
</div>
|
||||
{/if}
|
||||
<div class="title">{titlecase(item.name)}</div>
|
||||
{#if item.name}
|
||||
<div class="title">{titlecase(item.name)}</div>
|
||||
{/if}
|
||||
{#if item.description}
|
||||
<div class="description">{@html item.description}</div>
|
||||
{/if}
|
||||
@@ -139,7 +138,7 @@
|
||||
{#if $serialPort}
|
||||
{#if $deviceMeta?.factoryDefaults?.settings}
|
||||
<button
|
||||
use:action={{ title: "Reset Settings" }}
|
||||
{@attach actionTooltip("Reset Settings")}
|
||||
transition:fly={{ x: -8 }}
|
||||
onclick={() =>
|
||||
restoreFromFile($deviceMeta.factoryDefaults!.settings)}
|
||||
|
||||
@@ -1,85 +0,0 @@
|
||||
<script lang="ts">
|
||||
import type { PageData } from "./$types";
|
||||
|
||||
let { data }: { data: PageData } = $props();
|
||||
|
||||
$effect(() => {
|
||||
console.log(data);
|
||||
});
|
||||
</script>
|
||||
|
||||
<details>
|
||||
<summary>Full Log</summary>
|
||||
{#each data.data as item, i}
|
||||
{#if "press" in item}
|
||||
<div class="press">{item.press}</div>
|
||||
{:else if "release" in item}
|
||||
<div class="release">{item.release}</div>
|
||||
{:else if "keys" in item}
|
||||
<div class="report">
|
||||
<span class="icon">keyboard</span>
|
||||
<div class="modifiers">
|
||||
{item.modifiers.toString(2)}
|
||||
</div>
|
||||
<div class="keys">{item.keys.join(", ")}</div>
|
||||
</div>
|
||||
{:else if "out" in item}
|
||||
<pre class="out">{item.out}</pre>
|
||||
{:else if "in" in item}
|
||||
<pre class="in">{item.in}</pre>
|
||||
{:else if "tick" in item}
|
||||
<div class="tick"><span class="icon">timer_play</span>{item.tick}ms</div>
|
||||
{:else}
|
||||
<div>Unknown log item at index {i}</div>
|
||||
{/if}
|
||||
{/each}
|
||||
</details>
|
||||
|
||||
<style lang="scss">
|
||||
details {
|
||||
margin-top: 1rem;
|
||||
border: 1px solid var(--md-sys-color-outline);
|
||||
border-radius: 0.5rem;
|
||||
background-color: var(--md-sys-color-surface-variant);
|
||||
padding: 1rem;
|
||||
}
|
||||
|
||||
.report {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 1rem;
|
||||
margin-bottom: 0.5rem;
|
||||
border-radius: 0.25rem;
|
||||
background-color: var(--md-sys-color-primary-container);
|
||||
padding: 0.5rem;
|
||||
color: var(--md-sys-color-on-primary-container);
|
||||
}
|
||||
|
||||
.out {
|
||||
color: var(--md-sys-color-primary);
|
||||
}
|
||||
|
||||
.in {
|
||||
color: var(--md-sys-color-secondary);
|
||||
}
|
||||
|
||||
.tick {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
border-radius: 0.25rem;
|
||||
padding: 0.2rem 0.5rem;
|
||||
width: fit-content;
|
||||
color: var(--md-sys-color-tertiary);
|
||||
font-size: 0.6rem;
|
||||
}
|
||||
|
||||
.icon {
|
||||
font-size: inherit;
|
||||
}
|
||||
|
||||
input[type="range"] {
|
||||
margin-bottom: 1rem;
|
||||
width: 100%;
|
||||
}
|
||||
</style>
|
||||
@@ -1,49 +0,0 @@
|
||||
import type { PageLoad } from "./$types";
|
||||
import { browser } from "$app/environment";
|
||||
import { fromBase64 } from "$lib/serialization/base64";
|
||||
|
||||
export interface ReplaySerialIn {
|
||||
in: string;
|
||||
}
|
||||
|
||||
export interface ReplaySerialOut {
|
||||
out: string;
|
||||
}
|
||||
|
||||
export interface ReplaySerialReport {
|
||||
modifiers: number;
|
||||
keys: number[];
|
||||
}
|
||||
|
||||
export interface ReplaySerialPress {
|
||||
press: number;
|
||||
}
|
||||
|
||||
export interface ReplaySerialRelease {
|
||||
release: number;
|
||||
}
|
||||
|
||||
export interface ReplayTick {
|
||||
tick: number;
|
||||
}
|
||||
|
||||
export type ReplayDataItem =
|
||||
| ReplayTick
|
||||
| ReplaySerialIn
|
||||
| ReplaySerialOut
|
||||
| ReplaySerialReport
|
||||
| ReplaySerialPress
|
||||
| ReplaySerialRelease;
|
||||
|
||||
export const load = (async ({ url, fetch }) => {
|
||||
const replay = browser && new URLSearchParams(url.search).get("data");
|
||||
if (!replay) {
|
||||
return undefined;
|
||||
}
|
||||
const stream = (await fromBase64(replay, fetch))
|
||||
.stream()
|
||||
.pipeThrough(new DecompressionStream("deflate"));
|
||||
return {
|
||||
data: JSON.parse(await new Response(stream).text()) as ReplayDataItem[],
|
||||
};
|
||||
}) satisfies PageLoad;
|
||||
@@ -9,7 +9,7 @@
|
||||
learnConfig,
|
||||
learnConfigStored,
|
||||
} from "$lib/learn/chords";
|
||||
import { blur, fade } from "svelte/transition";
|
||||
import { fade } from "svelte/transition";
|
||||
import ChordActionEdit from "../../config/chords/ChordActionEdit.svelte";
|
||||
import TrackChords from "$lib/charrecorder/TrackChords.svelte";
|
||||
import type { InferredChord } from "$lib/charrecorder/core/types";
|
||||
@@ -144,7 +144,7 @@
|
||||
<tbody>
|
||||
{#each Object.entries($scores)
|
||||
.sort(([, a], [, b]) => b.lastTyped - a.lastTyped)
|
||||
.splice(0, 10) as [word, score]}
|
||||
.splice(0, 10) as [word, _score]}
|
||||
<tr class="decay">
|
||||
<td>{word}</td>
|
||||
</tr>
|
||||
@@ -164,16 +164,20 @@
|
||||
<td
|
||||
><input
|
||||
type="number"
|
||||
value={$learnConfig[key] ?? value}
|
||||
value={$learnConfig[key as keyof typeof $learnConfig] ?? value}
|
||||
step="0.1"
|
||||
oninput={(event) =>
|
||||
($learnConfigStored[key] = event.target.value)}
|
||||
($learnConfigStored[key as keyof typeof $learnConfig] = (
|
||||
event.target as HTMLInputElement
|
||||
).value as any)}
|
||||
/>
|
||||
</td>
|
||||
<td>
|
||||
<button
|
||||
disabled={!$learnConfigStored[key]}
|
||||
onclick={() => ($learnConfigStored[key] = undefined)}>⟲</button
|
||||
disabled={!$learnConfigStored[key as keyof typeof $learnConfig]}
|
||||
onclick={() =>
|
||||
($learnConfigStored[key as keyof typeof $learnConfigStored] =
|
||||
undefined)}>⟲</button
|
||||
>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
<script lang="ts">
|
||||
import { share } from "$lib/share";
|
||||
import tippy from "tippy.js";
|
||||
import { mount, setContext, unmount } from "svelte";
|
||||
import { setContext } from "svelte";
|
||||
import Layout from "$lib/components/layout/Layout.svelte";
|
||||
import { charaFileToUriComponent } from "$lib/share/share-url";
|
||||
import type { VisualLayoutConfig } from "$lib/components/layout/visual-layout";
|
||||
import { writable, derived } from "svelte/store";
|
||||
import { layout } from "$lib/undo-redo";
|
||||
@@ -26,7 +23,7 @@
|
||||
const result = new Set<number>();
|
||||
for (const layer of layout) {
|
||||
for (const key of layer) {
|
||||
result.add(key.action);
|
||||
result.add(key[0].action);
|
||||
}
|
||||
}
|
||||
return [...result];
|
||||
@@ -39,11 +36,12 @@
|
||||
([layout, currentAction]) => {
|
||||
const result: Array<{ layer: number; key: number }> = [];
|
||||
for (let layer = 0; layer <= layout.length; layer++) {
|
||||
if (layout[layer] === undefined) {
|
||||
const layerArr = layout[layer];
|
||||
if (layerArr === undefined) {
|
||||
continue;
|
||||
}
|
||||
for (let key = 0; key <= layout[layer].length; key++) {
|
||||
if (layout[layer][key]?.action === currentAction) {
|
||||
for (let key = 0; key <= layerArr.length; key++) {
|
||||
if (layerArr[key]?.[0].action === currentAction) {
|
||||
result.push({ layer, key });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -80,7 +80,7 @@
|
||||
];
|
||||
|
||||
const actionsCompletion: Completion[] = Array.from(
|
||||
KEYMAP_CODES,
|
||||
$KEYMAP_CODES,
|
||||
([id, info]) => {
|
||||
const isValidIdentifier =
|
||||
info.id && /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(info.id);
|
||||
@@ -195,7 +195,7 @@
|
||||
function runPlugin() {
|
||||
frame.contentWindow?.postMessage(
|
||||
{
|
||||
actionCodes: KEYMAP_CODES,
|
||||
actionCodes: $KEYMAP_CODES,
|
||||
script: editorView.state.doc.toString(),
|
||||
charaChannels: Object.keys(channels),
|
||||
} satisfies ChannelCharaEventData,
|
||||
|
||||
@@ -4,8 +4,8 @@
|
||||
|
||||
let recipes = $derived(
|
||||
$deviceMeta?.recipes?.toSorted((a, b) => {
|
||||
if (a.demo == null) return 1;
|
||||
if (b.demo == null) return -1;
|
||||
if (!a.demo?.title) return 1;
|
||||
if (!b.demo?.title) return -1;
|
||||
return a.demo.title.localeCompare(b.demo.title);
|
||||
}),
|
||||
);
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
});
|
||||
</script>
|
||||
|
||||
<!-- svelte-ignore a11y_no_static_element_interactions -->
|
||||
<section
|
||||
id={"demo-" + i}
|
||||
onmouseenter={() => (paused = false)}
|
||||
|
||||
@@ -1,14 +1,11 @@
|
||||
<script lang="ts">
|
||||
import CharRecorder from "$lib/charrecorder/CharRecorder.svelte";
|
||||
import { ReplayPlayer } from "$lib/charrecorder/core/player";
|
||||
import type { Replay } from "$lib/charrecorder/core/types";
|
||||
import ActionString from "$lib/components/ActionString.svelte";
|
||||
import ChordPhraseDisplay from "$lib/components/ChordPhraseDisplay.svelte";
|
||||
import type { E2eTest, E2eTestItem } from "$lib/meta/types/meta";
|
||||
import { osLayout } from "$lib/os-layout";
|
||||
import { deviceMeta } from "$lib/serial/connection";
|
||||
import { KEYMAP_IDS } from "$lib/serial/keymap-codes";
|
||||
import type { ChordInfo } from "$lib/undo-redo";
|
||||
|
||||
let { test, paused = false }: { test: E2eTest; paused?: boolean } = $props();
|
||||
|
||||
@@ -224,7 +221,8 @@
|
||||
<ul>
|
||||
{#each settings as [item, value]}
|
||||
<li>
|
||||
{item?.name ?? "Unknown Setting"}: {value?.toString()}
|
||||
{(typeof item === "object" ? item?.name : undefined) ??
|
||||
"Unknown Setting"}: {value?.toString()}
|
||||
</li>
|
||||
{/each}
|
||||
</ul>
|
||||
@@ -287,26 +285,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
.details {
|
||||
position: absolute;
|
||||
transform-origin: top;
|
||||
scale: 1 0.5;
|
||||
z-index: 1;
|
||||
margin-left: -17px;
|
||||
border: 1px solid var(--md-sys-color-outline);
|
||||
border-top: none;
|
||||
background-color: var(--md-sys-color-surface);
|
||||
padding: 16px;
|
||||
width: calc(100% + 2px);
|
||||
}
|
||||
|
||||
summary {
|
||||
cursor: pointer;
|
||||
margin-top: 0.5rem;
|
||||
font-weight: bold;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.replay {
|
||||
border-radius: 0.4rem;
|
||||
background: var(--md-sys-color-surface-variant);
|
||||
|
||||
Reference in New Issue
Block a user