mirror of
https://github.com/explosion/spaCy.git
synced 2025-02-14 10:30:34 +03:00
143 lines
5.3 KiB
JavaScript
143 lines
5.3 KiB
JavaScript
import React, { useState, useEffect, useRef } from 'react'
|
|
import PropTypes from 'prop-types'
|
|
import classNames from 'classnames'
|
|
import { window } from 'browser-monads'
|
|
|
|
import Link from './link'
|
|
import Dropdown from './dropdown'
|
|
import classes from '../styles/sidebar.module.sass'
|
|
|
|
function getActiveHeading(items, slug) {
|
|
if (/^\/?universe/.test(slug)) return 'Universe'
|
|
for (let section of items) {
|
|
for (let { isActive, url } of section.items) {
|
|
if (isActive || slug === url) {
|
|
return section.label
|
|
}
|
|
}
|
|
}
|
|
return 'Documentation'
|
|
}
|
|
|
|
const DropdownNavigation = ({ items, defaultValue }) => {
|
|
return (
|
|
<div className={classes.dropdown}>
|
|
<Dropdown className={classes.dropdownSelect} defaultValue={defaultValue}>
|
|
<option disabled>Select page...</option>
|
|
{items.map((section, i) =>
|
|
section.items.map(({ text, url }, j) => (
|
|
<option value={url} key={j}>
|
|
{section.label} › {text}
|
|
</option>
|
|
))
|
|
)}
|
|
</Dropdown>
|
|
</div>
|
|
)
|
|
}
|
|
|
|
const Sidebar = ({ items, pageMenu, slug }) => {
|
|
const [initialized, setInitialized] = useState(false)
|
|
const [activeSection, setActiveSection] = useState(null)
|
|
const activeRef = useRef()
|
|
const activeHeading = getActiveHeading(items, slug)
|
|
|
|
useEffect(() => {
|
|
const handleInView = ({ detail }) => setActiveSection(detail)
|
|
window.addEventListener('inview', handleInView, { passive: true })
|
|
if (!initialized) {
|
|
if (activeRef && activeRef.current) {
|
|
activeRef.current.scrollIntoView({ block: 'center' })
|
|
}
|
|
setInitialized(true)
|
|
}
|
|
return () => {
|
|
window.removeEventListener('inview', handleInView)
|
|
}
|
|
}, [initialized])
|
|
|
|
return (
|
|
<menu className={classNames('sidebar', classes.root)}>
|
|
<h1 hidden aria-hidden="true" className={classNames('h0', classes.activeHeading)}>
|
|
{activeHeading}
|
|
</h1>
|
|
<DropdownNavigation items={items} defaultValue={slug} />
|
|
{items.map((section, i) => (
|
|
<ul className={classes.section} key={i}>
|
|
<li className={classes.label}>{section.label}</li>
|
|
{section.items.map(({ text, url, onClick, menu, isActive }, j) => {
|
|
const currentMenu = menu || pageMenu || []
|
|
const active = isActive || slug === url
|
|
const itemClassNames = classNames(classes.link, {
|
|
[classes.isActive]: active,
|
|
'is-active': active,
|
|
})
|
|
|
|
return (
|
|
<li key={j} ref={active ? activeRef : null}>
|
|
<Link
|
|
to={url}
|
|
onClick={onClick}
|
|
className={itemClassNames}
|
|
hideIcon
|
|
>
|
|
{text}
|
|
</Link>
|
|
{active && !!currentMenu.length && (
|
|
<ul className={classes.crumbs}>
|
|
{currentMenu.map(crumb => {
|
|
const currentActive = activeSection || currentMenu[0].id
|
|
const crumbClassNames = classNames(classes.crumb, {
|
|
[classes.crumbActive]: currentActive === crumb.id,
|
|
})
|
|
return (
|
|
<li className={crumbClassNames} key={crumb.id}>
|
|
<a href={`#${crumb.id}`}>{crumb.text}</a>
|
|
</li>
|
|
)
|
|
})}
|
|
</ul>
|
|
)}
|
|
</li>
|
|
)
|
|
})}
|
|
</ul>
|
|
))}
|
|
</menu>
|
|
)
|
|
}
|
|
|
|
Sidebar.defaultProps = {
|
|
items: [],
|
|
pageMenu: [],
|
|
}
|
|
|
|
Sidebar.propTypes = {
|
|
items: PropTypes.arrayOf(
|
|
PropTypes.shape({
|
|
label: PropTypes.string.isRequired,
|
|
items: PropTypes.arrayOf(
|
|
PropTypes.shape({
|
|
text: PropTypes.string.isRequired,
|
|
url: PropTypes.string,
|
|
onClick: PropTypes.func,
|
|
menu: PropTypes.arrayOf(
|
|
PropTypes.shape({
|
|
text: PropTypes.string.isRequired,
|
|
id: PropTypes.string.isRequired,
|
|
})
|
|
),
|
|
})
|
|
).isRequired,
|
|
})
|
|
),
|
|
pageMenu: PropTypes.arrayOf(
|
|
PropTypes.shape({
|
|
text: PropTypes.string.isRequired,
|
|
id: PropTypes.string.isRequired,
|
|
})
|
|
),
|
|
}
|
|
|
|
export default Sidebar
|