mirror of
https://github.com/youwen5/site.git
synced 2024-11-24 17:33:51 -08:00
feat: overhaul sticky toc styling
This commit is contained in:
parent
cadc1f637f
commit
24e0a6f1ff
4 changed files with 59 additions and 105 deletions
|
@ -1,6 +1,7 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { ChevronRight } from 'svelte-radix';
|
import { ChevronRight } from 'svelte-radix';
|
||||||
import PostMetadata from './PostMetadata.svelte';
|
import PostMetadata from './PostMetadata.svelte';
|
||||||
|
import Separator from '../ui/separator/separator.svelte';
|
||||||
|
|
||||||
export let doc: BlogDocument;
|
export let doc: BlogDocument;
|
||||||
</script>
|
</script>
|
||||||
|
@ -31,5 +32,6 @@
|
||||||
|
|
||||||
<div class="markdown-body mt-8 font-serif">
|
<div class="markdown-body mt-8 font-serif">
|
||||||
{@html doc.content}
|
{@html doc.content}
|
||||||
|
<div role="note" id="end-marker" aria-label="End of article" class="invisible h-0 w-0">End</div>
|
||||||
</div>
|
</div>
|
||||||
</article>
|
</article>
|
||||||
|
|
|
@ -1,72 +0,0 @@
|
||||||
<script lang="ts">
|
|
||||||
import { toclink, type TocStore } from '@svelte-put/toc';
|
|
||||||
import * as Card from '$lib/components/ui/card';
|
|
||||||
import { onMount } from 'svelte';
|
|
||||||
|
|
||||||
export let tocStore: TocStore;
|
|
||||||
export let distanceFromRight: number;
|
|
||||||
|
|
||||||
let el: HTMLElement;
|
|
||||||
|
|
||||||
let hide = false;
|
|
||||||
|
|
||||||
const readjust = () => {
|
|
||||||
el && (el.style.right = `calc(${distanceFromRight - el.clientWidth}px - 20px)`);
|
|
||||||
};
|
|
||||||
|
|
||||||
onMount(() => {
|
|
||||||
readjust();
|
|
||||||
});
|
|
||||||
|
|
||||||
$: readjust();
|
|
||||||
|
|
||||||
$: if (distanceFromRight < 220 && !hide) {
|
|
||||||
hide = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
$: if (distanceFromRight >= 220 && hide) {
|
|
||||||
hide = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
const calcIndent = (el: HTMLElement) => {
|
|
||||||
readjust();
|
|
||||||
if (el.tagName === 'H1' || el.tagName === 'H2') return '0px';
|
|
||||||
if (el.tagName === 'H3') return '1rem';
|
|
||||||
if (el.tagName === 'H4') return '2rem';
|
|
||||||
if (el.tagName === 'H5') return '3rem';
|
|
||||||
if (el.tagName === 'H6') return '4rem';
|
|
||||||
return '0px';
|
|
||||||
};
|
|
||||||
|
|
||||||
const calcTextClasses = (el: HTMLElement) => {
|
|
||||||
if (el.tagName === 'H1') return 'text-lg mb-2';
|
|
||||||
if (el.tagName === 'H2') return 'text-lg my-2';
|
|
||||||
return 'text-sm my-2 text-muted-foreground';
|
|
||||||
};
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<aside class="fixed top-36 x-4 mx-4" bind:this={el}>
|
|
||||||
<Card.Root>
|
|
||||||
<Card.Header>
|
|
||||||
<Card.Title><h2 class="text-xl">On this page</h2></Card.Title>
|
|
||||||
</Card.Header>
|
|
||||||
<Card.Content>
|
|
||||||
{#if $tocStore.items.size}
|
|
||||||
<ol>
|
|
||||||
{#each $tocStore.items.values() as tocItem}
|
|
||||||
<li
|
|
||||||
style="margin-left: {calcIndent(tocItem.element)}"
|
|
||||||
class={calcTextClasses(tocItem.element)}
|
|
||||||
>
|
|
||||||
<!-- svelte-ignore a11y-missing-attribute a11y-missing-content -->
|
|
||||||
<a
|
|
||||||
use:toclink={{ store: tocStore, tocItem, observe: true }}
|
|
||||||
class="hover:underline"
|
|
||||||
/>
|
|
||||||
</li>
|
|
||||||
{/each}
|
|
||||||
</ol>
|
|
||||||
{/if}
|
|
||||||
</Card.Content>
|
|
||||||
</Card.Root>
|
|
||||||
</aside>
|
|
34
src/lib/components/Toc/StickyToc.svelte
Normal file
34
src/lib/components/Toc/StickyToc.svelte
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import { toclink, type TocStore } from '@svelte-put/toc';
|
||||||
|
import * as Card from '$lib/components/ui/card';
|
||||||
|
|
||||||
|
export let tocStore: TocStore;
|
||||||
|
|
||||||
|
const calcTextClasses = (el: HTMLElement) => {
|
||||||
|
if (el.tagName === 'H1') return 'text-md xl:text-lg';
|
||||||
|
if (el.tagName === 'H2') return 'text-md xl:text-lg';
|
||||||
|
if (el.id === 'end-marker') return 'text-md xl:text-lg';
|
||||||
|
return 'text-sm text-muted-foreground';
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<Card.Root>
|
||||||
|
<Card.Header>
|
||||||
|
<Card.Title><h2 class="text-lg xl:text-xl">On this page</h2></Card.Title>
|
||||||
|
</Card.Header>
|
||||||
|
<Card.Content>
|
||||||
|
{#if $tocStore.items.size}
|
||||||
|
<ol>
|
||||||
|
{#each $tocStore.items.values() as tocItem}
|
||||||
|
<li>
|
||||||
|
<!-- svelte-ignore a11y-missing-attribute a11y-missing-content -->
|
||||||
|
<a
|
||||||
|
use:toclink={{ store: tocStore, tocItem, observe: true }}
|
||||||
|
class={`hover:bg-muted px-2 py-1 rounded-r-sm transition-all border-l-secondary border-l-4 ${calcTextClasses(tocItem.element)}`}
|
||||||
|
/>
|
||||||
|
</li>
|
||||||
|
{/each}
|
||||||
|
</ol>
|
||||||
|
{/if}
|
||||||
|
</Card.Content>
|
||||||
|
</Card.Root>
|
|
@ -6,24 +6,9 @@
|
||||||
import { cn } from '$lib/utils.js';
|
import { cn } from '$lib/utils.js';
|
||||||
import Article from '$lib/components/Blog/Article.svelte';
|
import Article from '$lib/components/Blog/Article.svelte';
|
||||||
import { toc, createTocStore } from '@svelte-put/toc';
|
import { toc, createTocStore } from '@svelte-put/toc';
|
||||||
import StickyToc from '$lib/components/StickyToc.svelte';
|
import StickyToc from '$lib/components/Toc/StickyToc.svelte';
|
||||||
import { onMount } from 'svelte';
|
import { onMount } from 'svelte';
|
||||||
|
|
||||||
let distanceFromRight = 0;
|
|
||||||
|
|
||||||
let mainElement: HTMLElement;
|
|
||||||
|
|
||||||
const handleResize = () => {
|
|
||||||
const screenWidth = window.innerWidth;
|
|
||||||
const mainWidth = mainElement.offsetWidth;
|
|
||||||
distanceFromRight = screenWidth - mainWidth - mainElement.offsetLeft;
|
|
||||||
console.log(distanceFromRight);
|
|
||||||
};
|
|
||||||
|
|
||||||
onMount(() => {
|
|
||||||
handleResize();
|
|
||||||
});
|
|
||||||
|
|
||||||
const tocStore = createTocStore();
|
const tocStore = createTocStore();
|
||||||
|
|
||||||
export let data: PageData;
|
export let data: PageData;
|
||||||
|
@ -48,21 +33,26 @@
|
||||||
<meta name="author" content="Youwen Wu" />
|
<meta name="author" content="Youwen Wu" />
|
||||||
</svelte:head>
|
</svelte:head>
|
||||||
|
|
||||||
<svelte:window on:resize={handleResize} />
|
<div class="md:flex max-w-6xl mx-auto mt-14 px-4">
|
||||||
|
<main
|
||||||
|
class="flex-grow basis-3/4"
|
||||||
|
use:toc={{
|
||||||
|
store: tocStore,
|
||||||
|
observe: true,
|
||||||
|
anchor: {
|
||||||
|
properties: { 'aria-hidden': 'true', class: 'hidden' },
|
||||||
|
position: 'before'
|
||||||
|
},
|
||||||
|
scrollMarginTop: 120,
|
||||||
|
selector: 'h1, h2, h3, h4, h5, h6, #end-marker'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Article {doc} />
|
||||||
|
</main>
|
||||||
|
|
||||||
<main
|
<aside class="basis-1/4 relative hidden md:block">
|
||||||
bind:this={mainElement}
|
<div class="fixed mx-8">
|
||||||
class="max-w-4xl mx-auto lg:mx-0 xl:mx-auto px-4 mt-8 mb-14"
|
<StickyToc {tocStore} />
|
||||||
use:toc={{
|
</div>
|
||||||
store: tocStore,
|
</aside>
|
||||||
observe: true,
|
</div>
|
||||||
anchor: {
|
|
||||||
properties: { 'aria-hidden': 'true', 'tab-index': '-1', class: 'hidden' },
|
|
||||||
position: 'before'
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Article {doc} />
|
|
||||||
</main>
|
|
||||||
|
|
||||||
<StickyToc {tocStore} {distanceFromRight} />
|
|
||||||
|
|
Loading…
Reference in a new issue