Initial commit

This commit is contained in:
Akshay Kolli
2026-02-07 20:17:46 -05:00
parent 78111a5b61
commit 649d9c4555
86 changed files with 9530 additions and 100 deletions

View File

@@ -0,0 +1,79 @@
'use client';
import { useEffect, useState } from 'react';
type Heading = {
id: string;
text: string;
level: number;
};
export function TableOfContents({ headings }: { headings: Heading[] }) {
const [activeId, setActiveId] = useState<string>('');
useEffect(() => {
const handleScroll = () => {
const headingElements = headings.map((heading) => ({
id: heading.id,
element: document.getElementById(heading.id),
}));
// Find the first heading that is currently visible or just above the fold
// We look for headings that are above the 150px mark
let currentActiveId = '';
for (const { id, element } of headingElements) {
if (!element) continue;
const rect = element.getBoundingClientRect();
// If the heading is within the top portion of the screen
// OR if we haven't found a better one yet, this one 'might' be it
// We basically want the *last* heading that has a 'top' value <= some threshold
if (rect.top <= 150) {
currentActiveId = id;
}
}
// If we are at the very bottom, it's likely the last item
if ((window.innerHeight + window.scrollY) >= document.body.offsetHeight - 50) {
if (headings.length > 0) currentActiveId = headings[headings.length - 1].id;
}
if (currentActiveId) {
setActiveId(currentActiveId);
}
};
window.addEventListener('scroll', handleScroll, { passive: true });
// Trigger once on mount
handleScroll();
return () => window.removeEventListener('scroll', handleScroll);
}, [headings]);
if (headings.length === 0) return null;
return (
<nav className="text-sm animate-fade-in text-left">
<h4 className="font-bold text-zinc-900 dark:text-zinc-100 mb-4 uppercase tracking-wider text-xs">On this page</h4>
<ul className="space-y-3">
{Array.isArray(headings) && headings.map((heading) => (
<li
key={heading.id}
style={{ paddingRight: `${(heading.level - 2) * 12}px` }}
>
<a
href={`#${heading.id}`}
className={`block transition-all duration-200 border-l-2 pl-4 ${activeId === heading.id
? 'border-zinc-900 dark:border-zinc-100 text-zinc-900 dark:text-zinc-50 font-bold'
: 'border-transparent text-zinc-500 dark:text-zinc-500 hover:text-zinc-700 dark:hover:text-zinc-300'
}`}
>
{heading.text}
</a>
</li>
))}
</ul>
</nav>
);
}