- Create GuidePage with responsive layout (sticky TOC sidebar desktop, collapsible accordion mobile) - Add GuideTableOfContents with scroll-based active section tracking - Create GuideScreenshot and GuideTable shared components - Add guideTypes.ts with section metadata for all 10 sections - Add lazy-loaded /guide route in App.tsx with public access - Placeholder section components for all 10 guide sections Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
93 lines
2.8 KiB
TypeScript
93 lines
2.8 KiB
TypeScript
import { useState, useEffect } from 'react';
|
|
import { Accordion, AccordionSummary, AccordionDetails } from '@mui/material';
|
|
import ExpandMoreIcon from '@mui/icons-material/ExpandMore';
|
|
import { guideSections } from './guideTypes';
|
|
|
|
interface GuideTableOfContentsProps {
|
|
activeSection: string;
|
|
}
|
|
|
|
export const GuideTableOfContents = ({ activeSection }: GuideTableOfContentsProps) => {
|
|
const [isMobile, setIsMobile] = useState(false);
|
|
const [tocExpanded, setTocExpanded] = useState(false);
|
|
|
|
useEffect(() => {
|
|
const check = () => setIsMobile(window.innerWidth < 768);
|
|
check();
|
|
window.addEventListener('resize', check);
|
|
return () => window.removeEventListener('resize', check);
|
|
}, []);
|
|
|
|
const handleClick = (sectionId: string) => {
|
|
const element = document.getElementById(sectionId);
|
|
if (element) {
|
|
element.scrollIntoView({ behavior: 'smooth', block: 'start' });
|
|
}
|
|
if (isMobile) {
|
|
setTocExpanded(false);
|
|
}
|
|
};
|
|
|
|
const tocContent = (
|
|
<nav aria-label="Table of contents">
|
|
<ul className="space-y-1">
|
|
{guideSections.map((section) => (
|
|
<li key={section.id}>
|
|
<button
|
|
onClick={() => handleClick(section.id)}
|
|
className={`w-full text-left px-3 py-3 rounded-md text-sm transition-colors ${
|
|
activeSection === section.id
|
|
? 'bg-primary-500/15 text-primary-400 font-semibold'
|
|
: 'text-titanio/70 hover:text-titanio hover:bg-white/5'
|
|
}`}
|
|
>
|
|
{section.title}
|
|
</button>
|
|
</li>
|
|
))}
|
|
</ul>
|
|
</nav>
|
|
);
|
|
|
|
if (isMobile) {
|
|
return (
|
|
<div className="mb-6">
|
|
<Accordion
|
|
expanded={tocExpanded}
|
|
onChange={(_, expanded) => setTocExpanded(expanded)}
|
|
sx={{
|
|
backgroundColor: 'rgba(255,255,255,0.03)',
|
|
border: '1px solid rgba(255,255,255,0.08)',
|
|
borderRadius: '8px !important',
|
|
'&:before': { display: 'none' },
|
|
}}
|
|
>
|
|
<AccordionSummary
|
|
expandIcon={<ExpandMoreIcon sx={{ color: 'rgba(168,184,192,0.7)' }} />}
|
|
sx={{
|
|
color: 'rgba(242,243,246,0.9)',
|
|
fontWeight: 600,
|
|
minHeight: 48,
|
|
'& .MuiAccordionSummary-content': { margin: '12px 0' },
|
|
}}
|
|
>
|
|
Table of Contents
|
|
</AccordionSummary>
|
|
<AccordionDetails sx={{ pt: 0 }}>
|
|
{tocContent}
|
|
</AccordionDetails>
|
|
</Accordion>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
return (
|
|
<aside className="sticky top-20 w-64 flex-shrink-0 max-h-[calc(100vh-6rem)] overflow-y-auto pr-4">
|
|
<h2 className="text-sm font-semibold text-titanio/50 uppercase tracking-wider mb-4 px-3">
|
|
Contents
|
|
</h2>
|
|
{tocContent}
|
|
</aside>
|
|
);
|
|
};
|