import { graphql, useStaticQuery } from "gatsby" import descend from "ramda/es/descend" import sortWith from "ramda/es/sortWith" import React, { FC, HTMLAttributes, memo, useState } from "react" import { useLockBodyScroll } from "../../hooks/useLockBodyScroll" import useSidebar from "../../hooks/useSidebar" import TriangleDown from "../../icons/triangle-down.svg" import { IFileOrFolder, IFolder } from "../../types" import { getPath, humanize } from "../../utils" import { Sidebar } from "../Sidebar" import * as SC from "./styles" import useMatchingPath from "./useMatchingPath" import useTree from "./useTree" const ALL_RESOURCES = graphql` query AllTopicsAndAllLanguages { languages: allFile(filter: { sourceInstanceName: { eq: "languages" } }) { edges { node { relativePath childMdx { frontmatter { authors title } } } } } topics: allFile(filter: { sourceInstanceName: { eq: "topics" } }) { edges { node { relativePath childMdx { frontmatter { authors title } } } } } } ` const childrenSort = sortWith([ descend((f) => { if (f.title === "intro") { return 1 } if (f.type === "folder") { return 0 } return -1 }), ]) function Tree({ item, firstLevel, }: { item: IFileOrFolder index?: number firstLevel?: boolean }) { const { setOpenOnMobile } = useSidebar() const { unlock } = useLockBodyScroll() if (item.type === "file") { const path = getPath(item) return ( { setOpenOnMobile(false) unlock() }} > {humanize(item.title)} ) } if (firstLevel) { return } return } function Folder({ item }: { item: IFolder }) { const [collapsed, setCollapse] = useState(true) useMatchingPath(item.path, () => { setCollapse(false) }) function toggleCollapse() { setCollapse((prevState) => !prevState) } const sortedChildren = childrenSort(item.children) return ( {humanize(item.title)} {sortedChildren.map((node) => ( ))} ) } const FirstLevelFolder = memo(({ item }: { item: IFolder }) => { const { setCurrent } = useSidebar() const isProject = item.path.startsWith("/resources/projects") useMatchingPath(item.path, () => { setCurrent(item.title) }) const sortedChildren = childrenSort(item.children) return ( {humanize(item.title)} {sortedChildren .filter((child) => { // TODO: clean me up, temporary fix if (isProject && child.title === "intro") return false return true }) .map((node) => ( ))} ) }) FirstLevelFolder.displayName = "FirstLevelFolder" const ResourceList: FC<{ items: IFileOrFolder[] setExpanded: React.Dispatch> }> = ({ items, setExpanded }) => { const { current, setCurrent } = useSidebar() return ( {items.map((item) => ( { setCurrent(item.title) setExpanded(false) }} > {item.title} ))} ) } const ExpandResources: FC<{ expanded: boolean setExpanded: React.Dispatch> }> = ({ children, expanded, setExpanded }) => { const { current } = useSidebar() const showList = expanded || !current return ( {current && ( setExpanded((prevState) => !prevState)} > Expand resources {expanded ? : } )} {showList && children} ) } export const ResourcesSidebar: FC> = (props) => { const [expanded, setExpanded] = useState(false) const resources = useStaticQuery(ALL_RESOURCES) const languagesTree = useTree(resources.languages) const topicsTree = useTree(resources.topics) const { current } = useSidebar() const currentLanguage = languagesTree.find((lang) => lang.title === current) const currentTopic = topicsTree.find((topic) => topic.title === current) return ( {currentLanguage && } {currentTopic && } ) }