refactor: Migrate documentation content, rebuild UI components, and update core architecture.
This commit is contained in:
@@ -1,68 +1,80 @@
|
||||
import { useState, useCallback, useEffect, useRef } from 'react';
|
||||
import { TocItem } from '@/lib/toc';
|
||||
"use client"
|
||||
|
||||
import { useState, useCallback, useEffect, useRef } from "react"
|
||||
import { TocItem } from "@/lib/toc"
|
||||
|
||||
export function useActiveSection(tocs: TocItem[]) {
|
||||
const [activeId, setActiveId] = useState<string | null>(null);
|
||||
const observerRef = useRef<IntersectionObserver | null>(null);
|
||||
const clickedIdRef = useRef<string | null>(null);
|
||||
const [activeId, setActiveId] = useState<string | null>(null)
|
||||
const observerRef = useRef<IntersectionObserver | null>(null)
|
||||
const clickedIdRef = useRef<string | null>(null)
|
||||
|
||||
const activeIdRef = useRef<string | null>(null)
|
||||
|
||||
useEffect(() => {
|
||||
activeIdRef.current = activeId
|
||||
}, [activeId])
|
||||
|
||||
// Handle intersection observer for active section
|
||||
useEffect(() => {
|
||||
if (typeof document === 'undefined' || !tocs.length) return;
|
||||
if (typeof document === "undefined" || !tocs.length) return
|
||||
|
||||
const handleIntersect = (entries: IntersectionObserverEntry[]) => {
|
||||
if (clickedIdRef.current) return;
|
||||
if (clickedIdRef.current) return
|
||||
|
||||
const visibleEntries = entries.filter(entry => entry.isIntersecting);
|
||||
if (!visibleEntries.length) return;
|
||||
const visibleEntries = entries.filter((entry) => entry.isIntersecting)
|
||||
if (!visibleEntries.length) return
|
||||
|
||||
// Find the most visible entry
|
||||
const mostVisibleEntry = visibleEntries.reduce((prev, current) => {
|
||||
return current.intersectionRatio > prev.intersectionRatio ? current : prev;
|
||||
}, visibleEntries[0]);
|
||||
return current.intersectionRatio > prev.intersectionRatio ? current : prev
|
||||
}, visibleEntries[0])
|
||||
|
||||
const newActiveId = mostVisibleEntry.target.id;
|
||||
if (newActiveId !== activeId) {
|
||||
setActiveId(newActiveId);
|
||||
const newActiveId = mostVisibleEntry.target.id
|
||||
if (newActiveId !== activeIdRef.current) {
|
||||
setActiveId(newActiveId)
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// Determine the scroll root: #scroll-container is only used on desktop (lg)
|
||||
const isDesktop = window.innerWidth >= 1024
|
||||
const container = isDesktop ? document.getElementById("scroll-container") : null
|
||||
|
||||
// Initialize intersection observer
|
||||
observerRef.current = new IntersectionObserver(handleIntersect, {
|
||||
root: null,
|
||||
rootMargin: '0px 0px -80% 0px',
|
||||
threshold: 0.1,
|
||||
});
|
||||
root: container,
|
||||
rootMargin: isDesktop ? "0px 0px -60% 0px" : "-160px 0px -60% 0px",
|
||||
threshold: 0,
|
||||
})
|
||||
|
||||
// Observe all headings
|
||||
tocs.forEach(toc => {
|
||||
const element = document.getElementById(toc.href.slice(1));
|
||||
tocs.forEach((toc) => {
|
||||
const element = document.getElementById(toc.href.slice(1))
|
||||
if (element) {
|
||||
observerRef.current?.observe(element);
|
||||
observerRef.current?.observe(element)
|
||||
}
|
||||
});
|
||||
})
|
||||
|
||||
// Cleanup
|
||||
return () => {
|
||||
observerRef.current?.disconnect();
|
||||
};
|
||||
}, [tocs, activeId]);
|
||||
observerRef.current?.disconnect()
|
||||
}
|
||||
}, [tocs]) // Only depend on tocs, handle activeId via ref
|
||||
|
||||
const handleLinkClick = useCallback((id: string) => {
|
||||
clickedIdRef.current = id;
|
||||
setActiveId(id);
|
||||
clickedIdRef.current = id
|
||||
setActiveId(id)
|
||||
|
||||
// Reset clicked state after scroll completes
|
||||
const timer = setTimeout(() => {
|
||||
clickedIdRef.current = null;
|
||||
}, 1000);
|
||||
clickedIdRef.current = null
|
||||
}, 1000)
|
||||
|
||||
return () => clearTimeout(timer);
|
||||
}, []);
|
||||
return () => clearTimeout(timer)
|
||||
}, [])
|
||||
|
||||
return {
|
||||
activeId,
|
||||
setActiveId,
|
||||
handleLinkClick,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user