mirror of https://github.com/sveltejs/svelte
parent
d012369b0c
commit
37c9feb4f6
@ -0,0 +1,141 @@
|
||||
<script>
|
||||
import { onMount } from 'svelte';
|
||||
import { afterNavigate } from '$app/navigation';
|
||||
import { base } from '$app/paths';
|
||||
import { page } from '$app/stores';
|
||||
|
||||
/** @type {import('./$types').PageData['page']} */
|
||||
export let details;
|
||||
|
||||
/** @type {string} */
|
||||
let hash = '';
|
||||
|
||||
/** @type {number} */
|
||||
let height = 0;
|
||||
|
||||
/** @type {HTMLElement} */
|
||||
let content;
|
||||
|
||||
/** @type {NodeListOf<HTMLElement>} */
|
||||
let headings;
|
||||
|
||||
/** @type {number[]} */
|
||||
let positions = [];
|
||||
|
||||
onMount(async () => {
|
||||
await document.fonts.ready;
|
||||
|
||||
update();
|
||||
highlight();
|
||||
});
|
||||
|
||||
afterNavigate(() => {
|
||||
update();
|
||||
highlight();
|
||||
});
|
||||
|
||||
function update() {
|
||||
content = document.querySelector('.content');
|
||||
const { top } = content.getBoundingClientRect();
|
||||
|
||||
headings = content.querySelectorAll('h2[id]');
|
||||
|
||||
positions = Array.from(headings).map((heading) => {
|
||||
const style = getComputedStyle(heading);
|
||||
return heading.getBoundingClientRect().top - parseFloat(style.scrollMarginTop) - top;
|
||||
});
|
||||
|
||||
height = window.innerHeight;
|
||||
}
|
||||
|
||||
function highlight() {
|
||||
const { top, bottom } = content.getBoundingClientRect();
|
||||
let i = headings.length;
|
||||
|
||||
while (i--) {
|
||||
if (bottom - height < 50 || positions[i] + top < 100) {
|
||||
const heading = headings[i];
|
||||
hash = `#${heading.id}`;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
hash = '';
|
||||
}
|
||||
|
||||
/** @param {URL} url */
|
||||
function select(url) {
|
||||
// belt...
|
||||
setTimeout(() => {
|
||||
hash = url.hash;
|
||||
});
|
||||
|
||||
// ...and braces
|
||||
window.addEventListener(
|
||||
'scroll',
|
||||
() => {
|
||||
hash = url.hash;
|
||||
},
|
||||
{ once: true }
|
||||
);
|
||||
}
|
||||
</script>
|
||||
|
||||
<svelte:window on:scroll={highlight} on:resize={update} on:hashchange={() => select($page.url)} />
|
||||
|
||||
<aside class="on-this-page">
|
||||
<h2>On this page</h2>
|
||||
<nav>
|
||||
<ul>
|
||||
<li><a href="{base}/docs/{details.slug}" class:active={hash === ''}>{details.title}</a></li>
|
||||
{#each details.sections as { title, slug }}
|
||||
<li><a href={`#${slug}`} class:active={`#${slug}` === hash}>{title}</a></li>
|
||||
{/each}
|
||||
</ul>
|
||||
</nav>
|
||||
</aside>
|
||||
|
||||
<style>
|
||||
.on-this-page {
|
||||
display: var(--on-this-page-display);
|
||||
position: fixed;
|
||||
padding: 0 var(--sk-page-padding-side) 0 0;
|
||||
width: min(280px, calc(var(--sidebar-width) - var(--sk-page-padding-side)));
|
||||
/* top: calc(var(--sk-page-padding-top) + var(--sk-nav-height)); */
|
||||
top: var(--sk-nav-height);
|
||||
left: calc(100vw - (var(--sidebar-width)));
|
||||
}
|
||||
|
||||
h2 {
|
||||
text-transform: uppercase;
|
||||
font-size: 1.4rem;
|
||||
font-weight: 400;
|
||||
line-height: 0;
|
||||
margin: 0 0 1rem 0 !important;
|
||||
padding: 0 0 0 0.6rem;
|
||||
color: var(--sk-text-3);
|
||||
}
|
||||
|
||||
ul {
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
a {
|
||||
display: block;
|
||||
padding: 0.3rem 0.5rem;
|
||||
color: var(--sk-text-3);
|
||||
border-left: 2px solid transparent;
|
||||
|
||||
font-size: 1.3rem;
|
||||
}
|
||||
|
||||
a:hover {
|
||||
text-decoration: none;
|
||||
background: var(--sk-back-3);
|
||||
}
|
||||
|
||||
a.active {
|
||||
background: var(--sk-back-3);
|
||||
border-left-color: var(--sk-theme-1);
|
||||
}
|
||||
</style>
|
||||
Loading…
Reference in new issue