mirror of
https://github.com/CharaChorder/DeviceManager.git
synced 2026-01-23 02:12:41 +00:00
feat: sentence trainer prototype
feat: layout learner prototype
This commit is contained in:
132
src/routes/(app)/learn/layout/+page.svelte
Normal file
132
src/routes/(app)/learn/layout/+page.svelte
Normal file
@@ -0,0 +1,132 @@
|
||||
<script lang="ts">
|
||||
import { share } from "$lib/share";
|
||||
import tippy from "tippy.js";
|
||||
import { mount, setContext, unmount } 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";
|
||||
import Action from "$lib/components/Action.svelte";
|
||||
import { serialPort } from "$lib/serial/connection";
|
||||
|
||||
let hasStarted = $state(false);
|
||||
|
||||
setContext<VisualLayoutConfig>("visual-layout-config", {
|
||||
scale: 50,
|
||||
inactiveScale: 0.5,
|
||||
inactiveOpacity: 0.4,
|
||||
strokeWidth: 1,
|
||||
margin: 5,
|
||||
fontSize: 9,
|
||||
iconFontSize: 14,
|
||||
});
|
||||
|
||||
const actions = derived(layout, (layout) => {
|
||||
const result = new Set<number>();
|
||||
for (const layer of layout) {
|
||||
for (const key of layer) {
|
||||
result.add(key.action);
|
||||
}
|
||||
}
|
||||
return [...result];
|
||||
});
|
||||
|
||||
const currentAction = writable(0);
|
||||
|
||||
const expected = derived(
|
||||
[layout, currentAction],
|
||||
([layout, currentAction]) => {
|
||||
const result: Array<{ layer: number; key: number }> = [];
|
||||
for (let layer = 0; layer <= layout.length; layer++) {
|
||||
if (layout[layer] === undefined) {
|
||||
continue;
|
||||
}
|
||||
for (let key = 0; key <= layout[layer].length; key++) {
|
||||
if (layout[layer][key]?.action === currentAction) {
|
||||
result.push({ layer, key });
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
},
|
||||
);
|
||||
|
||||
const highlight = derived(
|
||||
expected,
|
||||
(expected) => new Set(expected.map(({ key }) => key)),
|
||||
);
|
||||
|
||||
const highlightAction = derived(
|
||||
currentAction,
|
||||
(currentAction) => new Set([currentAction]),
|
||||
);
|
||||
|
||||
const currentLayer = writable(0);
|
||||
|
||||
setContext("highlight", highlight);
|
||||
|
||||
setContext("highlight-action", highlightAction);
|
||||
|
||||
setContext("active-layer", currentLayer);
|
||||
|
||||
async function next() {
|
||||
console.log("Next");
|
||||
const nextAction = $actions[Math.floor(Math.random() * $actions.length)];
|
||||
if (nextAction !== undefined) {
|
||||
currentAction.set(nextAction);
|
||||
currentLayer.set($expected[0]?.layer ?? 0);
|
||||
const key = await $serialPort?.queryKey();
|
||||
if ($expected.some(({ key: expectedKey }) => expectedKey === key)) {
|
||||
console.log("Correct", key);
|
||||
} else {
|
||||
console.log("Incorrect", key);
|
||||
}
|
||||
next();
|
||||
}
|
||||
}
|
||||
|
||||
$effect(() => {
|
||||
if ($serialPort && $layout[0]?.[0] && !hasStarted) {
|
||||
hasStarted = true;
|
||||
next();
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<section>
|
||||
<div class="challenge">
|
||||
<Action display="inline-keys" action={$currentAction}></Action>
|
||||
</div>
|
||||
|
||||
<Layout />
|
||||
</section>
|
||||
|
||||
<style lang="scss">
|
||||
.challenge {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
|
||||
width: 100%;
|
||||
height: 100px;
|
||||
|
||||
font-size: 24px;
|
||||
}
|
||||
|
||||
.input {
|
||||
width: 100%;
|
||||
height: 100px;
|
||||
border: 1px solid black;
|
||||
}
|
||||
|
||||
section {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user