Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
71 changes: 71 additions & 0 deletions src/components/common/Tooltip.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
<script lang="ts">
import { fade } from "svelte/transition";
import { cubicOut } from "svelte/easing";
import clsx from "clsx";

export let title = "";
export let placement: "top" | "bottom" | "left" | "right" = "top";
export let delay = 0;

let visible = false;
let timeout: ReturnType<typeof setTimeout>;

function show() {
timeout = setTimeout(() => {
visible = true;
}, delay);
}

function hide() {
clearTimeout(timeout);
visible = false;
}

const placementClasses = {
top: "bottom-full left-1/2 -translate-x-1/2 mb-2",
bottom: "top-full left-1/2 -translate-x-1/2 mt-2",
left: "right-full top-1/2 -translate-y-1/2 mr-2",
right: "left-full top-1/2 -translate-y-1/2 ml-2",
};

const arrowClasses = {
top: "top-full left-1/2 -translate-x-1/2 border-l-transparent border-r-transparent border-b-transparent border-t-gray-800",
bottom:
"bottom-full left-1/2 -translate-x-1/2 border-l-transparent border-r-transparent border-t-transparent border-b-gray-800",
left: "left-full top-1/2 -translate-y-1/2 border-t-transparent border-b-transparent border-r-transparent border-l-gray-800",
right:
"right-full top-1/2 -translate-y-1/2 border-t-transparent border-b-transparent border-l-transparent border-r-gray-800",
};
</script>

<div
class="relative inline-flex"
role="presentation"
onmouseenter={show}
onmouseleave={hide}
onfocusin={show}
onfocusout={hide}
>
<slot />

{#if title && visible}
<div
role="tooltip"
in:fade={{ duration: 200, easing: cubicOut }}
out:fade={{ duration: 400, easing: cubicOut }}
class={clsx(
"pointer-events-none absolute z-50 w-max max-w-xs font-jetbrains",
"rounded-xs bg-stone-900 px-2.5 py-1.5 border border-stone-700",
"text-xs font-medium text-white shadow-md",
placementClasses[placement],
)}
>
{title}

<span
aria-hidden="true"
class={clsx("absolute h-0 w-0 border-4", arrowClasses[placement])}
></span>
</div>
{/if}
</div>
52 changes: 40 additions & 12 deletions src/components/layout/StatusBar.svelte
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
<script lang="ts">
import type { Server } from "../../lib/types.js";
import IconArrowUp from "phosphor-icons-svelte/IconArrowUpBold.svelte";
import IconArrowDown from "phosphor-icons-svelte/IconArrowDownBold.svelte";
import IconArrowsClockwise from "phosphor-icons-svelte/IconArrowsClockwiseBold.svelte";

import type { Server } from "../../lib/types.js";
import CornerBorders from "../ui/CornerBorders.svelte";
import Tooltip from "../common/Tooltip.svelte";

interface Props {
servers: Server[];
Expand All @@ -13,17 +16,23 @@

let { servers, isRunning, intervalSecs, lastChecked }: Props = $props();

let up = $derived(servers.filter((s) => s.status === "200 OK").length);
let down = $derived(
servers.filter((s) => s.status?.startsWith("error")).length,
let syncEnabledServers = $derived(
servers.filter((server) => server.sync_enabled),
);
let unknown = $derived(
servers.filter((s) => !s.status || s.status === "unknown").length,

let up = $derived(
syncEnabledServers.filter((s) => s.status === "200 OK").length,
);
let upPct = $derived(
servers.length === 0 ? 0 : Math.round((up / servers.length) * 100),

let down = $derived(
syncEnabledServers.filter((s) => s.status?.startsWith("error")).length,
);

let upPct = $derived(
syncEnabledServers.length <= 0
? 0
: Math.round((up / syncEnabledServers.length) * 100),
);
let nextSyncIn = $state(intervalSecs);

$effect(() => {
Expand Down Expand Up @@ -61,11 +70,30 @@
class="text-[11px] uppercase tracking-widest text-white/60 font-medium"
>Servers</span
>

<div class="text-3xl font-bold tabular-nums text-white leading-none">
{servers.length}
<div class="flex items-end justify-between">
<Tooltip title="Total servers">
<div
class="text-3xl font-bold tabular-nums text-white leading-none cursor-pointer"
>
{servers.length}
</div>
</Tooltip>

{#if syncEnabledServers.length > 0}
<div class="relative group">
<Tooltip title="Sync enabled servers">
<div
class="flex items-center gap-1.5 text-white/50 cursor-pointer hover:text-white/80 transition-colors"
>
<IconArrowsClockwise class="w-7 h-7" />
<span class="text-3xl font-bold tabular-nums">
{syncEnabledServers.length}
</span>
</div>
</Tooltip>
</div>
{/if}
</div>

<div class="flex items-end justify-between mt-auto">
<div>
<div class="flex items-center gap-1 text-terminal-green">
Expand Down