diff --git a/.flowconfig b/.flowconfig index b662cce..21952d6 100644 --- a/.flowconfig +++ b/.flowconfig @@ -1,4 +1,5 @@ [ignore] +.*/node_modules/polished/.* [include] diff --git a/__tests__/actions/Todo.test.js b/__tests__/actions/Todo.test.js index d89158f..aeab395 100644 --- a/__tests__/actions/Todo.test.js +++ b/__tests__/actions/Todo.test.js @@ -1,8 +1,6 @@ import configureStore from 'redux-mock-store'; -import { ADD_TODO } from '../../app/constants/actions'; - -import { addTodo } from '../../app/actions/add-todo'; +import { ADD_TODO, addTodo } from '../../app/redux/modules/todo'; const store = configureStore()(); diff --git a/__tests__/components/Sidebar.test.js b/__tests__/components/Sidebar.test.js index 1824a12..76518f4 100644 --- a/__tests__/components/Sidebar.test.js +++ b/__tests__/components/Sidebar.test.js @@ -3,7 +3,7 @@ import { render } from 'react-testing-library'; import { MemoryRouter } from 'react-router-dom'; import 'jest-dom/extend-expect'; -import { SidebarComponent } from '../../app/components/sidebar/index'; +import { SidebarComponent } from '../../app/components/Sidebar'; describe('', () => { describe('render()', () => { diff --git a/__tests__/reducers/Todo.test.js b/__tests__/reducers/Todo.test.js index 3ff57d1..50f19d9 100644 --- a/__tests__/reducers/Todo.test.js +++ b/__tests__/reducers/Todo.test.js @@ -1,5 +1,4 @@ -import todoReducer from '../../app/reducers/todo'; -import { ADD_TODO } from '../../app/constants/actions'; +import todoReducer, { ADD_TODO } from '../../app/redux/modules/todo'; describe('Todo Reducer', () => { test('should return the valid initial state', () => { diff --git a/app/app.js b/app/app.js index 7d632aa..0bfd998 100644 --- a/app/app.js +++ b/app/app.js @@ -3,15 +3,23 @@ import React from 'react'; import { Provider } from 'react-redux'; import { ConnectedRouter } from 'connected-react-router'; +import { ThemeProvider } from 'styled-components'; + import { configureStore, history } from './redux/create'; import { Router } from './router/container'; +import theme, { GlobalStyle } from './theme'; const store = configureStore({}); export default () => ( - - - - - + + + +
+ + +
+
+
+
); diff --git a/app/components/layout/index.js b/app/components/Layout.js similarity index 52% rename from app/components/layout/index.js rename to app/components/Layout.js index 564e9fb..d396038 100644 --- a/app/components/layout/index.js +++ b/app/components/Layout.js @@ -2,21 +2,26 @@ import React from 'react'; import styled from 'styled-components'; -import { styles } from './styles'; + +const Layout = styled.div` + display: flex; + flex-direction: column; + width: 200px; + position: absolute; + width: calc(100vh - 200px); + left: 0; + top: 0; + height: 100vh; + background: #ccc; +`; type Props = { chidren: any, // eslint-disable-line }; -const Layout = styled.div`${styles.layout}`; - export const LayoutComponent = (props: Props) => { // $FlowFixMe const { children } = props; // eslint-disable-line - return ( - - {children} - - ); + return {children}; }; diff --git a/app/components/sidebar/index.js b/app/components/Sidebar.js similarity index 53% rename from app/components/sidebar/index.js rename to app/components/Sidebar.js index 12985aa..2403bdb 100644 --- a/app/components/sidebar/index.js +++ b/app/components/Sidebar.js @@ -3,13 +3,21 @@ import React from 'react'; import styled from 'styled-components'; import { Link } from 'react-router-dom'; -import { MENU_OPTIONS } from '../../constants/sidebar'; -import { styles } from './styles'; +import { MENU_OPTIONS } from '../constants/sidebar'; -// TODO: Not sure this is the best approach to styling -// in a StyledComponents-powered application const Wrapper = styled.div` - ${styles.wrapper} + display: flex; + flex-direction: column; + width: 200px; + position: absolute; + left: 0; + top: 0; + height: 100vh; + background-color: ${props => props.theme.colors.secondary}; +`; + +const StyledLink = styled(Link)` + color: ${props => props.theme.colors.primary}; `; type MenuItem = { route: string, label: string }; @@ -21,9 +29,9 @@ type Props = { export const SidebarComponent = ({ options }: Props) => ( {(options || []).map(item => ( - + {item.label} - + ))} ); diff --git a/app/components/sidebar/sidebar.mdx b/app/components/Sidebar.mdx similarity index 50% rename from app/components/sidebar/sidebar.mdx rename to app/components/Sidebar.mdx index af7f216..50d64b4 100644 --- a/app/components/sidebar/sidebar.mdx +++ b/app/components/Sidebar.mdx @@ -3,7 +3,8 @@ name: Sidebar --- import { Playground, PropsTable } from 'docz' -import { SidebarComponent } from './index.js' +import { SidebarComponent } from './Sidebar.js' +import { DoczWrapper } from '../theme.js' # Sidebar @@ -12,5 +13,7 @@ import { SidebarComponent } from './index.js' ## Basic usage - + + {() => } + diff --git a/app/components/todo/todo-edit-input.js b/app/components/TodoEditInput.js similarity index 64% rename from app/components/todo/todo-edit-input.js rename to app/components/TodoEditInput.js index 919a4da..dcc1122 100644 --- a/app/components/todo/todo-edit-input.js +++ b/app/components/TodoEditInput.js @@ -1,7 +1,7 @@ // @flow import React, { Component } from 'react'; -import type { TodoType } from '../../types/todo'; +import type { TodoType } from '../types/todo'; type Props = { updateTodo: Function, @@ -33,17 +33,19 @@ export default class TodoEditInput extends Component { updateTodo(id, trimValue); this.setState({ value: '' }); } - } + }; handleCancel = (id: string) => { const { cancelUpdateTodo } = this.props; cancelUpdateTodo(id); - } + }; handleInputChange = (event: SyntheticInputEvent) => { - const { target: { value } } = event; + const { + target: { value }, + } = event; this.setState({ value }); - } + }; render() { const { value } = this.state; @@ -51,28 +53,13 @@ export default class TodoEditInput extends Component { return (
-
this.handleSubmit(e, todo.id)} - > - -
-
diff --git a/app/components/todo/todo-input.js b/app/components/TodoInput.js similarity index 67% rename from app/components/todo/todo-input.js rename to app/components/TodoInput.js index fd2884f..ae71f0e 100644 --- a/app/components/todo/todo-input.js +++ b/app/components/TodoInput.js @@ -26,30 +26,22 @@ export default class TodoInput extends Component { addTodo(trimValue); this.setState({ value: '' }); } - } + }; handleInputChange = (event: SyntheticInputEvent) => { - const { target: { value } } = event; + const { + target: { value }, + } = event; this.setState({ value }); - } + }; render() { const { value } = this.state; return ( -
- -
diff --git a/app/components/todo/todo-list.js b/app/components/TodoList.js similarity index 53% rename from app/components/todo/todo-list.js rename to app/components/TodoList.js index a643449..53aef64 100644 --- a/app/components/todo/todo-list.js +++ b/app/components/TodoList.js @@ -1,9 +1,9 @@ // @flow import React, { PureComponent } from 'react'; -import TodoEditInput from './todo-edit-input'; -import TodoListItem from './todo-list-item'; -import type { TodoType } from '../../types/todo'; +import TodoEditInput from './TodoEditInput'; +import TodoListItem from './TodoListItem'; +import type { TodoType } from '../types/todo'; type Props = { todos: Array, @@ -17,26 +17,14 @@ export default class TodoList extends PureComponent { renderTodoView = (todo: TodoType) => { const { deleteTodo, toggleEdit } = this.props; - return ( - - ); - } + return ; + }; renderEditView = (todo: TodoType) => { const { updateTodo, cancelUpdateTodo } = this.props; - return ( - - ); - } + return ; + }; renderList = () => { const { todos } = this.props; @@ -45,24 +33,15 @@ export default class TodoList extends PureComponent { return (
    {sortTodosByTime.map(todo => ( -
  • - {todo.editing ? ( - this.renderEditView(todo) - ) : ( - this.renderTodoView(todo) - )} +
  • + {todo.editing ? this.renderEditView(todo) : this.renderTodoView(todo)}
  • ))}
); - } + }; - renderEmptyState = () => ( -

No todos right now

- ); + renderEmptyState = () =>

No todos right now

; render() { const { todos } = this.props; diff --git a/app/components/TodoListItem.js b/app/components/TodoListItem.js new file mode 100644 index 0000000..d668f40 --- /dev/null +++ b/app/components/TodoListItem.js @@ -0,0 +1,55 @@ +// @flow + +import React, { PureComponent } from 'react'; +import type { TodoType } from '../types/todo'; + +type Props = { + todo: TodoType, + deleteTodo: Function, + toggleEdit: Function, +}; + +export default class TodoListItem extends PureComponent { + handleDelete = (id: string) => { + if (!id) return; + + const { deleteTodo } = this.props; + deleteTodo(id); + }; + + handleEditToggle = (id: string) => { + if (!id) return; + + const { toggleEdit } = this.props; + toggleEdit(id); + }; + + render() { + const { todo } = this.props; + + return ( +
+ {todo.text} +
+ + +
+
+ ); + } +} diff --git a/app/components/layout/styles.js b/app/components/layout/styles.js deleted file mode 100644 index 2b7250e..0000000 --- a/app/components/layout/styles.js +++ /dev/null @@ -1,15 +0,0 @@ -// @flow - -export const styles: Object = { - layout: ` - display: flex; - flex-direction: column; - width: 200px; - position: absolute; - width: calc(100vh - 200px); - left: 0; - top: 0; - height: 100vh; - background: #ccc; - `, -}; diff --git a/app/components/sidebar/styles.js b/app/components/sidebar/styles.js deleted file mode 100644 index 5a23074..0000000 --- a/app/components/sidebar/styles.js +++ /dev/null @@ -1,14 +0,0 @@ -// @flow - -export const styles: Object = { - wrapper: ` - display: flex; - flex-direction: column; - width: 200px; - position: absolute; - left: 0; - top: 0; - height: 100vh; - background: #ccc; - `, -}; diff --git a/app/components/todo/todo-list-item.js b/app/components/todo/todo-list-item.js deleted file mode 100644 index bf118ec..0000000 --- a/app/components/todo/todo-list-item.js +++ /dev/null @@ -1,56 +0,0 @@ -// @flow - -import React, { PureComponent } from 'react'; -import type { TodoType } from '../../types/todo'; - -type Props = { - todo: TodoType, - deleteTodo: Function, - toggleEdit: Function, -}; - -export default class TodoListItem extends PureComponent { - handleDelete = (id: string) => { - if (!id) return; - - const { deleteTodo } = this.props; - deleteTodo(id); - } - - handleEditToggle = (id: string) => { - if (!id) return; - - const { toggleEdit } = this.props; - toggleEdit(id); - } - - render() { - const { - todo, - } = this.props; - - return ( -
- - {todo.text} - -
- - -
-
- ); - } -} diff --git a/app/constants/themes.js b/app/constants/themes.js new file mode 100644 index 0000000..34bbef4 --- /dev/null +++ b/app/constants/themes.js @@ -0,0 +1,4 @@ +// @flow + +export const LIGHT = 'light'; +export const DARK = 'dark'; diff --git a/app/containers/sidebar.js b/app/containers/sidebar.js index d4dbc21..b74a6c5 100644 --- a/app/containers/sidebar.js +++ b/app/containers/sidebar.js @@ -1,7 +1,7 @@ // @flow import { connect } from 'react-redux'; -import { SidebarComponent } from '../components/sidebar'; +import { SidebarComponent } from '../components/Sidebar'; const mapStateToProps = (state: Object) => ({ todos: state.todos, diff --git a/app/theme.js b/app/theme.js new file mode 100644 index 0000000..7cf0ebd --- /dev/null +++ b/app/theme.js @@ -0,0 +1,35 @@ +// @flow +import React from 'react'; +import { ThemeProvider, createGlobalStyle } from 'styled-components'; +// $FlowFixMe +import { normalize } from 'polished'; +import theme from 'styled-theming'; + +import { DARK } from './constants/themes'; + +const appTheme = { + mode: DARK, + fontFamily: 'Open Sans', + colors: { + primary: theme('mode', { + light: '#fff', + dark: '#000', + }), + secondary: theme('mode', { + light: '#000', + dark: '#fff', + }), + }, + size: { + title: 18, + paragraph: 12, + }, +}; + +/* eslint-disable react/prop-types */ +// $FlowFixMe +export const DoczWrapper = ({ children }) => {children()}; + +export const GlobalStyle = createGlobalStyle`${normalize()}`; + +export default appTheme; diff --git a/app/views/todo.js b/app/views/todo.js index d6344d8..1de5d4e 100644 --- a/app/views/todo.js +++ b/app/views/todo.js @@ -1,8 +1,8 @@ // @flow import React from 'react'; -import TodoInput from '../components/todo/todo-input'; -import TodoList from '../components/todo/todo-list'; +import TodoInput from '../components/TodoInput'; +import TodoList from '../components/TodoList'; import type { TodoType } from '../types/todo'; import checklist from '../assets/images/checklist.svg'; @@ -17,12 +17,7 @@ type Props = { export default (props: Props) => { const { - addTodo, - todos, - deleteTodo, - toggleEdit, - updateTodo, - cancelUpdateTodo, + addTodo, todos, deleteTodo, toggleEdit, updateTodo, cancelUpdateTodo, } = props; return ( diff --git a/package.json b/package.json index 9319bce..dcca784 100644 --- a/package.json +++ b/package.json @@ -59,7 +59,7 @@ "eslint-plugin-jsx-a11y": "^6.0.3", "eslint-plugin-react": "^7.7.0", "file-loader": "^2.0.0", - "flow-bin": "^0.86.0", + "flow-bin": "^0.87.0", "glow": "^1.2.2", "html-webpack-plugin": "^3.1.0", "jest": "^23.6.0", @@ -86,6 +86,7 @@ "connected-react-router": "^5.0.1", "flow-coverage-report": "^0.6.0", "history": "^4.7.2", + "polished": "^2.3.0", "react": "^16.6.0", "react-dom": "^16.6.0", "react-redux": "^5.0.7", @@ -93,6 +94,7 @@ "redux": "^4.0.1", "redux-thunk": "^2.2.0", "styled-components": "^4.1.1", + "styled-theming": "^2.2.0", "uuid": "^3.3.2" }, "pre-commit": [ diff --git a/yarn.lock b/yarn.lock index f851a0c..f5467ae 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5752,10 +5752,10 @@ flow-annotation-check@1.8.1: glob "7.1.1" load-pkg "^3.0.1" -flow-bin@^0.86.0: - version "0.86.0" - resolved "https://registry.yarnpkg.com/flow-bin/-/flow-bin-0.86.0.tgz#153a28722b4dc13b7200c74b644dd4d9f4969a11" - integrity sha512-ulRvFH3ewGIYwg+qPk/OJXoe3Nhqi0RyR0wqgK0b1NzUDEC6O99zU39MBTickXvlrr6iwRO6Wm4lVGeDmnzbew== +flow-bin@^0.87.0: + version "0.87.0" + resolved "https://registry.yarnpkg.com/flow-bin/-/flow-bin-0.87.0.tgz#fab7f984d8cc767e93fa9eb01cf7d57ed744f19d" + integrity sha512-mnvBXXZkUp4y6A96bR5BHa3q1ioIIN2L10w5osxJqagAakTXFYZwjl0t9cT3y2aCEf1wnK6n91xgYypQS/Dqbw== flow-coverage-report@^0.6.0: version "0.6.0" @@ -12959,6 +12959,11 @@ styled-components@^4.1.1: stylis-rule-sheet "^0.0.10" supports-color "^5.5.0" +styled-theming@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/styled-theming/-/styled-theming-2.2.0.tgz#3084e43d40eaab4bc11ebafd3de04e3622fee37e" + integrity sha1-MITkPUDqq0vBHrr9PeBONiL+434= + stylehacks@^4.0.0: version "4.0.1" resolved "https://registry.yarnpkg.com/stylehacks/-/stylehacks-4.0.1.tgz#3186595d047ab0df813d213e51c8b94e0b9010f2"