
This removes the useApp hook from all org pages in favor of various context. This means there is no longer global state that gets passed around, instead each component that requires access to something shared (like account, or navigation) can just use the context instead. This is a first step, as a lot of shared components stil rely on app not to mention the dev and lab sites.
84 lines
2.5 KiB
JavaScript
84 lines
2.5 KiB
JavaScript
// Dependencies
|
|
import React, { useState, useEffect, useContext } from 'react'
|
|
import { useHotkeys } from 'react-hotkeys-hook'
|
|
// Hooks
|
|
import { useTheme } from 'shared/hooks/use-theme.mjs'
|
|
// Components
|
|
import { SwipeWrapper } from 'shared/components/wrappers/swipes.mjs'
|
|
import { LayoutWrapper, ns as layoutNs } from 'site/components/wrappers/layout.mjs'
|
|
import { DocsLayout, ns as docsNs } from 'site/components/layouts/docs.mjs'
|
|
import { Feeds } from 'site/components/feeds.mjs'
|
|
import { Spinner } from 'shared/components/spinner.mjs'
|
|
import { ModalContext } from 'shared/context/modal-context.mjs'
|
|
import { NavigationContext } from 'shared/context/navigation-context.mjs'
|
|
|
|
export const ns = [...new Set([...layoutNs, ...docsNs])]
|
|
|
|
/* This component should wrap all page content */
|
|
export const PageWrapper = (props) => {
|
|
/*
|
|
* Deconstruct props
|
|
*/
|
|
const { layout = DocsLayout, footer = true, children = [], path = [], locale = 'en' } = props
|
|
// Title is typically set in props.t but check props.title too
|
|
const pageTitle = props.t ? props.t : props.title ? props.title : null
|
|
|
|
/*
|
|
* This forces a re-render upon initial bootstrap of the app
|
|
* This is needed to avoid hydration errors because theme can't be set reliably in SSR
|
|
*/
|
|
const [theme, setTheme] = useTheme()
|
|
const [currentTheme, setCurrentTheme] = useState()
|
|
useEffect(() => setCurrentTheme(theme), [currentTheme, theme])
|
|
|
|
/*
|
|
* Contexts
|
|
*/
|
|
const { modalContent } = useContext(ModalContext)
|
|
const { title, setTitle, setNavigation } = useContext(NavigationContext)
|
|
|
|
/*
|
|
* Update navigation context with title and path
|
|
*/
|
|
useEffect(() => {
|
|
setNavigation({
|
|
title: pageTitle,
|
|
locale,
|
|
path,
|
|
})
|
|
}, [path, title, pageTitle])
|
|
|
|
/*
|
|
* Hotkeys (keyboard actions)
|
|
*/
|
|
// Trigger search with /
|
|
useHotkeys('/', (evt) => {
|
|
evt.preventDefault()
|
|
setSearch(true)
|
|
})
|
|
|
|
// Search state
|
|
const [search, setSearch] = useState(false)
|
|
|
|
// Helper object to pass props down (keeps things DRY)
|
|
const childProps = { footer, title: pageTitle }
|
|
|
|
// Make layout prop into a (uppercase) component
|
|
const Layout = layout
|
|
|
|
// Return wrapper
|
|
return (
|
|
<SwipeWrapper>
|
|
<div
|
|
data-theme={currentTheme} // This facilitates CSS selectors
|
|
key={currentTheme} // This forces the data-theme update
|
|
>
|
|
<Feeds />
|
|
<LayoutWrapper {...childProps}>
|
|
{Layout ? <Layout {...childProps}>{children}</Layout> : children}
|
|
</LayoutWrapper>
|
|
{modalContent}
|
|
</div>
|
|
</SwipeWrapper>
|
|
)
|
|
}
|