Files
telemt-api/web/src/routes/+layout.svelte
T
Denozordec 6b2e38d051
Publish telemt-api gateway Docker image / test (push) Successful in 23s
Publish telemt-api gateway Docker image / build-and-push (push) Successful in 2m18s
Fix navigation state handling in layout component
- Updated the `isNavigating` derived variable to use a boolean conversion instead of a strict null check, preventing the navigation indicator from hanging when `navigating` is undefined.
- Added a comment to clarify the reason for this change, enhancing code readability and maintainability.
2026-04-11 15:25:26 +07:00

74 lines
2.3 KiB
Svelte

<script lang="ts">
import './layout.css';
import { page, navigating } from '$app/state';
import { onMount } from 'svelte';
import { ModeWatcher } from 'mode-watcher';
import favicon from '$lib/assets/favicon.svg';
import AppSidebar from '$lib/components/app-sidebar.svelte';
import { fetchAggSummary } from '$lib/api/client.js';
import * as Sidebar from '$lib/components/ui/sidebar/index.js';
import * as Tooltip from '$lib/components/ui/tooltip/index.js';
import { Toaster } from '$lib/components/ui/sonner/index.js';
import SiteHeader from '$lib/components/site-header.svelte';
import { panelTitleFromPath } from '$lib/page-title.js';
let { children } = $props();
const docTitle = $derived(`${panelTitleFromPath(page.url.pathname)} · Telemt Panel`);
/** Нельзя использовать `!== null`: при `navigating === undefined` выражение истинно и полоска «зависает». */
const isNavigating = $derived(!!navigating);
let serverAliases = $state<string[]>([]);
const serverMatch = $derived.by(() => {
const m = page.url.pathname.match(/^\/servers\/([^/]+)/);
return m ? m[1] : '';
});
const serverPath = $derived(serverMatch ? `/servers/${serverMatch}` : '');
onMount(() => {
let cancelled = false;
fetchAggSummary({ top_n: 10 })
.then((env) => {
if (cancelled) return;
const set = new Set<string>();
for (const s of env.data.servers ?? []) {
if (s.alias) set.add(s.alias);
}
serverAliases = [...set].sort();
})
.catch(() => {
/* sidebar без списка — страницы сами покажут ошибку */
});
return () => {
cancelled = true;
};
});
</script>
<svelte:head>
<link rel="icon" href={favicon} />
<title>{docTitle}</title>
</svelte:head>
<ModeWatcher />
<Tooltip.Provider>
<Sidebar.Provider>
<AppSidebar {serverAliases} {serverPath} />
<Sidebar.Inset>
{#if isNavigating}
<div class="h-0.5 w-full overflow-hidden bg-transparent">
<div class="h-full w-1/3 animate-pulse rounded-full bg-primary"></div>
</div>
{/if}
<header class="flex h-14 w-full shrink-0 items-center gap-2 border-b border-border px-4">
<SiteHeader />
</header>
<div class="flex flex-1 flex-col p-4">
{@render children()}
</div>
</Sidebar.Inset>
</Sidebar.Provider>
<Toaster richColors closeButton position="top-right" />
</Tooltip.Provider>