diff options
Diffstat (limited to 'web/ui/src/routes/dashboard/+layout.svelte')
| -rw-r--r-- | web/ui/src/routes/dashboard/+layout.svelte | 90 |
1 files changed, 90 insertions, 0 deletions
diff --git a/web/ui/src/routes/dashboard/+layout.svelte b/web/ui/src/routes/dashboard/+layout.svelte new file mode 100644 index 0000000..9137c75 --- /dev/null +++ b/web/ui/src/routes/dashboard/+layout.svelte @@ -0,0 +1,90 @@ +<script lang="ts"> + import { page } from '$app/stores'; + import BrandMark from '$lib/components/BrandMark.svelte'; + import Footer from '$lib/components/Footer.svelte'; + import { PLANS } from '$lib/plans'; + + let { data, children } = $props(); + + const tabs = [ + { id: '01', slug: 'keys', label: 'Keys' }, + { id: '02', slug: 'usage', label: 'Usage' }, + { id: '03', slug: 'account', label: 'Account' } + ]; + + let currentPath = $derived($page.url.pathname); + let account = $derived(data.account); + let planInfo = $derived(account ? PLANS[account.plan] : PLANS.free); +</script> + +<svelte:head> + <title>Tidy Index — Dashboard</title> +</svelte:head> + +<header class="app-header"> + <div class="container app-header-inner"> + <a href="/dashboard/keys" class="brand" aria-label="Tidy Index dashboard home"> + <BrandMark /> + <span>Tidy Index</span> + </a> + + <div class="app-header-meta"> + <span class="plan-chip"> + plan: <strong>{planInfo.name.toLowerCase()}</strong> + </span> + {#if account?.email} + <span title={account.email}>{account.email}</span> + {:else if account?.pending_email} + <span class="pending-chip" title="Sign-in link sent — awaiting verification"> + pending · {account.pending_email} + </span> + {:else} + <span class="text-mute">anonymous</span> + {/if} + </div> + </div> +</header> + +<div class="container"> + {#if !account?.email && !account?.pending_email} + <div class="banner"> + <span> + You're using an anonymous session. + <strong>Sign in with an email so you don't lose access to your keys.</strong> + </span> + <a href="/dashboard/account?focus=email" class="btn btn-sm btn-ghost">Sign in</a> + </div> + {:else if account?.pending_email && !account?.email} + <div class="banner"> + <span> + We sent a sign-in link to <strong>{account.pending_email}</strong>. + Check your inbox to finish signing in. + </span> + <a href="/dashboard/account" class="btn btn-sm btn-ghost">Manage</a> + </div> + {/if} + + <nav class="tabs" aria-label="Dashboard sections"> + <div class="tabs-inner"> + {#each tabs as tab} + {@const active = currentPath.startsWith(`/dashboard/${tab.slug}`)} + <a + href="/dashboard/{tab.slug}" + class="tab {active ? 'active' : ''}" + aria-current={active ? 'page' : undefined} + > + <span class="tab-num">§ {tab.id}</span> + <span>{tab.label}</span> + </a> + {/each} + </div> + </nav> +</div> + +<main class="app-main"> + <div class="container"> + {@render children()} + </div> +</main> + +<Footer /> |
