mirror of
https://github.com/GitbookIO/gitbook.git
synced 2026-09-24 11:26:31 +00:00
Page outline: scroll to active item (#3578)
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"gitbook": patch
|
||||
---
|
||||
|
||||
Page outline: scroll to active item
|
||||
@@ -40,6 +40,7 @@ export function PageAside(props: {
|
||||
'group/aside',
|
||||
'hidden',
|
||||
'pt-8',
|
||||
'pb-4',
|
||||
|
||||
'xl:flex',
|
||||
'xl:max-3xl:chat-open:hidden',
|
||||
@@ -111,7 +112,7 @@ export function PageAside(props: {
|
||||
>
|
||||
<PageAsideHeader context={context} />
|
||||
{page.layout.outline ? (
|
||||
<div className="overflow-y-auto border-tint xl:max-2xl:page-api-block:border-t">
|
||||
<div className="flex shrink flex-col overflow-hidden">
|
||||
{document ? (
|
||||
<React.Suspense fallback={null}>
|
||||
<PageAsideSections document={document} context={context} />
|
||||
@@ -165,11 +166,7 @@ async function PageAsideSections(props: { document: JSONDocument; context: GitBo
|
||||
|
||||
const sections = await getDocumentSections(context, document);
|
||||
|
||||
return sections.length > 1 ? (
|
||||
<div className="-mt-8 pt-8 pb-5 empty:hidden xl:max-2xl:page-api-block:mt-0 xl:max-2xl:page-api-block:p-2">
|
||||
<ScrollSectionsList sections={sections} />
|
||||
</div>
|
||||
) : null;
|
||||
return sections.length > 1 ? <ScrollSectionsList sections={sections} /> : null;
|
||||
}
|
||||
|
||||
function PageAsideActions(props: {
|
||||
@@ -199,7 +196,7 @@ function PageAsideActions(props: {
|
||||
'border-t',
|
||||
'first:border-none',
|
||||
'border-tint-subtle',
|
||||
'py-5',
|
||||
'pt-5',
|
||||
'first:pt-0',
|
||||
'xl:max-2xl:page-api-block:p-5',
|
||||
'empty:hidden'
|
||||
@@ -275,7 +272,7 @@ async function PageAsideFooter(props: { context: GitBookSiteContext }) {
|
||||
'sticky bottom-0 z-10 mt-auto flex flex-col',
|
||||
'bg-tint-base theme-gradient-tint:bg-gradient-tint theme-gradient:bg-gradient-primary theme-muted:bg-tint-subtle [html.sidebar-filled.theme-bold.tint_&]:bg-tint-subtle',
|
||||
'border-tint-subtle xl:max-2xl:page-api-block:border-t xl:max-2xl:page-api-block:p-2',
|
||||
'py-4'
|
||||
'pt-4'
|
||||
)}
|
||||
>
|
||||
{/* Mode Switcher */}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
'use client';
|
||||
import { motion } from 'framer-motion';
|
||||
import React from 'react';
|
||||
|
||||
import { useScrollActiveId } from '@/components/hooks';
|
||||
@@ -15,6 +14,11 @@ import { AsideSectionHighlight } from './AsideSectionHighlight';
|
||||
*/
|
||||
const SECTION_INTERSECTING_THRESHOLD = 0.9;
|
||||
|
||||
/**
|
||||
* The offset from the top of the page when scrolling to the active item.
|
||||
*/
|
||||
const ACTIVE_ITEM_OFFSET = 100;
|
||||
|
||||
const springCurve = {
|
||||
type: 'spring',
|
||||
stiffness: 700,
|
||||
@@ -39,10 +43,25 @@ export function ScrollSectionsList(props: { sections: DocumentSection[] }) {
|
||||
enabled,
|
||||
});
|
||||
|
||||
const scrollContainerRef = React.useRef<HTMLUListElement>(null);
|
||||
const activeItemRef = React.useRef<HTMLLIElement>(null);
|
||||
|
||||
React.useEffect(() => {
|
||||
if (activeId && activeItemRef.current && scrollContainerRef.current) {
|
||||
scrollContainerRef.current?.scrollTo({
|
||||
top: activeItemRef.current.offsetTop - ACTIVE_ITEM_OFFSET,
|
||||
behavior: 'smooth',
|
||||
});
|
||||
}
|
||||
}, [activeId]);
|
||||
|
||||
return (
|
||||
<ul className="flex flex-col border-tint-subtle sidebar-list-line:border-l">
|
||||
<ul
|
||||
className="relative flex flex-col overflow-y-auto border-tint-subtle sidebar-list-line:border-l pb-5 xl:max-2xl:page-api-block:mt-0 xl:max-2xl:page-api-block:p-2"
|
||||
ref={scrollContainerRef}
|
||||
>
|
||||
{sections.map((section) => (
|
||||
<motion.li
|
||||
<li
|
||||
key={section.id}
|
||||
className={tcls(
|
||||
'flex',
|
||||
@@ -54,6 +73,7 @@ export function ScrollSectionsList(props: { sections: DocumentSection[] }) {
|
||||
'mb-0.5',
|
||||
section.depth > 1 && ['ml-3', 'my-0', 'sidebar-list-line:ml-0']
|
||||
)}
|
||||
ref={activeId === section.id ? activeItemRef : null}
|
||||
>
|
||||
{activeId === section.id ? (
|
||||
<AsideSectionHighlight
|
||||
@@ -148,7 +168,7 @@ export function ScrollSectionsList(props: { sections: DocumentSection[] }) {
|
||||
{section.title}
|
||||
</span>
|
||||
</a>
|
||||
</motion.li>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user