├── .editorconfig ├── .eslintrc.js ├── .gitignore ├── babel.config.js ├── config ├── dev.js ├── index.js └── prod.js ├── package.json ├── project.config.json ├── src ├── actions │ └── index.js ├── app.config.js ├── app.js ├── app.scss ├── components │ ├── Footer │ │ ├── Footer.js │ │ └── Footer.scss │ ├── TodoItem │ │ ├── TodoItem.js │ │ └── TodoItem.scss │ └── TodoTextInput │ │ ├── TodoTextInput.js │ │ └── TodoTextInput.scss ├── constants │ ├── ActionTypes.js │ └── TodoFilters.js ├── containers │ ├── FilterLink │ │ ├── FilterLink.js │ │ └── FilterLink.scss │ ├── Header │ │ ├── Header.js │ │ └── Header.scss │ ├── MainSection │ │ ├── MainSection.js │ │ └── MainSection.scss │ └── TodoList │ │ ├── TodoList.js │ │ └── TodoList.scss ├── index.html ├── pages │ └── index │ │ ├── index.config.js │ │ ├── index.js │ │ └── index.scss ├── reducers │ ├── index.js │ ├── todos.js │ └── visibilityFilter.js ├── selectors │ └── index.js ├── store │ └── index.js └── utils │ └── index.js └── yarn.lock /.editorconfig: -------------------------------------------------------------------------------- 1 | # http://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | indent_style = space 6 | indent_size = 2 7 | charset = utf-8 8 | trim_trailing_whitespace = true 9 | insert_final_newline = true 10 | 11 | [*.md] 12 | trim_trailing_whitespace = false 13 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | 'extends': [ 3 | // add more generic rulesets here, such as: 4 | // 'eslint:recommended', 5 | 'taro/react' 6 | ] 7 | } 8 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | dist/ 2 | .temp/ 3 | .rn_temp/ 4 | node_modules/ 5 | .DS_Store 6 | -------------------------------------------------------------------------------- /babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: [ 3 | ['taro', { 4 | framework: 'react', 5 | ts: false 6 | }] 7 | ] 8 | } -------------------------------------------------------------------------------- /config/dev.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | env: { 3 | NODE_ENV: '"development"' 4 | }, 5 | defineConstants: { 6 | }, 7 | mini: {}, 8 | h5: {} 9 | } 10 | -------------------------------------------------------------------------------- /config/index.js: -------------------------------------------------------------------------------- 1 | const config = { 2 | projectName: 'todo-list', 3 | date: '2018-7-9', 4 | designWidth: 750, 5 | sourceRoot: 'src', 6 | outputRoot: 'dist', 7 | framework: 'react', 8 | defineConstants: { 9 | }, 10 | mini: { 11 | 12 | }, 13 | h5: { 14 | publicPath: '/', 15 | staticDirectory: 'static', 16 | esnextModules: ['taro-ui'], 17 | module: { 18 | postcss: { 19 | autoprefixer: { 20 | enable: true 21 | } 22 | } 23 | } 24 | } 25 | } 26 | 27 | module.exports = function (merge) { 28 | if (process.env.NODE_ENV === 'development') { 29 | return merge({}, config, require('./dev')) 30 | } 31 | return merge({}, config, require('./prod')) 32 | } 33 | -------------------------------------------------------------------------------- /config/prod.js: -------------------------------------------------------------------------------- 1 | const wba = require('webpack-bundle-analyzer').BundleAnalyzerPlugin 2 | 3 | module.exports = { 4 | env: { 5 | NODE_ENV: '"production"' 6 | }, 7 | defineConstants: { 8 | }, 9 | mini: {}, 10 | h5: { 11 | webpackChain (chain) { 12 | chain.plugin('analyzer') 13 | .use(wba, []) 14 | }, 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "todo-list", 3 | "version": "1.0.0", 4 | "private": true, 5 | "description": "todo-list", 6 | "main": "index.js", 7 | "scripts": { 8 | "build:rn": "taro build --type rn", 9 | "build:weapp": "taro build --type weapp", 10 | "build:h5": "taro build --type h5", 11 | "dev:rn": "npm run build:rn -- --watch", 12 | "dev:weapp": "npm run build:weapp -- --watch", 13 | "dev:h5": "npm run build:h5 -- --watch", 14 | "test": "echo \"Error: no test specified\" && exit 1" 15 | }, 16 | "author": "", 17 | "license": "MIT", 18 | "dependencies": { 19 | "@babel/runtime": "7.11.2", 20 | "@tarojs/components": "3.4.9", 21 | "@tarojs/helper": "3.4.9", 22 | "@tarojs/plugin-platform-weapp": "3.4.9", 23 | "@tarojs/plugin-platform-alipay": "3.4.9", 24 | "@tarojs/plugin-platform-tt": "3.4.9", 25 | "@tarojs/plugin-platform-swan": "3.4.9", 26 | "@tarojs/plugin-platform-jd": "3.4.9", 27 | "@tarojs/plugin-platform-qq": "3.4.9", 28 | "@tarojs/router": "3.4.9", 29 | "@tarojs/react": "3.4.9", 30 | "@tarojs/runtime": "3.4.9", 31 | "@tarojs/shared": "3.4.9", 32 | "@tarojs/taro": "3.4.9", 33 | "@tarojs/taro-h5": "3.4.9", 34 | "@tarojs/plugin-framework-react": "3.4.9", 35 | "classnames": "2.2.6", 36 | "react": "^17.0.0", 37 | "react-dom": "^17.0.0", 38 | "react-redux": "^7.2.0", 39 | "redux": "^4.0.0", 40 | "redux-devtools-extension": "2.13.8", 41 | "redux-logger": "3.0.6", 42 | "redux-thunk": "2.3.0", 43 | "reselect": "4.0.0" 44 | }, 45 | "devDependencies": { 46 | "@babel/core": "7.11.4", 47 | "@types/webpack-env": "1.15.2", 48 | "@types/react": "16.9.48", 49 | "@types/redux-actions": "2.6.1", 50 | "@tarojs/mini-runner": "3.4.9", 51 | "@tarojs/webpack-runner": "3.4.9", 52 | "@pmmmwh/react-refresh-webpack-plugin": "0.5.5", 53 | "react-refresh": "0.11.0", 54 | "babel-preset-taro": "3.4.9", 55 | "eslint": "^8.12.0", 56 | "eslint-config-taro": "3.4.9", 57 | "eslint-plugin-import": "^2.12.0", 58 | "eslint-plugin-react": "^7.8.2", 59 | "eslint-plugin-react-hooks": "^4.2.0", 60 | "stylelint": "13.6.1", 61 | "typescript": "4.0.2", 62 | "webpack": "4.46.0", 63 | "webpack-bundle-analyzer": "3.8.0" 64 | }, 65 | "resolutions": { 66 | "@types/react": "^17.0.2" 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /project.config.json: -------------------------------------------------------------------------------- 1 | { 2 | "miniprogramRoot": "dist/", 3 | "projectname": "open-todo", 4 | "description": "todo-list", 5 | "appid": "touristappid", 6 | "setting": { 7 | "urlCheck": true, 8 | "scopeDataCheck": false, 9 | "coverView": true, 10 | "es6": false, 11 | "postcss": false, 12 | "compileHotReLoad": false, 13 | "preloadBackgroundData": false, 14 | "minified": false, 15 | "autoAudits": false, 16 | "newFeature": true, 17 | "uglifyFileName": false, 18 | "uploadWithSourceMap": true, 19 | "useIsolateContext": true, 20 | "nodeModules": false, 21 | "enhance": false, 22 | "useCompilerModule": false, 23 | "userConfirmedUseCompilerModuleSwitch": false, 24 | "showShadowRootInWxmlPanel": true 25 | }, 26 | "compileType": "miniprogram", 27 | "simulatorType": "wechat", 28 | "simulatorPluginLibVersion": {}, 29 | "condition": {} 30 | } -------------------------------------------------------------------------------- /src/actions/index.js: -------------------------------------------------------------------------------- 1 | import * as types from '../constants/ActionTypes' 2 | 3 | export const addTodo = text => ({ type: types.ADD_TODO, text }) 4 | export const deleteTodo = id => ({ type: types.DELETE_TODO, id }) 5 | export const editTodo = (id, text) => ({ type: types.EDIT_TODO, id, text }) 6 | export const completeTodo = id => ({ type: types.COMPLETE_TODO, id }) 7 | export const completeAllTodos = () => ({ type: types.COMPLETE_ALL_TODOS }) 8 | export const clearCompleted = () => ({ type: types.CLEAR_COMPLETED }) 9 | export const setVisibilityFilter = filter => ({ type: types.SET_VISIBILITY_FILTER, filter}) 10 | -------------------------------------------------------------------------------- /src/app.config.js: -------------------------------------------------------------------------------- 1 | export default { 2 | pages: [ 3 | 'pages/index/index' 4 | ], 5 | window: { 6 | backgroundTextStyle: 'light', 7 | navigationBarBackgroundColor: '#fff', 8 | navigationBarTitleText: 'WeChat', 9 | navigationBarTextStyle: 'black' 10 | } 11 | } -------------------------------------------------------------------------------- /src/app.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { Provider } from 'react-redux' 3 | import { createStore, applyMiddleware } from 'redux' 4 | import { composeWithDevTools } from 'redux-devtools-extension' 5 | 6 | import reducer from './reducers' 7 | 8 | import './app.scss' 9 | 10 | const store = createStore(reducer, composeWithDevTools( 11 | applyMiddleware() 12 | // other store enhancers if any 13 | )) 14 | 15 | class App extends React.Component { 16 | render () { 17 | return ( 18 | 19 | {this.props.children} 20 | 21 | ) 22 | } 23 | } 24 | 25 | export default App 26 | -------------------------------------------------------------------------------- /src/app.scss: -------------------------------------------------------------------------------- 1 | html, 2 | body { 3 | margin: 0; 4 | padding: 0; 5 | } 6 | 7 | // 元素选择器 8 | button { 9 | margin: 0; 10 | padding: 0; 11 | border: 0; 12 | //background: none; 13 | // font-size: 100%; 14 | vertical-align: baseline; 15 | font-family: inherit; 16 | font-weight: inherit; 17 | color: inherit; 18 | //-webkit-appearance: none; 19 | //appearance: none; 20 | //-webkit-font-smoothing: antialiased; 21 | //-moz-osx-font-smoothing: grayscale; 22 | //&::after { 23 | // border: 0; 24 | //} 25 | } 26 | 27 | body, page { 28 | font: 28px 'Helvetica Neue', Helvetica, Arial, sans-serif; 29 | background: #f5f5f5; 30 | color: #4d4d4d; 31 | margin: 0 auto; 32 | //-webkit-font-smoothing: antialiased; 33 | //-moz-osx-font-smoothing: grayscale; 34 | font-weight: 300; 35 | } 36 | 37 | :focus { 38 | outline: 0; 39 | } 40 | 41 | .hidden { 42 | display: none; 43 | } 44 | 45 | .todoapp { 46 | background: #fff; 47 | margin: 210px 0 40px 0; 48 | position: relative; 49 | //box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.2), 50 | // 0 25px WebkitTextRendering50px 0 rgba(0, 0, 0, 0.1); 51 | } 52 | 53 | input::-webkit-input-placeholder { 54 | font-style: italic; 55 | font-weight: 300; 56 | color: #e6e6e6; 57 | } 58 | 59 | input::-moz-placeholder { 60 | font-style: italic; 61 | font-weight: 300; 62 | color: #e6e6e6; 63 | } 64 | 65 | //input::input-placeholder { 66 | // font-style: italic; 67 | // font-weight: 300; 68 | // color: #e6e6e6; 69 | //} 70 | 71 | .info { 72 | margin: 130px auto 0; 73 | color: #bfbfbf; 74 | //font-size: 20px; 75 | text-shadow: 0 2px 0 rgba(255, 255, 255, 0.5); 76 | //text-align: center; 77 | } 78 | 79 | .info p { 80 | line-height: 1; 81 | } 82 | 83 | .info a { 84 | color: inherit; 85 | text-decoration: none; 86 | font-weight: 400; 87 | } 88 | 89 | .info a:hover { 90 | text-decoration: underline; 91 | } 92 | 93 | .toggle-all, 94 | .todo-list .list-item .toggle { 95 | //background: none; 96 | } 97 | 98 | .todo-list .list-item .toggle { 99 | //height: 80px; 100 | } 101 | 102 | .weui-cells_checkbox { 103 | margin-right: 10px; 104 | } 105 | -------------------------------------------------------------------------------- /src/components/Footer/Footer.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { View, Text } from '@tarojs/components' 3 | 4 | import './Footer.scss' 5 | 6 | export default class Footer extends React.Component { 7 | 8 | onClearCompleted = () => { 9 | console.log('onClearCompleted') 10 | this.props.onClearCompleted() 11 | } 12 | 13 | render () { 14 | const {activeCount, completedCount} = this.props 15 | const itemWord = activeCount === 1 ? 'item' : 'items' 16 | return ( 17 | 18 | 19 | 20 | {activeCount || 'No'}{' '}{itemWord} left 21 | 22 | { 23 | !!completedCount && 24 | 28 | Clear completed 29 | 30 | } 31 | 32 | 33 | ) 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/components/Footer/Footer.scss: -------------------------------------------------------------------------------- 1 | /*postcss-pxtransform rn eject enable*/ 2 | .footer:before { 3 | content: ''; 4 | position: absolute; 5 | z-index: -1; 6 | right: 0; 7 | bottom: 0; 8 | left: 0; 9 | height: 100px; 10 | overflow: hidden; 11 | box-shadow: 0 1px 1px rgba(0, 0, 0, 0.2), 12 | 0 8px 0 -3px #f6f6f6, 13 | 0 9px 1px -3px rgba(0, 0, 0, 0.2), 14 | 0 16px 0 -6px #f6f6f6, 15 | 0 17px 2px -6px rgba(0, 0, 0, 0.2); 16 | } 17 | 18 | /*postcss-pxtransform rn eject disable*/ 19 | 20 | .footer { 21 | padding: 20px 30px; 22 | border-top-width: 2px; 23 | border-top-color: #e6e6e6; 24 | border-style: solid; 25 | border-bottom-width: 0; 26 | border-left-width: 0; 27 | border-right-width: 0; 28 | } 29 | 30 | .footer-content { 31 | display: flex; 32 | flex-direction: row; 33 | } 34 | 35 | .todo-count { 36 | flex: 1; 37 | color: #777; 38 | } 39 | 40 | .todo-count strong { 41 | font-weight: 300; 42 | } 43 | 44 | .clear-completed-text { 45 | display: flex; 46 | color: #777; 47 | justify-content: flex-end; 48 | } 49 | 50 | @media (max-width: 430px) { 51 | .footer { 52 | height: 50px; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/components/TodoItem/TodoItem.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { View, Checkbox, Label, CheckboxGroup, Text } from '@tarojs/components' 3 | import classnames from 'classnames' 4 | 5 | import TodoTextInput from '../TodoTextInput/TodoTextInput' 6 | import './TodoItem.scss' 7 | 8 | export default class TodoItem extends React.Component { 9 | static defaultProps = { 10 | todo: {} 11 | } 12 | 13 | state = { 14 | editing: false 15 | } 16 | 17 | handleSubmit = () => { 18 | const val = this.state.editText.trim() 19 | if (val) { 20 | this.props.onSave(val) 21 | this.setState({editText: val}) 22 | } else { 23 | this.props.onDestroy() 24 | } 25 | } 26 | 27 | handleDoubleClick = () => { 28 | this.setState({editing: true}) 29 | } 30 | 31 | handleSave = (id, text) => { 32 | if (text.length === 0) { 33 | this.props.onDeleteTodo(id) 34 | } else { 35 | this.props.onEditTodo(id, text) 36 | } 37 | this.setState({editing: false}) 38 | } 39 | 40 | handleCompleteTodo = (todo) => { 41 | console.log('handleCompleteTodo') 42 | this.props.onCompleteTodo(todo.id) 43 | } 44 | 45 | render () { 46 | const {todo} = this.props 47 | 48 | let element 49 | if (this.state.editing) { 50 | element = ( 51 | 52 | ) 53 | } else { 54 | element = ( 55 | 56 | 57 | 61 | 62 | 63 | ) 64 | } 65 | 66 | return ( 67 | 73 | {element} 74 | 75 | ) 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /src/components/TodoItem/TodoItem.scss: -------------------------------------------------------------------------------- 1 | .checkbox-label { 2 | display: flex; 3 | margin: 10px; 4 | flex-direction: row; 5 | align-items: center; 6 | } 7 | 8 | .checkbox { 9 | margin-right: 10px; 10 | } 11 | -------------------------------------------------------------------------------- /src/components/TodoTextInput/TodoTextInput.js: -------------------------------------------------------------------------------- 1 | import Taro from '@tarojs/taro' 2 | import React from 'react' 3 | import classnames from 'classnames' 4 | import { Input } from '@tarojs/components' 5 | 6 | import './TodoTextInput.scss' 7 | 8 | export default class TodoTextInput extends React.Component { 9 | state = { 10 | todoText: this.props.text || '' 11 | } 12 | 13 | handleSubmit = e => { 14 | console.log('handleSubmit', e) 15 | const text = e.target.value.trim() 16 | this.props.onSave(text) 17 | if (this.props.newTodo) { 18 | this.setState({todoText: ''}) 19 | } 20 | } 21 | 22 | handleSubmitKey = e => { 23 | console.log('handleSubmitKey', e) 24 | const text = e.target.value.trim() 25 | if (e.which === 13) { 26 | this.props.onSave(text) 27 | if (this.props.newTodo) { 28 | this.setState({todoText: ''}) 29 | } 30 | } 31 | } 32 | 33 | handleChange = e => { 34 | if (Taro.getEnv() === Taro.ENV_TYPE.WEAPP) return 35 | console.log('handleChange', e) 36 | this.setState({todoText: e.target.value}) 37 | } 38 | 39 | handleInput = e => { 40 | console.log('handleChange', e) 41 | this.setState({todoText: e.target.value}) 42 | } 43 | 44 | handleBlur = e => { 45 | console.log('handleBlur', e) 46 | if (!this.props.newTodo) { 47 | this.props.onSave(e.target.value) 48 | } 49 | } 50 | 51 | render () { 52 | return ( 53 | 71 | ) 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /src/components/TodoTextInput/TodoTextInput.scss: -------------------------------------------------------------------------------- 1 | .new-todo { 2 | padding: 32px; 3 | font-size: 48px; 4 | font-style: italic; 5 | font-weight: 300; 6 | color: black; 7 | box-shadow: none; 8 | background: rgba(0, 0, 0, 0.003); 9 | } 10 | 11 | -------------------------------------------------------------------------------- /src/constants/ActionTypes.js: -------------------------------------------------------------------------------- 1 | export const ADD_TODO = 'ADD_TODO' 2 | export const DELETE_TODO = 'DELETE_TODO' 3 | export const EDIT_TODO = 'EDIT_TODO' 4 | export const COMPLETE_TODO = 'COMPLETE_TODO' 5 | export const COMPLETE_ALL_TODOS = 'COMPLETE_ALL_TODOS' 6 | export const CLEAR_COMPLETED = 'CLEAR_COMPLETED' 7 | export const SET_VISIBILITY_FILTER = 'SET_VISIBILITY_FILTER' 8 | -------------------------------------------------------------------------------- /src/constants/TodoFilters.js: -------------------------------------------------------------------------------- 1 | export const SHOW_ALL = 'show_all' 2 | export const SHOW_COMPLETED = 'show_completed' 3 | export const SHOW_ACTIVE = 'show_active' 4 | -------------------------------------------------------------------------------- /src/containers/FilterLink/FilterLink.js: -------------------------------------------------------------------------------- 1 | import { connect } from 'react-redux' 2 | import React from 'react' 3 | import { Text } from '@tarojs/components' 4 | import classnames from 'classnames' 5 | 6 | import { setVisibilityFilter } from '../../actions' 7 | import { SHOW_ALL, SHOW_COMPLETED, SHOW_ACTIVE } from '../../constants/TodoFilters' 8 | 9 | import './FilterLink.scss' 10 | 11 | const FILTER_TITLES = { 12 | [SHOW_ALL]: 'All', 13 | [SHOW_ACTIVE]: 'Active', 14 | [SHOW_COMPLETED]: 'Completed' 15 | } 16 | 17 | const mapStateToProps = ({visibilityFilter}) => ({ 18 | visibilityFilter 19 | }) 20 | 21 | const mapDispatchToProps = (dispatch) => ({ 22 | setFilter: (filter) => { 23 | dispatch(setVisibilityFilter(filter)) 24 | } 25 | }) 26 | 27 | @connect( 28 | mapStateToProps, 29 | mapDispatchToProps 30 | ) 31 | class FilterLink extends React.Component { 32 | onClickHandler = () => { 33 | console.log('onClickHandler', this.props.filter) 34 | this.props.setFilter(this.props.filter) 35 | } 36 | 37 | render () { 38 | const {filter, visibilityFilter} = this.props 39 | const text = FILTER_TITLES[filter] 40 | const active = visibilityFilter === filter 41 | return ( 42 | 46 | {text} 47 | 48 | ) 49 | } 50 | } 51 | 52 | export default FilterLink -------------------------------------------------------------------------------- /src/containers/FilterLink/FilterLink.scss: -------------------------------------------------------------------------------- 1 | .filters-link { 2 | display: flex; 3 | padding: 6px 14px; 4 | // transparent 不支持?? TODO 5 | border-width: 2px; 6 | border-style: solid; 7 | border-color: transparent; 8 | border-radius: 6px; 9 | } 10 | 11 | .filters-link:hover { 12 | border-color: #efd5d5; 13 | } 14 | 15 | .selected { 16 | border-color: #efd5d5; 17 | border-width: 2px; 18 | } 19 | -------------------------------------------------------------------------------- /src/containers/Header/Header.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { View, Text } from '@tarojs/components' 3 | import { connect } from 'react-redux' 4 | import { bindActionCreators } from 'redux' 5 | 6 | import TodoTextInput from '../../components/TodoTextInput/TodoTextInput' 7 | import FilterLink from '../FilterLink/FilterLink' 8 | import { SHOW_ALL, SHOW_COMPLETED, SHOW_ACTIVE } from '../../constants/TodoFilters' 9 | import * as TodoActions from '../../actions' 10 | import './Header.scss' 11 | 12 | const FILTER_TITLES = { 13 | [SHOW_ALL]: 'All', 14 | [SHOW_ACTIVE]: 'Active', 15 | [SHOW_COMPLETED]: 'Completed' 16 | } 17 | 18 | const mapDispatchToProps = dispatch => ({ 19 | actions: bindActionCreators(TodoActions, dispatch) 20 | }) 21 | 22 | @connect( 23 | () => ({}), 24 | mapDispatchToProps 25 | ) 26 | class Header extends React.Component { 27 | onCheckClickHandler = () => { 28 | console.log('onCheckClickHandler') 29 | const {actions} = this.props 30 | actions.completeAllTodos() 31 | } 32 | 33 | onSaveHandler = (text) => { 34 | if (text.length !== 0) { 35 | this.props.actions.addTodo(text) 36 | } 37 | } 38 | 39 | render () { 40 | return ( 41 | 42 | 43 | todos 44 | 45 | 46 | {Object.keys(FILTER_TITLES).map((filter, index) => 47 | 48 | 49 | 50 | )} 51 | 52 | 53 | 54 | 55 | 61 | 62 | 63 | 64 | ) 65 | } 66 | } 67 | 68 | export default Header 69 | -------------------------------------------------------------------------------- /src/containers/Header/Header.scss: -------------------------------------------------------------------------------- 1 | .title { 2 | width: 100%; 3 | font-size: 100px; 4 | font-weight: 100; 5 | text-align: center; 6 | color: rgba(175, 47, 47, 0.55); 7 | //-webkit-text-rendering: optimizeLegibility; 8 | //-moz-text-rendering: optimizeLegibility; 9 | //text-rendering: optimizeLegibility; 10 | } 11 | 12 | .header-title-wrap { 13 | display: flex; 14 | background-color: #F5F5F5; 15 | } 16 | 17 | .textinput-wrap { 18 | display: flex; 19 | flex-direction: row; 20 | align-items: center; 21 | border: 1px solid #e6e6e6; 22 | } 23 | 24 | .textinput-wrap-icon { 25 | font-size: 44px; 26 | color: #e6e6e6; 27 | padding: 20px 54px 20px 54px; 28 | transform: rotate(90deg); 29 | } 30 | 31 | .todo-text-input { 32 | flex: 1; 33 | } 34 | 35 | .textinput-wrap-input { 36 | flex: 1; 37 | } 38 | 39 | .filters { 40 | display: flex; 41 | font-weight: 400; 42 | margin: 0; 43 | padding: 0; 44 | flex-direction: row; 45 | background-color: #F5F5F5; 46 | } 47 | 48 | .filters-item { 49 | margin: 6px; 50 | } 51 | 52 | -------------------------------------------------------------------------------- /src/containers/MainSection/MainSection.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { View } from '@tarojs/components' 3 | import { connect } from 'react-redux' 4 | import { bindActionCreators } from 'redux' 5 | 6 | import * as TodoActions from '../../actions' 7 | import Footer from '../../components/Footer/Footer' 8 | import TodoList from '../TodoList/TodoList' 9 | import { getCompletedTodoCount } from '../../selectors' 10 | 11 | import './MainSection.scss' 12 | 13 | const mapStateToProps = state => ({ 14 | todosCount: state.todos.length, 15 | completedCount: getCompletedTodoCount(state) 16 | }) 17 | 18 | 19 | const mapDispatchToProps = dispatch => ({ 20 | actions: bindActionCreators(TodoActions, dispatch) 21 | }) 22 | 23 | @connect( 24 | mapStateToProps, 25 | mapDispatchToProps 26 | ) 27 | class MainSection extends React.Component { 28 | onCheckClickHandler = () => { 29 | const { actions } = this.props 30 | actions.completeAllTodos() 31 | } 32 | 33 | onChangeHandler = () => {} 34 | 35 | render () { 36 | const { todosCount, completedCount, actions } = this.props 37 | return ( 38 | 39 | 40 | { 41 | !!todosCount && 42 |