TOC & Typography Test Page
A kitchen-sink post that exercises the table of contents, reading progress bar, scroll-spy, and prose styling. Delete me once everything looks right.
This post exists to verify the reading experience end-to-end: the sticky table of contents on the right, the scroll-spy highlight following your position, the progress bar at the very top of the viewport, and the prose typography for headings, lists, quotes, code, and links. If anything here looks off, the component that owns it is the first suspect.
Introduction
Every h2 on this page should appear as a top-level entry in the TOC. As
you scroll into each section, the corresponding TOC link should become
bold and brighter because the IntersectionObserver in
TableOfContents.astro adds the is-active class when the heading
enters the top third of the viewport.
The thin accent-colored bar pinned to the top of the window is the
ReadingProgress component. It listens for scroll events and updates
its width via requestAnimationFrame, so it should move smoothly as you
scroll without jittering.
What to look for
- The TOC is sticky on desktop (
lg:breakpoint and above). - On mobile, it isn’t rendered — there’s no collapsed
<details>yet, that’s a known deferred item. - Links inside the prose body should be underlined with a wavy accent color, not black.
- The page title h1 should NOT appear inside the TOC — the filter is
depth >= 2 && depth <= 4.
Even deeper
h4 headings should also show up in the TOC, indented further than h3. This section exists to prove that.
Paragraphs and inline formatting
Here is a paragraph with bold text, italic text, both at once,
inline code, and a link to Astro docs. The
link should use the accent-color wavy underline from the prose overrides
in global.css.
Lists
An unordered list:
- First item
- Second item with bold inside it
- Third item with a link
- Fourth item with
inline code
An ordered list:
- One
- Two
- Three
Nested lists
- Parent
- Child A
- Child B
- Grandchild
- Sibling
Blockquote
This is a blockquote. It should render with a left border, muted foreground color, and italic text thanks to
@tailwindcss/typography. Multiple lines in the same block quote collapse into one paragraph.
A second, single-line quote for good measure.
Code blocks
Inline code like const x = 42; should use Geist Mono and pick up the
muted background from the prose overrides.
A JavaScript fence:
// This exercises rehype-pretty-code with the vitesse-light / vitesse-dark
// dual-theme setup. Switch the site theme with the header button and
// this block should recolor without a page reload.
function fibonacci(n) {
if (n < 2) return n;
let a = 0;
let b = 1;
for (let i = 2; i <= n; i++) {
const next = a + b;
a = b;
b = next;
}
return b;
}
console.log(fibonacci(10)); // 55
A TypeScript fence:
type Post = {
title: string;
pubDate: Date;
tags: string[];
};
const example: Post = {
title: "Hello",
pubDate: new Date("2026-04-13"),
tags: ["meta", "test"],
};
A shell fence:
npm run dev
npm run build
npx astro check
Another h3 under Code blocks
Confirming that h3 headings under the same parent h2 still appear in the TOC as siblings, indented correctly.
Horizontal rule and images
Below should be a horizontal rule:
And that’s it — there’s no image in this post because content collection
images need to be in src/content/posts/ alongside the MDX and the test
post doesn’t ship one.
A long section to force scrolling
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla ac neque nec arcu aliquet suscipit. Quisque tempor, nisi sed fermentum elementum, nibh arcu aliquet justo, vel feugiat nulla magna a lorem. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Proin eget tortor risus.
Mauris blandit aliquet elit, eget tincidunt nibh pulvinar a. Donec sollicitudin molestie malesuada. Vivamus suscipit tortor eget felis porttitor volutpat. Nulla quis lorem ut libero malesuada feugiat. Cras ultricies ligula sed magna dictum porta.
Sed porttitor lectus nibh. Mauris blandit aliquet elit, eget tincidunt nibh pulvinar a. Proin eget tortor risus. Quisque velit nisi, pretium ut lacinia in, elementum id enim. Vestibulum ac diam sit amet quam vehicula elementum sed sit amet dui.
Reading time sanity check
The header of this post should say something like “4 min read” or
similar — the remark-reading-time plugin counts words and clamps the
result to at least 1. If the number looks absurdly low or high, check
src/lib/remark-reading-time.mjs.
Scroll-spy sanity check
Scroll slowly from the top to here. The TOC link for “A long section to force scrolling” should become active as this section enters the top of the viewport. When you continue past this heading to the conclusion, the active link should advance accordingly.
Conclusion
If every section above renders cleanly, the TOC updates as you scroll, the progress bar advances, code blocks recolor when you toggle the theme, and the wavy heading anchors don’t strike through the heading text, the reading subsystem is in good shape.
Delete this file (src/content/posts/toc-test.mdx) once you’re
satisfied — it’s only here as a kitchen sink.