Monorepo containing core modules of Zeichen.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

283 lines
6.6 KiB

  1. import * as React from 'react'
  2. import styled, { createGlobalStyle } from 'styled-components'
  3. import SecondaryNavItem from '../SecondaryNavItem/SecondaryNavItem'
  4. import PrimaryNavItem from '../PrimaryNavItem/PrimaryNavItem'
  5. import Link from 'next/link'
  6. const Base = styled('aside')({
  7. width: 360,
  8. height: '100%',
  9. position: 'fixed',
  10. top: 0,
  11. left: -360,
  12. backgroundColor: 'var(--color-fg)',
  13. color: 'var(--color-bg)',
  14. zIndex: 1,
  15. '@media (min-width: 1080px)': {
  16. width: `${100 / 3}%`,
  17. left: 0,
  18. },
  19. })
  20. const PrimaryNavItems = styled('nav')({
  21. width: '100%',
  22. height: '4rem',
  23. position: 'fixed',
  24. bottom: 0,
  25. left: 0,
  26. zIndex: 1,
  27. backgroundColor: 'var(--color-fg)',
  28. color: 'var(--color-bg)',
  29. justifyContent: 'center',
  30. '@media (min-width: 1080px)': {
  31. position: 'static',
  32. bottom: 'auto',
  33. left: 'auto',
  34. width: '4rem',
  35. height: '100%',
  36. },
  37. })
  38. const PrimaryNavItemsContainer = styled('div')({
  39. width: '100%',
  40. height: '100%',
  41. maxWidth: 720,
  42. display: 'flex',
  43. margin: '0 auto',
  44. '@media (min-width: 1080px)': {
  45. width: '100%',
  46. flexDirection: 'column',
  47. justifyContent: 'space-between',
  48. alignItems: 'stretch',
  49. },
  50. })
  51. const PrimaryNavItemGroup = styled('div')({
  52. display: 'contents',
  53. '@media (min-width: 1080px)': {
  54. display: 'block',
  55. },
  56. })
  57. const SecondaryNavItems = styled('nav')({
  58. width: '100%',
  59. height: '100%',
  60. position: 'fixed',
  61. top: 0,
  62. left: 0,
  63. paddingBottom: '4rem',
  64. boxSizing: 'border-box',
  65. pointerEvents: 'none',
  66. '@media (min-width: 1080px)': {
  67. position: 'relative',
  68. top: 'auto',
  69. left: 'auto',
  70. flex: 'auto',
  71. width: 'auto',
  72. paddingBottom: 0,
  73. pointerEvents: 'initial',
  74. },
  75. })
  76. const SecondaryNavItemsFg = styled('div')({
  77. height: '100%',
  78. backgroundColor: 'var(--color-bg)',
  79. width: 360,
  80. position: 'absolute',
  81. top: 0,
  82. left: -360,
  83. paddingBottom: '4rem',
  84. boxSizing: 'border-box',
  85. transitionProperty: 'left',
  86. transitionDuration: '350ms',
  87. transitionTimingFunction: 'ease-out',
  88. '::before': {
  89. content: "''",
  90. display: 'block',
  91. top: 0,
  92. left: 0,
  93. width: '100%',
  94. height: '100%',
  95. position: 'absolute',
  96. backgroundColor: 'black',
  97. opacity: 0.03125,
  98. },
  99. '@media (min-width: 1080px)': {
  100. position: 'relative',
  101. top: 'auto',
  102. left: 'auto',
  103. flex: 'auto',
  104. width: 'auto',
  105. paddingBottom: 0,
  106. },
  107. })
  108. const SecondaryNavItemsBg = styled('a')({
  109. opacity: 0,
  110. transitionProperty: 'opacity',
  111. transitionDuration: '350ms',
  112. transitionTimingFunction: 'ease-out',
  113. '::before': {
  114. content: "''",
  115. display: 'block',
  116. top: 0,
  117. left: 0,
  118. width: '100%',
  119. height: '100%',
  120. position: 'absolute',
  121. backgroundColor: 'black',
  122. opacity: 0.75,
  123. },
  124. })
  125. const SecondaryNavItemsOverflow = styled('div')({
  126. overflow: 'auto',
  127. width: '100%',
  128. height: '100%',
  129. position: 'relative',
  130. })
  131. const NavbarItems = styled('div')({
  132. display: 'flex',
  133. width: '100%',
  134. height: '100%',
  135. })
  136. const NavbarContainer = styled('div')({
  137. display: 'block',
  138. width: '100%',
  139. height: '100%',
  140. margin: '0 0 0 auto',
  141. boxSizing: 'border-box',
  142. maxWidth: 360,
  143. })
  144. const SecondaryVisibleDummy = styled('div')({
  145. display: 'none',
  146. })
  147. const Visible = createGlobalStyle({
  148. [`div + ${SecondaryNavItems}`]: {
  149. pointerEvents: 'initial',
  150. },
  151. [`div + ${SecondaryNavItems} ${SecondaryNavItemsFg}`]: {
  152. left: 0,
  153. },
  154. [`div + ${SecondaryNavItems} ${SecondaryNavItemsBg}`]: {
  155. opacity: 1,
  156. },
  157. '@media (min-width: 1080px)': {
  158. [`div + ${SecondaryNavItems} ${SecondaryNavItemsFg}`]: {
  159. left: 'auto',
  160. },
  161. [`div + ${SecondaryNavItems} ${SecondaryNavItemsBg}`]: {
  162. opacity: 0,
  163. },
  164. }
  165. })
  166. const Navbar = ({
  167. closeHref,
  168. secondaryVisible,
  169. primaryItemsStart = [],
  170. primaryItemsEnd = [],
  171. secondaryItemsHeader = [],
  172. secondaryItems = [],
  173. }) => (
  174. <React.Fragment>
  175. <Visible />
  176. <Base>
  177. <NavbarContainer>
  178. <NavbarItems>
  179. <PrimaryNavItems>
  180. <PrimaryNavItemsContainer>
  181. <PrimaryNavItemGroup>
  182. {
  183. Array.isArray(primaryItemsStart!)
  184. && primaryItemsStart.map(i => (
  185. <PrimaryNavItem
  186. key={i.id}
  187. mobileOnly={i.mobileOnly}
  188. href={i.href}
  189. iconName={i.iconName}
  190. title={i.title}
  191. active={i.active}
  192. />
  193. ))
  194. }
  195. </PrimaryNavItemGroup>
  196. {
  197. Array.isArray(primaryItemsEnd!)
  198. && (
  199. <PrimaryNavItemGroup>
  200. {
  201. primaryItemsEnd.map(i => (
  202. <PrimaryNavItem
  203. key={i.id}
  204. href={i.href}
  205. iconName={i.iconName}
  206. title={i.title}
  207. active={i.active}
  208. />
  209. ))
  210. }
  211. </PrimaryNavItemGroup>
  212. )
  213. }
  214. </PrimaryNavItemsContainer>
  215. </PrimaryNavItems>
  216. {
  217. secondaryVisible
  218. && (
  219. <SecondaryVisibleDummy />
  220. )
  221. }
  222. <SecondaryNavItems>
  223. <Link
  224. href={closeHref}
  225. passHref
  226. shallow
  227. >
  228. <SecondaryNavItemsBg />
  229. </Link>
  230. <SecondaryNavItemsFg>
  231. <SecondaryNavItemsOverflow>
  232. {
  233. secondaryItemsHeader.map(i => (
  234. <SecondaryNavItem
  235. key={i.id}
  236. active={i.active}
  237. href={i.href}
  238. replace={i.replace}
  239. iconName={i.iconName}
  240. title={i.title}
  241. subtitle={i.subtitle}
  242. actions={i.actions}
  243. />
  244. ))
  245. }
  246. {
  247. secondaryItems.map(i => (
  248. <SecondaryNavItem
  249. key={i.id}
  250. active={i.active}
  251. href={i.href}
  252. replace={i.replace}
  253. iconName={i.iconName}
  254. title={i.title}
  255. subtitle={i.subtitle}
  256. actions={i.actions}
  257. />
  258. ))
  259. }
  260. </SecondaryNavItemsOverflow>
  261. </SecondaryNavItemsFg>
  262. </SecondaryNavItems>
  263. </NavbarItems>
  264. </NavbarContainer>
  265. </Base>
  266. </React.Fragment>
  267. )
  268. export default Navbar