Add Web Updater functionality, improved layout for small displays
This commit is contained in:
parent
4f15eee72b
commit
e53b487236
4
.github/workflows/workflow.yml
vendored
4
.github/workflows/workflow.yml
vendored
@ -41,7 +41,7 @@ jobs:
|
|||||||
node-version: lts/*
|
node-version: lts/*
|
||||||
cache: yarn
|
cache: yarn
|
||||||
cache-dependency-path: '**/yarn.lock'
|
cache-dependency-path: '**/yarn.lock'
|
||||||
- uses: actions/cache@v3
|
- uses: actions/cache@v4
|
||||||
with:
|
with:
|
||||||
path: |
|
path: |
|
||||||
~/.cache/pip
|
~/.cache/pip
|
||||||
@ -80,6 +80,8 @@ jobs:
|
|||||||
run: mkdir -p output && echo "$BLOCK_HEIGHT" > output/version.txt
|
run: mkdir -p output && echo "$BLOCK_HEIGHT" > output/version.txt
|
||||||
- name: gzip build for LittleFS
|
- name: gzip build for LittleFS
|
||||||
run: find dist -type f ! -name ".*" -exec sh -c 'mkdir -p "build_gz/$(dirname "${1#dist/}")" && gzip -k "$1" -c > "build_gz/${1#dist/}".gz' _ {} \;
|
run: find dist -type f ! -name ".*" -exec sh -c 'mkdir -p "build_gz/$(dirname "${1#dist/}")" && gzip -k "$1" -c > "build_gz/${1#dist/}".gz' _ {} \;
|
||||||
|
- name: Write git rev to file
|
||||||
|
run: echo "$GITHUB_SHA" > build_gz/fs_hash.txt
|
||||||
- name: Check GZipped directory size
|
- name: Check GZipped directory size
|
||||||
run: |
|
run: |
|
||||||
# Set the threshold size in bytes
|
# Set the threshold size in bytes
|
||||||
|
@ -60,6 +60,12 @@
|
|||||||
"uptime": "Betriebszeit",
|
"uptime": "Betriebszeit",
|
||||||
"wifiSignalStrength": "WiFi-Signalstärke",
|
"wifiSignalStrength": "WiFi-Signalstärke",
|
||||||
"wsDataConnection": "BTClock-Datenquelle verbindung"
|
"wsDataConnection": "BTClock-Datenquelle verbindung"
|
||||||
|
},
|
||||||
|
"firmwareUpdater": {
|
||||||
|
"fileUploadSuccess": "Datei erfolgreich hochgeladen, Gerät neu gestartet. WebUI in {countdown} Sekunden neu geladen",
|
||||||
|
"fileUploadFailed": "Das Hochladen der Datei ist fehlgeschlagen. \nStellen Sie sicher, dass Sie die richtige Datei ausgewählt haben, und versuchen Sie es erneut.",
|
||||||
|
"uploading": "Hochladen",
|
||||||
|
"firmwareUpdateText": "Wenn Sie die Firmware-Upload-Funktion verwenden, stellen Sie sicher, dass Sie die richtigen Dateien verwenden. \nDas Hochladen der falschen Dateien kann dazu führen, dass das Gerät nicht mehr funktioniert. \nWenn es schief geht, können Sie die Firmware wiederherstellen, indem Sie das vollständige Image hochladen, nachdem Sie das Gerät in den BOOT-Modus versetzt haben."
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"colors": {
|
"colors": {
|
||||||
@ -88,5 +94,6 @@
|
|||||||
},
|
},
|
||||||
"rssiBar": {
|
"rssiBar": {
|
||||||
"tooltip": "Werte > -67 dBm gelten als gut. > -30 dBm ist erstaunlich"
|
"tooltip": "Werte > -67 dBm gelten als gut. > -30 dBm ist erstaunlich"
|
||||||
}
|
},
|
||||||
|
"warning": "Achtung"
|
||||||
}
|
}
|
||||||
|
@ -48,7 +48,9 @@
|
|||||||
"hostname": "Hostname",
|
"hostname": "Hostname",
|
||||||
"frontlight": "Frontlight",
|
"frontlight": "Frontlight",
|
||||||
"turnOn": "Turn on",
|
"turnOn": "Turn on",
|
||||||
"flashFrontlight": "Flash"
|
"flashFrontlight": "Flash",
|
||||||
|
"firmwareUpdate": "Firmware update",
|
||||||
|
"fwCommit": "Firmware commit"
|
||||||
},
|
},
|
||||||
"status": {
|
"status": {
|
||||||
"title": "Status",
|
"title": "Status",
|
||||||
@ -60,6 +62,12 @@
|
|||||||
"uptime": "Uptime",
|
"uptime": "Uptime",
|
||||||
"wifiSignalStrength": "WiFi Signal strength",
|
"wifiSignalStrength": "WiFi Signal strength",
|
||||||
"wsDataConnection": "BTClock data-source connection"
|
"wsDataConnection": "BTClock data-source connection"
|
||||||
|
},
|
||||||
|
"firmwareUpdater": {
|
||||||
|
"fileUploadFailed": "File upload failed. Make sure you have selected the correct file and try again.",
|
||||||
|
"fileUploadSuccess": "File uploaded successfully, restarting device and reloading WebUI in {countdown} seconds",
|
||||||
|
"uploading": "Uploading",
|
||||||
|
"firmwareUpdateText": "When you use the firmware upload functionality, make sure you use the correct files. Uploading the wrong files can result in a non-working device. If it goes wrong, you can restore firmware by uploading the full image after setting the device in BOOT-mode."
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"colors": {
|
"colors": {
|
||||||
@ -88,5 +96,6 @@
|
|||||||
},
|
},
|
||||||
"rssiBar": {
|
"rssiBar": {
|
||||||
"tooltip": "Values > -67 dBm are considered good. > -30 dBm is amazing"
|
"tooltip": "Values > -67 dBm are considered good. > -30 dBm is amazing"
|
||||||
}
|
},
|
||||||
|
"warning": "Warning"
|
||||||
}
|
}
|
||||||
|
@ -59,6 +59,12 @@
|
|||||||
"title": "Estado",
|
"title": "Estado",
|
||||||
"wifiSignalStrength": "Fuerza de la señal WiFi",
|
"wifiSignalStrength": "Fuerza de la señal WiFi",
|
||||||
"wsDataConnection": "Conexión de fuente de datos BTClock"
|
"wsDataConnection": "Conexión de fuente de datos BTClock"
|
||||||
|
},
|
||||||
|
"firmwareUpdater": {
|
||||||
|
"fileUploadSuccess": "Archivo cargado exitosamente, reiniciando el dispositivo. Recargando WebUI en {countdown} segundos",
|
||||||
|
"fileUploadFailed": "Error al cargar el archivo. \nAsegúrese de haber seleccionado el archivo correcto e inténtelo nuevamente.",
|
||||||
|
"uploading": "Subiendo",
|
||||||
|
"firmwareUpdateText": "Cuando utilice la función de carga de firmware, asegúrese de utilizar los archivos correctos. \nCargar archivos incorrectos puede provocar que el dispositivo no funcione. \nSi sale mal, puede restaurar el firmware cargando la imagen completa después de configurar el dispositivo en modo BOOT."
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"button": {
|
"button": {
|
||||||
@ -87,5 +93,6 @@
|
|||||||
},
|
},
|
||||||
"rssiBar": {
|
"rssiBar": {
|
||||||
"tooltip": "Se consideran buenos valores > -67 dBm. > -30 dBm es increíble"
|
"tooltip": "Se consideran buenos valores > -67 dBm. > -30 dBm es increíble"
|
||||||
}
|
},
|
||||||
|
"warning": "Aviso"
|
||||||
}
|
}
|
||||||
|
@ -59,6 +59,12 @@
|
|||||||
"uptime": "Uptime",
|
"uptime": "Uptime",
|
||||||
"wifiSignalStrength": "WiFi signaalsterkte",
|
"wifiSignalStrength": "WiFi signaalsterkte",
|
||||||
"wsDataConnection": "BTClock-gegevensbron verbinding"
|
"wsDataConnection": "BTClock-gegevensbron verbinding"
|
||||||
|
},
|
||||||
|
"firmwareUpdater": {
|
||||||
|
"fileUploadSuccess": "Bestand geüpload, apparaat herstart. WebUI opnieuw geladen over {countdown} seconden",
|
||||||
|
"fileUploadFailed": "Bestandsupload mislukt. \nZorg ervoor dat het juiste bestand is geselecteerd en probeer het opnieuw.",
|
||||||
|
"uploading": "Uploaden",
|
||||||
|
"firmwareUpdateText": "Zorg bij het gebruiken van de firmware upload dat de juiste bestanden gebruikt worden. \nHet uploaden van de verkeerde bestanden kan resulteren in een niet-werkend apparaat. \nAls het misgaat, kunt u de firmware herstellen door de volledige afbeelding te uploaden nadat u het apparaat in de BOOT-modus hebt gezet."
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"colors": {
|
"colors": {
|
||||||
@ -87,5 +93,6 @@
|
|||||||
},
|
},
|
||||||
"rssiBar": {
|
"rssiBar": {
|
||||||
"tooltip": "Waarden > -67 dBm zijn goed. > -30 dBm is verbazingwekkend"
|
"tooltip": "Waarden > -67 dBm zijn goed. > -30 dBm is verbazingwekkend"
|
||||||
}
|
},
|
||||||
|
"warning": "Waarschuwing"
|
||||||
}
|
}
|
||||||
|
9
src/lib/screen.ts
Normal file
9
src/lib/screen.ts
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
import { writable } from 'svelte/store';
|
||||||
|
|
||||||
|
// Create a writable store to track screen size
|
||||||
|
export const screenSize = writable<number>(window.innerWidth);
|
||||||
|
|
||||||
|
// Function to update the screen size
|
||||||
|
export const updateScreenSize = () => {
|
||||||
|
screenSize.set(window.innerWidth);
|
||||||
|
};
|
@ -36,33 +36,34 @@ $input-font-size-sm: $font-size-base * 0.875;
|
|||||||
@import '../node_modules/bootstrap/scss/progress';
|
@import '../node_modules/bootstrap/scss/progress';
|
||||||
@import '../node_modules/bootstrap/scss/tooltip';
|
@import '../node_modules/bootstrap/scss/tooltip';
|
||||||
@import '../node_modules/bootstrap/scss/toasts';
|
@import '../node_modules/bootstrap/scss/toasts';
|
||||||
|
@import '../node_modules/bootstrap/scss/alert';
|
||||||
|
|
||||||
@import '../node_modules/bootstrap/scss/helpers';
|
@import '../node_modules/bootstrap/scss/helpers';
|
||||||
@import '../node_modules/bootstrap/scss/utilities/api';
|
@import '../node_modules/bootstrap/scss/utilities/api';
|
||||||
|
|
||||||
@include media-breakpoint-down(xl) {
|
// @include media-breakpoint-down(xl) {
|
||||||
html {
|
// html {
|
||||||
font-size: 85%;
|
// // font-size: 85%;
|
||||||
}
|
// }
|
||||||
|
|
||||||
button.btn,
|
// button.btn,
|
||||||
input[type='button'].btn,
|
// input[type='button'].btn,
|
||||||
input[type='submit'].btn,
|
// input[type='submit'].btn,
|
||||||
input[type='reset'].btn {
|
// input[type='reset'].btn {
|
||||||
@include button-size(
|
// @include button-size(
|
||||||
$btn-padding-y-sm,
|
// $btn-padding-y-sm,
|
||||||
$btn-padding-x-sm,
|
// $btn-padding-x-sm,
|
||||||
$font-size-sm,
|
// $font-size-sm,
|
||||||
$btn-border-radius-sm
|
// $btn-border-radius-sm
|
||||||
);
|
// );
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
@include media-breakpoint-down(lg) {
|
// @include media-breakpoint-down(lg) {
|
||||||
html {
|
// html {
|
||||||
font-size: 75%;
|
// font-size: 75%;
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
nav {
|
nav {
|
||||||
margin-bottom: 15px;
|
margin-bottom: 15px;
|
||||||
@ -208,3 +209,8 @@ nav {
|
|||||||
font-style: italic;
|
font-style: italic;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.firmwareUploadStatusAlert,
|
||||||
|
#firmwareUploadProgress {
|
||||||
|
@extend .my-2;
|
||||||
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { PUBLIC_BASE_URL } from '$lib/config';
|
import { PUBLIC_BASE_URL } from '$lib/config';
|
||||||
|
import { screenSize, updateScreenSize } from '$lib/screen';
|
||||||
|
|
||||||
import { Container, Row, Toast, ToastBody } from 'sveltestrap';
|
import { Container, Row, Toast, ToastBody } from 'sveltestrap';
|
||||||
|
|
||||||
@ -13,6 +14,12 @@
|
|||||||
fgColor: '0'
|
fgColor: '0'
|
||||||
});
|
});
|
||||||
|
|
||||||
|
let uiSettings = writable({
|
||||||
|
inputSize: 'sm',
|
||||||
|
selectClass: '',
|
||||||
|
btnSize: 'lg'
|
||||||
|
});
|
||||||
|
|
||||||
let status = writable({
|
let status = writable({
|
||||||
data: ['L', 'O', 'A', 'D', 'I', 'N', 'G'],
|
data: ['L', 'O', 'A', 'D', 'I', 'N', 'G'],
|
||||||
espFreeHeap: 0,
|
espFreeHeap: 0,
|
||||||
@ -61,8 +68,43 @@
|
|||||||
let dataObj = JSON.parse(e.data);
|
let dataObj = JSON.parse(e.data);
|
||||||
status.set(dataObj);
|
status.set(dataObj);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
function handleResize() {
|
||||||
|
updateScreenSize();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add an event listener to update the screen size when the window is resized
|
||||||
|
window.addEventListener('resize', handleResize);
|
||||||
|
|
||||||
|
// Call the function initially to set the initial screen size
|
||||||
|
updateScreenSize();
|
||||||
|
|
||||||
|
// Cleanup function to remove the event listener when the component is destroyed
|
||||||
|
return () => {
|
||||||
|
window.removeEventListener('resize', handleResize);
|
||||||
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
|
$: {
|
||||||
|
const lgBreakpoint = parseInt(
|
||||||
|
getComputedStyle(document.documentElement).getPropertyValue('--bs-breakpoint-lg')
|
||||||
|
);
|
||||||
|
|
||||||
|
if ($screenSize >= lgBreakpoint) {
|
||||||
|
uiSettings.set({
|
||||||
|
inputSize: 'sm',
|
||||||
|
selectClass: 'form-select-sm',
|
||||||
|
btnSize: 'sm'
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
uiSettings.set({
|
||||||
|
inputSize: 'lg',
|
||||||
|
selectClass: 'form-select-lg',
|
||||||
|
btnSize: 'xl'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let toastIsOpen = false;
|
let toastIsOpen = false;
|
||||||
let toastColor = 'success';
|
let toastColor = 'success';
|
||||||
let toastBody = '';
|
let toastBody = '';
|
||||||
@ -79,10 +121,15 @@
|
|||||||
</svelte:head>
|
</svelte:head>
|
||||||
|
|
||||||
<Container fluid>
|
<Container fluid>
|
||||||
<Row>
|
<Row cols={{ lg: 3, sm: 1 }}>
|
||||||
<Control bind:settings bind:status></Control>
|
<Control bind:settings bind:uiSettings bind:status></Control>
|
||||||
<Status bind:settings bind:status></Status>
|
<Status bind:settings bind:status></Status>
|
||||||
<Settings bind:settings on:showToast={showToast} on:formReset={fetchSettingsData}></Settings>
|
<Settings
|
||||||
|
bind:settings
|
||||||
|
bind:uiSettings
|
||||||
|
on:showToast={showToast}
|
||||||
|
on:formReset={fetchSettingsData}
|
||||||
|
></Settings>
|
||||||
</Row>
|
</Row>
|
||||||
</Container>
|
</Container>
|
||||||
<div class="position-fixed bottom-0 end-0 p-2">
|
<div class="position-fixed bottom-0 end-0 p-2">
|
||||||
|
@ -15,8 +15,11 @@
|
|||||||
Label,
|
Label,
|
||||||
Row
|
Row
|
||||||
} from 'sveltestrap';
|
} from 'sveltestrap';
|
||||||
|
import FirmwareUpdater from './FirmwareUpdater.svelte';
|
||||||
|
|
||||||
export let settings = {};
|
export let settings = {};
|
||||||
|
export let uiSettings;
|
||||||
|
|
||||||
export let customText: string;
|
export let customText: string;
|
||||||
export let status: Writable<{ leds: [] }>;
|
export let status: Writable<{ leds: [] }>;
|
||||||
let ledStatus = [];
|
let ledStatus = [];
|
||||||
@ -102,25 +105,35 @@
|
|||||||
<CardBody>
|
<CardBody>
|
||||||
<Form>
|
<Form>
|
||||||
<Row>
|
<Row>
|
||||||
<Label md={4} for="customText">{$_('section.control.text')}</Label>
|
<Label md={4} for="customText" size={$uiSettings.inputSize}
|
||||||
|
>{$_('section.control.text')}</Label
|
||||||
|
>
|
||||||
<Col md="8">
|
<Col md="8">
|
||||||
<Input
|
<Input
|
||||||
type="text"
|
type="text"
|
||||||
id="customText"
|
id="customText"
|
||||||
bind:value={customText}
|
bind:value={customText}
|
||||||
bsSize="sm"
|
bsSize="$uiSettings.inputSize"
|
||||||
maxLength={$settings.numScreens}
|
maxLength={$settings.numScreens}
|
||||||
/>
|
/>
|
||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
<Button color="primary" on:click={setCustomText}>{$_('section.control.showText')}</Button>
|
<Row>
|
||||||
|
<Col class="d-flex justify-content-end">
|
||||||
|
<Button color="primary" on:click={setCustomText} bsSize={$uiSettings.btnSize}
|
||||||
|
>{$_('section.control.showText')}</Button
|
||||||
|
>
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
</Form>
|
</Form>
|
||||||
<hr />
|
<hr />
|
||||||
{#if !$settings.disableLeds}
|
{#if !$settings.disableLeds}
|
||||||
<h3>LEDs</h3>
|
<h3>LEDs</h3>
|
||||||
<Form>
|
<Form>
|
||||||
<Row>
|
<Row>
|
||||||
<Label md={4} for="ledColorPicker" size="sm">{$_('section.control.ledColor')}</Label>
|
<Label md={4} for="ledColorPicker" size={$uiSettings.inputSize}
|
||||||
|
>{$_('section.control.ledColor')}</Label
|
||||||
|
>
|
||||||
<Col md="8">
|
<Col md="8">
|
||||||
<Row class="justify-content-between">
|
<Row class="justify-content-between">
|
||||||
{#if ledStatus}
|
{#if ledStatus}
|
||||||
@ -137,51 +150,84 @@
|
|||||||
{/each}
|
{/each}
|
||||||
{/if}
|
{/if}
|
||||||
</Row>
|
</Row>
|
||||||
<Row class="justify-content-between">
|
<Row>
|
||||||
<Col>
|
<Col class="d-flex justify-content-end">
|
||||||
<Input
|
<Input
|
||||||
bind:checked={keepLedsSameColor}
|
bind:checked={keepLedsSameColor}
|
||||||
type="switch"
|
type="switch"
|
||||||
class="mx-auto"
|
|
||||||
label={$_('sections.control.keepSameColor')}
|
label={$_('sections.control.keepSameColor')}
|
||||||
|
bsSize={$uiSettings.inputSize}
|
||||||
/>
|
/>
|
||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
<Button color="secondary" id="turnOffLedsBtn" on:click={turnOffLeds}
|
<Row>
|
||||||
>{$_('section.control.turnOff')}</Button
|
<Col class="d-flex justify-content-end">
|
||||||
>
|
<Button
|
||||||
<Button color="primary" on:click={setLEDcolor}>{$_('section.control.setColor')}</Button>
|
color="secondary"
|
||||||
|
id="turnOffLedsBtn"
|
||||||
|
on:click={turnOffLeds}
|
||||||
|
bsSize={$uiSettings.inputSize}>{$_('section.control.turnOff')}</Button
|
||||||
|
>
|
||||||
|
<div class="mx-2"></div>
|
||||||
|
<Button color="primary" on:click={setLEDcolor} bsSize={$uiSettings.inputSize}
|
||||||
|
>{$_('section.control.setColor')}</Button
|
||||||
|
>
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
</Form>
|
</Form>
|
||||||
<hr />
|
<hr />
|
||||||
{/if}
|
{/if}
|
||||||
{#if $settings.hasFrontlight}
|
{#if $settings.hasFrontlight}
|
||||||
<h3>{$_('section.control.frontlight')}</h3>
|
<h3>{$_('section.control.frontlight')}</h3>
|
||||||
<Button color="secondary" id="turnOffFrontlightBtn" on:click={turnOffFrontlight}
|
<Row class="d-flex justify-content-between justify-content-md-end">
|
||||||
>{$_('section.control.turnOff')}</Button
|
<Col md="auto" class="">
|
||||||
>
|
<Button color="secondary" id="turnOffFrontlightBtn" on:click={turnOffFrontlight}
|
||||||
<Button color="primary" on:click={turnOnFrontlight}>{$_('section.control.turnOn')}</Button>
|
>{$_('section.control.turnOff')}</Button
|
||||||
<Button color="success" id="flashFrontlight" on:click={flashFrontlight}
|
>
|
||||||
>{$_('section.control.flashFrontlight')}</Button
|
</Col><Col md="auto" class="">
|
||||||
>
|
<Button color="primary" on:click={turnOnFrontlight}
|
||||||
|
>{$_('section.control.turnOn')}</Button
|
||||||
|
>
|
||||||
|
</Col><Col md="auto" class="">
|
||||||
|
<Button color="success" id="flashFrontlight" on:click={flashFrontlight}
|
||||||
|
>{$_('section.control.flashFrontlight')}</Button
|
||||||
|
>
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
<hr />
|
<hr />
|
||||||
{/if}
|
{/if}
|
||||||
<h3>{$_('section.control.systemInfo')}</h3>
|
<h3>{$_('section.control.systemInfo')}</h3>
|
||||||
<ul class="small system_info">
|
<ul class="small system_info">
|
||||||
<li>{$_('section.control.version')}: {$settings.gitRev}</li>
|
|
||||||
<li>
|
<li>
|
||||||
{$_('section.control.buildTime')}: {new Date(
|
{$_('section.control.buildTime')}: {new Date(
|
||||||
$settings.lastBuildTime * 1000
|
$settings.lastBuildTime * 1000
|
||||||
).toLocaleString()}
|
).toLocaleString()}
|
||||||
</li>
|
</li>
|
||||||
<li>IP: {$settings.ip}</li>
|
<li>IP: {$settings.ip}</li>
|
||||||
|
<li>HW revision: {$settings.hwRev}</li>
|
||||||
|
<li>{$_('section.control.fwCommit')}: {$settings.gitRev}</li>
|
||||||
|
<li>WebUI commit: {$settings.fsRev}</li>
|
||||||
<li>{$_('section.control.hostname')}: {$settings.hostname}</li>
|
<li>{$_('section.control.hostname')}: {$settings.hostname}</li>
|
||||||
</ul>
|
</ul>
|
||||||
<Button color="danger" id="restartBtn" on:click={restartClock}>{$_('button.restart')}</Button>
|
<Row>
|
||||||
<Button color="warning" id="forceFullRefresh" on:click={forceFullRefresh}
|
<Col class="d-flex justify-content-end">
|
||||||
>{$_('button.forceFullRefresh')}</Button
|
<Button color="danger" id="restartBtn" on:click={restartClock}
|
||||||
>
|
>{$_('button.restart')}</Button
|
||||||
|
>
|
||||||
|
<div class="mx-2"></div>
|
||||||
|
|
||||||
|
<Button color="warning" id="forceFullRefresh" on:click={forceFullRefresh}
|
||||||
|
>{$_('button.forceFullRefresh')}</Button
|
||||||
|
>
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
{#if $settings.otaEnabled}
|
||||||
|
<hr />
|
||||||
|
<h3>{$_('section.control.firmwareUpdate')}</h3>
|
||||||
|
<FirmwareUpdater bind:settings />
|
||||||
|
{/if}
|
||||||
</CardBody>
|
</CardBody>
|
||||||
</Card>
|
</Card>
|
||||||
</Col>
|
</Col>
|
||||||
|
155
src/routes/FirmwareUpdater.svelte
Normal file
155
src/routes/FirmwareUpdater.svelte
Normal file
@ -0,0 +1,155 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import { PUBLIC_BASE_URL } from '$lib/config';
|
||||||
|
import { _ } from 'svelte-i18n';
|
||||||
|
import { writable } from 'svelte/store';
|
||||||
|
import { Progress, Alert, Button } from 'sveltestrap';
|
||||||
|
|
||||||
|
export let settings = { hwRev: '' };
|
||||||
|
const countdown = writable(10);
|
||||||
|
let firmwareUploadFile: File | null = null;
|
||||||
|
let firmwareWebUiFile: File | null = null;
|
||||||
|
|
||||||
|
let firmwareUploadProgress = 0;
|
||||||
|
let firmwareUploadSuccess = false;
|
||||||
|
let firmwareUploadError = false;
|
||||||
|
|
||||||
|
const handleFileChange = (event: Event, setFile: (file: File) => void) => {
|
||||||
|
const target = event.target as HTMLInputElement;
|
||||||
|
if (target.files && target.files.length > 0) {
|
||||||
|
setFile(target.files[0]);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
function startCountdownToReload(duration: number) {
|
||||||
|
let timeRemaining = duration;
|
||||||
|
|
||||||
|
const interval = setInterval(() => {
|
||||||
|
timeRemaining -= 1;
|
||||||
|
countdown.set(timeRemaining);
|
||||||
|
|
||||||
|
if (timeRemaining <= 0) {
|
||||||
|
clearInterval(interval);
|
||||||
|
location.reload();
|
||||||
|
}
|
||||||
|
}, 1000); // Update every second
|
||||||
|
}
|
||||||
|
|
||||||
|
const uploadFile = async (file: File | null, endpoint: string) => {
|
||||||
|
if (!file) return;
|
||||||
|
|
||||||
|
const formData = new FormData();
|
||||||
|
formData.append('file', file);
|
||||||
|
firmwareUploadSuccess = false;
|
||||||
|
firmwareUploadError = false;
|
||||||
|
try {
|
||||||
|
const xhr = new XMLHttpRequest();
|
||||||
|
xhr.open('POST', endpoint);
|
||||||
|
|
||||||
|
xhr.upload.onprogress = (event: ProgressEvent) => {
|
||||||
|
if (event.lengthComputable) {
|
||||||
|
firmwareUploadProgress = Math.round((event.loaded * 100) / event.total);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
xhr.onload = () => {
|
||||||
|
if (xhr.status === 200 && xhr.responseText != 'FAIL') {
|
||||||
|
firmwareUploadSuccess = true;
|
||||||
|
startCountdownToReload(10);
|
||||||
|
} else {
|
||||||
|
firmwareUploadError = true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
xhr.onerror = () => {
|
||||||
|
firmwareUploadError = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
xhr.send(formData);
|
||||||
|
} catch (error) {
|
||||||
|
firmwareUploadError = true;
|
||||||
|
console.error(error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const uploadFirmwareFile = () => {
|
||||||
|
uploadFile(firmwareUploadFile, `${PUBLIC_BASE_URL}/upload/firmware`);
|
||||||
|
};
|
||||||
|
|
||||||
|
const uploadWebUiFile = () => {
|
||||||
|
uploadFile(firmwareWebUiFile, `${PUBLIC_BASE_URL}/upload/webui`);
|
||||||
|
};
|
||||||
|
|
||||||
|
const getFirmwareBinaryName = () => {
|
||||||
|
let binaryFilename = '';
|
||||||
|
switch ($settings.hwRev) {
|
||||||
|
case 'REV_B_EPD_2_13':
|
||||||
|
binaryFilename = 'btclock_rev_b_213epd_firmware.bin';
|
||||||
|
break;
|
||||||
|
case 'REV_A_EPD_2_13':
|
||||||
|
binaryFilename = 'lolin_s3_mini_213epd_firmware.bin';
|
||||||
|
break;
|
||||||
|
case 'REV_A_EPD_2_9':
|
||||||
|
binaryFilename = 'lolin_s3_mini_29epd_firmware.bin';
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
binaryFilename = 'Unsupported hardware, unable to determine firmware binary filename';
|
||||||
|
}
|
||||||
|
|
||||||
|
return binaryFilename;
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<section class="row row-cols-lg-auto align-items-end">
|
||||||
|
<div class="col-12">
|
||||||
|
<label for="firmwareFile" class="form-label">Firmware file ({getFirmwareBinaryName()})</label>
|
||||||
|
<input
|
||||||
|
type="file"
|
||||||
|
id="firmwareFile"
|
||||||
|
on:change={(e) => handleFileChange(e, (file) => (firmwareUploadFile = file))}
|
||||||
|
name="update"
|
||||||
|
class="form-control"
|
||||||
|
accept=".bin"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="flex-fill">
|
||||||
|
<Button block on:click={uploadFirmwareFile} color="primary" disabled={!firmwareUploadFile}
|
||||||
|
>Update firmware</Button
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
<div class="col mt-2">
|
||||||
|
<label for="webuiFile" class="form-label">WebUI file (littlefs.bin)</label>
|
||||||
|
<input
|
||||||
|
type="file"
|
||||||
|
id="webuiFile"
|
||||||
|
name="update"
|
||||||
|
class="form-control"
|
||||||
|
placeholder="littlefs.bin"
|
||||||
|
on:change={(e) => handleFileChange(e, (file) => (firmwareWebUiFile = file))}
|
||||||
|
accept=".bin"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="flex-fill">
|
||||||
|
<Button block on:click={uploadWebUiFile} color="secondary" disabled={!firmwareWebUiFile}
|
||||||
|
>Update WebUI</Button
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
{#if firmwareUploadProgress > 0}
|
||||||
|
<Progress striped value={firmwareUploadProgress} class="progress" id="firmwareUploadProgress"
|
||||||
|
>{$_('section.firmwareUpdater.uploading')}... {firmwareUploadProgress}%</Progress
|
||||||
|
>
|
||||||
|
{/if}
|
||||||
|
{#if firmwareUploadSuccess}
|
||||||
|
<Alert color="success" class="firmwareUploadStatusAlert"
|
||||||
|
>{$_('section.firmwareUpdater.fileUploadSuccess', { values: { countdown: $countdown } })}
|
||||||
|
</Alert>
|
||||||
|
{/if}
|
||||||
|
|
||||||
|
{#if firmwareUploadError}
|
||||||
|
<Alert color="danger" class="firmwareUploadStatusAlert"
|
||||||
|
>{$_('section.firmwareUpdater.fileUploadFailed')}</Alert
|
||||||
|
>
|
||||||
|
{/if}
|
||||||
|
<small
|
||||||
|
>⚠️ <strong>{$_('warning')}</strong>: {$_('section.firmwareUpdater.firmwareUpdateText')}</small
|
||||||
|
>
|
@ -20,6 +20,7 @@
|
|||||||
} from 'sveltestrap';
|
} from 'sveltestrap';
|
||||||
|
|
||||||
export let settings;
|
export let settings;
|
||||||
|
export let uiSettings;
|
||||||
|
|
||||||
const wifiTxPowerMap = new Map<string, number>([
|
const wifiTxPowerMap = new Map<string, number>([
|
||||||
['Default', 80],
|
['Default', 80],
|
||||||
@ -89,7 +90,7 @@
|
|||||||
<CardBody>
|
<CardBody>
|
||||||
<Form on:submit={onSave}>
|
<Form on:submit={onSave}>
|
||||||
<Row>
|
<Row>
|
||||||
<Label md={6} for="fgColor" size="sm"
|
<Label md={6} for="fgColor" size={$uiSettings.inputSize}
|
||||||
>{$_('section.settings.textColor', { default: 'Text color' })}</Label
|
>{$_('section.settings.textColor', { default: 'Text color' })}</Label
|
||||||
>
|
>
|
||||||
<Col md="6">
|
<Col md="6">
|
||||||
@ -98,8 +99,8 @@
|
|||||||
bind:value={$settings.fgColor}
|
bind:value={$settings.fgColor}
|
||||||
name="select"
|
name="select"
|
||||||
id="fgColor"
|
id="fgColor"
|
||||||
bsSize="sm"
|
bsSize={$uiSettings.inputSize}
|
||||||
class="form-select-sm"
|
class={$uiSettings.selectClass}
|
||||||
>
|
>
|
||||||
<option value="0">{$_('colors.black')}</option>
|
<option value="0">{$_('colors.black')}</option>
|
||||||
<option value="65535">{$_('colors.white')}</option>
|
<option value="65535">{$_('colors.white')}</option>
|
||||||
@ -107,15 +108,17 @@
|
|||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
<Row>
|
<Row>
|
||||||
<Label md={6} for="bgColor" size="sm">{$_('section.settings.backgroundColor')}</Label>
|
<Label md={6} for="bgColor" size={$uiSettings.inputSize}
|
||||||
|
>{$_('section.settings.backgroundColor')}</Label
|
||||||
|
>
|
||||||
<Col md="6">
|
<Col md="6">
|
||||||
<Input
|
<Input
|
||||||
type="select"
|
type="select"
|
||||||
bind:value={$settings.bgColor}
|
bind:value={$settings.bgColor}
|
||||||
name="select"
|
name="select"
|
||||||
id="bgColor"
|
id="bgColor"
|
||||||
bsSize="sm"
|
bsSize={$uiSettings.inputSize}
|
||||||
class="form-select-sm"
|
class={$uiSettings.selectClass}
|
||||||
>
|
>
|
||||||
<option value="0">{$_('colors.black')}</option>
|
<option value="0">{$_('colors.black')}</option>
|
||||||
<option value="65535">{$_('colors.white')}</option>
|
<option value="65535">{$_('colors.white')}</option>
|
||||||
@ -123,9 +126,11 @@
|
|||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
<Row>
|
<Row>
|
||||||
<Label md={6} for="timePerScreen" size="sm">{$_('section.settings.timePerScreen')}</Label>
|
<Label md={6} for="timePerScreen" size={$uiSettings.inputSize}
|
||||||
|
>{$_('section.settings.timePerScreen')}</Label
|
||||||
|
>
|
||||||
<Col md="6">
|
<Col md="6">
|
||||||
<InputGroup size="sm">
|
<InputGroup size={$uiSettings.inputSize}>
|
||||||
<Input
|
<Input
|
||||||
type="number"
|
type="number"
|
||||||
id="timePerScreen"
|
id="timePerScreen"
|
||||||
@ -138,11 +143,11 @@
|
|||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
<Row>
|
<Row>
|
||||||
<Label md={6} for="fullRefreshMin" size="sm"
|
<Label md={6} for="fullRefreshMin" size={$uiSettings.inputSize}
|
||||||
>{$_('section.settings.fullRefreshEvery')}</Label
|
>{$_('section.settings.fullRefreshEvery')}</Label
|
||||||
>
|
>
|
||||||
<Col md="6">
|
<Col md="6">
|
||||||
<InputGroup size="sm">
|
<InputGroup size={$uiSettings.inputSize}>
|
||||||
<Input
|
<Input
|
||||||
type="number"
|
type="number"
|
||||||
id="fullRefreshMin"
|
id="fullRefreshMin"
|
||||||
@ -155,11 +160,11 @@
|
|||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
<Row>
|
<Row>
|
||||||
<Label md={6} for="minSecPriceUpd" size="sm"
|
<Label md={6} for="minSecPriceUpd" size={$uiSettings.inputSize}
|
||||||
>{$_('section.settings.timeBetweenPriceUpdates')}</Label
|
>{$_('section.settings.timeBetweenPriceUpdates')}</Label
|
||||||
>
|
>
|
||||||
<Col md="6">
|
<Col md="6">
|
||||||
<InputGroup size="sm">
|
<InputGroup size={$uiSettings.inputSize}>
|
||||||
<Input
|
<Input
|
||||||
type="number"
|
type="number"
|
||||||
id="minSecPriceUpd"
|
id="minSecPriceUpd"
|
||||||
@ -173,9 +178,11 @@
|
|||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
<Row>
|
<Row>
|
||||||
<Label md={6} for="tzOffset" size="sm">{$_('section.settings.timezoneOffset')}</Label>
|
<Label md={6} for="tzOffset" size={$uiSettings.inputSize}
|
||||||
|
>{$_('section.settings.timezoneOffset')}</Label
|
||||||
|
>
|
||||||
<Col md="6">
|
<Col md="6">
|
||||||
<InputGroup size="sm">
|
<InputGroup size={$uiSettings.inputSize}>
|
||||||
<Input
|
<Input
|
||||||
type="number"
|
type="number"
|
||||||
step="1"
|
step="1"
|
||||||
@ -189,7 +196,9 @@
|
|||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
<Row>
|
<Row>
|
||||||
<Label md={6} for="ledBrightness" size="sm">{$_('section.settings.ledBrightness')}</Label>
|
<Label md={6} for="ledBrightness" size={$uiSettings.inputSize}
|
||||||
|
>{$_('section.settings.ledBrightness')}</Label
|
||||||
|
>
|
||||||
<Col md="6">
|
<Col md="6">
|
||||||
<Input
|
<Input
|
||||||
type="range"
|
type="range"
|
||||||
@ -204,7 +213,7 @@
|
|||||||
</Row>
|
</Row>
|
||||||
{#if $settings.hasFrontlight}
|
{#if $settings.hasFrontlight}
|
||||||
<Row>
|
<Row>
|
||||||
<Label md={6} for="flMaxBrightness" size="sm"
|
<Label md={6} for="flMaxBrightness" size={$uiSettings.inputSize}
|
||||||
>{$_('section.settings.flMaxBrightness')}</Label
|
>{$_('section.settings.flMaxBrightness')}</Label
|
||||||
>
|
>
|
||||||
<Col md="6">
|
<Col md="6">
|
||||||
@ -221,7 +230,7 @@
|
|||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
<Row>
|
<Row>
|
||||||
<Label md={6} for="flEffectDelay" size="sm"
|
<Label md={6} for="flEffectDelay" size={$uiSettings.inputSize}
|
||||||
>{$_('section.settings.flEffectDelay')}</Label
|
>{$_('section.settings.flEffectDelay')}</Label
|
||||||
>
|
>
|
||||||
<Col md="6">
|
<Col md="6">
|
||||||
@ -238,7 +247,7 @@
|
|||||||
</Row>
|
</Row>
|
||||||
{/if}
|
{/if}
|
||||||
<Row>
|
<Row>
|
||||||
<Label md={6} for="hostnamePrefix" size="sm"
|
<Label md={6} for="hostnamePrefix" size={$uiSettings.inputSize}
|
||||||
>{$_('section.settings.hostnamePrefix')}</Label
|
>{$_('section.settings.hostnamePrefix')}</Label
|
||||||
>
|
>
|
||||||
<Col md="6">
|
<Col md="6">
|
||||||
@ -247,12 +256,12 @@
|
|||||||
bind:value={$settings.hostnamePrefix}
|
bind:value={$settings.hostnamePrefix}
|
||||||
name="hostnamePrefix"
|
name="hostnamePrefix"
|
||||||
id="hostnamePrefix"
|
id="hostnamePrefix"
|
||||||
bsSize="sm"
|
bsSize={$uiSettings.inputSize}
|
||||||
></Input>
|
></Input>
|
||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
<Row>
|
<Row>
|
||||||
<Label md={6} for="wifiTxPower" size="sm"
|
<Label md={6} for="wifiTxPower" size={$uiSettings.inputSize}
|
||||||
>{$_('section.settings.wifiTxPower', { default: 'WiFi Tx Power' })}</Label
|
>{$_('section.settings.wifiTxPower', { default: 'WiFi Tx Power' })}</Label
|
||||||
>
|
>
|
||||||
<Col md="6">
|
<Col md="6">
|
||||||
@ -261,8 +270,8 @@
|
|||||||
bind:value={$settings.txPower}
|
bind:value={$settings.txPower}
|
||||||
name="select"
|
name="select"
|
||||||
id="fgColor"
|
id="fgColor"
|
||||||
bsSize="sm"
|
bsSize={$uiSettings.inputSize}
|
||||||
class="form-select-sm"
|
class={$uiSettings.selectClass}
|
||||||
>
|
>
|
||||||
{#each wifiTxPowerMap as [key, value]}
|
{#each wifiTxPowerMap as [key, value]}
|
||||||
<option {value}>{key}</option>
|
<option {value}>{key}</option>
|
||||||
@ -277,7 +286,7 @@
|
|||||||
id="ledTestOnPower"
|
id="ledTestOnPower"
|
||||||
bind:checked={$settings.ledTestOnPower}
|
bind:checked={$settings.ledTestOnPower}
|
||||||
type="switch"
|
type="switch"
|
||||||
bsSize="sm"
|
bsSize={$uiSettings.inputSize}
|
||||||
label={$_('section.settings.ledPowerOnTest')}
|
label={$_('section.settings.ledPowerOnTest')}
|
||||||
/>
|
/>
|
||||||
</Col>
|
</Col>
|
||||||
@ -286,7 +295,7 @@
|
|||||||
id="ledFlashOnUpd"
|
id="ledFlashOnUpd"
|
||||||
bind:checked={$settings.ledFlashOnUpd}
|
bind:checked={$settings.ledFlashOnUpd}
|
||||||
type="switch"
|
type="switch"
|
||||||
bsSize="sm"
|
bsSize={$uiSettings.inputSize}
|
||||||
label={$_('section.settings.ledFlashOnBlock')}
|
label={$_('section.settings.ledFlashOnBlock')}
|
||||||
/>
|
/>
|
||||||
</Col>
|
</Col>
|
||||||
@ -295,7 +304,7 @@
|
|||||||
id="stealFocus"
|
id="stealFocus"
|
||||||
bind:checked={$settings.stealFocus}
|
bind:checked={$settings.stealFocus}
|
||||||
type="switch"
|
type="switch"
|
||||||
bsSize="sm"
|
bsSize={$uiSettings.inputSize}
|
||||||
label={$_('section.settings.StealFocusOnNewBlock')}
|
label={$_('section.settings.StealFocusOnNewBlock')}
|
||||||
/>
|
/>
|
||||||
</Col>
|
</Col>
|
||||||
@ -304,7 +313,7 @@
|
|||||||
id="mcapBigChar"
|
id="mcapBigChar"
|
||||||
bind:checked={$settings.mcapBigChar}
|
bind:checked={$settings.mcapBigChar}
|
||||||
type="switch"
|
type="switch"
|
||||||
bsSize="sm"
|
bsSize={$uiSettings.inputSize}
|
||||||
label={$_('section.settings.useBigCharsMcap')}
|
label={$_('section.settings.useBigCharsMcap')}
|
||||||
/>
|
/>
|
||||||
</Col>
|
</Col>
|
||||||
@ -313,7 +322,7 @@
|
|||||||
id="otaEnabled"
|
id="otaEnabled"
|
||||||
bind:checked={$settings.otaEnabled}
|
bind:checked={$settings.otaEnabled}
|
||||||
type="switch"
|
type="switch"
|
||||||
bsSize="sm"
|
bsSize={$uiSettings.inputSize}
|
||||||
label="{$_('section.settings.otaUpdates')} ({$_('restartRequired')})"
|
label="{$_('section.settings.otaUpdates')} ({$_('restartRequired')})"
|
||||||
/>
|
/>
|
||||||
</Col>
|
</Col>
|
||||||
@ -322,7 +331,7 @@
|
|||||||
id="mdnsEnabled"
|
id="mdnsEnabled"
|
||||||
bind:checked={$settings.mdnsEnabled}
|
bind:checked={$settings.mdnsEnabled}
|
||||||
type="switch"
|
type="switch"
|
||||||
bsSize="sm"
|
bsSize={$uiSettings.inputSize}
|
||||||
label="{$_('section.settings.enableMdns')} ({$_('restartRequired')})"
|
label="{$_('section.settings.enableMdns')} ({$_('restartRequired')})"
|
||||||
/>
|
/>
|
||||||
</Col>
|
</Col>
|
||||||
@ -331,7 +340,7 @@
|
|||||||
id="fetchEurPrice"
|
id="fetchEurPrice"
|
||||||
bind:checked={$settings.fetchEurPrice}
|
bind:checked={$settings.fetchEurPrice}
|
||||||
type="switch"
|
type="switch"
|
||||||
bsSize="sm"
|
bsSize={$uiSettings.inputSize}
|
||||||
label="{$_('section.settings.fetchEuroPrice')} ({$_('restartRequired')})"
|
label="{$_('section.settings.fetchEuroPrice')} ({$_('restartRequired')})"
|
||||||
/>
|
/>
|
||||||
</Col>
|
</Col>
|
||||||
@ -340,7 +349,7 @@
|
|||||||
id="useBlkCountdown"
|
id="useBlkCountdown"
|
||||||
bind:checked={$settings.useBlkCountdown}
|
bind:checked={$settings.useBlkCountdown}
|
||||||
type="switch"
|
type="switch"
|
||||||
bsSize="sm"
|
bsSize={$uiSettings.inputSize}
|
||||||
label={$_('section.settings.useBlkCountdown')}
|
label={$_('section.settings.useBlkCountdown')}
|
||||||
/>
|
/>
|
||||||
</Col>
|
</Col>
|
||||||
@ -349,7 +358,7 @@
|
|||||||
id="useSatsSymbol"
|
id="useSatsSymbol"
|
||||||
bind:checked={$settings.useSatsSymbol}
|
bind:checked={$settings.useSatsSymbol}
|
||||||
type="switch"
|
type="switch"
|
||||||
bsSize="sm"
|
bsSize={$uiSettings.inputSize}
|
||||||
label={$_('section.settings.useSatsSymbol')}
|
label={$_('section.settings.useSatsSymbol')}
|
||||||
/>
|
/>
|
||||||
</Col>
|
</Col>
|
||||||
@ -358,7 +367,7 @@
|
|||||||
id="suffixPrice"
|
id="suffixPrice"
|
||||||
bind:checked={$settings.suffixPrice}
|
bind:checked={$settings.suffixPrice}
|
||||||
type="switch"
|
type="switch"
|
||||||
bsSize="sm"
|
bsSize={$uiSettings.inputSize}
|
||||||
label={$_('section.settings.suffixPrice')}
|
label={$_('section.settings.suffixPrice')}
|
||||||
/>
|
/>
|
||||||
</Col>
|
</Col>
|
||||||
@ -367,7 +376,7 @@
|
|||||||
id="disableLeds"
|
id="disableLeds"
|
||||||
bind:checked={$settings.disableLeds}
|
bind:checked={$settings.disableLeds}
|
||||||
type="switch"
|
type="switch"
|
||||||
bsSize="sm"
|
bsSize={$uiSettings.inputSize}
|
||||||
label={$_('section.settings.disableLeds')}
|
label={$_('section.settings.disableLeds')}
|
||||||
/>
|
/>
|
||||||
</Col>
|
</Col>
|
||||||
@ -376,7 +385,7 @@
|
|||||||
id="ownDataSource"
|
id="ownDataSource"
|
||||||
bind:checked={$settings.ownDataSource}
|
bind:checked={$settings.ownDataSource}
|
||||||
type="switch"
|
type="switch"
|
||||||
bsSize="sm"
|
bsSize={$uiSettings.inputSize}
|
||||||
label="{$_('section.settings.ownDataSource')} ({$_('restartRequired')})"
|
label="{$_('section.settings.ownDataSource')} ({$_('restartRequired')})"
|
||||||
/>
|
/>
|
||||||
</Col>
|
</Col>
|
||||||
@ -386,7 +395,7 @@
|
|||||||
id="flAlwaysOn"
|
id="flAlwaysOn"
|
||||||
bind:checked={$settings.flAlwaysOn}
|
bind:checked={$settings.flAlwaysOn}
|
||||||
type="switch"
|
type="switch"
|
||||||
bsSize="sm"
|
bsSize={$uiSettings.inputSize}
|
||||||
label={$_('section.settings.flAlwaysOn')}
|
label={$_('section.settings.flAlwaysOn')}
|
||||||
/>
|
/>
|
||||||
</Col>
|
</Col>
|
||||||
@ -395,7 +404,7 @@
|
|||||||
id="flFlashOnUpd"
|
id="flFlashOnUpd"
|
||||||
bind:checked={$settings.flFlashOnUpd}
|
bind:checked={$settings.flFlashOnUpd}
|
||||||
type="switch"
|
type="switch"
|
||||||
bsSize="sm"
|
bsSize={$uiSettings.inputSize}
|
||||||
label={$_('section.settings.flFlashOnUpd')}
|
label={$_('section.settings.flFlashOnUpd')}
|
||||||
/>
|
/>
|
||||||
</Col>
|
</Col>
|
||||||
@ -411,15 +420,20 @@
|
|||||||
id="screens_{s.id}"
|
id="screens_{s.id}"
|
||||||
bind:checked={s.enabled}
|
bind:checked={s.enabled}
|
||||||
type="switch"
|
type="switch"
|
||||||
bsSize="sm"
|
bsSize={$uiSettings.inputSize}
|
||||||
label={s.name}
|
label={s.name}
|
||||||
/>
|
/>
|
||||||
</Col>
|
</Col>
|
||||||
{/each}
|
{/each}
|
||||||
{/if}
|
{/if}
|
||||||
</Row>
|
</Row>
|
||||||
<Button on:click={handleReset} color="secondary">{$_('button.reset')}</Button>
|
<Row>
|
||||||
<Button color="primary">{$_('button.save')}</Button>
|
<Col class="d-flex justify-content-end">
|
||||||
|
<Button on:click={handleReset} color="secondary">{$_('button.reset')}</Button>
|
||||||
|
<div class="mx-2"></div>
|
||||||
|
<Button color="primary">{$_('button.save')}</Button>
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
</Form>
|
</Form>
|
||||||
</CardBody>
|
</CardBody>
|
||||||
</Card>
|
</Card>
|
||||||
|
Loading…
Reference in New Issue
Block a user