feat: app level theming
This commit is contained in:
@@ -1,15 +1,21 @@
|
||||
import React from "react"
|
||||
import { ThemeProvider } from "emotion-theming"
|
||||
import Firebase, { FirebaseContext } from "./src/components/firebase"
|
||||
import theme from "./src/styles/theme"
|
||||
|
||||
const selectedTheme =
|
||||
new Date().getHours() >= 7 && new Date().getHours() <= 21 ? "LIGHT" : "DARK"
|
||||
import { ThemeProvider as EmotionThemeProvider } from "emotion-theming"
|
||||
import Firebase, { FirebaseContext } from "components/firebase"
|
||||
import theme from "styles/theme"
|
||||
import ThemeTogglerContext, { ThemeToggler } from "components/context/theme"
|
||||
|
||||
export const wrapRootElement = ({ element }) => {
|
||||
return (
|
||||
<FirebaseContext.Provider value={new Firebase()}>
|
||||
<ThemeProvider theme={theme[selectedTheme]}>{element}</ThemeProvider>
|
||||
<ThemeToggler>
|
||||
<ThemeTogglerContext.Consumer>
|
||||
{({ themeName }) => (
|
||||
<EmotionThemeProvider theme={theme[themeName]}>
|
||||
{element}
|
||||
</EmotionThemeProvider>
|
||||
)}
|
||||
</ThemeTogglerContext.Consumer>
|
||||
</ThemeToggler>
|
||||
</FirebaseContext.Provider>
|
||||
)
|
||||
}
|
||||
|
||||
37
src/App.js
37
src/App.js
@@ -2,11 +2,11 @@ import React, { Component } from "react"
|
||||
import { Router } from "@reach/router"
|
||||
import { compose } from "recompose"
|
||||
import styled from "@emotion/styled"
|
||||
import { ThemeProvider } from "emotion-theming"
|
||||
import { withTheme } from "emotion-theming"
|
||||
|
||||
import { SIZES } from "./styles/constants"
|
||||
|
||||
import theme from "./styles/theme"
|
||||
// import theme from "./styles/theme"
|
||||
import Navbar from "./components/Navbar"
|
||||
import Day from "routes/Day"
|
||||
import Month from "routes/Month"
|
||||
@@ -19,6 +19,7 @@ import PrivateRoute from "./components/PrivateRoute"
|
||||
import { OnlineContext } from "./components/context/online"
|
||||
import { withAuthentication } from "./components/session"
|
||||
import { withFirebase } from "./components/firebase"
|
||||
import ThemeTogglerContext from "components/context/theme"
|
||||
|
||||
const FullscreenLayout = styled.div`
|
||||
background-color: ${props => props.theme.colors.bodyBackground};
|
||||
@@ -36,10 +37,7 @@ const RouteLayout = styled.div`
|
||||
|
||||
class App extends Component {
|
||||
state = {
|
||||
selectedTheme:
|
||||
new Date().getHours() >= 7 && new Date().getHours() <= 21
|
||||
? "LIGHT"
|
||||
: "DARK",
|
||||
selectedTheme: this.props.theme.name,
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
@@ -57,28 +55,17 @@ class App extends Component {
|
||||
})
|
||||
}
|
||||
|
||||
onChangeTheme = () => {
|
||||
const { selectedTheme } = this.state
|
||||
const body = document.body
|
||||
const newTheme = selectedTheme === "LIGHT" ? "DARK" : "LIGHT"
|
||||
body.style.setProperty(
|
||||
"background-color",
|
||||
theme[newTheme].colors.bodyBackground
|
||||
)
|
||||
this.setState({ selectedTheme: newTheme })
|
||||
}
|
||||
|
||||
render() {
|
||||
const { selectedTheme, authUser, online } = this.state
|
||||
const { authUser: propAuthUser } = this.props
|
||||
const { authUser, online } = this.state
|
||||
const { authUser: propAuthUser, theme } = this.props
|
||||
const authed = !!propAuthUser || !!authUser
|
||||
|
||||
const currentTheme = theme[selectedTheme]
|
||||
return (
|
||||
<ThemeProvider theme={currentTheme}>
|
||||
<ThemeTogglerContext.Consumer>
|
||||
{({ toggle }) => (
|
||||
<OnlineContext.Provider value={online}>
|
||||
<FullscreenLayout>
|
||||
<Navbar toggleTheme={this.onChangeTheme} />
|
||||
<Navbar toggleTheme={toggle} />
|
||||
<RouteLayout>
|
||||
<Router>
|
||||
<PrivateRoute
|
||||
@@ -116,12 +103,14 @@ class App extends Component {
|
||||
</RouteLayout>
|
||||
</FullscreenLayout>
|
||||
</OnlineContext.Provider>
|
||||
</ThemeProvider>
|
||||
)}
|
||||
</ThemeTogglerContext.Consumer>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default compose(
|
||||
withAuthentication,
|
||||
withFirebase
|
||||
withFirebase,
|
||||
withTheme
|
||||
)(App)
|
||||
|
||||
@@ -13,6 +13,7 @@ import { todayUrl, yearUrl } from "utils/date"
|
||||
import Logo from "components/Logo"
|
||||
import Icon from "components/Icon"
|
||||
import { withAuthentication } from "components/session"
|
||||
import ThemeTogglerContext from "components/context/theme"
|
||||
|
||||
const Header = styled.div`
|
||||
background-color: ${props => props.theme.colors.headerBackground};
|
||||
@@ -93,16 +94,24 @@ const Navbar = ({ authUser, theme, toggleTheme }) => (
|
||||
/>
|
||||
</React.Fragment>
|
||||
) : (
|
||||
<>
|
||||
<Link to={"/login"} style={{ textDecoration: "none" }}>
|
||||
<Icon name="ArrowRight" label="Login" size={20} />
|
||||
</Link>
|
||||
<Icon
|
||||
tabindex={0}
|
||||
onClick={() => toggleTheme()}
|
||||
onKeyPress={() => toggleTheme()}
|
||||
name={theme.name === "Dark" ? "Sun" : "Moon"}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
</NavIcons>
|
||||
</Nav>
|
||||
</Header>
|
||||
)
|
||||
|
||||
const SimpleNav = ({ theme, toggleTheme }) => (
|
||||
const SimpleNav = ({ authUser, theme }) => (
|
||||
<Header>
|
||||
<Nav>
|
||||
<LogoSection onClick={() => navigate("/")}>
|
||||
@@ -111,17 +120,34 @@ const SimpleNav = ({ theme, toggleTheme }) => (
|
||||
<LogoText color={theme.colors.secondary}>JOURNAL</LogoText>
|
||||
</LogoSection>
|
||||
<NavIcons>
|
||||
{/* <Tooltip title="Login"> */}
|
||||
{authUser ? (
|
||||
<StyledLink to={"/"}>
|
||||
<Icon name="Circle" />
|
||||
</StyledLink>
|
||||
) : (
|
||||
<Link to={"/login"} style={{ textDecoration: "none" }}>
|
||||
<Icon name="ArrowRight" label="Login" size={20} />
|
||||
</Link>
|
||||
{/* </Tooltip> */}
|
||||
)}
|
||||
<ThemeTogglerContext.Consumer>
|
||||
{({ toggle }) => (
|
||||
<Icon
|
||||
tabindex={0}
|
||||
onClick={() => toggle()}
|
||||
onKeyPress={() => toggle()}
|
||||
name={theme.name === "Dark" ? "Sun" : "Moon"}
|
||||
/>
|
||||
)}
|
||||
</ThemeTogglerContext.Consumer>
|
||||
</NavIcons>
|
||||
</Nav>
|
||||
</Header>
|
||||
)
|
||||
|
||||
const SimpleNavbar = withTheme(SimpleNav)
|
||||
const SimpleNavbar = compose(
|
||||
withAuthentication,
|
||||
withTheme
|
||||
)(SimpleNav)
|
||||
|
||||
export { SimpleNavbar }
|
||||
|
||||
|
||||
46
src/components/context/theme.js
Normal file
46
src/components/context/theme.js
Normal file
@@ -0,0 +1,46 @@
|
||||
import React from "react"
|
||||
import theme from "styles/theme"
|
||||
|
||||
const ThemeTogglerContext = React.createContext({
|
||||
themeName: "LIGHT",
|
||||
toggle: () => {},
|
||||
})
|
||||
|
||||
class ThemeToggler extends React.Component {
|
||||
state = {
|
||||
themeName:
|
||||
new Date().getHours() >= 7 && new Date().getHours() <= 21
|
||||
? "LIGHT"
|
||||
: "DARK",
|
||||
}
|
||||
|
||||
toggle = () => {
|
||||
const { themeName } = this.state
|
||||
const body = document.body
|
||||
const newTheme = themeName === "LIGHT" ? "DARK" : "LIGHT"
|
||||
body.style.setProperty(
|
||||
"background-color",
|
||||
theme[newTheme].colors.bodyBackground
|
||||
)
|
||||
this.setState({ themeName: newTheme })
|
||||
}
|
||||
|
||||
render() {
|
||||
const { children } = this.props
|
||||
const { themeName } = this.state
|
||||
return (
|
||||
<ThemeTogglerContext.Provider
|
||||
value={{
|
||||
themeName,
|
||||
toggle: this.toggle,
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
</ThemeTogglerContext.Provider>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default ThemeTogglerContext
|
||||
|
||||
export { ThemeToggler }
|
||||
@@ -11,6 +11,18 @@ export const H1 = styled.h1`
|
||||
color: ${props => props.color};
|
||||
`
|
||||
|
||||
export const SimpleH1 = styled.h1`
|
||||
color: ${props => props.color};
|
||||
`
|
||||
|
||||
export const SimpleH2 = styled.h1`
|
||||
color: ${props => props.color};
|
||||
`
|
||||
|
||||
export const Em = styled.em`
|
||||
color: ${props => props.color};
|
||||
`
|
||||
|
||||
export const Input = styled.input`
|
||||
color: ${props => props.colors.primary};
|
||||
background-color: ${props => props.colors.headerBackground};
|
||||
|
||||
@@ -30,7 +30,10 @@ const LoginPage = ({ theme }) => (
|
||||
{firebase => <LoginForm firebase={firebase} />}
|
||||
</FirebaseContext.Consumer>
|
||||
<P colors={theme.colors} style={{ fontStyle: "italic" }}>
|
||||
Don't have an account? <Link to={"/register"}>Sign Up</Link>
|
||||
Don't have an account?{" "}
|
||||
<Link style={{ color: theme.colors.primary }} to={"/register"}>
|
||||
Sign Up
|
||||
</Link>
|
||||
</P>
|
||||
</LoginLayout>
|
||||
</Layout>
|
||||
@@ -91,7 +94,7 @@ class LoginFormBase extends Component {
|
||||
Login
|
||||
</Button>
|
||||
</LoginGrid>
|
||||
{error && <p>{error.message}</p>}
|
||||
{error && <P colors={theme.colors}>{error.message}</P>}
|
||||
</form>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,19 +1,22 @@
|
||||
import React from "react"
|
||||
|
||||
import { P } from "components/elements"
|
||||
import { SimpleH1, SimpleH2, P, Em } from "components/elements"
|
||||
import Layout from "components/Layout"
|
||||
import Container from "components/container"
|
||||
import { SimpleNavbar } from "components/Navbar"
|
||||
import { withTheme } from "emotion-theming"
|
||||
|
||||
const Terms = () => (
|
||||
const Terms = ({ theme }) => (
|
||||
<Layout>
|
||||
<SimpleNavbar />
|
||||
<Container>
|
||||
<h1>Privacy Policy</h1>
|
||||
<em>Last update: April 30, 2019</em>
|
||||
<SimpleH1 color={theme.colors.primary}>Privacy Policy</SimpleH1>
|
||||
<Em color={theme.colors.secondary}>Last update: April 30, 2019</Em>{" "}
|
||||
<P>
|
||||
Sol Journal supports the following browsers: Chrome (latest), Safari
|
||||
(latest), Firefox (50+)
|
||||
</P>
|
||||
<h2>Rights</h2>
|
||||
<SimpleH2 color={theme.colors.secondary}>Rights</SimpleH2>
|
||||
<P>
|
||||
You don't have to provide your real name when you register to an
|
||||
account, but you need to use a valid/verifiable email address.
|
||||
@@ -43,7 +46,7 @@ const Terms = () => (
|
||||
<br />
|
||||
Any new features that affect privacy will be strictly opt-in.
|
||||
</P>
|
||||
<h2>Responsibilites</h2>
|
||||
<SimpleH2 color={theme.colors.secondary}>Responsibilites</SimpleH2>
|
||||
<P>
|
||||
You will not use the site to store illegal information or data under
|
||||
United States law (or any law).
|
||||
@@ -68,7 +71,7 @@ const Terms = () => (
|
||||
(millions of entries or overloading services with requests) or use it in
|
||||
an unreasonable manner.
|
||||
</P>
|
||||
<h2>Other</h2>
|
||||
<SimpleH2 color={theme.colors.secondary}>Other</SimpleH2>
|
||||
<P>
|
||||
Other important legal stuff Though I want to provide a great service,
|
||||
there are certain things about the service I cannot promise. For
|
||||
@@ -88,4 +91,4 @@ const Terms = () => (
|
||||
</Layout>
|
||||
)
|
||||
|
||||
export default Terms
|
||||
export default withTheme(Terms)
|
||||
|
||||
@@ -29,7 +29,10 @@ const RegisterPage = ({ theme }) => (
|
||||
{firebase => <RegisterForm firebase={firebase} />}
|
||||
</FirebaseContext.Consumer>
|
||||
<P colors={theme.colors} style={{ fontStyle: "italic" }}>
|
||||
Already have an account? <Link to={"/login"}>Login</Link>
|
||||
Already have an account?{" "}
|
||||
<Link style={{ color: theme.colors.primary }} to={"/login"}>
|
||||
Login
|
||||
</Link>
|
||||
</P>
|
||||
</RegisterLayout>
|
||||
</Layout>
|
||||
@@ -133,7 +136,7 @@ class RegisterFormBase extends Component {
|
||||
</Button>
|
||||
</RegisterGrid>
|
||||
|
||||
{error && <p>{error.message}</p>}
|
||||
{error && <P colors={theme.colors}>{error.message}</P>}
|
||||
</form>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,20 +1,23 @@
|
||||
import React from "react"
|
||||
|
||||
import { P } from "components/elements"
|
||||
import { SimpleH1, SimpleH2, P, Em } from "components/elements"
|
||||
import Layout from "components/Layout"
|
||||
import Container from "components/container"
|
||||
import { SimpleNavbar } from "components/Navbar"
|
||||
import { withTheme } from "emotion-theming"
|
||||
|
||||
const Terms = () => (
|
||||
const Terms = ({ theme }) => (
|
||||
<Layout>
|
||||
<SimpleNavbar />
|
||||
<Container>
|
||||
<h1>Terms of Service</h1>
|
||||
<em>Last update: April 30, 2019</em>
|
||||
<h2>Scope of Service</h2>
|
||||
<SimpleH1 color={theme.colors.primary}>Terms of Service</SimpleH1>
|
||||
<Em color={theme.colors.secondary}>Last update: April 30, 2019</Em>
|
||||
<SimpleH2 color={theme.colors.secondary}>Scope of Service</SimpleH2>
|
||||
<P>
|
||||
Sol Journal supports the following browsers: Chrome (latest), Safari
|
||||
(latest), Firefox (50+)
|
||||
</P>
|
||||
<h2>Rights</h2>
|
||||
<SimpleH2 color={theme.colors.secondary}>Rights</SimpleH2>
|
||||
<P>
|
||||
You don't have to provide your real name when you register to an
|
||||
account, but you need to use a valid/verifiable email address.
|
||||
@@ -37,7 +40,7 @@ const Terms = () => (
|
||||
<br />
|
||||
Any new features that affect privacy will be strictly opt-in.
|
||||
</P>
|
||||
<h2>Responsibilites</h2>
|
||||
<SimpleH2 color={theme.colors.secondary}>Responsibilites</SimpleH2>
|
||||
<P>
|
||||
You will not use the site to store illegal information or data under
|
||||
United States law (or any law).
|
||||
@@ -62,7 +65,7 @@ const Terms = () => (
|
||||
(millions of entries or overloading services with requests) or use it in
|
||||
an unreasonable manner.
|
||||
</P>
|
||||
<h2>Other</h2>
|
||||
<SimpleH2 color={theme.colors.secondary}>Other</SimpleH2>
|
||||
<P>
|
||||
Other important legal stuff Though I want to provide a great service,
|
||||
there are certain things about the service I cannot promise. For
|
||||
@@ -82,4 +85,4 @@ const Terms = () => (
|
||||
</Layout>
|
||||
)
|
||||
|
||||
export default Terms
|
||||
export default withTheme(Terms)
|
||||
|
||||
@@ -120,7 +120,7 @@ class Start extends Component {
|
||||
}
|
||||
`}
|
||||
render={data => {
|
||||
return theme.name === "Light" ? (
|
||||
return theme.name === "LIGHT" ? (
|
||||
<Img
|
||||
style={{
|
||||
maxWidth: 320,
|
||||
@@ -131,7 +131,15 @@ class Start extends Component {
|
||||
fluid={data.landingGraphicLight.childImageSharp.fluid}
|
||||
/>
|
||||
) : (
|
||||
<Img fluid={data.LandingGraphicDark.childImageSharp.fluid} />
|
||||
<Img
|
||||
style={{
|
||||
maxWidth: 320,
|
||||
width: "100%",
|
||||
maxHeight: 350,
|
||||
height: "100%",
|
||||
}}
|
||||
fluid={data.landingGraphicDark.childImageSharp.fluid}
|
||||
/>
|
||||
)
|
||||
}}
|
||||
/>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
const theme = {
|
||||
LIGHT: {
|
||||
name: "Light",
|
||||
name: "LIGHT",
|
||||
colors: {
|
||||
logo: "#344157",
|
||||
primary: "#2E3136",
|
||||
@@ -11,10 +11,11 @@ const theme = {
|
||||
bodyBackground: "#FFF",
|
||||
inputBackground: "#FAFBFC",
|
||||
hover: "hsla(233, 5%, 31%, 0.12)",
|
||||
button: "#f2f3f5",
|
||||
},
|
||||
},
|
||||
DARK: {
|
||||
name: "Dark",
|
||||
name: "DARK",
|
||||
colors: {
|
||||
logo: "#EAEAEA",
|
||||
primary: "#F3F6F8",
|
||||
@@ -25,6 +26,7 @@ const theme = {
|
||||
bodyBackground: "#262B34",
|
||||
inputBackground: "#272f3d",
|
||||
hover: "hsla(233, 100%, 96%, 0.12)",
|
||||
button: "#464d5d",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user