1
0
mirror of https://github.com/avinal/avinal.github.io.git synced 2026-07-04 07:40:09 +05:30

feat: add TOC, related posts, and reading progress bar

Assisted by Claude Code

Signed-off-by: Avinal Kumar <avinal.xlvii@gmail.com>
This commit is contained in:
2026-05-02 18:17:30 +05:30
parent f613005a23
commit 5fa9a10203
4 changed files with 304 additions and 1 deletions
+41
View File
@@ -1,5 +1,8 @@
---
import BaseLayout from "./BaseLayout.astro";
import TableOfContents from "@/components/TableOfContents.astro";
import RelatedPosts from "@/components/RelatedPosts.astro";
import type { CollectionEntry } from "astro:content";
interface Props {
title: string;
@@ -10,6 +13,8 @@ interface Props {
tags?: string[];
image?: string;
readingTime: string;
headings?: { depth: number; slug: string; text: string }[];
relatedPosts?: CollectionEntry<"posts">[];
}
const {
@@ -21,6 +26,8 @@ const {
tags = [],
image,
readingTime,
headings = [],
relatedPosts = [],
} = Astro.props;
const fmtDate = (d: Date) =>
@@ -49,6 +56,7 @@ const blogPostingLd = {
---
<BaseLayout title={title} description={description} ogImage={image || undefined} jsonLd={blogPostingLd}>
<div class="reading-progress" aria-hidden="true"></div>
<article class="post-page">
{image && (
<div class="post-hero-img">
@@ -83,9 +91,13 @@ const blogPostingLd = {
)}
</header>
{headings.length > 0 && <TableOfContents headings={headings} />}
<div class="prose">
<slot />
</div>
{relatedPosts.length > 0 && <RelatedPosts posts={relatedPosts} />}
</article>
</BaseLayout>
@@ -114,6 +126,7 @@ const blogPostingLd = {
margin-bottom: var(--space-10);
padding-bottom: var(--space-6);
border-bottom: 1px solid var(--border);
text-align: center;
}
.post-category {
@@ -136,6 +149,7 @@ const blogPostingLd = {
.post-meta-row {
display: flex;
align-items: center;
justify-content: center;
flex-wrap: wrap;
gap: var(--space-2);
font-size: var(--text-sm);
@@ -153,6 +167,7 @@ const blogPostingLd = {
.post-tags {
display: flex;
flex-wrap: wrap;
justify-content: center;
gap: var(--space-2);
margin-top: var(--space-3);
}
@@ -165,4 +180,30 @@ const blogPostingLd = {
border-radius: var(--radius-sm);
border: 1px solid var(--border);
}
.reading-progress {
position: fixed;
top: 0;
left: 0;
height: 3px;
width: 0%;
background-color: var(--accent);
z-index: 200;
pointer-events: none;
}
</style>
<script>
const bar = document.querySelector<HTMLElement>('.reading-progress');
const article = document.querySelector('.post-page');
if (bar && article) {
const update = () => {
const total = article.scrollHeight - window.innerHeight;
const scrolled = window.scrollY - (article as HTMLElement).offsetTop;
const pct = Math.min(100, Math.max(0, (scrolled / total) * 100));
bar.style.width = `${pct}%`;
};
window.addEventListener('scroll', update, { passive: true });
update();
}
</script>