📦 Moves statusbar to own component
This commit is contained in:
@@ -1,27 +0,0 @@
|
||||
<script lang="ts">
|
||||
import Battery0 from '~icons/tabler/battery';
|
||||
import Battery25 from '~icons/tabler/battery-1';
|
||||
import Battery50 from '~icons/tabler/battery-2';
|
||||
import Battery75 from '~icons/tabler/battery-3';
|
||||
import Battery100 from '~icons/tabler/battery-4';
|
||||
import BatteryCharging from '~icons/tabler/battery-charging-2';
|
||||
|
||||
export let current = 0;
|
||||
export let voltage = 0;
|
||||
</script>
|
||||
|
||||
<div class="tooltip tooltip-left z-10" data-tip="{voltage}V {Math.floor(current*10)/10} mA">
|
||||
{#if voltage == 0}
|
||||
<BatteryCharging class="{$$props.class || ''} -rotate-90 animate-pulse" />
|
||||
{:else if voltage > 8.2}
|
||||
<Battery100 class="{$$props.class || ''} -rotate-90" />
|
||||
{:else if voltage > 8}
|
||||
<Battery75 class="{$$props.class || ''} -rotate-90" />
|
||||
{:else if voltage > 7.8}
|
||||
<Battery50 class="{$$props.class || ''} -rotate-90" />
|
||||
{:else if voltage > 7.6}
|
||||
<Battery25 class="{$$props.class || ''} -rotate-90" />
|
||||
{:else}
|
||||
<Battery0 class="{$$props.class || ''} text-error -rotate-90 animate-pulse" />
|
||||
{/if}
|
||||
</div>
|
||||
@@ -1,40 +0,0 @@
|
||||
<script lang="ts">
|
||||
import WiFi from '~icons/tabler/wifi';
|
||||
import WiFi0 from '~icons/tabler/wifi-0';
|
||||
import WiFi1 from '~icons/tabler/wifi-1';
|
||||
import WiFi2 from '~icons/tabler/wifi-2';
|
||||
import WifiOff from '~icons/tabler/wifi-off';
|
||||
|
||||
export let showDBm = true;
|
||||
export let rssi_dbm = 0;
|
||||
</script>
|
||||
|
||||
<div class="indicator">
|
||||
<div class="tooltip tooltip-left" data-tip={rssi_dbm + " dBm"}>
|
||||
{#if showDBm}
|
||||
<span class="indicator-item indicator-start badge badge-accent badge-outline badge-xs">
|
||||
{rssi_dbm} dBm
|
||||
</span>
|
||||
{/if}
|
||||
{#if rssi_dbm >= -55}
|
||||
<WiFi class={$$props.class || ''} />
|
||||
{:else if rssi_dbm >= -75}
|
||||
<div class="{$$props.class || ''} relative">
|
||||
<WiFi class="absolute inset-0 h-full w-full opacity-30" />
|
||||
<WiFi2 class="absolute inset-0 h-full w-full" />
|
||||
</div>
|
||||
{:else if rssi_dbm >= -85}
|
||||
<div class="{$$props.class || ''} relative">
|
||||
<WiFi class="absolute inset-0 h-full w-full opacity-30" />
|
||||
<WiFi1 class="absolute inset-0 h-full w-full" />
|
||||
</div>
|
||||
{:else if rssi_dbm === 0}
|
||||
<WifiOff class={$$props.class || ''} />
|
||||
{:else}
|
||||
<div class="{$$props.class || ''} relative">
|
||||
<WiFi class="absolute inset-0 h-full w-full opacity-30" />
|
||||
<WiFi0 class="absolute inset-0 h-full w-full" />
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
@@ -1,106 +0,0 @@
|
||||
<script lang="ts">
|
||||
import { page } from '$app/stores';
|
||||
import { openModal, closeAllModals } from 'svelte-modals';
|
||||
import { user } from '$lib/stores/user';
|
||||
import { notifications } from '$lib/components/toasts/notifications';
|
||||
import ConfirmDialog from '$lib/components/ConfirmDialog.svelte';
|
||||
import Firmware from '~icons/tabler/refresh-alert';
|
||||
import Cancel from '~icons/tabler/x';
|
||||
import CloudDown from '~icons/tabler/cloud-download';
|
||||
import GithubUpdateDialog from '$lib/components/GithubUpdateDialog.svelte';
|
||||
import { compareVersions } from 'compare-versions';
|
||||
import { onMount } from 'svelte';
|
||||
import { api } from '$lib/api';
|
||||
import type { GithubRelease } from '$lib/models';
|
||||
|
||||
export let update = false;
|
||||
|
||||
let firmwareVersion: string;
|
||||
let firmwareDownloadLink: string;
|
||||
|
||||
async function getGithubAPI() {
|
||||
const headers = {
|
||||
accept: 'application/vnd.github+json',
|
||||
'X-GitHub-Api-Version': '2022-11-28'
|
||||
}
|
||||
const result = await api.get<GithubRelease>(`https://api.github.com/repos/${$page.data.github}/releases/latest`, {headers})
|
||||
if (result.inner.message === "404" || result.inner.message == "Not Found") {
|
||||
console.warn('Error: Could not find releases in the repository');
|
||||
return
|
||||
}
|
||||
if (result.isErr()) {
|
||||
console.error('Error:', result.inner);
|
||||
return
|
||||
}
|
||||
|
||||
const results = result.inner;
|
||||
update = false;
|
||||
firmwareVersion = '';
|
||||
|
||||
if (compareVersions(results.tag_name, $page.data.features.firmware_version) === 1) {
|
||||
// iterate over assets and find the correct one
|
||||
for (let i = 0; i < results.assets.length; i++) {
|
||||
// check if the asset is of type *.bin
|
||||
if (
|
||||
results.assets[i].name.includes('.bin') &&
|
||||
results.assets[i].name.includes($page.data.features.firmware_built_target)
|
||||
) {
|
||||
update = true;
|
||||
firmwareVersion = results.tag_name;
|
||||
firmwareDownloadLink = results.assets[i].browser_download_url;
|
||||
notifications.info('Firmware update available.', 5000);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function postGithubDownload(url: string) {
|
||||
const result = await api.post('/api/downloadUpdate', { download_url: url });
|
||||
if (result.isErr()){
|
||||
console.error('Error:', result.inner);
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
onMount(async () => {
|
||||
if ($page.data.features.download_firmware && (!$page.data.features.security || $user.admin)) {
|
||||
await getGithubAPI();
|
||||
const interval = setInterval(
|
||||
async () => {
|
||||
await getGithubAPI();
|
||||
},
|
||||
60 * 60 * 1000
|
||||
); // once per hour
|
||||
}
|
||||
});
|
||||
|
||||
function confirmGithubUpdate(url: string) {
|
||||
openModal(ConfirmDialog, {
|
||||
title: 'Confirm flashing new firmware to the device',
|
||||
message: 'Are you sure you want to overwrite the existing firmware with a new one?',
|
||||
labels: {
|
||||
cancel: { label: 'Abort', icon: Cancel },
|
||||
confirm: { label: 'Update', icon: CloudDown }
|
||||
},
|
||||
onConfirm: () => {
|
||||
postGithubDownload(url);
|
||||
openModal(GithubUpdateDialog, {
|
||||
onConfirm: () => closeAllModals()
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
{#if update}
|
||||
<button
|
||||
class="btn btn-square btn-ghost h-9 w-9"
|
||||
on:click={() => confirmGithubUpdate(firmwareDownloadLink)}
|
||||
>
|
||||
<span
|
||||
class="indicator-item indicator-top indicator-center badge badge-info badge-xs top-2 scale-75 lg:top-1"
|
||||
>{firmwareVersion}</span
|
||||
>
|
||||
<Firmware class="h-7 w-7" />
|
||||
</button>
|
||||
{/if}
|
||||
@@ -0,0 +1,32 @@
|
||||
<script lang="ts">
|
||||
import { useFeatureFlags } from '$lib/stores';
|
||||
import type { Battery } from '$lib/types/models';
|
||||
import Battery0 from '~icons/tabler/battery';
|
||||
import Battery25 from '~icons/tabler/battery-1';
|
||||
import Battery50 from '~icons/tabler/battery-2';
|
||||
import Battery75 from '~icons/tabler/battery-3';
|
||||
import Battery100 from '~icons/tabler/battery-4';
|
||||
import BatteryCharging from '~icons/tabler/battery-charging-2';
|
||||
|
||||
const features = useFeatureFlags();
|
||||
|
||||
export let battery:Battery;
|
||||
|
||||
const getBatteryIcon = () => {
|
||||
if (battery.voltage === 0) return BatteryCharging;
|
||||
if (battery.voltage > 8.2) return Battery100;
|
||||
if (battery.voltage > 8) return Battery75;
|
||||
if (battery.voltage > 7.8) return Battery50;
|
||||
if (battery.voltage > 7.6) return Battery25;
|
||||
return Battery0;
|
||||
};
|
||||
</script>
|
||||
|
||||
{#if $features.battery}
|
||||
<div class="tooltip tooltip-left z-10" data-tip="{battery.voltage}V {Math.floor(battery.current*10)/10} mA">
|
||||
<svelte:component
|
||||
this={getBatteryIcon()}
|
||||
class="h-7 w-7 -rotate-90 {battery.voltage === 0 || battery.voltage <= 7.6 ? 'animate-pulse' : ''} {battery.voltage <= 7.6 ? 'text-error' : ''}"
|
||||
/>
|
||||
</div>
|
||||
{/if}
|
||||
@@ -0,0 +1,11 @@
|
||||
<script lang="ts">
|
||||
import { isFullscreen, toggleFullscreen } from '$lib/stores';
|
||||
import MdiFullscreen from '~icons/mdi/fullscreen';
|
||||
import MdiFullscreenExit from '~icons/mdi/fullscreen-exit';
|
||||
</script>
|
||||
|
||||
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
||||
<!-- svelte-ignore a11y-no-static-element-interactions -->
|
||||
<div on:click={toggleFullscreen}>
|
||||
<svelte:component this={isFullscreen ? MdiFullscreenExit : MdiFullscreen} class="h-7 w-7" />
|
||||
</div>
|
||||
@@ -0,0 +1,34 @@
|
||||
<script lang="ts">
|
||||
import WiFi from '~icons/tabler/wifi';
|
||||
import WiFi0 from '~icons/tabler/wifi-0';
|
||||
import WiFi1 from '~icons/tabler/wifi-1';
|
||||
import WiFi2 from '~icons/tabler/wifi-2';
|
||||
import WifiOff from '~icons/tabler/wifi-off';
|
||||
|
||||
export let showDBm = false;
|
||||
export let rssi = 0;
|
||||
|
||||
const getWiFiIcon = () => {
|
||||
if (rssi === 0) return WifiOff;
|
||||
if (rssi >= -55) return WiFi;
|
||||
if (rssi >= -75) return WiFi2;
|
||||
if (rssi >= -85) return WiFi1;
|
||||
return WiFi0;
|
||||
};
|
||||
</script>
|
||||
|
||||
<div class="indicator">
|
||||
<div class="tooltip tooltip-left" data-tip={rssi + " dBm"}>
|
||||
{#if showDBm}
|
||||
<span class="indicator-item indicator-start badge badge-accent badge-outline badge-xs">
|
||||
{rssi} dBm
|
||||
</span>
|
||||
{/if}
|
||||
<div class="h-7 w-7">
|
||||
{#if rssi !== 0 && rssi < -55}
|
||||
<WiFi class="absolute inset-0 h-full w-full opacity-30" />
|
||||
{/if}
|
||||
<svelte:component this={getWiFiIcon()} class="absolute inset-0 h-full w-full" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,35 @@
|
||||
<script lang="ts">
|
||||
import { useFeatureFlags } from '$lib/stores';
|
||||
import { closeModal, openModal } from 'svelte-modals';
|
||||
import ConfirmDialog from '$lib/components/ConfirmDialog.svelte';
|
||||
import Power from '~icons/tabler/power';
|
||||
import Cancel from '~icons/tabler/x';
|
||||
import { api } from '$lib/api';
|
||||
|
||||
const features = useFeatureFlags();
|
||||
|
||||
const postSleep = async () => await api.post('/api/sleep');
|
||||
|
||||
const confirmSleep = () => {
|
||||
openModal(ConfirmDialog, {
|
||||
title: 'Confirm Power Down',
|
||||
message: 'Are you sure you want to switch off the device?',
|
||||
labels: {
|
||||
cancel: { label: 'Abort', icon: Cancel },
|
||||
confirm: { label: 'Switch Off', icon: Power }
|
||||
},
|
||||
onConfirm: () => {
|
||||
closeModal();
|
||||
postSleep();
|
||||
}
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
{#if $features.sleep}
|
||||
<div class="flex-none">
|
||||
<button class="btn btn-square btn-ghost h-9 w-10" on:click={confirmSleep}>
|
||||
<Power class="text-error h-9 w-9" />
|
||||
</button>
|
||||
</div>
|
||||
{/if}
|
||||
@@ -0,0 +1,10 @@
|
||||
<script lang="ts">
|
||||
import { mode, modes } from "$lib/stores";
|
||||
|
||||
const deactivate = async () => {
|
||||
mode.set(modes.indexOf('deactivated'));
|
||||
};
|
||||
</script>
|
||||
|
||||
|
||||
<button on:click={deactivate} class="bg-error text-white btn rounded-none">STOP</button>
|
||||
@@ -0,0 +1,10 @@
|
||||
<script lang="ts">
|
||||
import MdiWeatherSunny from '~icons/mdi/weather-sunny';
|
||||
import MdiMoonAndStars from '~icons/mdi/moon-and-stars';
|
||||
</script>
|
||||
|
||||
<label class="swap swap-rotate">
|
||||
<input type="checkbox" value="light" class="theme-controller" />
|
||||
<MdiWeatherSunny class="swap-off h-7 w-7" />
|
||||
<MdiMoonAndStars class="swap-on h-7 w-7" />
|
||||
</label>
|
||||
@@ -0,0 +1,114 @@
|
||||
<script lang="ts">
|
||||
import { page } from '$app/stores';
|
||||
import { openModal, closeAllModals } from 'svelte-modals';
|
||||
import { user } from '$lib/stores/user';
|
||||
import { notifications } from '$lib/components/toasts/notifications';
|
||||
import ConfirmDialog from '$lib/components/ConfirmDialog.svelte';
|
||||
import Firmware from '~icons/tabler/refresh-alert';
|
||||
import Cancel from '~icons/tabler/x';
|
||||
import CloudDown from '~icons/tabler/cloud-download';
|
||||
import GithubUpdateDialog from '$lib/components/GithubUpdateDialog.svelte';
|
||||
import { compareVersions } from 'compare-versions';
|
||||
import { onMount } from 'svelte';
|
||||
import { api } from '$lib/api';
|
||||
import type { GithubRelease } from '$lib/models';
|
||||
import { useFeatureFlags } from '$lib/stores/featureFlags';
|
||||
|
||||
const features = useFeatureFlags();
|
||||
|
||||
export let update = false;
|
||||
|
||||
let firmwareVersion: string;
|
||||
let firmwareDownloadLink: string;
|
||||
|
||||
async function getGithubAPI() {
|
||||
const headers = {
|
||||
accept: 'application/vnd.github+json',
|
||||
'X-GitHub-Api-Version': '2022-11-28'
|
||||
};
|
||||
const result = await api.get<GithubRelease>(
|
||||
`https://api.github.com/repos/${$page.data.github}/releases/latest`,
|
||||
{ headers }
|
||||
);
|
||||
if (result.inner.message === '404' || result.inner.message == 'Not Found') {
|
||||
console.warn('Error: Could not find releases in the repository');
|
||||
return;
|
||||
}
|
||||
if (result.isErr()) {
|
||||
console.error('Error:', result.inner);
|
||||
return;
|
||||
}
|
||||
|
||||
const results = result.inner;
|
||||
update = false;
|
||||
firmwareVersion = '';
|
||||
|
||||
if (compareVersions(results.tag_name, $features.firmware_version) === 1) {
|
||||
// iterate over assets and find the correct one
|
||||
for (let i = 0; i < results.assets.length; i++) {
|
||||
// check if the asset is of type *.bin
|
||||
if (
|
||||
results.assets[i].name.includes('.bin') &&
|
||||
results.assets[i].name.includes($features.firmware_built_target)
|
||||
) {
|
||||
update = true;
|
||||
firmwareVersion = results.tag_name;
|
||||
firmwareDownloadLink = results.assets[i].browser_download_url;
|
||||
notifications.info('Firmware update available.', 5000);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function postGithubDownload(url: string) {
|
||||
const result = await api.post('/api/downloadUpdate', { download_url: url });
|
||||
if (result.isErr()) {
|
||||
console.error('Error:', result.inner);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
onMount(async () => {
|
||||
if ($features.download_firmware && (!$features.security || $user.admin)) {
|
||||
await getGithubAPI();
|
||||
const interval = setInterval(
|
||||
async () => {
|
||||
await getGithubAPI();
|
||||
},
|
||||
60 * 60 * 1000
|
||||
); // once per hour
|
||||
}
|
||||
});
|
||||
|
||||
function confirmGithubUpdate(url: string) {
|
||||
openModal(ConfirmDialog, {
|
||||
title: 'Confirm flashing new firmware to the device',
|
||||
message: 'Are you sure you want to overwrite the existing firmware with a new one?',
|
||||
labels: {
|
||||
cancel: { label: 'Abort', icon: Cancel },
|
||||
confirm: { label: 'Update', icon: CloudDown }
|
||||
},
|
||||
onConfirm: () => {
|
||||
postGithubDownload(url);
|
||||
openModal(GithubUpdateDialog, {
|
||||
onConfirm: () => closeAllModals()
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
{#if update}
|
||||
<div class="indicator flex-none">
|
||||
<button
|
||||
class="btn btn-square btn-ghost h-9 w-9"
|
||||
on:click={() => confirmGithubUpdate(firmwareDownloadLink)}
|
||||
>
|
||||
<span
|
||||
class="indicator-item indicator-top indicator-center badge badge-info badge-xs top-2 scale-75 lg:top-1"
|
||||
>{firmwareVersion}</span
|
||||
>
|
||||
<Firmware class="h-7 w-7" />
|
||||
</button>
|
||||
</div>
|
||||
{/if}
|
||||
@@ -0,0 +1,6 @@
|
||||
<script lang="ts">
|
||||
import { selectedView, views } from "$lib/stores/application";
|
||||
import Selector from "../widget/Selector.svelte";
|
||||
</script>
|
||||
|
||||
<Selector bind:selectedOption={$selectedView} options={$views.map((v) => v.name)} />
|
||||
@@ -0,0 +1,41 @@
|
||||
<script lang="ts">
|
||||
import { page } from '$app/stores';
|
||||
import { telemetry } from '$lib/stores/telemetry';
|
||||
import Hamburger from '~icons/tabler/menu-2';
|
||||
|
||||
import RssiIndicator from '$lib/components/statusbar/RSSIIndicator.svelte';
|
||||
import BatteryIndicator from '$lib/components/statusbar/BatteryIndicator.svelte';
|
||||
import UpdateIndicator from '$lib/components/statusbar/UpdateIndicator.svelte';
|
||||
import SleepButton from './SleepButton.svelte';
|
||||
import ThemeButton from './ThemeButton.svelte';
|
||||
import FullscreenButton from './FullscreenButton.svelte';
|
||||
import StopButton from './StopButton.svelte';
|
||||
import ViewSelector from './ViewSelector.svelte';
|
||||
</script>
|
||||
|
||||
<div class="navbar bg-base-300 sticky top-0 z-10 h-12 min-h-fit drop-shadow-lg lg:h-16 gap-2 pr-0">
|
||||
<div class="flex-1">
|
||||
<label for="main-menu" class="btn btn-ghost btn-circle btn-sm drawer-button">
|
||||
<Hamburger class="h-6 w-auto" />
|
||||
</label>
|
||||
{#if $page.data.title === 'Controller'}
|
||||
<ViewSelector />
|
||||
{:else}
|
||||
<h1 class="px-2 text-xl font-bold lg:text-2xl">{$page.data.title}</h1>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<UpdateIndicator />
|
||||
|
||||
<FullscreenButton />
|
||||
|
||||
<ThemeButton/>
|
||||
|
||||
<RssiIndicator rssi={$telemetry.rssi.rssi}/>
|
||||
|
||||
<BatteryIndicator battery={$telemetry.battery} />
|
||||
|
||||
<SleepButton />
|
||||
|
||||
<StopButton />
|
||||
</div>
|
||||
@@ -6,8 +6,8 @@ let telemetry_data = {
|
||||
rssi: 0
|
||||
},
|
||||
battery: {
|
||||
voltage: 100,
|
||||
current: false
|
||||
voltage: 0,
|
||||
current: 0
|
||||
},
|
||||
download_ota: {
|
||||
status: 'none',
|
||||
|
||||
@@ -71,7 +71,7 @@ export type RSSI = {
|
||||
|
||||
export type Battery = {
|
||||
voltage: number;
|
||||
current: boolean;
|
||||
current: number;
|
||||
};
|
||||
|
||||
export type DownloadOTA = {
|
||||
|
||||
@@ -1,97 +0,0 @@
|
||||
<script lang="ts">
|
||||
import { page } from '$app/stores';
|
||||
import { telemetry } from '$lib/stores/telemetry';
|
||||
import { openModal, closeModal } from 'svelte-modals';
|
||||
import ConfirmDialog from '$lib/components/ConfirmDialog.svelte';
|
||||
import WiFiOff from '~icons/tabler/wifi-off';
|
||||
import Hamburger from '~icons/tabler/menu-2';
|
||||
import Power from '~icons/tabler/power';
|
||||
import Cancel from '~icons/tabler/x';
|
||||
import RssiIndicator from '$lib/components/RSSIIndicator.svelte';
|
||||
import BatteryIndicator from '$lib/components/BatteryIndicator.svelte';
|
||||
import UpdateIndicator from '$lib/components/UpdateIndicator.svelte';
|
||||
import MdiWeatherSunny from '~icons/mdi/weather-sunny';
|
||||
import MdiMoonAndStars from '~icons/mdi/moon-and-stars';
|
||||
import MdiFullscreen from '~icons/mdi/fullscreen';
|
||||
import MdiFullscreenExit from '~icons/mdi/fullscreen-exit';
|
||||
import { api } from '$lib/api';
|
||||
import { isFullscreen, mode, modes, toggleFullscreen } from '$lib/stores';
|
||||
import Selector from '$lib/components/widget/Selector.svelte';
|
||||
import { selectedView, views } from '$lib/stores/application';
|
||||
|
||||
const postSleep = async () => await api.post('/api/sleep');
|
||||
|
||||
function confirmSleep() {
|
||||
openModal(ConfirmDialog, {
|
||||
title: 'Confirm Power Down',
|
||||
message: 'Are you sure you want to switch off the device?',
|
||||
labels: {
|
||||
cancel: { label: 'Abort', icon: Cancel },
|
||||
confirm: { label: 'Switch Off', icon: Power }
|
||||
},
|
||||
onConfirm: () => {
|
||||
closeModal();
|
||||
postSleep();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
const deactivate = async () => {
|
||||
mode.set(modes.indexOf('deactivated'));
|
||||
};
|
||||
</script>
|
||||
|
||||
<div class="navbar bg-base-300 sticky top-0 z-10 h-12 min-h-fit drop-shadow-lg lg:h-16 gap-2 pr-0">
|
||||
<div class="flex-1">
|
||||
<label for="main-menu" class="btn btn-ghost btn-circle btn-sm drawer-button"
|
||||
><Hamburger class="h-6 w-auto" /></label
|
||||
>
|
||||
{#if $page.data.title === 'Controller'}
|
||||
<Selector bind:selectedOption={$selectedView} options={$views.map((v) => v.name)} />
|
||||
{:else}
|
||||
<h1 class="px-2 text-xl font-bold lg:text-2xl">{$page.data.title}</h1>
|
||||
{/if}
|
||||
</div>
|
||||
<div class="indicator flex-none">
|
||||
<UpdateIndicator />
|
||||
</div>
|
||||
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
||||
<!-- svelte-ignore a11y-no-static-element-interactions -->
|
||||
<div class="flex-none" on:click={toggleFullscreen}>
|
||||
<svelte:component this={isFullscreen ? MdiFullscreenExit : MdiFullscreen} class="h-7 w-7" />
|
||||
</div>
|
||||
|
||||
<div class="flex-none">
|
||||
<label class="swap swap-rotate">
|
||||
<input type="checkbox" value="light" class="theme-controller" />
|
||||
<MdiWeatherSunny class="swap-off h-7 w-7" />
|
||||
<MdiMoonAndStars class="swap-on h-7 w-7" />
|
||||
</label>
|
||||
</div>
|
||||
<div class="flex-none">
|
||||
{#if $telemetry.rssi.disconnected}
|
||||
<WiFiOff class="h-7 w-7" />
|
||||
{:else}
|
||||
<RssiIndicator showDBm={false} rssi_dbm={$telemetry.rssi.rssi} class="h-7 w-7" />
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
{#if $page.data.features.battery}
|
||||
<div class="flex-none">
|
||||
<BatteryIndicator
|
||||
voltage={$telemetry.battery.voltage}
|
||||
current={$telemetry.battery.current}
|
||||
class="h-7 w-7"
|
||||
/>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
{#if $page.data.features.sleep}
|
||||
<div class="flex-none">
|
||||
<button class="btn btn-square btn-ghost h-9 w-10" on:click={confirmSleep}>
|
||||
<Power class="text-error h-9 w-9" />
|
||||
</button>
|
||||
</div>
|
||||
{/if}
|
||||
<button on:click={deactivate} class="bg-error text-white btn rounded-none">STOP</button>
|
||||
</div>
|
||||
Reference in New Issue
Block a user