redesign: add toc to ArticleContent
This commit is contained in:
parent
df43ac617b
commit
90fea1f2f6
|
|
@ -8,18 +8,72 @@ type Props = {
|
||||||
|
|
||||||
const { entry } = Astro.props;
|
const { entry } = Astro.props;
|
||||||
|
|
||||||
const { Content } = await render(entry);
|
const { Content, headings } = await render(entry);
|
||||||
---
|
---
|
||||||
|
|
||||||
<Container size="md">
|
<div class="article-layout">
|
||||||
|
<!-- Sidebar -->
|
||||||
|
<aside
|
||||||
|
class="animate toc font-departure max-w-3xl mx-auto px-5 xl:fixed xl:top-24 xl:right-[max(2rem,calc((100vw-84rem)/2))] xl:h-max xl:w-66"
|
||||||
|
>
|
||||||
|
<h3 class="font-semibold text-[0.9rem] opacity-70 mb-2">
|
||||||
|
On this page
|
||||||
|
</h3>
|
||||||
|
<ul class="list-none p-0 m-0">
|
||||||
|
{
|
||||||
|
headings.map((h) => (
|
||||||
|
<li class={`level-${h.depth}`}>
|
||||||
|
<a href={`#${h.slug}`}>{h.text}</a>
|
||||||
|
</li>
|
||||||
|
))
|
||||||
|
}
|
||||||
|
</ul>
|
||||||
|
</aside>
|
||||||
|
|
||||||
|
<!-- Main content -->
|
||||||
|
<Container size="md">
|
||||||
<article class="animate content">
|
<article class="animate content">
|
||||||
<Content />
|
<Content />
|
||||||
</article>
|
</article>
|
||||||
</Container>
|
</Container>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.toc li {
|
||||||
|
margin-bottom: 0.4rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.toc li.level-2 {
|
||||||
|
margin-left: 0.5rem;
|
||||||
|
}
|
||||||
|
.toc li.level-3 {
|
||||||
|
margin-left: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.toc a {
|
||||||
|
opacity: 0.7;
|
||||||
|
text-decoration: none;
|
||||||
|
transition: opacity 0.15s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.toc a.active {
|
||||||
|
opacity: 1;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.toc a:hover {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
article.content {
|
||||||
|
grid-area: content;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
<style is:global>
|
<style is:global>
|
||||||
article.content :is(h1, h2, h3, h4, h5, h6) {
|
article.content :is(h1, h2, h3, h4, h5, h6) {
|
||||||
font-family: "DepartureMono", monospace;
|
font-family: "DepartureMono", monospace;
|
||||||
|
scroll-margin-top: 6rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
article.content a {
|
article.content a {
|
||||||
|
|
@ -31,3 +85,33 @@ const { Content } = await render(entry);
|
||||||
text-decoration: underline;
|
text-decoration: underline;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
const headings = document.querySelectorAll(
|
||||||
|
"article.content h1[id], article.content h2[id], article.content h3[id]",
|
||||||
|
);
|
||||||
|
const tocLinks = document.querySelectorAll(".toc a");
|
||||||
|
|
||||||
|
const observer = new IntersectionObserver(
|
||||||
|
(entries) => {
|
||||||
|
entries.forEach((entry) => {
|
||||||
|
if (entry.isIntersecting) {
|
||||||
|
const id = entry.target.getAttribute("id");
|
||||||
|
|
||||||
|
tocLinks.forEach((link) => {
|
||||||
|
link.classList.toggle(
|
||||||
|
"active",
|
||||||
|
link.getAttribute("href") === `#${id}`,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
{
|
||||||
|
rootMargin: "0px 0px -80% 0px",
|
||||||
|
threshold: 0.1,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
headings.forEach((h) => observer.observe(h));
|
||||||
|
</script>
|
||||||
|
|
|
||||||
|
|
@ -3,9 +3,10 @@ import { cn } from "@/lib/utils";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
size: "sm" | "md" | "lg" | "xl" | "2xl";
|
size: "sm" | "md" | "lg" | "xl" | "2xl";
|
||||||
|
class?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
const { size } = Astro.props;
|
const { size, class: className } = Astro.props;
|
||||||
---
|
---
|
||||||
|
|
||||||
<div
|
<div
|
||||||
|
|
@ -16,6 +17,7 @@ const { size } = Astro.props;
|
||||||
size === "lg" && "max-w-5xl",
|
size === "lg" && "max-w-5xl",
|
||||||
size === "xl" && "max-w-7xl",
|
size === "xl" && "max-w-7xl",
|
||||||
size === "2xl" && "max-w-screen-2xl",
|
size === "2xl" && "max-w-screen-2xl",
|
||||||
|
className,
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<slot />
|
<slot />
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue