aboutsummaryrefslogtreecommitdiff
path: root/src/components/Sidebar/index.js
blob: ac57ceefcff0f4bcd6b23bffdfaef32a3c20c460 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
/** @jsx jsx */
import { useCallback, useMemo, useState } from "react";
import { useStaticQuery, graphql, withPrefix } from "gatsby";
import { jsx } from "theme-ui";
import SidebarContent from "../../sidebar.mdx";
import Branding from "./Branding";
import Link from "../Link";
import Item, { isItemActive } from "./Item";
import { getActiveItem, getActiveItemParentLinks, getItems } from "./utils";

const setOpenItems = (state, items) => {
  for (const item of items) {
    if (item.items) {
      state.openItems[item.link] =
        isItemActive(state.activeItemParentLinks, item) ||
        withPrefix(state.activeItem.link) === item.link;

      setOpenItems(state, item.items);
    }
  }
};

function Sidebar({ children, sidebar, open = true, location }) {
  const { site } = useStaticQuery(graphql`
    query {
      site {
        pathPrefix
      }
    }
  `);

  const items = useMemo(() => getItems(children, site.pathPrefix), [
    children,
    site.pathPrefix
  ]);

  const [{ openItems, activeItem, activeItemParentLinks }, setState] = useState(
    () => {
      const activeItem = getActiveItem(items, location);

      const state = {
        openItems: {},
        activeItem,
        activeItemParentLinks: getActiveItemParentLinks(items, activeItem, [])
      };

      setOpenItems(state, items);

      return state;
    }
  );

  const toggleItem = useCallback(item => {
    setState(state => ({
      ...state,
      openItems: {
        ...state.openItems,
        [item.link]: !state.openItems[item.link]
      }
    }));
  }, []);

  return (
    <section
      id="__sidebar"
      key="sidebar"
      ref={sidebar}
      tabIndex="-1"
      className={open ? "active" : ""}
      sx={{ variant: "layout.sidebar", zIndex: 99 }}
    >
      <Branding />

      <nav
        aria-label="Navigation Menu"
        sx={{
          variant: "layout.container",
          px: 0,
          ul: { listStyle: "none", m: 0, p: 0 }
        }}
      >
        <ul sx={{ ul: { pl: "1.5em" } }}>
          {items.map(item => (
            <Item
              key={item.link}
              item={item}
              location={location}
              openItems={openItems}
              activeItem={activeItem}
              activeItemParentLinks={activeItemParentLinks}
              toggleItem={toggleItem}
            />
          ))}
        </ul>
      </nav>

      <Link to="/search/" sx={{ pl: "1em", variant: "linkStyles.nav" }}>
        Search
      </Link>
    </section>
  );
}

export default props => (
  <SidebarContent
    {...props}
    components={{
      wrapper: Sidebar
    }}
  />
);