summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNick Van Doorn <vandoorn.nick@gmail.com>2019-04-05 15:45:17 -0700
committerNick Van Doorn <vandoorn.nick@gmail.com>2019-04-05 15:45:17 -0700
commitfa0d37650d6e43bbd846260da5e42f30f354c707 (patch)
tree7370ea07b1c253244aec8701658ba056d3d34e15
parent2f1eaba7726ba31c0bc5af3fef185e5de8ff262e (diff)
Factor layout into several components for theming
-rw-r--r--src/components/base-layout.js55
-rw-r--r--src/components/layout.js148
2 files changed, 133 insertions, 70 deletions
diff --git a/src/components/base-layout.js b/src/components/base-layout.js
new file mode 100644
index 0000000..cb95f70
--- /dev/null
+++ b/src/components/base-layout.js
@@ -0,0 +1,55 @@
+import React from 'react'
+import { ThemeProvider } from 'emotion-theming'
+import Helmet from 'react-helmet'
+import { Global, css } from '@emotion/core'
+
+import { Container } from './container'
+
+const globalStyles = ({ colours, transitions, fontStack, baseFontSize }) => css`
+ *,
+ html,
+ body {
+ margin: 0;
+ padding: 0;
+ }
+ p,
+ a,
+ h1,
+ h2,
+ h3,
+ h4,
+ h5,
+ div,
+ button {
+ font-family: ${fontStack};
+ color: ${colours.main};
+ }
+ p,
+ li {
+ line-height: 2em;
+ }
+ li {
+ list-style-position: outside;
+ margin-left: 20px;
+ }
+ a {
+ border-bottom: 1px dotted;
+ text-decoration: none;
+ &: hover {
+ transition: ${transitions.hover};
+ }
+ }
+ body {
+ background: ${colours.background};
+ }
+`
+
+export const BaseLayout = ({ helmetData, children, height, theme }) => (
+ <ThemeProvider theme={theme}>
+ <Global styles={globalStyles} />
+ <Helmet {...helmetData}>
+ <html lang="en" />
+ </Helmet>
+ <Container height={height}>{children}</Container>
+ </ThemeProvider>
+)
diff --git a/src/components/layout.js b/src/components/layout.js
index 5e8ce25..fcc942e 100644
--- a/src/components/layout.js
+++ b/src/components/layout.js
@@ -1,7 +1,5 @@
-import React from 'react'
-import Helmet from 'react-helmet'
-import { css, Global } from '@emotion/core'
-import { colours, fontStack, transitions } from './globals'
+import React, { Component } from 'react'
+import { themes } from './globals'
import {
faSpotify,
faGithub,
@@ -9,50 +7,26 @@ import {
faKeybase
} from '@fortawesome/free-brands-svg-icons'
-import { Container } from './container'
import { Header } from './header'
import { FontAwesome } from './font-awesome'
+import { ThemeSwitcher } from './theme-switcher'
+import { BaseLayout } from './base-layout'
+import { parseQuery, writeQuery } from '../lib/url'
-const globalStyles = css`
- *,
- html,
- body {
- margin: 0;
- padding: 0;
- }
- path {
- fill: ${colours.main};
- }
- p,
- a,
- h1,
- h2,
- h3,
- h4,
- h5,
- div {
- font-family: ${fontStack};
- color: ${colours.main};
- }
- p,
- li {
- line-height: 2em;
- }
- li {
- list-style-position: outside;
- margin-left: 20px;
- }
- a {
- border-bottom: 1px dotted;
- text-decoration: none;
- &: hover {
- transition: ${transitions.hover};
+const helmetData = {
+ title: 'Nicholas Van Doorn',
+ meta: [
+ {
+ name: 'description',
+ content: 'Portfolio for Nicholas Van Doorn'
+ },
+ {
+ name: 'keywords',
+ content: 'software, engineer, development, web'
}
- }
- body {
- background: ${colours.background};
- }
-`
+ ]
+}
+
const siteData = {
siteName: 'Nicholas Van Doorn',
navLinks: [
@@ -71,47 +45,81 @@ const siteData = {
],
socialEntries: [
{
- href: '//github.com/nvandoorn',
+ href: 'https://github.com/nvandoorn',
name: 'GitHub',
icon: <FontAwesome icon={faGithub} size="30px" />
},
{
- href: '//twitter.com/nickvandoorn',
+ href: 'https://twitter.com/nickvandoorn',
name: 'Twitter',
icon: <FontAwesome icon={faTwitter} size="30px" />
},
{
- href: '//keybase.io/nvandoorn',
+ href: 'https://keybase.io/nvandoorn',
name: 'Keybase',
icon: <FontAwesome icon={faKeybase} size="30px" />
},
{
- href: '//open.spotify.com/user/pontonn',
+ href: 'https://open.spotify.com/user/pontonn',
name: 'Spotify',
icon: <FontAwesome icon={faSpotify} size="30px" />
}
]
}
-export default ({ children, height }) => (
- <>
- <Global styles={globalStyles} />
- <Helmet
- title="Nicholas Van Doorn"
- meta={[
- { name: 'description', content: 'Portfolio for Nicholas Van Doorn' },
- { name: 'keywords', content: 'software, engineer, development, web' }
- ]}
- >
- <html lang="en" />
- </Helmet>
- <Container height={height}>
- <Header
- siteName={siteData.siteName}
- links={siteData.navLinks}
- socialEntries={siteData.socialEntries}
- />
- {children}
- </Container>
- </>
-)
+const getThemeKeyFromUrl = () => {
+ const queryObj = parseQuery()
+ return queryObj && queryObj.themeKey
+}
+
+const initState = () => {
+ let currentThemeKey = getThemeKeyFromUrl() || 'mainTheme'
+ return {
+ theme: themes[currentThemeKey],
+ currentThemeKey
+ }
+}
+
+// persist state globally
+// (theme should stay
+// across page changes)
+let lastState = initState()
+
+export default class Layout extends Component {
+ state = lastState
+
+ changeTheme = themeKey => {
+ const theme = themes[themeKey]
+ const newState = { theme, currentThemeKey: themeKey }
+ lastState = newState
+ this.setState(newState)
+ writeQuery({ themeKey })
+ }
+
+ render() {
+ const { children, height } = this.props
+ return (
+ <BaseLayout
+ height={height}
+ theme={this.state.theme}
+ helmetData={helmetData}
+ >
+ <Header
+ siteName={siteData.siteName}
+ links={siteData.navLinks}
+ socialEntries={siteData.socialEntries}
+ />
+
+ {children}
+ <ThemeSwitcher
+ currentTheme={this.state.currentThemeKey}
+ themes={[
+ { name: '👔', key: 'mainTheme' },
+ { name: '📰', key: 'highContrastTheme' }
+ ]}
+ onClick={t => this.changeTheme(t)}
+ />
+ </BaseLayout>
+ )
+ }
+}