File
Blob: ui/shared/Shell.svelte
| 1 | <script lang="ts"> |
| 2 | import type { Snippet } from 'svelte'; |
| 3 | |
| 4 | type Props = { |
| 5 | label: string; |
| 6 | home: string; |
| 7 | navigation?: { label: string; href: string; active?: boolean }[]; |
| 8 | children: Snippet; |
| 9 | }; |
| 10 | |
| 11 | let { label, home, navigation = [], children }: Props = $props(); |
| 12 | </script> |
| 13 | |
| 14 | <a |
| 15 | href="#main-content" |
| 16 | class="sr-only focus:not-sr-only focus:fixed focus:top-3 focus:left-3 focus:z-50 focus:rounded-md focus:bg-surface focus:px-3 focus:py-2 focus:text-accent-300" |
| 17 | >Skip to content</a> |
| 18 | |
| 19 | <header class="border-b border-line bg-chrome"> |
| 20 | <div class="mx-auto flex min-h-14 max-w-6xl flex-wrap items-center gap-x-5 gap-y-1 px-4 py-2 sm:px-6"> |
| 21 | <a href={home} class="flex min-h-10 items-center gap-2.5 rounded-sm text-foreground"> |
| 22 | <span class="text-lg font-semibold tracking-tight">specter</span> |
| 23 | <span class="border-l border-line pl-2.5 text-sm text-muted">{label}</span> |
| 24 | </a> |
| 25 | {#if navigation.length} |
| 26 | <nav aria-label="Operator" class="flex flex-wrap items-center gap-1"> |
| 27 | {#each navigation as item (item.href)} |
| 28 | <a |
| 29 | href={item.href} |
| 30 | aria-current={item.active ? 'page' : undefined} |
| 31 | class={[ |
| 32 | 'inline-flex min-h-10 items-center rounded-md px-3 text-sm font-medium', |
| 33 | item.active ? 'bg-surface text-accent-300' : 'text-muted hover:bg-surface hover:text-foreground', |
| 34 | ]} |
| 35 | >{item.label}</a> |
| 36 | {/each} |
| 37 | </nav> |
| 38 | {/if} |
| 39 | </div> |
| 40 | </header> |
| 41 | |
| 42 | <main id="main-content" tabindex="-1" class="mx-auto w-full min-w-0 max-w-6xl px-4 py-5 sm:px-6 sm:py-6"> |
| 43 | {@render children()} |
| 44 | </main> |