Skip to content

Commit

Permalink
Add settings handler (and redux)
Browse files Browse the repository at this point in the history
  • Loading branch information
rowanhogan committed Sep 11, 2018
1 parent 83b2fb8 commit ddba6e1
Show file tree
Hide file tree
Showing 23 changed files with 746 additions and 224 deletions.
6 changes: 5 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,12 @@
"react-click-outside": "^3.0.1",
"react-dom": "^16.4.0",
"react-fastclick": "^3.0.2",
"react-redux": "^5.0.7",
"react-router-dom": "^4.2.2",
"react-scripts": "1.1.4"
"react-scripts": "1.1.4",
"redux": "^4.0.0",
"redux-logger": "^3.0.6",
"redux-thunk": "^2.3.0"
},
"scripts": {
"start": "npm-run-all -p watch-css start-js",
Expand Down
18 changes: 18 additions & 0 deletions src/components/footer/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import React, { Component } from 'react'
import { Link } from 'react-router-dom'
import Settings from '../settings'

class Footer extends Component {
render() {
return window === window.top ? (
<footer className="footer">
<Settings />
<Link className="logo" to="/">
Wikipedia
</Link>
</footer>
) : null
}
}

export default Footer
4 changes: 3 additions & 1 deletion src/components/sections/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,9 @@ class Sections extends Component {
<a
key={index}
href={`#${section.anchor}`}
onClick={() => this.setState({ open: false })}>
onClick={() =>
setTimeout(() => this.setState({ open: false }), 100)
}>
<span
className={`section-level section-level-${section.toclevel}`}>
{section.number}.
Expand Down
66 changes: 66 additions & 0 deletions src/components/settings/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import React, { Component } from 'react'
import { compose } from 'redux'
import { connect } from 'react-redux'
import { updateSetting } from '../../store/settings'
import withClickOutside from 'react-click-outside'

import Toggle from '../toggle'

class Settings extends Component {
constructor() {
super()
this.state = {
open: false
}
}

handleClickOutside(event) {
if (this.state.open) {
event.preventDefault()
this.setState({ open: false })
}
}

render() {
const { settings } = this.props
const { open } = this.state

return (
<div className="settings">
<button
className="settings-button"
onClick={() => this.setState({ open: true })}>
Settings
</button>
{open && (
<div className="modal settings-modal">
<button
className="close"
onClick={() => this.setState({ open: false })}>
Close
</button>
<h3>Settings</h3>

<Toggle
label="Low contrast"
name="lowContrast"
checked={settings.lowContrast}
onChange={this.props.updateSetting}
/>
<p className="settings-hint">
Reduce eye strain for low-light reading.
</p>
</div>
)}
</div>
)
}
}

const mapStateToProps = ({ settings }) => ({ settings })
const mapDispatchToProps = { updateSetting }

export default compose(
connect(mapStateToProps, mapDispatchToProps),
withClickOutside
)(Settings)
20 changes: 20 additions & 0 deletions src/components/toggle/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import React from 'react'

const Toggle = ({ label, name, checked, onChange }) => (
<label className="toggle-label" htmlFor={name}>
<span>{label}</span>
<div className="toggle">
<input
id={name}
className="toggle-input"
type="checkbox"
name={name}
checked={checked}
onChange={({ target: { checked } }) => onChange(name, checked)}
/>
<span className="toggle-ui" />
</div>
</label>
)

export default Toggle
17 changes: 11 additions & 6 deletions src/index.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
import React from 'react'
import ReactDOM from 'react-dom'
import { BrowserRouter } from 'react-router-dom'
import { Provider } from 'react-redux'
import ReactDOM from 'react-dom'
import configureStore from './store'
import initReactFastclick from 'react-fastclick'
import registerServiceWorker from './registerServiceWorker'
import App from './routes/app'
import './styles/styles.css'
import initReactFastclick from 'react-fastclick'

import App from './routes'

if ('ontouchstart' in document.documentElement) {
document.body.style.cursor = 'pointer'
Expand All @@ -13,9 +16,11 @@ if ('ontouchstart' in document.documentElement) {
initReactFastclick()

ReactDOM.render(
<BrowserRouter>
<App />
</BrowserRouter>,
<Provider store={configureStore()}>
<BrowserRouter>
<App />
</BrowserRouter>
</Provider>,
document.getElementById('root')
)
registerServiceWorker()
9 changes: 0 additions & 9 deletions src/routes/app/app.test.js

This file was deleted.

34 changes: 12 additions & 22 deletions src/routes/app/index.js
Original file line number Diff line number Diff line change
@@ -1,29 +1,19 @@
import React from 'react'
import { Switch, Redirect, Route } from 'react-router-dom'
import { connect } from 'react-redux'

import Home from '../home'
import Page from '../page'
import Media from '../media'
import Header from '../../components/header'
import Footer from '../../components/footer'

const PageNotFound = () => (
<div>
<span role="img" aria-label="Sad face">
😢
</span>
Not Found
</div>
)

export default () => (
<div>
const App = ({ classNames, children }) => (
<div className={classNames.join(' ')}>
<Header />
<Switch>
<Route exact path="/" component={Home} />
<Route exact path="/Main_page" render={() => <Redirect to="/" />} />
<Route path="/File::title" component={Media} />
<Route path="/:title" component={Page} />
<Route component={PageNotFound} />
</Switch>
{children}
<Footer />
</div>
)

const mapStateToProps = ({ settings }) => ({
classNames: Object.keys(settings).filter(setting => settings[setting])
})

export default connect(mapStateToProps)(App)
20 changes: 20 additions & 0 deletions src/routes/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import React from 'react'
import { Switch, Redirect, Route } from 'react-router-dom'

import App from './app'
import Home from './home'
import Page from './page'
import Media from './media'
import PageNotFound from './not-found'

export default () => (
<App>
<Switch>
<Route exact path="/" component={Home} />
<Route exact path="/Main_page" render={() => <Redirect to="/" />} />
<Route path="/File::title" component={Media} />
<Route path="/:title" component={Page} />
<Route component={PageNotFound} />
</Switch>
</App>
)
2 changes: 0 additions & 2 deletions src/routes/media/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,6 @@ export default class extends Component {
render() {
const { loading, title, content, error } = this.state

console.log(content)

return (
<div className="media container">
{loading ? (
Expand Down
12 changes: 12 additions & 0 deletions src/routes/not-found/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import React from 'react'

const PageNotFound = () => (
<div>
<span role="img" aria-label="Sad face">
😢
</span>
Not Found
</div>
)

export default PageNotFound
16 changes: 16 additions & 0 deletions src/store/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { combineReducers, createStore, applyMiddleware } from 'redux'
import thunk from 'redux-thunk'
import createLogger from 'redux-logger'

import settings from './settings'

const initialState = {}

export default () =>
createStore(
combineReducers({
settings
}),
initialState,
applyMiddleware(thunk, createLogger)
)
28 changes: 28 additions & 0 deletions src/store/settings/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
export const updateSetting = (name, value) => dispatch =>
Promise.resolve()
.then(() => localStorage.setItem(name, value))
.then(() =>
dispatch({
type: 'SETTINGS/UPDATE',
payload: { name, value }
})
)

const getBooleanValue = key => localStorage.getItem(key) === 'true'

const initialState = {
lowContrast: getBooleanValue('lowContrast')
}

export default (state = initialState, action) => {
switch (action.type) {
case 'SETTINGS/UPDATE':
const { name, value } = action.payload
return {
...state,
[name]: value
}
default:
return state
}
}
2 changes: 1 addition & 1 deletion src/styles/_home.scss
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
}

.page {
.root h2 .mw-headline:before {
h2 .mw-headline:before {
display: none;
}
}
Expand Down
Loading

0 comments on commit ddba6e1

Please sign in to comment.