Merge pull request #162 from the-programmers-hangout/feat-improve-sidebar-ux

feat(resources): improve sidebar ux
This commit is contained in:
Jean-Philippe Sirois
2019-11-08 19:39:16 -08:00
committed by GitHub
6 changed files with 92 additions and 8 deletions
+43
View File
@@ -0,0 +1,43 @@
import { WindowLocation } from "@reach/router"
import React, { FC, PropsWithChildren, useMemo } from "react"
function appendSlashToPath(path: string): string {
return path.endsWith("/") ? path : `${path}/`
}
export interface ILocationContextInterface {
location: WindowLocation | void
isHome: boolean
isMatchingPath: (path: string) => boolean
}
interface ILocationProviderProps {
location: WindowLocation | void
}
export const LocationContext = React.createContext<ILocationContextInterface | null>(
null
)
export const LocationProvider: FC<
PropsWithChildren<ILocationProviderProps>
> = ({ children, location }) => {
const memoizedContextValue = useMemo(
() => ({
location,
isHome: location ? location.pathname === "/" : false,
isMatchingPath: (path: string) => {
return location
? appendSlashToPath(location.pathname).startsWith(path)
: false
},
}),
[location]
)
return (
<LocationContext.Provider value={memoizedContextValue}>
{children}
</LocationContext.Provider>
)
}
+10
View File
@@ -10,6 +10,7 @@ import { ThemeToggler } from "../ThemeToggler"
import useSidebar from "./../../hooks/useSidebar" import useSidebar from "./../../hooks/useSidebar"
import * as SC from "./styles" import * as SC from "./styles"
import useBuildTree from "./useBuildTree" import useBuildTree from "./useBuildTree"
import useMatchingPath from "./useMatchingPath"
const ALL_RESOURCES = graphql` const ALL_RESOURCES = graphql`
query { query {
@@ -49,6 +50,10 @@ function plantTree(item: IFileOrFolder, index?: number, firstLevel?: boolean) {
function Folder({ item }: { item: IFolder }) { function Folder({ item }: { item: IFolder }) {
const [collapsed, setCollapse] = useState(true) const [collapsed, setCollapse] = useState(true)
useMatchingPath(item.path, () => {
setCollapse(false)
})
function toggleCollapse() { function toggleCollapse() {
setCollapse(prevState => !prevState) setCollapse(prevState => !prevState)
} }
@@ -66,6 +71,11 @@ function Folder({ item }: { item: IFolder }) {
const FirstLevelFolder = memo( const FirstLevelFolder = memo(
({ item, index }: { item: IFolder; index: number }) => { ({ item, index }: { item: IFolder; index: number }) => {
const { current, setCurrent } = useSidebar() const { current, setCurrent } = useSidebar()
useMatchingPath(item.path, () => {
setCurrent(index)
})
const collapsed = current !== index const collapsed = current !== index
return ( return (
@@ -0,0 +1,12 @@
import { useEffect } from "react"
import useLocation from "../../hooks/useLocation"
export default function useMatchingPath(path: string, callback: () => void) {
const { isMatchingPath } = useLocation()
useEffect(() => {
if (isMatchingPath(path)) {
callback()
}
}, [])
}
+12
View File
@@ -0,0 +1,12 @@
import { useContext } from "react"
import { ILocationContextInterface, LocationContext } from "../LocationProvider"
export default function useLocation(): ILocationContextInterface {
const locationContext = useContext(LocationContext)
if (!locationContext) {
throw Error("Need context")
}
return locationContext
}
+3 -2
View File
@@ -13,12 +13,13 @@ import { Footer } from "../../components/Footer"
import { Header } from "../../components/Header" import { Header } from "../../components/Header"
import { WavesBottom } from "../../components/Waves" import { WavesBottom } from "../../components/Waves"
import { GlobalStyles } from "../../globalStyles" import { GlobalStyles } from "../../globalStyles"
import useLocation from "../../hooks/useLocation"
import { useLockBodyScroll } from "../../hooks/useLockBodyScroll" import { useLockBodyScroll } from "../../hooks/useLockBodyScroll"
import { ThemeProvider } from "../../ThemeProvider" import { ThemeProvider } from "../../ThemeProvider"
import * as SC from "./styles" import * as SC from "./styles"
export const Layout: FC<RouteComponentProps> = ({ children, location }) => { export const Layout: FC<RouteComponentProps> = ({ children }) => {
const isHome = location ? location.pathname === "/" : false const { isHome } = useLocation()
const { locked, unlock } = useLockBodyScroll() const { locked, unlock } = useLockBodyScroll()
useEffect(() => { useEffect(() => {
+12 -6
View File
@@ -1,4 +1,6 @@
import { WindowLocation } from "@reach/router"
import React, { PropsWithChildren } from "react" import React, { PropsWithChildren } from "react"
import { LocationProvider } from "../LocationProvider"
import { Layout } from "./Layout" import { Layout } from "./Layout"
import { ResourcesLayout } from "./ResourcesLayout" import { ResourcesLayout } from "./ResourcesLayout"
@@ -10,11 +12,15 @@ export default function BaseLayout({
pageContext: { pageContext: {
layout?: string layout?: string
} }
location: Location location: WindowLocation
}>) { }>) {
if (pageContext.layout === "resources") { return (
return <ResourcesLayout>{children}</ResourcesLayout> <LocationProvider location={location}>
} {pageContext.layout === "resources" ? (
<ResourcesLayout>{children}</ResourcesLayout>
return <Layout location={location}>{children}</Layout> ) : (
<Layout>{children}</Layout>
)}
</LocationProvider>
)
} }