
This is a workaround for the following problem that I can't seem to understand. This JSX code: <p data-theme={props.app.theme}>{props.app.theme}</p> Is rendered as: <p data-theme="light">dark</p> This happens only upon initial page load because on the server side we don't know the user's preferred theme. So we start with the default (light). Then, as the app bootstraps in the browser, it updated the content of the P tag with the new theme (dark). However, for reasons that I really don't understand, it does not update the `data-theme` attribute. So this works around that be forcing a different component for each theme that has the data-theme hardcoded. By force-rendering a different component, we can be certain React has no choice be to re-render the entire tag. If anybody could explain to me why this happen, I'd gladly buy you a coffee or something.
78 lines
2.4 KiB
JavaScript
78 lines
2.4 KiB
JavaScript
import React, { useState, useEffect } from 'react'
|
|
import { useSwipeable } from 'react-swipeable'
|
|
import { useRouter } from 'next/router'
|
|
//import Head from 'next/head'
|
|
//import { useHotkeys } from 'react-hotkeys-hook'
|
|
//import themes from '@/shared/themes'
|
|
//import config from '@/site/freesewing.config.js'
|
|
// Shared components
|
|
import Layout from 'shared/components/layouts/default'
|
|
//import ProgressBar from '@/shared/components/progress-bar'
|
|
//import Navbar from '@/shared/components/sections/navbar'
|
|
//import Footer from '@/site/components/footer'
|
|
//import useNavigation from '@/shared/hooks/useNavigation'
|
|
//
|
|
|
|
|
|
/* This component should wrap all page content */
|
|
const AppWrapper= props => {
|
|
|
|
const swipeHandlers = useSwipeable({
|
|
onSwipedLeft: evt => (props.app.primaryMenu) ? props.app.setPrimaryMenu(false) : null,
|
|
onSwipedRight: evt => (props.app.primaryMenu) ? null : props.app.setPrimaryMenu(true),
|
|
trackMouse: true
|
|
})
|
|
|
|
const router = useRouter()
|
|
props.app.setSlug(router.asPath.slice(1))
|
|
//const locale = router.locale || config.language
|
|
//const tree = useNavigation(locale, path)
|
|
|
|
// Trigger search with Ctrl+k
|
|
//useHotkeys('ctrl+k', (evt) => {
|
|
// evt.preventDefault()
|
|
// setSearch(true)
|
|
//})
|
|
|
|
//const [menu, setMenu] = useState(false)
|
|
//const [search, setSearch] = useState(false)
|
|
|
|
//useEffect(() => {
|
|
// themeChange(false)
|
|
//}, [menu])
|
|
|
|
const childProps = {
|
|
app: props.app,
|
|
title: props.title,
|
|
}
|
|
// menu, setMenu, toggleMenu: () => setMenu(!menu),
|
|
// search, setSearch, toggleSearch: () => setSearch(!search),
|
|
// path, tree,
|
|
// title: props.title,
|
|
// t: props.t ? props.t : (x) => x,
|
|
// locale, languages: config.languages,
|
|
//}
|
|
|
|
// Cannot understand why, but a re-render does update the content
|
|
// but not the attributes. So this is a hackish workaround
|
|
const themeWrappers = {
|
|
light: props => <div {...props} data-theme="light" />,
|
|
dark: props => <div {...props} data-theme="dark" />,
|
|
hax0r: props => <div {...props} data-theme="hax0r" />,
|
|
lgbtq: props => <div {...props} data-theme="lgbtq" />,
|
|
trans: props => <div {...props} data-theme="trans" />,
|
|
}
|
|
const Wrapper = themeWrappers[props.app.theme]
|
|
|
|
return (
|
|
<Wrapper>
|
|
{props.noLayout
|
|
? props.children
|
|
: <Layout {...childProps}><p className={`theme-${props.app.theme}`} data-theme={props.app.theme}>{props.app.theme}</p>{props.children}</Layout>
|
|
}
|
|
</Wrapper>
|
|
)
|
|
}
|
|
|
|
export default AppWrapper
|
|
|