Skip to content

Commit 7b41164

Browse files
committed
Make rough scrolling toc for blog
1 parent b691a88 commit 7b41164

File tree

4 files changed

+114
-4
lines changed

4 files changed

+114
-4
lines changed

src/components/blog/Toc.astro

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
---
2+
// Copied from https://dev.to/fazzaamiarso/add-toc-with-scroll-spy-in-astro-3d25
3+
// A fixed table of contents on the right side that is updated as you scroll
4+
5+
interface Props {
6+
headings: { slug: string; text: string; depth: number }[];
7+
}
8+
9+
const { headings } = Astro.props;
10+
---
11+
12+
<script>
13+
const setCurrentHeading: IntersectionObserverCallback = (entries) => {
14+
console.log(entries.map((entry) => entry.target.id));
15+
for (const entry of entries) {
16+
const tocLinkEl = document.querySelector(`#toc-${entry.target.id}`);
17+
if (!tocLinkEl) return;
18+
console.log(tocLinkEl);
19+
if (entry.isIntersecting) {
20+
// Make all other links inactive and make only this one active
21+
console.log(tocLinkEl);
22+
document
23+
.querySelectorAll("#toc a")
24+
.forEach((e) => e.classList.remove("active"));
25+
tocLinkEl.classList.add("active");
26+
break;
27+
}
28+
}
29+
};
30+
31+
const observer = new IntersectionObserver(setCurrentHeading, {
32+
threshold: 1,
33+
rootMargin: "0px 0px -66%",
34+
});
35+
document
36+
.querySelectorAll("article :is(h2,h3)")
37+
.forEach((el) => observer.observe(el));
38+
</script>
39+
40+
<aside id="toc">
41+
<ul>
42+
{
43+
headings
44+
.filter((heading) => heading.depth < 4)
45+
.map(({ slug, text, depth }) => (
46+
<li>
47+
<a id={`toc-${slug}`} href={`#${slug}`}>
48+
{"\xa0\xa0".repeat(depth - 2) + text}
49+
</a>
50+
</li>
51+
))
52+
}
53+
</ul>
54+
</aside>
55+
56+
<style lang="scss">
57+
@import "../../styles/common.scss";
58+
59+
// TODO rather than a fixed position, use a flexbox or something
60+
aside {
61+
position: fixed;
62+
top: 15rem;
63+
64+
border-left: 2px solid var(--highlight-color);
65+
66+
// Hide even on tablets, because it's too big to fit
67+
display: none;
68+
69+
@media (min-width: 1300px) {
70+
display: block;
71+
right: 4ch;
72+
}
73+
74+
@media (min-width: 1500px) {
75+
display: block;
76+
right: 8ch;
77+
}
78+
79+
@media (min-width: 1600px) {
80+
display: block;
81+
right: 10ch;
82+
}
83+
}
84+
85+
ul {
86+
list-style: none;
87+
margin: 0;
88+
padding-left: 2ch;
89+
}
90+
91+
.active {
92+
font-weight: 600;
93+
}
94+
95+
a {
96+
text-decoration: none;
97+
}
98+
</style>

src/layouts/BlogPost.astro

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,26 @@
11
---
22
import type { CollectionEntry } from "astro:content";
3-
import FormattedDate from "../components/FormattedDate.astro";
3+
import FormattedDate from "../components/blog/FormattedDate.astro";
44
import BaseLayout from "./BaseLayout.astro";
5+
import Toc from "../components/blog/Toc.astro";
6+
import { render } from "astro:content";
7+
import { getCollection } from "astro:content";
58
69
type Props = CollectionEntry<"blog">["data"];
710
811
const { title, description, author, pubDate, updatedDate, heroImage } =
912
Astro.props;
13+
14+
const posts = await getCollection("blog", ({ data }) => data.title === title);
15+
const entry = posts[0];
16+
const { Content, headings } = await render(entry);
1017
---
1118

12-
<BaseLayout title={title} isBlogPost={true} description={description ?? "Team CYB3RL4NG's blog"}>
19+
<BaseLayout
20+
title={title}
21+
isBlogPost={true}
22+
description={description ?? "Team CYB3RL4NG's blog"}
23+
>
1324
<article>
1425
<div class="hero-image">
1526
{heroImage && <img width={1020} height={510} src={heroImage} alt="" />}
@@ -30,7 +41,8 @@ const { title, description, author, pubDate, updatedDate, heroImage } =
3041
</div>
3142
<hr />
3243
</div>
33-
<slot />
44+
<Content />
45+
<Toc headings={headings} />
3446
</div>
3547
</article>
3648
</BaseLayout>

src/pages/blog/index.astro

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
---
22
import { getCollection } from "astro:content";
3-
import FormattedDate from "../../components/FormattedDate.astro";
3+
import FormattedDate from "../../components/blog/FormattedDate.astro";
44
import BaseLayout from "../../layouts/BaseLayout.astro";
55
import { RSS_LINK } from "../../consts";
66
import DescText from "../../components/DescText.astro";

0 commit comments

Comments
 (0)