feat: new settings page design

This commit is contained in:
2025-05-06 16:34:34 +02:00
parent ff7e4f7b2e
commit f76882a09c

View File

@@ -40,100 +40,52 @@
</svelte:head> </svelte:head>
<section> <section>
<fieldset> <nav>
<legend>{$LL.backup.TITLE()}</legend> {#if $deviceMeta}
<label {#each $deviceMeta?.settings as category}
><input <a href={`#${category.name}`}>{titlecase(category.name)}</a>
type="checkbox" {/each}
use:preference={"backup"} {/if}
/>{$LL.backup.AUTO_BACKUP()}</label <a href="#backup">Backup</a>
> </nav>
<p class="disclaimer"> <div class="content">
{$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 <label
>{$LL.deviceManager.AUTO_CONNECT()}<input >{$LL.deviceManager.AUTO_CONNECT()}<input
type="checkbox" type="checkbox"
use:preference={"autoConnect"} use:preference={"autoConnect"}
/></label /></label
> >
{#if $serialPort} {#if $deviceMeta}
{#if $deviceMeta?.factoryDefaults?.settings} {#each $deviceMeta.settings as category}
<button <fieldset id={category.name}>
use:action={{ title: "Reset Settings" }} <legend>
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)} {titlecase(category.name)}
</legend>
{#if category.description}
<p>{category.description}</p>
{/if} {/if}
</legend> {#each category.items as item}
{#if category.description}
<p>{category.description}</p>
{/if}
{#each category.items as item}
{#if item.name !== "enable"}
{#if item.unit === "H"} {#if item.unit === "H"}
<label <label
><input type="color" use:setting={{ id: item.id }} /> Color</label ><input type="color" use:setting={{ id: item.id }} /> Color</label
> >
{:else if item.unit !== "S" && item.unit !== "B"} {:else if item.unit !== "S" && item.unit !== "B"}
<label <label class:enable-item={item.name === "enable"}
>{#if item.enum} >{#if item.enum}
<select use:setting={{ id: item.id }}> <select class="value" use:setting={{ id: item.id }}>
{#each item.enum as name, value} {#each item.enum as name, value}
<option {value}>{titlecase(name)}</option> <option {value}>{titlecase(name)}</option>
{/each} {/each}
</select> </select>
{:else if item.range[0] === 0 && item.range[1] === 1} {:else if item.range[0] === 0 && item.range[1] === 1}
<input type="checkbox" use:setting={{ id: item.id }} /> <input
class="value"
type="checkbox"
use:setting={{ id: item.id }}
/>
{:else} {:else}
<span class="unit" <div class="value unit">
><input <input
type="number" type="number"
min={settingValue(item.range[0], item)} min={settingValue(item.range[0], item)}
max={settingValue(item.range[1], item)} max={settingValue(item.range[1], item)}
@@ -147,62 +99,96 @@
inverse: item.inverse, inverse: item.inverse,
scale: item.scale, scale: item.scale,
}} }}
/>{item.unit}</span />{item.unit}
> </div>
{/if} {/if}
<div class="title">{titlecase(item.name)}</div>
{#if item.description} {#if item.description}
<span <div class="description">{item.description}</div>
>{titlecase(item.name)}
<p>{item.description}</p></span
>
{:else}
{titlecase(item.name)}
{/if} {/if}
</label> </label>
{/if} {/if}
{/if} {/each}
{/each} </fieldset>
</fieldset> {/each}
{/each} {/if}
{/if}
<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>
<div class="footer">
{#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 use:popup={ResetPopup}>Recovery...</button>
{/if}
</div>
</div>
</section> </section>
<style lang="scss"> <style lang="scss">
section { section {
display: grid;
grid-template-columns: auto 1fr;
max-width: 100%;
overflow: hidden;
}
.content {
overflow-y: auto; overflow-y: auto;
display: flex; scroll-behavior: smooth;
flex-flow: row wrap; max-width: 20cm;
gap: 16px;
justify-content: center;
margin-block: auto;
padding-block-end: 48px;
} }
button.outline { legend {
border: 1px solid currentcolor; color: var(--md-sys-color-primary);
border-radius: 8px; font-size: 32px;
height: 2em;
margin-block: 2em;
margin-inline: auto;
}
legend,
legend > label {
font-size: 24px;
font-weight: bold; font-weight: bold;
position: relative; position: relative;
padding: 0 16px;
}
legend:has(label) {
padding: 0; padding: 0;
} }
legend:not(:has(label)) {
opacity: 0.8;
}
input[type="checkbox"] { input[type="checkbox"] {
font-size: 12px !important; font-size: 12px !important;
} }
@@ -210,22 +196,28 @@
fieldset { fieldset {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
position: relative;
max-width: 400px; width: 100%;
border: 1px solid var(--md-sys-color-outline); margin-inline: 0;
border-radius: 24px; border: none;
margin-block-end: 32px;
/*&:has(> legend input:not(:checked)) > :not(legend) { > p {
pointer-events: none; padding-inline-start: 16px;
opacity: 0.7; }
}*/
> label { > label {
appearance: none;
position: relative; position: relative;
display: flex; display: flex;
gap: 16px; flex-wrap: wrap;
align-items: center; align-items: center;
justify-content: space-between; justify-content: flex-start;
height: auto;
font-weight: normal;
padding: 8px;
width: fit-content;
margin-block: 4px; margin-block: 4px;
@@ -238,6 +230,26 @@
filter: none; filter: none;
} }
} }
&.enable-item {
background: var(--md-sys-color-surface-variant);
color: var(--md-sys-color-on-surface-variant);
margin-inline-start: 8px;
padding-inline-end: 16px;
padding-inline-start: 8px;
}
}
.title {
margin-inline-start: 16px;
font-weight: 600;
}
.description {
width: 100%;
font-size: 12px;
white-space: normal;
text-wrap: wrap;
} }
.unit { .unit {
@@ -285,6 +297,16 @@
} }
} }
select {
appearance: none;
background: var(--md-sys-color-secondary);
border: none;
padding: 4px 8px;
border-radius: 8px;
font: inherit;
font-size: 12px;
}
// stylelint-disable-next-line // stylelint-disable-next-line
label:global(:has(.pending-changes)) { label:global(:has(.pending-changes)) {
color: var(--md-sys-color-primary); color: var(--md-sys-color-primary);
@@ -302,9 +324,15 @@
display: flex; display: flex;
justify-content: space-evenly; justify-content: space-evenly;
margin-block: 8px; margin-block: 8px;
width: fit-content;
} }
input[type="file"] { input[type="file"] {
display: none; display: none;
} }
.footer {
display: flex;
justify-content: flex-end;
}
</style> </style>