92 lines
2.6 KiB
Svelte
92 lines
2.6 KiB
Svelte
<script lang="ts">
|
|
import '../app.css';
|
|
import Icon from '@iconify/svelte';
|
|
import { onMount } from 'svelte';
|
|
import { writable } from 'svelte/store';
|
|
import { checkHealth } from '$lib/api';
|
|
let { children } = $props();
|
|
|
|
interface Notification {
|
|
id: number;
|
|
type: 'success' | 'error';
|
|
message: string;
|
|
}
|
|
|
|
let notifications: Notification[] = $state([]);
|
|
let notificationId = 0;
|
|
|
|
let healthStatus = writable<'healthy' | 'unhealthy'>('unhealthy');
|
|
|
|
async function updateHealthStatus() {
|
|
const status = await checkHealth();
|
|
healthStatus.set(status);
|
|
}
|
|
|
|
function showNotification(type: 'success' | 'error', message: string): void {
|
|
const id = notificationId++;
|
|
notifications = [...notifications, { id, type, message }];
|
|
setTimeout(() => {
|
|
notifications = notifications.filter((n) => n.id !== id);
|
|
}, 4000);
|
|
}
|
|
|
|
onMount(() => {
|
|
window.showNotification = showNotification;
|
|
updateHealthStatus();
|
|
setInterval(updateHealthStatus, 10000); // Check health every 10 seconds
|
|
});
|
|
</script>
|
|
|
|
<nav class="bg-gray-800 text-white shadow-md">
|
|
<div class="container mx-auto flex justify-between items-center p-4">
|
|
<a href="/" class="text-2xl font-bold hover:text-gray-400">Project Monitor</a>
|
|
<div class="flex space-x-6">
|
|
<a href="/" class="text-lg hover:text-gray-400">Home</a>
|
|
<a href="/scripts" class="text-lg hover:text-gray-400">Scripts</a>
|
|
<a href="/notifications" class="text-lg hover:text-gray-400">Notifications</a>
|
|
<a href="/settings" class="text-lg hover:text-gray-400">
|
|
<Icon icon="material-symbols:settings" width="24" height="24" />
|
|
</a>
|
|
</div>
|
|
</div>
|
|
</nav>
|
|
|
|
<div class="relative">
|
|
{@render children()}
|
|
|
|
<div class="fixed bottom-4 right-4 space-y-2">
|
|
{#each notifications as notification (notification.id)}
|
|
<div
|
|
class="p-4 rounded shadow-lg text-white"
|
|
class:bg-green-500={notification.type === 'success'}
|
|
class:bg-red-500={notification.type === 'error'}
|
|
>
|
|
{notification.message}
|
|
</div>
|
|
{/each}
|
|
</div>
|
|
</div>
|
|
|
|
<div class="fixed bottom-4 left-4 group">
|
|
{#if $healthStatus === 'healthy'}
|
|
<Icon
|
|
icon="material-symbols:check-circle-rounded"
|
|
width="24"
|
|
height="24"
|
|
class="text-green-400"
|
|
/>
|
|
<div
|
|
class="absolute bottom-full left-1/2 hidden group-hover:flex group-hover:w-max bg-green-500 text-white px-2 py-1 rounded shadow-lg"
|
|
>
|
|
Connected to backend
|
|
</div>
|
|
{:else}
|
|
<Icon icon="ix:disconnected-circle-filled" width="24" height="24" class="text-red-400" />
|
|
<div
|
|
class="absolute bottom-full left-1/2 hidden group-hover:flex group-hover:w-max bg-red-500 text-white px-2 py-1 rounded shadow-lg"
|
|
>
|
|
Not connected
|
|
</div>
|
|
{/if}
|
|
</div>
|