Skip to content

Commit 76bfeb5

Browse files
committed
Update styles and behavior.
1 parent 1437645 commit 76bfeb5

File tree

1 file changed

+195
-174
lines changed

1 file changed

+195
-174
lines changed

src/pages/[...slug].astro

Lines changed: 195 additions & 174 deletions
Original file line numberDiff line numberDiff line change
@@ -51,186 +51,207 @@ const description = post.data.subtitle;
5151
---
5252

5353
<Layout title={title} description={description} toc={post.data.toc}>
54-
55-
{ post.data.toc ?
56-
<TwoCols>
57-
<Fragment slot="content">
58-
<Headline id="contents" as="h4" title="Table of contents" />
59-
<div id="toc" class="mb-6 last:mb-0 rounded-lg shadow-md bg-white p-6"></div>
60-
</Fragment>
61-
<Fragment slot="sidebar">
62-
<Prose class="pb-20" >
63-
<Content
64-
components={{
65-
ButtonLink,
66-
Map,
67-
MapSprints,
68-
YouTube,
69-
BenefitItem,
70-
BenefitsList,
71-
HighlightCard,
72-
HighlightItem,
73-
Note,
74-
SponsorTiers,
75-
hr: Separator,
76-
Accordion,
77-
}}
78-
/>
79-
</Prose>
80-
</Fragment>
81-
</TwoCols>
82-
:
83-
<Prose class="pb-20" >
84-
<Content
85-
components={{
86-
ButtonLink,
87-
Map,
88-
MapSprints,
89-
YouTube,
90-
BenefitItem,
91-
BenefitsList,
92-
HighlightCard,
93-
HighlightItem,
94-
Note,
95-
SponsorTiers,
96-
hr: Separator,
97-
Accordion,
98-
}}
99-
/>
100-
</Prose>
101-
}
54+
{
55+
post.data.toc ? (
56+
<TwoCols>
57+
<Fragment slot="content">
58+
<div
59+
id="toc"
60+
class="mt-24 mb-6 last:mb-0 rounded-lg shadow-md bg-white p-6"
61+
>
62+
<span class="text-lg font-bold">Table of contents</span>
63+
</div>
64+
</Fragment>
65+
<Fragment slot="sidebar">
66+
<Prose class="pb-20">
67+
<Content
68+
components={{
69+
ButtonLink,
70+
Map,
71+
MapSprints,
72+
YouTube,
73+
BenefitItem,
74+
BenefitsList,
75+
HighlightCard,
76+
HighlightItem,
77+
Note,
78+
SponsorTiers,
79+
hr: Separator,
80+
Accordion,
81+
}}
82+
/>
83+
</Prose>
84+
</Fragment>
85+
</TwoCols>
86+
) : (
87+
<Prose class="pb-20">
88+
<Content
89+
components={{
90+
ButtonLink,
91+
Map,
92+
MapSprints,
93+
YouTube,
94+
BenefitItem,
95+
BenefitsList,
96+
HighlightCard,
97+
HighlightItem,
98+
Note,
99+
SponsorTiers,
100+
hr: Separator,
101+
Accordion,
102+
}}
103+
/>
104+
</Prose>
105+
)
106+
}
102107
</Layout>
103108

104109
<script is:inline>
105-
document.addEventListener("DOMContentLoaded", () => {
106-
const tocContainer = document.getElementById("toc");
107-
if (!tocContainer) return;
108-
109-
const headings = Array.from(document.querySelectorAll("article h2, article h3, article h4, article summary span:nth-child(1)"));
110-
if (!headings.length) return;
111-
112-
const rootUl = document.createElement("ul");
113-
let currentUl = rootUl;
114-
let lastLevel = 2;
115-
const parents = [rootUl];
116-
117-
headings.forEach((heading, index) => {
118-
if (!heading.id) {
119-
heading.id = `heading-${index}`;
120-
}
121-
122-
const level = parseInt(heading.tagName[1], 10);
123-
const li = document.createElement("li");
124-
const a = document.createElement("a");
125-
a.href = `#${heading.id}`;
126-
a.textContent = heading.textContent;
127-
li.appendChild(a);
128-
129-
if (level > lastLevel) {
130-
const newUl = document.createElement("ul");
131-
parents[parents.length - 1].lastElementChild?.appendChild(newUl);
132-
parents.push(newUl);
133-
} else if (level < lastLevel) {
134-
parents.splice(-(lastLevel - level));
135-
}
136-
137-
currentUl = parents[parents.length - 1];
138-
currentUl.appendChild(li);
139-
lastLevel = level;
140-
});
141-
142-
// Add "Back to top" link
143-
const backToTop = document.createElement("li");
144-
const topLink = document.createElement("a");
145-
topLink.href = "#";
146-
topLink.textContent = "↑ Back to top";
147-
topLink.style.marginTop = "1em";
148-
backToTop.appendChild(topLink);
149-
rootUl.appendChild(backToTop);
150-
151-
tocContainer.appendChild(rootUl);
152-
153-
// Scroll spy: highlight active link
154-
const observer = new IntersectionObserver(
155-
entries => {
156-
entries.forEach(entry => {
157-
const id = entry.target.id;
158-
const tocLink = tocContainer.querySelector(`a[href="#${id}"]`);
159-
if (tocLink) {
160-
if (entry.isIntersecting) {
161-
tocContainer.querySelectorAll("a").forEach(a => a.classList.remove("active"));
162-
tocLink.classList.add("active");
110+
document.addEventListener("DOMContentLoaded", () => {
111+
const tocContainer = document.getElementById("toc");
112+
if (!tocContainer) return;
113+
114+
const headings = Array.from(
115+
document.querySelectorAll(
116+
"article h2, article h3, article h4, article summary span:nth-child(1)",
117+
),
118+
);
119+
if (!headings.length) return;
120+
121+
const rootUl = document.createElement("ul");
122+
let currentUl = rootUl;
123+
let lastLevel = 2;
124+
const parents = [rootUl];
125+
126+
headings.forEach((heading, index) => {
127+
if (!heading.id) {
128+
heading.id = `heading-${index}`;
129+
}
130+
131+
const level = parseInt(heading.tagName[1], 10);
132+
const li = document.createElement("li");
133+
const a = document.createElement("a");
134+
a.href = `#${heading.id}`;
135+
a.textContent = heading.textContent;
136+
li.appendChild(a);
137+
138+
if (level > lastLevel) {
139+
const newUl = document.createElement("ul");
140+
parents[parents.length - 1].lastElementChild?.appendChild(newUl);
141+
parents.push(newUl);
142+
} else if (level < lastLevel) {
143+
parents.splice(-(lastLevel - level));
144+
}
145+
146+
currentUl = parents[parents.length - 1];
147+
currentUl.appendChild(li);
148+
lastLevel = level;
149+
});
150+
151+
// Add "Back to top" link
152+
const backToTop = document.createElement("li");
153+
const topLink = document.createElement("a");
154+
topLink.href = "#";
155+
topLink.textContent = "↑ Back to top";
156+
157+
topLink.classList.add("hidden");
158+
topLink.classList.add("lg:block");
159+
topLink.style.marginTop = "1em";
160+
backToTop.appendChild(topLink);
161+
rootUl.appendChild(backToTop);
162+
163+
tocContainer.appendChild(rootUl);
164+
165+
// Scroll spy: highlight active link
166+
const observer = new IntersectionObserver(
167+
(entries) => {
168+
entries.forEach((entry) => {
169+
const id = entry.target.id;
170+
const tocLink = tocContainer.querySelector(`a[href="#${id}"]`);
171+
if (tocLink) {
172+
if (entry.isIntersecting) {
173+
tocContainer
174+
.querySelectorAll("a")
175+
.forEach((a) => a.classList.remove("active"));
176+
tocLink.classList.add("active");
177+
}
163178
}
164-
}
165-
});
166-
},
167-
{
168-
rootMargin: "-30% 0px -60% 0px",
169-
threshold: 0,
170-
}
171-
);
172-
173-
headings.forEach(heading => observer.observe(heading));
174-
});
179+
});
180+
},
181+
{
182+
rootMargin: "-10% 0px -60% 0px",
183+
threshold: 0,
184+
},
185+
);
186+
187+
headings.forEach((heading) => observer.observe(heading));
188+
});
175189
</script>
176190

177191
<style is:global>
178-
179-
#toc {
180-
font-size: 0.95rem;
181-
line-height: 1.5;
182-
padding: 1rem;
183-
border-left: 1px solid #e0e0e0;
184-
position: sticky;
185-
top: 1rem;
186-
}
187-
188-
#toc ul {
189-
list-style: none;
190-
padding-left: 0;
191-
margin: 0;
192-
}
193-
194-
#toc li {
195-
margin: 0.25em 0;
196-
}
197-
198-
#toc li ul {
199-
margin-left: 1em;
200-
border-left: 1px dashed #ddd;
201-
padding-left: 0.75em;
202-
}
203-
204-
#toc a {
205-
text-decoration: none;
206-
color: #333;
207-
display: block;
208-
padding: 0.25em 0.5em;
209-
/*border-radius: 4px;*/
210-
transition: background 0.2s ease, color 0.2s ease;
211-
}
212-
213-
#toc a:hover {
214-
background: #f0f0f0;
215-
color: #007acc;
216-
}
217-
218-
#toc a.active {
219-
font-weight: 600;
220-
color: #007acc;
221-
border-left: 3px solid #007acc;
222-
background: rgba(0, 122, 204, 0.1);
223-
padding-left: 0.5em;
224-
}
225-
226-
#toc a[href="#"] {
227-
font-size: 0.9em;
228-
color: #555;
229-
margin-top: 0.5em;
230-
}
231-
232-
#toc a[href="#"]:hover {
233-
color: #007acc;
234-
text-decoration: underline;
192+
#toc {
193+
font-size: 0.95rem;
194+
line-height: 1.5;
195+
padding: 1rem;
196+
border-left: 1px solid #e0e0e0;
197+
position: sticky;
198+
top: 1rem;
199+
}
200+
201+
#toc ul {
202+
list-style: none;
203+
padding-left: 0;
204+
margin: 0;
205+
}
206+
207+
#toc li {
208+
margin: 0.25em 0;
209+
}
210+
211+
#toc li ul {
212+
margin-left: 1em;
213+
border-left: 1px dashed #ddd;
214+
padding-left: 0.75em;
215+
}
216+
217+
#toc a {
218+
text-decoration: none;
219+
color: #333;
220+
padding: 0.25em 0.5em;
221+
transition:
222+
background 0.2s ease,
223+
color 0.2s ease;
224+
}
225+
226+
#toc a:hover {
227+
background: #f0f0f0;
228+
color: #007acc;
229+
}
230+
231+
#toc a.active {
232+
font-weight: 600;
233+
color: #007acc;
234+
border-left: 3px solid #007acc;
235+
background: rgba(0, 122, 204, 0.1);
236+
padding-left: 0.5em;
237+
}
238+
239+
#toc a[href="#"] {
240+
font-size: 0.9em;
241+
color: #555;
242+
margin-top: 0.5em;
243+
}
244+
245+
#toc a[href="#"]:hover {
246+
color: #007acc;
247+
text-decoration: underline;
248+
}
249+
250+
251+
article h2,
252+
article h3,
253+
article h4,
254+
article summary span:nth-child(1) {
255+
scroll-margin-top: 120px; /* Same offset as used in JS */
235256
}
236257
</style>

0 commit comments

Comments
 (0)