forked from wrenn/wrenn
Move sidebar into layout files and fix timer cleanup across frontend
Sidebar and AdminSidebar were re-instantiated on every page navigation (17 pages total), causing unnecessary DOM teardown/rebuild and redundant localStorage reads. Now each lives in its respective +layout.svelte as a single persistent instance. Also adds onDestroy cleanup for leaked timers (settings, team, login RAF loop) and CSS containment on <main> to isolate layout recalculations.
This commit is contained in:
@ -1,7 +1,19 @@
|
||||
<script lang="ts">
|
||||
import AdminSidebar from '$lib/components/AdminSidebar.svelte';
|
||||
import Toaster from '$lib/components/Toaster.svelte';
|
||||
let { children } = $props();
|
||||
|
||||
let collapsed = $state(
|
||||
typeof window !== 'undefined'
|
||||
? localStorage.getItem('wrenn_sidebar_collapsed') === 'true'
|
||||
: false
|
||||
);
|
||||
</script>
|
||||
|
||||
<div class="flex h-screen overflow-hidden">
|
||||
<AdminSidebar bind:collapsed />
|
||||
<div class="flex flex-1 flex-col overflow-hidden">
|
||||
{@render children()}
|
||||
</div>
|
||||
</div>
|
||||
<Toaster />
|
||||
{@render children()}
|
||||
|
||||
@ -1,5 +1,4 @@
|
||||
<script lang="ts">
|
||||
import AdminSidebar from '$lib/components/AdminSidebar.svelte';
|
||||
import CreateCapsuleDialog from '$lib/components/CreateCapsuleDialog.svelte';
|
||||
import DestroyDialog from '$lib/components/DestroyDialog.svelte';
|
||||
import CopyButton from '$lib/components/CopyButton.svelte';
|
||||
@ -15,12 +14,6 @@
|
||||
const REFRESH_INTERVAL = 15;
|
||||
const SPIN_DURATION = 600;
|
||||
|
||||
let collapsed = $state(
|
||||
typeof window !== 'undefined'
|
||||
? localStorage.getItem('wrenn_sidebar_collapsed') === 'true'
|
||||
: false
|
||||
);
|
||||
|
||||
let capsules = $state<Capsule[]>([]);
|
||||
let loading = $state(true);
|
||||
let error = $state<string | null>(null);
|
||||
@ -243,11 +236,8 @@
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="flex h-screen overflow-hidden bg-[var(--color-bg-0)]">
|
||||
<AdminSidebar bind:collapsed />
|
||||
|
||||
<main class="flex min-w-0 flex-1 flex-col overflow-hidden">
|
||||
<!-- Header -->
|
||||
<main class="flex min-w-0 flex-1 flex-col overflow-hidden">
|
||||
<!-- Header -->
|
||||
<div class="shrink-0 px-8 pt-8 pb-6">
|
||||
<div class="flex items-center justify-between">
|
||||
<div>
|
||||
@ -521,8 +511,7 @@
|
||||
<span class="font-mono text-label uppercase tracking-[0.04em] text-[var(--color-text-secondary)]">All systems operational</span>
|
||||
</div>
|
||||
</footer>
|
||||
</main>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<CreateCapsuleDialog
|
||||
open={showCreateDialog}
|
||||
|
||||
@ -2,7 +2,6 @@
|
||||
import { onMount, onDestroy } from 'svelte';
|
||||
import { page } from '$app/stores';
|
||||
import { goto } from '$app/navigation';
|
||||
import AdminSidebar from '$lib/components/AdminSidebar.svelte';
|
||||
import TerminalTab from '$lib/components/TerminalTab.svelte';
|
||||
import FilesTab from '$lib/components/FilesTab.svelte';
|
||||
import MetricsPanel from '$lib/components/MetricsPanel.svelte';
|
||||
@ -19,12 +18,6 @@
|
||||
const capsuleId: string = $page.params.id ?? '';
|
||||
const API_BASE = '/api/v1/admin/capsules';
|
||||
|
||||
let collapsed = $state(
|
||||
typeof window !== 'undefined'
|
||||
? localStorage.getItem('wrenn_sidebar_collapsed') === 'true'
|
||||
: false
|
||||
);
|
||||
|
||||
let capsule = $state<Capsule | null>(null);
|
||||
let capsuleLoading = $state(true);
|
||||
let capsuleError = $state<string | null>(null);
|
||||
@ -129,10 +122,7 @@
|
||||
<title>Wrenn Admin — {capsuleId}</title>
|
||||
</svelte:head>
|
||||
|
||||
<div class="flex h-screen overflow-hidden bg-[var(--color-bg-0)]">
|
||||
<AdminSidebar bind:collapsed />
|
||||
|
||||
<main class="flex min-w-0 flex-1 flex-col overflow-hidden">
|
||||
<main class="flex min-w-0 flex-1 flex-col overflow-hidden">
|
||||
{#if capsuleLoading}
|
||||
<div class="flex flex-1 items-center justify-center">
|
||||
<div class="flex items-center gap-3 text-ui text-[var(--color-text-secondary)]">
|
||||
@ -237,8 +227,7 @@
|
||||
<span class="font-mono text-label uppercase tracking-[0.04em] text-[var(--color-text-secondary)]">All systems operational</span>
|
||||
</div>
|
||||
</footer>
|
||||
</main>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<!-- Snapshot dialog -->
|
||||
{#if showSnapshot}
|
||||
|
||||
@ -1,5 +1,4 @@
|
||||
<script lang="ts">
|
||||
import AdminSidebar from '$lib/components/AdminSidebar.svelte';
|
||||
import { onMount } from 'svelte';
|
||||
import { toast } from '$lib/toast.svelte';
|
||||
import { formatDate, timeAgo } from '$lib/utils/format';
|
||||
@ -16,12 +15,6 @@
|
||||
|
||||
const PAGE_SIZE = 50;
|
||||
|
||||
let collapsed = $state(
|
||||
typeof window !== 'undefined'
|
||||
? localStorage.getItem('wrenn_sidebar_collapsed') === 'true'
|
||||
: false
|
||||
);
|
||||
|
||||
let activeTab = $state<'platform' | 'byoc'>('platform');
|
||||
|
||||
// All hosts fetched once
|
||||
@ -163,19 +156,16 @@
|
||||
onMount(fetchHosts);
|
||||
</script>
|
||||
|
||||
<div class="flex h-screen overflow-hidden bg-[var(--color-bg-0)]">
|
||||
<AdminSidebar bind:collapsed />
|
||||
<main class="flex min-w-0 flex-1 flex-col overflow-hidden">
|
||||
<!-- Header -->
|
||||
<header class="relative shrink-0 border-b border-[var(--color-border)] bg-[var(--color-bg-1)]">
|
||||
<!-- Subtle gradient wash behind header for depth -->
|
||||
<div class="absolute inset-0 bg-gradient-to-b from-[var(--color-accent)]/[0.02] to-transparent pointer-events-none"></div>
|
||||
|
||||
<main class="flex min-w-0 flex-1 flex-col overflow-hidden">
|
||||
<!-- Header -->
|
||||
<header class="relative shrink-0 border-b border-[var(--color-border)] bg-[var(--color-bg-1)]">
|
||||
<!-- Subtle gradient wash behind header for depth -->
|
||||
<div class="absolute inset-0 bg-gradient-to-b from-[var(--color-accent)]/[0.02] to-transparent pointer-events-none"></div>
|
||||
|
||||
<div class="relative flex items-start justify-between px-8 pt-7 pb-5">
|
||||
<div>
|
||||
<h1 class="font-serif text-page leading-none text-[var(--color-text-bright)]">
|
||||
Hosts
|
||||
<div class="relative flex items-start justify-between px-8 pt-7 pb-5">
|
||||
<div>
|
||||
<h1 class="font-serif text-page leading-none text-[var(--color-text-bright)]">
|
||||
Hosts
|
||||
</h1>
|
||||
<p class="mt-2 text-ui text-[var(--color-text-tertiary)]">
|
||||
Platform and BYOC compute across all teams.
|
||||
@ -303,7 +293,6 @@
|
||||
{/if}
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
|
||||
{#snippet skeletonRows()}
|
||||
<div class="rounded-[var(--radius-card)] border border-[var(--color-border)] bg-[var(--color-bg-1)] overflow-hidden shadow-sm">
|
||||
|
||||
@ -1,5 +1,4 @@
|
||||
<script lang="ts">
|
||||
import AdminSidebar from '$lib/components/AdminSidebar.svelte';
|
||||
import { onMount } from 'svelte';
|
||||
import { toast } from '$lib/toast.svelte';
|
||||
import { formatDate } from '$lib/utils/format';
|
||||
@ -11,12 +10,6 @@
|
||||
type AdminTeamsResponse
|
||||
} from '$lib/api/team';
|
||||
|
||||
let collapsed = $state(
|
||||
typeof window !== 'undefined'
|
||||
? localStorage.getItem('wrenn_sidebar_collapsed') === 'true'
|
||||
: false
|
||||
);
|
||||
|
||||
// Data state
|
||||
let teams = $state<AdminTeam[]>([]);
|
||||
let loading = $state(true);
|
||||
@ -145,11 +138,8 @@
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="flex h-screen overflow-hidden bg-[var(--color-bg-0)]">
|
||||
<AdminSidebar bind:collapsed />
|
||||
|
||||
<main class="flex min-w-0 flex-1 flex-col overflow-hidden">
|
||||
<!-- Header -->
|
||||
<main class="flex min-w-0 flex-1 flex-col overflow-hidden">
|
||||
<!-- Header -->
|
||||
<header class="relative shrink-0 border-b border-[var(--color-border)] bg-[var(--color-bg-1)]">
|
||||
<div class="absolute inset-0 bg-gradient-to-b from-[var(--color-accent)]/[0.02] to-transparent pointer-events-none"></div>
|
||||
|
||||
@ -379,8 +369,7 @@
|
||||
<span class="font-mono text-label uppercase tracking-[0.04em] text-[var(--color-text-secondary)]">All systems operational</span>
|
||||
</div>
|
||||
</footer>
|
||||
</main>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<!-- BYOC confirmation dialog -->
|
||||
{#if byocTarget}
|
||||
|
||||
@ -1,5 +1,4 @@
|
||||
<script lang="ts">
|
||||
import AdminSidebar from '$lib/components/AdminSidebar.svelte';
|
||||
import CopyButton from '$lib/components/CopyButton.svelte';
|
||||
import { onMount, onDestroy } from 'svelte';
|
||||
import { toast } from '$lib/toast.svelte';
|
||||
@ -15,12 +14,6 @@
|
||||
type AdminTemplate
|
||||
} from '$lib/api/builds';
|
||||
|
||||
let collapsed = $state(
|
||||
typeof window !== 'undefined'
|
||||
? localStorage.getItem('wrenn_sidebar_collapsed') === 'true'
|
||||
: false
|
||||
);
|
||||
|
||||
let activeTab = $state<'templates' | 'builds'>('templates');
|
||||
|
||||
// Templates state
|
||||
@ -265,12 +258,9 @@
|
||||
});
|
||||
</script>
|
||||
|
||||
<div class="flex h-screen overflow-hidden bg-[var(--color-bg-0)]">
|
||||
<AdminSidebar bind:collapsed />
|
||||
|
||||
<main class="flex min-w-0 flex-1 flex-col overflow-hidden">
|
||||
<!-- Header -->
|
||||
<header class="relative shrink-0 border-b border-[var(--color-border)] bg-[var(--color-bg-1)]">
|
||||
<main class="flex min-w-0 flex-1 flex-col overflow-hidden">
|
||||
<!-- Header -->
|
||||
<header class="relative shrink-0 border-b border-[var(--color-border)] bg-[var(--color-bg-1)]">
|
||||
<!-- Subtle gradient wash behind header for depth -->
|
||||
<div class="absolute inset-0 bg-gradient-to-b from-[var(--color-accent)]/[0.02] to-transparent pointer-events-none"></div>
|
||||
|
||||
@ -373,8 +363,7 @@
|
||||
{/if}
|
||||
{/if}
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<!-- ── Snippets ─────────────────────────────────────────────────────── -->
|
||||
|
||||
|
||||
@ -1,5 +1,4 @@
|
||||
<script lang="ts">
|
||||
import AdminSidebar from '$lib/components/AdminSidebar.svelte';
|
||||
import { onMount } from 'svelte';
|
||||
import { toast } from '$lib/toast.svelte';
|
||||
import { formatDate } from '$lib/utils/format';
|
||||
@ -9,12 +8,6 @@
|
||||
type AdminUser,
|
||||
} from '$lib/api/admin-users';
|
||||
|
||||
let collapsed = $state(
|
||||
typeof window !== 'undefined'
|
||||
? localStorage.getItem('wrenn_sidebar_collapsed') === 'true'
|
||||
: false
|
||||
);
|
||||
|
||||
// Data state
|
||||
let users = $state<AdminUser[]>([]);
|
||||
let loading = $state(true);
|
||||
@ -112,12 +105,9 @@
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="flex h-screen overflow-hidden bg-[var(--color-bg-0)]">
|
||||
<AdminSidebar bind:collapsed />
|
||||
|
||||
<main class="flex min-w-0 flex-1 flex-col overflow-hidden">
|
||||
<!-- Header -->
|
||||
<header class="relative shrink-0 border-b border-[var(--color-border)] bg-[var(--color-bg-1)]">
|
||||
<main class="flex min-w-0 flex-1 flex-col overflow-hidden">
|
||||
<!-- Header -->
|
||||
<header class="relative shrink-0 border-b border-[var(--color-border)] bg-[var(--color-bg-1)]">
|
||||
<div class="absolute inset-0 bg-gradient-to-b from-[var(--color-accent)]/[0.02] to-transparent pointer-events-none"></div>
|
||||
|
||||
<div class="relative flex items-start justify-between px-8 pt-7 pb-5">
|
||||
@ -301,5 +291,4 @@
|
||||
<span class="font-mono text-label uppercase tracking-[0.04em] text-[var(--color-text-secondary)]">All systems operational</span>
|
||||
</div>
|
||||
</footer>
|
||||
</main>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
Reference in New Issue
Block a user