diff --git a/src/routes/logs/+page.svelte b/src/routes/logs/+page.svelte index 7205991..0990b66 100644 --- a/src/routes/logs/+page.svelte +++ b/src/routes/logs/+page.svelte @@ -11,6 +11,7 @@ import { ScrollArea } from "$lib/components/ui/scroll-area/index.js"; import { Input } from "$lib/components/ui/input/index.js"; import { Label } from "$lib/components/ui/label/index.js"; + import { Skeleton } from "$lib/components/ui/skeleton/index.js"; import { cn } from "$lib/utils.js"; import { CalendarDate, DateFormatter, getLocalTimeZone, today, type DateValue } from "@internationalized/date"; @@ -37,7 +38,7 @@ import { page } from "$app/state"; import { goto } from "$app/navigation"; - import { LoaderCircleIcon, FileTextIcon, ArrowDownWideNarrowIcon, ArrowUpNarrowWideIcon, CalendarIcon, ExternalLinkIcon, FilterIcon, SearchIcon } from "@lucide/svelte"; + import { LoaderCircleIcon, FileTextIcon, ArrowDownWideNarrowIcon, ArrowUpNarrowWideIcon, CalendarIcon, ExternalLinkIcon, FilterIcon, SearchIcon, ChartColumnIcon } from "@lucide/svelte"; import { dateTimeFormat, type TitleContext } from "$lib/common"; @@ -52,6 +53,11 @@ day?: string; }; + type StatsResponse = { + messageCount: number; + topChatters?: Array<{ userId: string; userLogin: string; messageCount: number }>; + }; + getContext("title").set("Logs"); const lineHeight = 20; @@ -59,7 +65,7 @@ let error: string | null = $state(null); let loading = $state(false); - let isPopoverOpen = $state(false); + let datePopoverOpen = $state(false); let selectedIndex = $state(0); // Track selected item @@ -196,6 +202,11 @@ let channelId = $state(""); + // Channel Stats + let statsPopoverOpen = $state(false); + let channelStats = $state(null); + let statsError = $state(null); + // Emotes const channelEmotes = new SvelteMap(); const globalEmotes = new SvelteMap(); @@ -386,12 +397,38 @@ else return `${channelType}/${encodeURIComponent(channel)}${user ? `/${userType}/${encodeURIComponent(user)}` : ""}`; }; + const fetchChannelStats = async () => { + if (!channelName) return; + + statsError = null; + + try { + const res = await fetch(`https://logs.zonian.dev/${parseChannelUser(channelName, userName, false)}/stats`); + if (!res.ok) { + if (res.status === 404) statsError = "No stats found for this channel"; + else statsError = `Error from server: ${res.status} ${res.statusText}`; + return; + } + + channelStats = await res.json(); + } catch (err) { + statsError = err instanceof Error ? err.message : "Failed to fetch channel stats"; + } + }; + + $effect(() => { + if (statsPopoverOpen && !channelStats) { + fetchChannelStats(); + } + }); + $effect(() => { // fetch available dates if (!channelName) return; untrack(async () => { availableDates = []; chatLogs = []; + channelStats = null; loading = true; const res = await fetch(`https://logs.zonian.dev/list?${parseChannelUser(channelName, userName, true)}`); @@ -784,55 +821,116 @@ {/if} -
-
-
-
- - - - {#if foundChannels.length && foundChannels[0].target !== inputChannelName.toLowerCase()} -
- - - - {#each foundChannels as c, index (c.target)} +
+ +
+
+
+ + + + {#if foundChannels.length && foundChannels[0].target !== inputChannelName.toLowerCase()} +
+ -
(selectedIndex = index)} - onclick={() => selectResult(index)} - > - {c.target} -
- {/each} -
-
- {/if} -
+ onmouseenter={() => (selectedIndex = index)} + onclick={() => selectResult(index)} + > + {c.target} +
+ {/each} + +
+ {/if} +
-
- - -
+
+ + +
-
- - {#if loading} - - {/if} +
+ + {#if loading} + + {/if} +
+ +
+ + + + + + + + + {#if statsError} +

{statsError}

+ {:else} +
+
+

+ Total Messages + {#if userName} + by {userName} + {/if} +

+ {#if channelStats} +

{channelStats.messageCount.toLocaleString()}

+ {:else} + + {/if} +
+ + {#if !userName} +
+

Top Chatters

+
+ {#if channelStats?.topChatters} + {#each channelStats.topChatters as chatter, index (chatter.userId)} +
+
+ {index + 1}. + {chatter.userLogin} +
+ {chatter.messageCount.toLocaleString()} +
+ {/each} + {:else} + + + + + + {/if} +
+
+ {/if} +
+ {/if} +
+
+
+
+
{#if dateContent} {#if dateContent.day} - + - + {:else}
- + {dateContent.year}-{String(dateContent.month).padStart(2, "0")}{dateContent.day ? `-${String(dateContent.day).padStart(2, "0")}` : ""} @@ -1065,7 +1163,7 @@ {/if}
-{#if isPopoverOpen} +{#if datePopoverOpen || statsPopoverOpen} {/if}