Skip to content
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
164 changes: 120 additions & 44 deletions src/components/Layout/Toc.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,58 +6,134 @@
import {useTocHighlight} from './useTocHighlight';
import type {Toc} from '../MDX/TocContext';

import {useState, useEffect} from 'react';

function ScrollToTop() {
const [isVisible, setIsVisible] = useState(false);

// 控制按钮显示
const toggleVisibility = () => {
if (window.pageYOffset > 300) {
setIsVisible(true);
} else {
setIsVisible(false);
}
};

// 滚动到顶部
const scrollToTop = () => {
window.scrollTo({
top: 0,
behavior: 'smooth',
});
};

useEffect(() => {
window.addEventListener('scroll', toggleVisibility);
return () => {
window.removeEventListener('scroll', toggleVisibility);
};
}, []);

return (
<>
{isVisible && (
<div
onClick={scrollToTop}
style={{
position: 'fixed',
bottom: '40px',
right: '40px',
cursor: 'pointer',
backgroundColor: '#007bff',
borderRadius: '50%',
width: '40px',
height: '40px',
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
boxShadow: '0 2px 10px rgba(0,0,0,0.2)',
transition: 'all 0.3s ease',
opacity: '0.8',
zIndex: 1000,
'&:hover': {

Check failure on line 59 in src/components/Layout/Toc.tsx

View workflow job for this annotation

GitHub Actions / Lint on node 20.x and ubuntu-latest

Type '{ position: "fixed"; bottom: string; right: string; cursor: "pointer"; backgroundColor: "#007bff"; borderRadius: string; width: string; height: string; display: "flex"; justifyContent: "center"; ... 5 more ...; '&:hover': { ...; }; }' is not assignable to type 'Properties<string | number, string & {}>'.
opacity: 1,
transform: 'translateY(-2px)',
},
}}>
<svg
width="20"
height="20"
viewBox="0 0 24 24"
fill="none"
stroke="white"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round">
<path d="M12 19V5M5 12l7-7 7 7" />
</svg>
</div>
)}
</>
);
}

export function Toc({headings}: {headings: Toc}) {
const {currentIndex} = useTocHighlight();
// TODO: We currently have a mismatch between the headings in the document
// and the headings we find in MarkdownPage (i.e. we don't find Recap or Challenges).
// Select the max TOC item we have here for now, but remove this after the fix.
const selectedIndex = Math.min(currentIndex, headings.length - 1);

return (
<nav role="navigation" className="pt-20 sticky top-0 end-0">
{headings.length > 0 && (
<h2 className="mb-3 lg:mb-3 uppercase tracking-wide font-bold text-sm text-secondary dark:text-secondary-dark px-4 w-full">
On this page
</h2>
)}
<div
className="h-full overflow-y-auto ps-4 max-h-[calc(100vh-7.5rem)]"
style={{
overscrollBehavior: 'contain',
}}>
<ul className="space-y-2 pb-16">
{headings.length > 0 &&
headings.map((h, i) => {
if (!h.url && process.env.NODE_ENV === 'development') {
console.error('Heading does not have URL');
}
return (
<li
key={`heading-${h.url}-${i}`}
className={cx(
'text-sm px-2 rounded-s-xl',
selectedIndex === i
? 'bg-highlight dark:bg-highlight-dark'
: null,
{
'ps-4': h?.depth === 3,
hidden: h.depth && h.depth > 3,
}
)}>
<a
<>
<nav role="navigation" className="pt-20 sticky top-0 end-0">
{headings.length > 0 && (
<h2 className="mb-3 lg:mb-3 uppercase tracking-wide font-bold text-sm text-secondary dark:text-secondary-dark px-4 w-full">
On this page
</h2>
)}
<div
className="h-full overflow-y-auto ps-4 max-h-[calc(100vh-7.5rem)]"
style={{
overscrollBehavior: 'contain',
}}>
<ul className="space-y-2 pb-16">
{headings.length > 0 &&
headings.map((h, i) => {
if (!h.url && process.env.NODE_ENV === 'development') {
console.error('Heading does not have URL');
}
return (
<li
key={`heading-${h.url}-${i}`}
className={cx(
'text-sm px-2 rounded-s-xl',
selectedIndex === i
? 'text-link dark:text-link-dark font-bold'
: 'text-secondary dark:text-secondary-dark',
'block hover:text-link dark:hover:text-link-dark leading-normal py-2'
)}
href={h.url}>
{h.text}
</a>
</li>
);
})}
</ul>
</div>
</nav>
? 'bg-highlight dark:bg-highlight-dark'
: null,
{
'ps-4': h?.depth === 3,
hidden: h.depth && h.depth > 3,
}
)}>
<a
className={cx(
selectedIndex === i
? 'text-link dark:text-link-dark font-bold'
: 'text-secondary dark:text-secondary-dark',
'block hover:text-link dark:hover:text-link-dark leading-normal py-2'
)}
href={h.url}>
{h.text}
</a>
</li>
);
})}
</ul>
</div>
</nav>
<ScrollToTop />
</>
);
}
Loading