mirror of
https://github.com/CharaChorder/DeviceManager.git
synced 2026-02-06 01:02:43 +00:00
305 lines
7.4 KiB
Svelte
305 lines
7.4 KiB
Svelte
<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";
|
|
import LL from "$i18n/i18n-svelte";
|
|
import {
|
|
createChordBackup,
|
|
createLayoutBackup,
|
|
createSettingsBackup,
|
|
downloadBackup,
|
|
downloadFile,
|
|
restoreBackup,
|
|
restoreFromFile,
|
|
} from "$lib/backup/backup";
|
|
import { preference } from "$lib/preferences";
|
|
import { action } from "$lib/title";
|
|
import { fly } from "svelte/transition";
|
|
import type { SettingsItemMeta } from "$lib/meta/types/meta";
|
|
|
|
function titlecase(str: string) {
|
|
return str.charAt(0).toUpperCase() + str.slice(1);
|
|
}
|
|
|
|
function settingValue(value: number, setting: SettingsItemMeta) {
|
|
if (setting.inverse !== undefined) {
|
|
return setting.inverse / value;
|
|
}
|
|
if (setting.scale !== undefined) {
|
|
return value * setting.scale;
|
|
}
|
|
return value;
|
|
}
|
|
</script>
|
|
|
|
<svelte:head>
|
|
<title>Device Settings - CharaChorder Device Manager</title>
|
|
<meta name="description" content="Change your device's settings" />
|
|
</svelte:head>
|
|
|
|
<section>
|
|
<fieldset>
|
|
<legend>{$LL.backup.TITLE()}</legend>
|
|
<label
|
|
><input
|
|
type="checkbox"
|
|
use:preference={"backup"}
|
|
/>{$LL.backup.AUTO_BACKUP()}</label
|
|
>
|
|
<p class="disclaimer">
|
|
{$LL.backup.DISCLAIMER()}
|
|
</p>
|
|
<div class="row" style="margin-top: auto">
|
|
<button onclick={() => downloadFile(createChordBackup())}>
|
|
<span class="icon">piano</span>
|
|
{$LL.configure.chords.TITLE()}
|
|
</button>
|
|
<button onclick={() => downloadFile(createLayoutBackup())}>
|
|
<span class="icon">keyboard</span>
|
|
{$LL.configure.layout.TITLE()}
|
|
</button>
|
|
<button onclick={() => downloadFile(createSettingsBackup())}>
|
|
<span class="icon">settings</span>
|
|
Settings
|
|
</button>
|
|
</div>
|
|
<div class="row">
|
|
<button class="primary" onclick={downloadBackup}
|
|
><span class="icon">download</span>{$LL.backup.DOWNLOAD()}</button
|
|
>
|
|
<label class="button"
|
|
><input oninput={restoreBackup} type="file" /><span class="icon"
|
|
>settings_backup_restore</span
|
|
>{$LL.backup.RESTORE()}</label
|
|
>
|
|
</div>
|
|
</fieldset>
|
|
|
|
<fieldset>
|
|
<legend>Device</legend>
|
|
<label
|
|
>{$LL.deviceManager.AUTO_CONNECT()}<input
|
|
type="checkbox"
|
|
use:preference={"autoConnect"}
|
|
/></label
|
|
>
|
|
{#if $serialPort}
|
|
{#if $deviceMeta?.factoryDefaults?.settings}
|
|
<button
|
|
use:action={{ title: "Reset Settings" }}
|
|
transition:fly={{ x: -8 }}
|
|
onclick={() => restoreFromFile($deviceMeta.factoryDefaults!.settings)}
|
|
><span class="icon">reset_settings</span>Reset Settings</button
|
|
>
|
|
{/if}
|
|
<button class="outline" use:popup={ResetPopup}>Recovery...</button>
|
|
{/if}
|
|
</fieldset>
|
|
{#if $deviceMeta}
|
|
{#each $deviceMeta.settings as category}
|
|
<fieldset>
|
|
<legend>
|
|
{#if category.items[0]?.name === "enable"}
|
|
<label
|
|
><input
|
|
type="checkbox"
|
|
use:setting={{ id: category.items[0].id }}
|
|
/>{titlecase(category.name)}</label
|
|
>
|
|
{:else}
|
|
{titlecase(category.name)}
|
|
{/if}
|
|
</legend>
|
|
{#if category.description}
|
|
<p>{category.description}</p>
|
|
{/if}
|
|
{#each category.items as item}
|
|
{#if item.name !== "enable"}
|
|
<label
|
|
>{#if item.enum}
|
|
<select use:setting={{ id: item.id }}>
|
|
{#each item.enum as name, value}
|
|
<option {value}>{titlecase(name)}</option>
|
|
{/each}
|
|
</select>
|
|
{:else if item.range[0] === 0 && item.range[1] === 1}
|
|
<input type="checkbox" use:setting={{ id: item.id }} />
|
|
{:else}
|
|
<span class="unit"
|
|
><input
|
|
type="number"
|
|
min={settingValue(item.range[0], item)}
|
|
max={settingValue(item.range[1], item)}
|
|
step={item.inverse !== undefined ||
|
|
item.scale !== undefined ||
|
|
item.step === undefined
|
|
? undefined
|
|
: settingValue(item.step, item)}
|
|
use:setting={{
|
|
id: item.id,
|
|
inverse: item.inverse,
|
|
scale: item.scale,
|
|
}}
|
|
/>{item.unit}</span
|
|
>
|
|
{/if}
|
|
{#if item.description}
|
|
<span
|
|
>{titlecase(item.name)}
|
|
<p>{item.description}</p></span
|
|
>
|
|
{:else}
|
|
{titlecase(item.name)}
|
|
{/if}
|
|
</label>
|
|
{/if}
|
|
{/each}
|
|
</fieldset>
|
|
{/each}
|
|
{/if}
|
|
</section>
|
|
|
|
<style lang="scss">
|
|
section {
|
|
overflow-y: auto;
|
|
display: flex;
|
|
flex-flow: row wrap;
|
|
gap: 16px;
|
|
justify-content: center;
|
|
|
|
margin-block: auto;
|
|
padding-block-end: 48px;
|
|
}
|
|
|
|
button.outline {
|
|
border: 1px solid currentcolor;
|
|
border-radius: 8px;
|
|
height: 2em;
|
|
margin-block: 2em;
|
|
margin-inline: auto;
|
|
}
|
|
|
|
legend,
|
|
legend > label {
|
|
font-size: 24px;
|
|
font-weight: bold;
|
|
position: relative;
|
|
padding: 0 16px;
|
|
}
|
|
|
|
legend:has(label) {
|
|
padding: 0;
|
|
}
|
|
|
|
legend:not(:has(label)) {
|
|
opacity: 0.8;
|
|
}
|
|
|
|
input[type="checkbox"] {
|
|
font-size: 12px !important;
|
|
}
|
|
|
|
fieldset {
|
|
display: flex;
|
|
flex-direction: column;
|
|
|
|
max-width: 400px;
|
|
border: 1px solid var(--md-sys-color-outline);
|
|
border-radius: 24px;
|
|
|
|
/*&:has(> legend input:not(:checked)) > :not(legend) {
|
|
pointer-events: none;
|
|
opacity: 0.7;
|
|
}*/
|
|
|
|
> label {
|
|
position: relative;
|
|
display: flex;
|
|
gap: 16px;
|
|
align-items: center;
|
|
justify-content: space-between;
|
|
|
|
margin-block: 4px;
|
|
|
|
font-size: 14px;
|
|
|
|
&:has(input[type="number"]) {
|
|
cursor: text;
|
|
|
|
&:hover {
|
|
filter: none;
|
|
}
|
|
}
|
|
}
|
|
|
|
.unit {
|
|
overflow: hidden;
|
|
display: flex;
|
|
gap: 4px;
|
|
align-items: center;
|
|
justify-content: flex-start;
|
|
|
|
width: 67px;
|
|
padding-inline-end: auto;
|
|
|
|
font-size: 12px;
|
|
font-weight: bold;
|
|
|
|
background: var(--md-sys-color-secondary-container);
|
|
border-radius: 16px;
|
|
}
|
|
|
|
input[type="number"] {
|
|
display: flex;
|
|
|
|
width: 5ch;
|
|
height: 100%;
|
|
padding-block: 4px;
|
|
|
|
font-family: "Noto Sans Mono", monospace;
|
|
color: var(--md-sys-color-on-secondary);
|
|
text-align: end;
|
|
|
|
background: var(--md-sys-color-secondary);
|
|
border: none;
|
|
|
|
&::-webkit-inner-spin-button {
|
|
display: none;
|
|
}
|
|
|
|
&::after {
|
|
content: "bleh";
|
|
}
|
|
|
|
&:focus {
|
|
outline: none;
|
|
}
|
|
}
|
|
}
|
|
|
|
// stylelint-disable-next-line
|
|
label:global(:has(.pending-changes)) {
|
|
color: var(--md-sys-color-primary);
|
|
|
|
&::before {
|
|
position: absolute;
|
|
font-size: 16px;
|
|
top: 0.5em;
|
|
right: 0.25em;
|
|
content: "•";
|
|
}
|
|
}
|
|
|
|
.row {
|
|
display: flex;
|
|
justify-content: space-evenly;
|
|
margin-block: 8px;
|
|
}
|
|
|
|
input[type="file"] {
|
|
display: none;
|
|
}
|
|
</style>
|