You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
189 lines
3.6 KiB
189 lines
3.6 KiB
|
5 months ago
|
<script lang="ts">
|
||
|
|
import { page } from '$app/state';
|
||
|
|
import type { NavSection } from '../_data/nav';
|
||
|
|
|
||
|
|
let { nav }: { nav: readonly NavSection[] } = $props();
|
||
|
|
|
||
|
|
const currentPath = $derived(page.url.pathname.replace(/\/$/, ''));
|
||
|
|
|
||
|
|
function isActive(href: string): boolean {
|
||
|
|
const normalized = href.replace(/\/$/, '');
|
||
|
|
return currentPath === normalized;
|
||
|
|
}
|
||
|
|
</script>
|
||
|
|
|
||
|
|
<nav class="sidebar" aria-label="Documentation">
|
||
|
|
{#each nav as section (section.title)}
|
||
|
|
<div class="section">
|
||
|
|
<h3 class="section-title">{section.title}</h3>
|
||
|
|
<ul>
|
||
|
|
{#each section.items as item (item.href)}
|
||
|
|
<li>
|
||
|
|
<a
|
||
|
|
href={item.href}
|
||
|
|
class="link"
|
||
|
|
class:active={isActive(item.href)}
|
||
|
|
aria-current={isActive(item.href) ? 'page' : undefined}
|
||
|
|
>
|
||
|
|
<span class="link-label">
|
||
|
|
<span>{item.label}</span>
|
||
|
|
{#if item.alias}
|
||
|
|
<span class="alias">{item.alias}</span>
|
||
|
|
{/if}
|
||
|
|
</span>
|
||
|
|
{#if item.tag}
|
||
|
|
<span class="badge" data-tag={item.tag}>{item.tag}</span>
|
||
|
|
{/if}
|
||
|
|
</a>
|
||
|
|
</li>
|
||
|
|
{/each}
|
||
|
|
</ul>
|
||
|
|
</div>
|
||
|
|
{/each}
|
||
|
|
</nav>
|
||
|
|
|
||
|
|
<style>
|
||
|
|
.sidebar {
|
||
|
|
padding: 1.25rem 0.65rem 3rem;
|
||
|
|
font-size: 0.875rem;
|
||
|
|
}
|
||
|
|
|
||
|
|
.section {
|
||
|
|
margin-bottom: 1.5rem;
|
||
|
|
}
|
||
|
|
|
||
|
|
.section + .section {
|
||
|
|
padding-top: 1rem;
|
||
|
|
border-top: 1px dashed var(--c-border);
|
||
|
|
}
|
||
|
|
|
||
|
|
.section-title {
|
||
|
|
font-size: 0.7rem;
|
||
|
|
font-weight: 600;
|
||
|
|
text-transform: uppercase;
|
||
|
|
letter-spacing: 0.09em;
|
||
|
|
color: var(--c-fg-subtle);
|
||
|
|
margin: 0 0 0.55rem;
|
||
|
|
padding: 0 0.75rem;
|
||
|
|
}
|
||
|
|
|
||
|
|
ul {
|
||
|
|
list-style: none;
|
||
|
|
margin: 0;
|
||
|
|
padding: 0;
|
||
|
|
display: flex;
|
||
|
|
flex-direction: column;
|
||
|
|
gap: 1px;
|
||
|
|
}
|
||
|
|
|
||
|
|
.link {
|
||
|
|
position: relative;
|
||
|
|
display: flex;
|
||
|
|
align-items: center;
|
||
|
|
justify-content: space-between;
|
||
|
|
gap: 0.5rem;
|
||
|
|
padding: 0.4rem 0.75rem;
|
||
|
|
border-radius: var(--r-md);
|
||
|
|
color: var(--c-fg-muted);
|
||
|
|
font-weight: 500;
|
||
|
|
line-height: 1.4;
|
||
|
|
transition:
|
||
|
|
background-color 120ms var(--ease),
|
||
|
|
color 120ms var(--ease);
|
||
|
|
}
|
||
|
|
|
||
|
|
.link::before {
|
||
|
|
content: '';
|
||
|
|
position: absolute;
|
||
|
|
left: 0;
|
||
|
|
top: 50%;
|
||
|
|
width: 2px;
|
||
|
|
height: 0;
|
||
|
|
background: var(--c-accent);
|
||
|
|
border-radius: 2px;
|
||
|
|
transform: translateY(-50%);
|
||
|
|
transition: height 180ms var(--ease);
|
||
|
|
}
|
||
|
|
|
||
|
|
.link.active::before {
|
||
|
|
height: 60%;
|
||
|
|
}
|
||
|
|
|
||
|
|
.link-label {
|
||
|
|
display: inline-flex;
|
||
|
|
align-items: baseline;
|
||
|
|
gap: 0.4rem;
|
||
|
|
min-width: 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
.alias {
|
||
|
|
font-family: var(--font-mono);
|
||
|
|
font-size: 0.7rem;
|
||
|
|
font-weight: 500;
|
||
|
|
color: var(--c-fg-subtle);
|
||
|
|
}
|
||
|
|
|
||
|
|
.link.active .alias {
|
||
|
|
color: var(--c-accent);
|
||
|
|
opacity: 0.8;
|
||
|
|
}
|
||
|
|
|
||
|
|
.link:hover {
|
||
|
|
background: var(--c-bg-muted);
|
||
|
|
color: var(--c-fg);
|
||
|
|
text-decoration: none;
|
||
|
|
}
|
||
|
|
|
||
|
|
.link.active {
|
||
|
|
background: var(--c-accent-muted);
|
||
|
|
color: var(--c-accent-emphasized);
|
||
|
|
font-weight: 600;
|
||
|
|
}
|
||
|
|
|
||
|
|
:global([data-theme='dark']) .link.active {
|
||
|
|
background: var(--c-accent-subtle);
|
||
|
|
color: var(--c-fg);
|
||
|
|
}
|
||
|
|
|
||
|
|
:global([data-theme='dark']) .link.active .alias {
|
||
|
|
color: var(--c-accent-emphasized);
|
||
|
|
opacity: 1;
|
||
|
|
}
|
||
|
|
|
||
|
|
.badge {
|
||
|
|
font-size: 0.65rem;
|
||
|
|
font-weight: 600;
|
||
|
|
text-transform: uppercase;
|
||
|
|
letter-spacing: 0.04em;
|
||
|
|
padding: 0.05em 0.4em;
|
||
|
|
border-radius: var(--r-sm);
|
||
|
|
background: var(--c-bg-muted);
|
||
|
|
color: var(--c-fg-subtle);
|
||
|
|
border: 1px solid var(--c-border);
|
||
|
|
}
|
||
|
|
|
||
|
|
.badge[data-tag='new'] {
|
||
|
|
background: var(--c-accent-muted);
|
||
|
|
color: var(--c-accent-emphasized);
|
||
|
|
border-color: var(--c-accent-subtle);
|
||
|
|
}
|
||
|
|
|
||
|
|
.badge[data-tag='beta'] {
|
||
|
|
background: #fef3c7;
|
||
|
|
color: #92400e;
|
||
|
|
border-color: #fde68a;
|
||
|
|
}
|
||
|
|
|
||
|
|
:global([data-theme='dark']) .badge[data-tag='beta'] {
|
||
|
|
background: #422006;
|
||
|
|
color: #fbbf24;
|
||
|
|
border-color: #78350f;
|
||
|
|
}
|
||
|
|
|
||
|
|
.badge[data-tag='stub'] {
|
||
|
|
background: var(--c-bg-muted);
|
||
|
|
color: var(--c-fg-subtle);
|
||
|
|
border-color: var(--c-border);
|
||
|
|
}
|
||
|
|
</style>
|