aboutsummaryrefslogtreecommitdiff
path: root/frontend/src/routes/+page.svelte
diff options
context:
space:
mode:
authorzwlucas <lucas.fariamo08@gmail.com>2026-05-29 20:53:13 +0000
committerzwlucas <lucas.fariamo08@gmail.com>2026-05-29 20:53:13 +0000
commit17b159c563278c3b3b8b3884be37f8d5025ce0c7 (patch)
tree2b0a85780aac498cc22c9da6dfc5901cb3f4794c /frontend/src/routes/+page.svelte
parent9218d22954d61296a32c49373ab0f17f0be59cfe (diff)
downloadyaum-17b159c563278c3b3b8b3884be37f8d5025ce0c7.tar.gz
yaum-17b159c563278c3b3b8b3884be37f8d5025ce0c7.zip
feat: implement kiosk mode with wake lock and UI adjustments
Signed-off-by: zwlucas <lucas.fariamo08@gmail.com>
Diffstat (limited to 'frontend/src/routes/+page.svelte')
-rw-r--r--frontend/src/routes/+page.svelte82
1 files changed, 78 insertions, 4 deletions
diff --git a/frontend/src/routes/+page.svelte b/frontend/src/routes/+page.svelte
index 172e6b8..6a57fd4 100644
--- a/frontend/src/routes/+page.svelte
+++ b/frontend/src/routes/+page.svelte
@@ -1,5 +1,5 @@
<script lang="ts">
- import { onMount } from 'svelte';
+ import { onMount, tick } from 'svelte';
import { deleteService } from '$lib/api';
import ServiceCard from '$lib/components/ServiceCard.svelte';
import AddServiceModal from '$lib/components/AddServiceModal.svelte';
@@ -18,6 +18,12 @@
let error = $state('');
let showModal = $state(false);
+ let isKiosk = $state(false);
+ let kioskFloating = $state(false);
+ let kioskTimer: ReturnType<typeof setTimeout> | undefined;
+ let wakeLock: WakeLockSentinel | null = $state(null);
+ let pulseId = $state(0);
+
$effect(() => {
if (!initialized && data) {
services = [...data.services];
@@ -78,20 +84,60 @@
}
}
+ function toggleKiosk() {
+ isKiosk = !isKiosk;
+ requestAnimationFrame(() => {
+ if (isKiosk) {
+ document.documentElement.classList.add('kiosk-mode');
+ requestWakeLock();
+ } else {
+ document.documentElement.classList.remove('kiosk-mode');
+ releaseWakeLock();
+ kioskFloating = false;
+ }
+ });
+ }
+
+ async function requestWakeLock() {
+ try {
+ if ('wakeLock' in navigator) {
+ wakeLock = await navigator.wakeLock.request('screen');
+ wakeLock.addEventListener('release', () => { wakeLock = null; });
+ }
+ } catch { /* wake lock not available */ }
+ }
+
+ function releaseWakeLock() {
+ if (wakeLock) {
+ wakeLock.release();
+ wakeLock = null;
+ }
+ }
+
+ function handleKioskMouseMove() {
+ if (!isKiosk) return;
+ kioskFloating = true;
+ clearTimeout(kioskTimer);
+ kioskTimer = setTimeout(() => { kioskFloating = false; }, 3000);
+ }
+
onMount(() => {
const unsub = subscribeHeartbeats((hb) => {
let wasUp: boolean | undefined;
+ let changed = false;
services = services.map((s) => {
if (s.id !== hb.service_id) return s;
if (s.last_heartbeat) {
wasUp = s.last_heartbeat.is_up;
}
+ changed = true;
return {
...s,
last_heartbeat: hb,
heartbeats: [...s.heartbeats, hb].slice(-30)
};
});
+ if (changed) pulseId += 1;
const svc = services.find((s) => s.id === hb.service_id);
if (!svc) return;
@@ -114,11 +160,38 @@
<title>YAUM — Yet Another Uptime Monitor</title>
</svelte:head>
-<div class="mb-8">
- <h1 class="text-2xl font-semibold tracking-tight text-white">Dashboard</h1>
- <p class="mt-1 text-sm text-[var(--text-muted)]">Status dos serviços monitorados</p>
+<div class="mb-8 flex items-start justify-between" class:kiosk-hidden={isKiosk}>
+ <div>
+ <h1 class="text-2xl font-semibold tracking-tight text-white">Dashboard</h1>
+ <p class="mt-1 text-sm text-[var(--text-muted)]">Status dos serviços monitorados</p>
+ </div>
+ <button
+ onclick={toggleKiosk}
+ class="kiosk-hidden shrink-0 rounded-xl border border-[var(--border-color)] bg-[var(--bg-card)] px-3.5 py-2 text-xs font-medium text-[var(--text-muted)] transition-all hover:border-[var(--green)]/30 hover:text-[var(--green)]"
+ title="Modo TV — tela cheia para monitores de parede"
+ >
+ <svg class="-ml-0.5 mr-1.5 inline h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="1.5">
+ <path stroke-linecap="round" stroke-linejoin="round" d="M9 17.25v1.007a3 3 0 01-.879 2.122L7.5 21h9l-.621-.621A3 3 0 0115 18.257V17.25m6-12V15a2.25 2.25 0 01-2.25 2.25H5.25A2.25 2.25 0 013 15V5.25A2.25 2.25 0 015.25 3h13.5A2.25 2.25 0 0121 5.25z" />
+ </svg>
+ Modo TV
+ </button>
</div>
+<!-- Floating exit button (kiosk only) -->
+{#if isKiosk}
+ <button
+ onclick={toggleKiosk}
+ class="fixed bottom-6 right-6 z-50 rounded-xl border border-white/10 bg-black/60 px-4 py-2.5 text-xs font-medium text-white/70 backdrop-blur-sm transition-all duration-300 hover:bg-black/80 hover:text-white"
+ class:opacity-0={!kioskFloating}
+ class:opacity-100={kioskFloating}
+ class:pointer-events-none={!kioskFloating}
+ >
+ Sair do Modo TV
+ </button>
+{/if}
+
+<!-- eslint-disable-next-line svelte/no-reactive-reassign -->
+<div onmousemove={handleKioskMouseMove} role="region" class:kiosk-active={isKiosk} class:pulse={pulseId > 0} data-pulse={pulseId}>
{#if error}
<div class="rounded-2xl border border-[var(--red)]/20 bg-[var(--red)]/5 p-8 text-center">
<svg class="mx-auto mb-3 h-8 w-8 text-[var(--red)]/60" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="1.5">
@@ -164,6 +237,7 @@
<ActivityLog entries={logEntries} />
</div>
{/if}
+</div>
<AddServiceModal
show={showModal}