diff --git a/src/LocationProvider.tsx b/src/LocationProvider.tsx index 4b8fd92..b7eb316 100644 --- a/src/LocationProvider.tsx +++ b/src/LocationProvider.tsx @@ -5,10 +5,17 @@ function appendSlashToPath(path: string): string { return path.endsWith("/") ? path : `${path}/` } +function getSecondLevel(path: string): string | void { + const [, , secondLevel] = path.split("/") + + return secondLevel +} + export interface ILocationContextInterface { location: WindowLocation | void isHome: boolean isMatchingPath: (path: string) => boolean + getSecondLevel: (path: string) => string | void } interface ILocationProviderProps { @@ -19,9 +26,9 @@ export const LocationContext = React.createContext -> = ({ children, location }) => { +export const LocationProvider: FC> = ({ children, location }) => { const memoizedContextValue = useMemo( () => ({ location, @@ -31,6 +38,7 @@ export const LocationProvider: FC< ? appendSlashToPath(location.pathname).startsWith(path) : false }, + getSecondLevel, }), [location] ) diff --git a/src/SidebarProvider.tsx b/src/SidebarProvider.tsx index 917a635..f69258e 100644 --- a/src/SidebarProvider.tsx +++ b/src/SidebarProvider.tsx @@ -1,8 +1,9 @@ -import React, { FC, useMemo, useState } from "react" +import React, { FC, useEffect, useMemo, useState } from "react" +import useLocation from "./hooks/useLocation" export interface ISidebarContextInterface { - current: number - setCurrent: (index: number) => void + current: string | null + setCurrent: (key: string) => void openOnMobile: boolean setOpenOnMobile: (active: boolean) => void } @@ -12,9 +13,19 @@ export const SidebarContext = React.createContext { - const [current, setCurrent] = useState(0) + const { location, getSecondLevel } = useLocation() + const [current, setCurrent] = useState(null) const [openOnMobile, setOpenOnMobile] = useState(false) + useEffect(() => { + if (location && location.pathname) { + const secondLevel = getSecondLevel(location.pathname) + setCurrent(secondLevel || null) + } else { + setCurrent(null) + } + }, [location]) + const memoizedContextValue = useMemo( () => ({ current, diff --git a/src/components/ResourcesSidebar/index.tsx b/src/components/ResourcesSidebar/index.tsx index da18d5e..f9ee91f 100644 --- a/src/components/ResourcesSidebar/index.tsx +++ b/src/components/ResourcesSidebar/index.tsx @@ -46,7 +46,6 @@ const childrenSort = sortWith([ function Tree({ item, - index, firstLevel, }: { item: IFileOrFolder @@ -74,8 +73,8 @@ function Tree({ ) } - if (firstLevel && index !== undefined) { - return + if (firstLevel) { + return } return @@ -108,46 +107,81 @@ function Folder({ item }: { item: IFolder }) { ) } -const FirstLevelFolder = memo( - ({ item, index }: { item: IFolder; index: number }) => { - const { current, setCurrent } = useSidebar() +const FirstLevelFolder = memo(({ item }: { item: IFolder }) => { + const { setCurrent } = useSidebar() - useMatchingPath(item.path, () => { - setCurrent(index) - }) + useMatchingPath(item.path, () => { + setCurrent(item.title) + }) - const collapsed = current !== index - const sortedChildren = childrenSort(item.children) + const sortedChildren = childrenSort(item.children) - return ( - - setCurrent(index)} - > - {humanize(item.title)} - - - - {sortedChildren.map(node => ( - + return ( + + {humanize(item.title)} + + {sortedChildren.map(node => ( + + ))} + + + ) +}) + +const AllLanguages: FC<{ + items: IFileOrFolder[] + expanded: boolean + setExpanded: React.Dispatch> +}> = ({ items, expanded, setExpanded }) => { + const { current, setCurrent } = useSidebar() + + return ( + + setExpanded(prevState => !prevState)} + > + Expand languages {expanded ? : } + + {expanded && ( + + {items.map(item => ( + { + setCurrent(item.title) + setExpanded(false) + }} + > + {item.title} + ))} - - - ) - } -) + + )} + + ) +} export const ResourcesSidebar: FC> = props => { + const [expandedLanguages, setExpandedLanguages] = useState(false) const resources = useStaticQuery(ALL_RESOURCES) - const tree = useBuildTree(resources, "/resources") - const sortedTree = sort((a, b) => a.title.localeCompare(b.title), tree) + const languages = useBuildTree(resources, "/resources") + const { current } = useSidebar() + const sortedLanguages = sort( + (a, b) => a.title.localeCompare(b.title), + languages + ) + + const currentLanguage = + sortedLanguages.find(lang => lang.title === current) || sortedLanguages[0] return ( - {sortedTree.map((node, index) => ( - - ))} + + ) } diff --git a/src/components/ResourcesSidebar/styles.tsx b/src/components/ResourcesSidebar/styles.tsx index fbcf973..4b0edf7 100644 --- a/src/components/ResourcesSidebar/styles.tsx +++ b/src/components/ResourcesSidebar/styles.tsx @@ -1,7 +1,9 @@ import { Link } from "gatsby" import { transparentize } from "polished" -import styled from "styled-components" +import styled, { css } from "styled-components" import ChevronUp from "../../icons/chevron-up.svg" +import Collapse from "../../icons/collapse.svg" +import Expand from "../../icons/expand.svg" export const Children = styled.div` padding-left: 16px; @@ -10,6 +12,10 @@ export const Children = styled.div` flex-direction: column; align-items: flex-start; overflow: hidden; + + &:last-child { + padding-bottom: 0; + } ` export const Label = styled.div` @@ -44,7 +50,7 @@ export const FirstLabel = styled.div` box-sizing: border-box; padding: 12px 15px 12px 0; font-weight: 700; - color: ${props => transparentize(0.5, props.theme.sidebar.foreground)}; + color: ${props => props.theme.sidebar.foreground}; cursor: pointer; &:hover { @@ -55,30 +61,17 @@ export const FirstLabel = styled.div` } } - &.active { - color: ${props => props.theme.sidebar.foreground}; - } - svg { margin-left: auto; transform: rotate(90deg); - transition: transform 0.3s; path { fill: ${props => transparentize(0.5, props.theme.sidebar.foreground)}; } } - - &.active svg { - transform: rotate(0); - - path { - fill: ${props => props.theme.sidebar.foreground}; - } - } ` -export const TreeWrapper = styled.div<{ collapsed: boolean }>` +export const TreeWrapper = styled.div<{ collapsed?: boolean }>` display: flex; flex-direction: column; width: 100%; @@ -88,11 +81,6 @@ export const TreeWrapper = styled.div<{ collapsed: boolean }>` overflow: hidden; } - & + & { - border-top: 1px solid - ${props => transparentize(0.8, props.theme.sidebar.foreground)}; - } - ${Children} { display: ${props => (props.collapsed ? "none" : "flex")}; } @@ -105,22 +93,64 @@ export const TreeWrapper = styled.div<{ collapsed: boolean }>` export const CollapseToggler = styled(ChevronUp)`` -export const PageLink = styled(Link)` +export const CollapseIcon = styled(Collapse)` + margin-left: auto; + + path { + fill: ${props => transparentize(0.5, props.theme.sidebar.foreground)}; + } +` + +export const ExpandIcon = styled(Expand)` + margin-left: auto; + + path { + fill: ${props => transparentize(0.5, props.theme.sidebar.foreground)}; + } +` + +export const ExpandLanguages = styled.div` + padding: 12px 15px 12px 0; + + border-bottom: 1px solid + ${props => transparentize(0.8, props.theme.sidebar.foreground)}; + margin-bottom: 8px; +` + +export const ExpandLanguagesHeader = styled.div` + user-select: none; + display: flex; + align-items: center; + cursor: pointer; + color: ${props => transparentize(0.5, props.theme.sidebar.foreground)}; + font-weight: 700; +` + +export const ExpandLanguagesList = styled.div` + padding: 8px 0; + display: flex; + flex-direction: column; + align-items: flex-start; + overflow: hidden; +` + +const item = css` display: block; - padding: 4px 0 0; margin-bottom: 4px; color: ${props => props.theme.sidebar.foreground}; align-self: flex-start; text-decoration: none; border-bottom: 2px solid transparent; + cursor: pointer; &:hover { border-color: ${props => transparentize(0.7, props.theme.sidebar.foreground)}; } - & + & { - margin-top: 4px; + & + &, + ${TreeWrapper} + & { + padding: 8px 0 0; } &.active { @@ -132,3 +162,11 @@ export const PageLink = styled(Link)` border-color: ${props => transparentize(0.7, props.theme.sidebar.active)}; } ` + +export const Language = styled.div` + ${item}; +` + +export const PageLink = styled(Link)` + ${item}; +` diff --git a/src/icons/collapse.svg b/src/icons/collapse.svg new file mode 100644 index 0000000..377c420 --- /dev/null +++ b/src/icons/collapse.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/icons/expand.svg b/src/icons/expand.svg new file mode 100644 index 0000000..dd562ae --- /dev/null +++ b/src/icons/expand.svg @@ -0,0 +1,4 @@ + + + +