Files
market_screener/ui/src/routes/+layout.svelte
T
saikiranvella 662a717916 UI enhancemnts
2026-06-09 19:34:31 -04:00

81 lines
2.7 KiB
Svelte

<script lang="ts">
import { page, navigating } from '$app/stores';
import { goto } from '$app/navigation';
import '../styles/app.scss';
import Spinner from '$lib/components/shared/Spinner.svelte';
import { authStore } from '$lib/stores/auth.store.svelte.js';
import { watchlistStore } from '$lib/stores/watchlist.store.svelte.js';
import type { Snippet } from 'svelte';
let { children }: { children: Snippet } = $props();
// Resolve active path optimistically — use the destination during navigation
// so the nav link highlights immediately on click, not after load completes.
const activePath = $derived($navigating?.to?.url?.pathname ?? $page.url.pathname);
// All routes except /auth/* require login
$effect(() => {
const path = $page.url.pathname;
if (!path.startsWith('/auth/') && !authStore.isLoggedIn) {
goto('/auth/login');
}
});
// Load watchlist once when user is authenticated
$effect(() => {
if (authStore.isLoggedIn && !watchlistStore.ready && !watchlistStore.loading) {
watchlistStore.load();
}
});
const navLabel = $derived(
activePath === '/portfolio' ? 'Loading portfolio…' :
activePath?.startsWith('/calls') ? 'Loading market calls…' :
activePath === '/safe-buys' ? 'Screening safe buys…' :
'Loading…'
);
</script>
<div class="shell">
<nav>
<span class="brand">📊 Market Screener</span>
<div class="links">
{#if authStore.isLoggedIn}
<a href="/" class:active={activePath === '/'}>Screener</a>
<a href="/portfolio" class:active={activePath === '/portfolio'}>Portfolio</a>
<a href="/calls" class:active={activePath?.startsWith('/calls')}>Market Calls</a>
<a href="/safe-buys" class:active={activePath === '/safe-buys'}>🛡 Safe Buys</a>
{/if}
</div>
<div class="nav-auth">
{#if authStore.isLoggedIn}
<span class="nav-user">{authStore.user?.email}</span>
<button class="btn-ghost btn-sm" onclick={() => { authStore.clearAuth(); goto('/auth/login'); }}>
Sign out
</button>
{:else}
<a href="/auth/login" class="btn-ghost btn-sm">Sign in</a>
{/if}
</div>
</nav>
<!-- Thin progress bar at top of screen — always visible even on first nav -->
{#if $navigating}
<div class="nav-progress">
<div class="nav-bar"></div>
</div>
{/if}
<main>
{#if $navigating}
<!-- Replace old page content immediately — old page disappears, spinner takes over -->
<div class="nav-overlay">
<Spinner size="lg" label={navLabel} />
</div>
{:else}
{@render children()}
{/if}
</main>
</div>
<!-- All layout styles live in src/styles/_layout.css (global) -->