phase-1: optimize code
This commit is contained in:
@@ -0,0 +1,132 @@
|
||||
<script>
|
||||
import { page, navigating } from '$app/stores';
|
||||
import '../app.css';
|
||||
let { children } = $props();
|
||||
|
||||
// Label shown under the nav progress bar while loading a page
|
||||
const navLabel = $derived(
|
||||
$navigating?.to?.url?.pathname === '/portfolio' ? 'Loading portfolio…' :
|
||||
$navigating?.to?.url?.pathname?.startsWith('/calls') ? 'Loading market calls…' :
|
||||
$navigating?.to?.url?.pathname === '/safe-buys' ? 'Screening safe buys…' :
|
||||
'Loading…'
|
||||
);
|
||||
</script>
|
||||
|
||||
<div class="shell">
|
||||
<nav>
|
||||
<span class="brand">📊 Market Screener</span>
|
||||
<div class="links">
|
||||
<a href="/" class:active={$page.url.pathname === '/'}>Screener</a>
|
||||
<a href="/portfolio" class:active={$page.url.pathname === '/portfolio'}>Portfolio</a>
|
||||
<a href="/calls" class:active={$page.url.pathname.startsWith('/calls')}>Market Calls</a>
|
||||
<a href="/safe-buys" class:active={$page.url.pathname === '/safe-buys'}>🛡 Safe Buys</a>
|
||||
</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">
|
||||
<div class="nav-spinner"></div>
|
||||
<span class="nav-label">{navLabel}</span>
|
||||
</div>
|
||||
{:else}
|
||||
{@render children()}
|
||||
{/if}
|
||||
</main>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.shell { min-height: 100vh; display: flex; flex-direction: column; }
|
||||
|
||||
nav {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 24px;
|
||||
padding: 14px 32px;
|
||||
border-bottom: 1px solid #1e293b;
|
||||
background: #0f1117;
|
||||
position: sticky;
|
||||
top: 0;
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
.brand { font-size: 15px; font-weight: 700; color: #f1f5f9; }
|
||||
|
||||
.links { display: flex; gap: 4px; margin-left: auto; }
|
||||
|
||||
.links a {
|
||||
color: #64748b;
|
||||
text-decoration: none;
|
||||
padding: 6px 14px;
|
||||
border-radius: 6px;
|
||||
font-weight: 500;
|
||||
transition: color 0.15s, background 0.15s;
|
||||
}
|
||||
.links a:hover { color: #e2e8f0; background: #1e293b; }
|
||||
.links a.active { color: #e2e8f0; background: #1e293b; }
|
||||
|
||||
main { flex: 1; padding: 28px 32px; }
|
||||
|
||||
/* ── Navigation progress ─────────────────────────────────────────── */
|
||||
.nav-progress {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
height: 2px;
|
||||
z-index: 100;
|
||||
background: #1e293b;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.nav-bar {
|
||||
height: 100%;
|
||||
background: #3b82f6;
|
||||
animation: progress 1.5s ease-in-out infinite;
|
||||
transform-origin: left;
|
||||
}
|
||||
|
||||
@keyframes progress {
|
||||
0% { transform: translateX(-100%) scaleX(0.3); }
|
||||
50% { transform: translateX(0%) scaleX(0.7); }
|
||||
100% { transform: translateX(100%) scaleX(0.3); }
|
||||
}
|
||||
|
||||
/* Centered spinner + label in the page body */
|
||||
.nav-overlay {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 14px;
|
||||
padding: 100px 0;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.nav-spinner {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
border: 3px solid #1e293b;
|
||||
border-top-color: #3b82f6;
|
||||
border-radius: 50%;
|
||||
animation: spin 0.7s linear infinite;
|
||||
}
|
||||
|
||||
.nav-label {
|
||||
font-size: 12px;
|
||||
color: #475569;
|
||||
letter-spacing: 0.02em;
|
||||
}
|
||||
|
||||
@keyframes spin {
|
||||
to { transform: rotate(360deg); }
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user