From a80738c95db6406be71d53118119ef879b10d195 Mon Sep 17 00:00:00 2001 From: Ryan Cartwright Date: Tue, 8 Oct 2024 14:41:58 +1100 Subject: [PATCH 1/2] scroll only when headings have been reached --- src/app/[[...slug]]/layout.tsx | 1 - src/components/layout/DocToC.tsx | 56 ++++++++++++++++++------ src/components/layout/DocTracingBeam.tsx | 37 +++++----------- 3 files changed, 54 insertions(+), 40 deletions(-) diff --git a/src/app/[[...slug]]/layout.tsx b/src/app/[[...slug]]/layout.tsx index d871cc17f..02783991c 100644 --- a/src/app/[[...slug]]/layout.tsx +++ b/src/app/[[...slug]]/layout.tsx @@ -3,7 +3,6 @@ import { Prose } from '@/components/Prose' import React from 'react' import { allDocs } from '@/content' import DocToc from '@/components/layout/DocToC' -import { Feedback } from '@/components/Feedback' import { Button } from '@/components/ui/button' import { GitHubIcon } from '@/components/icons/GitHubIcon' import Breadcrumbs from '@/components/Breadcrumbs' diff --git a/src/components/layout/DocToC.tsx b/src/components/layout/DocToC.tsx index e3c219f3f..5110311dc 100644 --- a/src/components/layout/DocToC.tsx +++ b/src/components/layout/DocToC.tsx @@ -1,20 +1,12 @@ 'use client' import type { Doc } from '@/content' -import React, { useRef } from 'react' -import { Badge } from '../ui/badge' +import { useRef, useLayoutEffect, useState, useEffect } from 'react' import Link from 'next/link' -import { FaFacebook, FaFilePdf, FaLinkedin } from 'react-icons/fa' import { DocTracingBeam } from './DocTracingBeam' -import { BASE_URL } from '@/lib/constants' -import { title } from 'radash' import { Button } from '../ui/button' import { GitHubIcon } from '../icons/GitHubIcon' - -interface Props { - doc: Doc - articleRef?: React.RefObject -} +import { useMotionValue } from 'framer-motion' interface Toc { url: string @@ -22,18 +14,54 @@ interface Toc { depth: number } -const DocToC: React.FC = ({ doc }) => { - const articleRef = useRef(null) +const DocToC = ({ doc }: { doc: Doc }) => { + const initial = 14 + const sectionSize = 28 + const offset = 10 + + const y1 = useMotionValue(0) + const y2 = useMotionValue(0) + + useEffect(() => { + const headings = document + .querySelectorAll('.md-content-header') + .values() + .toArray() + + const options = { + root: null, + rootMargin: '0px', + threshold: 1, // Adjust based on when you want to highlight + } + + const observer = new IntersectionObserver((entries) => { + entries.forEach((entry) => { + if (entry.isIntersecting) { + const index = headings.findIndex( + (heading) => heading.textContent === entry.target.textContent, + ) + + y2.set(initial + (index * sectionSize + offset)) + } + }) + }, options) + + headings.forEach((h2) => observer.observe(h2)) + + return () => { + headings.forEach((h2) => observer.unobserve(h2)) + } + }, []) return ( -
+