diff --git a/src/components/TodoList/Todo.vue b/src/components/TodoList/Todo.vue new file mode 100644 index 0000000000000000000000000000000000000000..028acfc70213456f295b89158c914772b89f0065 --- /dev/null +++ b/src/components/TodoList/Todo.vue @@ -0,0 +1,70 @@ +<template> + <li class="todo" :class="{ completed: todo.done, editing: editing }"> + <div class="view"> + <input class="toggle" + type="checkbox" + :checked="todo.done" + @change="toggleTodo( todo)"> + <label v-text="todo.text" @dblclick="editing = true"></label> + <button class="destroy" @click="deleteTodo( todo )"></button> + </div> + <input class="edit" + v-show="editing" + v-focus="editing" + :value="todo.text" + @keyup.enter="doneEdit" + @keyup.esc="cancelEdit" + @blur="doneEdit"> + </li> +</template> + +<script> +export default { + name: 'Todo', + props: ['todo'], + data() { + return { + editing: false + } + }, + directives: { + focus(el, { value }, { context }) { + if (value) { + context.$nextTick(() => { + el.focus() + }) + } + } + }, + methods: { + deleteTodo(todo) { + this.$emit('deleteTodo', todo) + }, + editTodo({ todo, value }) { + this.$emit('editTodo', { todo, value }) + }, + toggleTodo(todo) { + this.$emit('toggleTodo', todo) + }, + doneEdit(e) { + const value = e.target.value.trim() + const { todo } = this + if (!value) { + this.deleteTodo({ + todo + }) + } else if (this.editing) { + this.editTodo({ + todo, + value + }) + this.editing = false + } + }, + cancelEdit(e) { + e.target.value = this.todo.text + this.editing = false + } + } +} +</script> diff --git a/src/components/TodoList/index.scss b/src/components/TodoList/index.scss new file mode 100644 index 0000000000000000000000000000000000000000..071bf1de231c57e2cf6b216837d6039cbb596b27 --- /dev/null +++ b/src/components/TodoList/index.scss @@ -0,0 +1,318 @@ +.todoapp { + font: 14px 'Helvetica Neue', Helvetica, Arial, sans-serif; + line-height: 1.4em; + color: #4d4d4d; + min-width: 230px; + max-width: 550px; + margin: 40PX auto 0; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + font-weight: 300; + button { + margin: 0; + padding: 0; + border: 0; + background: none; + font-size: 100%; + vertical-align: baseline; + font-family: inherit; + font-weight: inherit; + color: inherit; + -webkit-appearance: none; + appearance: none; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + } + :focus { + outline: 0; + } + .hidden { + display: none; + } + .todoapp { + background: #fff; + margin: 130px 0 40px 0; + position: relative; + box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.2), 0 25px 50px 0 rgba(0, 0, 0, 0.1); + } + .todoapp input::-webkit-input-placeholder { + font-style: italic; + font-weight: 300; + color: #e6e6e6; + } + .todoapp input::-moz-placeholder { + font-style: italic; + font-weight: 300; + color: #e6e6e6; + } + .todoapp input::input-placeholder { + font-style: italic; + font-weight: 300; + color: #e6e6e6; + } + .todoapp h1 { + position: absolute; + top: -155px; + width: 100%; + font-size: 100px; + font-weight: 100; + text-align: center; + color: rgba(175, 47, 47, 0.15); + -webkit-text-rendering: optimizeLegibility; + -moz-text-rendering: optimizeLegibility; + text-rendering: optimizeLegibility; + } + .new-todo, + .edit { + position: relative; + margin: 0; + width: 100%; + font-size: 18px; + font-family: inherit; + font-weight: inherit; + line-height: 1.4em; + border: 0; + color: inherit; + padding: 6px; + border: 1px solid #999; + box-shadow: inset 0 -1px 5px 0 rgba(0, 0, 0, 0.2); + box-sizing: border-box; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + } + .new-todo { + padding: 16px 16px 16px 60px; + border: none; + background: rgba(0, 0, 0, 0.003); + box-shadow: inset 0 -2px 1px rgba(0, 0, 0, 0.03); + } + .main { + position: relative; + z-index: 2; + border-top: 1px solid #e6e6e6; + } + .toggle-all { + text-align: center; + border: none; + /* Mobile Safari */ + opacity: 0; + position: absolute; + } + .toggle-all+label { + width: 60px; + height: 34px; + font-size: 0; + position: absolute; + top: -52px; + left: -13px; + -webkit-transform: rotate(90deg); + transform: rotate(90deg); + } + .toggle-all+label:before { + content: 'â¯'; + font-size: 22px; + color: #e6e6e6; + padding: 10px 27px 10px 27px; + } + .toggle-all:checked+label:before { + color: #737373; + } + .todo-list { + margin: 0; + padding: 0; + list-style: none; + } + .todo-list li { + position: relative; + font-size: 24px; + border-bottom: 1px solid #ededed; + } + .todo-list li:last-child { + border-bottom: none; + } + .todo-list li.editing { + border-bottom: none; + padding: 0; + } + .todo-list li.editing .edit { + display: block; + width: 506px; + padding: 12px 16px; + margin: 0 0 0 43px; + } + .todo-list li.editing .view { + display: none; + } + .todo-list li .toggle { + text-align: center; + width: 40px; + /* auto, since non-WebKit browsers doesn't support input styling */ + height: auto; + position: absolute; + top: 0; + bottom: 0; + margin: auto 0; + border: none; + /* Mobile Safari */ + -webkit-appearance: none; + appearance: none; + } + .todo-list li .toggle { + opacity: 0; + } + .todo-list li .toggle+label { + /* + Firefox requires `#` to be escaped - https://bugzilla.mozilla.org/show_bug.cgi?id=922433 + IE and Edge requires *everything* to be escaped to render, so we do that instead of just the `#` - https://developer.microsoft.com/en-us/microsoft-edge/platform/issues/7157459/ + */ + background-image: url('data:image/svg+xml;utf8,%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20width%3D%2240%22%20height%3D%2240%22%20viewBox%3D%22-10%20-18%20100%20135%22%3E%3Ccircle%20cx%3D%2250%22%20cy%3D%2250%22%20r%3D%2250%22%20fill%3D%22none%22%20stroke%3D%22%23ededed%22%20stroke-width%3D%223%22/%3E%3C/svg%3E'); + background-repeat: no-repeat; + background-position: center left; + background-size: 36px; + } + .todo-list li .toggle:checked+label { + background-size: 36px; + background-image: url('data:image/svg+xml;utf8,%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20width%3D%2240%22%20height%3D%2240%22%20viewBox%3D%22-10%20-18%20100%20135%22%3E%3Ccircle%20cx%3D%2250%22%20cy%3D%2250%22%20r%3D%2250%22%20fill%3D%22none%22%20stroke%3D%22%23bddad5%22%20stroke-width%3D%223%22/%3E%3Cpath%20fill%3D%22%235dc2af%22%20d%3D%22M72%2025L42%2071%2027%2056l-4%204%2020%2020%2034-52z%22/%3E%3C/svg%3E'); + } + .todo-list li label { + word-break: break-all; + padding: 15px 15px 15px 50px; + display: block; + line-height: 1.0; + font-size: 14px; + transition: color 0.4s; + } + .todo-list li.completed label { + color: #d9d9d9; + text-decoration: line-through; + } + .todo-list li .destroy { + display: none; + position: absolute; + top: 0; + right: 10px; + bottom: 0; + width: 40px; + height: 40px; + margin: auto 0; + font-size: 30px; + color: #cc9a9a; + margin-bottom: 11px; + transition: color 0.2s ease-out; + } + .todo-list li .destroy:hover { + color: #af5b5e; + } + .todo-list li .destroy:after { + content: '×'; + } + .todo-list li:hover .destroy { + display: block; + } + .todo-list li .edit { + display: none; + } + .todo-list li.editing:last-child { + margin-bottom: -1px; + } + .footer { + color: #777; + position: relative; + padding: 10px 15px; + height: 40px; + text-align: center; + border-top: 1px solid #e6e6e6; + } + .footer:before { + content: ''; + position: absolute; + right: 0; + bottom: 0; + left: 0; + height: 50px; + overflow: hidden; + box-shadow: 0 1px 1px rgba(0, 0, 0, 0.2), 0 8px 0 -3px #f6f6f6, 0 9px 1px -3px rgba(0, 0, 0, 0.2), 0 16px 0 -6px #f6f6f6, 0 17px 2px -6px rgba(0, 0, 0, 0.2); + } + .todo-count { + float: left; + text-align: left; + } + .todo-count strong { + font-weight: 300; + } + .filters { + margin: 0; + padding: 0; + list-style: none; + position: absolute; + right: 0; + left: 0; + } + .filters li { + display: inline; + } + .filters li a { + color: inherit; + margin: 3px; + padding: 3px 7px; + text-decoration: none; + border: 1px solid transparent; + border-radius: 3px; + } + .filters li a:hover { + border-color: rgba(175, 47, 47, 0.1); + } + .filters li a.selected { + border-color: rgba(175, 47, 47, 0.2); + } + .clear-completed, + html .clear-completed:active { + float: right; + position: relative; + line-height: 20px; + text-decoration: none; + cursor: pointer; + } + .clear-completed:hover { + text-decoration: underline; + } + .info { + margin: 65px auto 0; + color: #bfbfbf; + font-size: 10px; + text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5); + text-align: center; + } + .info p { + line-height: 1; + } + .info a { + color: inherit; + text-decoration: none; + font-weight: 400; + } + .info a:hover { + text-decoration: underline; + } + /* + Hack to remove background from Mobile Safari. + Can't use it globally since it destroys checkboxes in Firefox +*/ + @media screen and (-webkit-min-device-pixel-ratio:0) { + .toggle-all, + .todo-list li .toggle { + background: none; + } + .todo-list li .toggle { + height: 40px; + } + } + @media (max-width: 430px) { + .footer { + height: 50px; + } + .filters { + bottom: 10px; + } + } +} diff --git a/src/components/TodoList/index.vue b/src/components/TodoList/index.vue new file mode 100644 index 0000000000000000000000000000000000000000..ae0cbc571fd06b4dff021bce92913a453017ecbf --- /dev/null +++ b/src/components/TodoList/index.vue @@ -0,0 +1,116 @@ +<template> + <section class="todoapp"> + <!-- header --> + <header class="header"> + <input class="new-todo" autofocus autocomplete="off" placeholder="TODO LIST?" @keyup.enter="addTodo"> + </header> + <!-- main section --> + <section class="main" v-show="todos.length"> + <input class="toggle-all" id="toggle-all" type="checkbox" :checked="allChecked" @change="toggleAll({ done: !allChecked })"> + <label for="toggle-all"></label> + <ul class="todo-list"> + <todo @toggleTodo='toggleTodo' @editTodo='editTodo' @deleteTodo='deleteTodo' v-for="(todo, index) in filteredTodos" :key="index" + :todo="todo"></todo> + </ul> + </section> + <!-- footer --> + <footer class="footer" v-show="todos.length"> + <span class="todo-count"> + <strong>{{ remaining }}</strong> + {{ remaining | pluralize('item') }} left + </span> + <ul class="filters"> + <li v-for="(val, key) in filters" :key="key"> + <a :class="{ selected: visibility === key }" @click.prevent="visibility = key">{{ key | capitalize }}</a> + </li> + </ul> + <button class="clear-completed" v-show="todos.length > remaining" @click="clearCompleted"> + Clear completed + </button> + </footer> + </section> +</template> + +<script> +import Todo from './Todo.vue' +const STORAGE_KEY = 'todos' +const filters = { + all: todos => todos, + active: todos => todos.filter(todo => !todo.done), + completed: todos => todos.filter(todo => todo.done) +} +const defalutList = [ + { text: 'star this repository', done: false }, + { text: 'fork this repository', done: false }, + { text: 'follow author', done: false } +] +export default { + components: { Todo }, + data() { + return { + visibility: 'all', + filters, + todos: JSON.parse(window.localStorage.getItem(STORAGE_KEY)) || defalutList + } + }, + computed: { + allChecked() { + return this.todos.every(todo => todo.done) + }, + filteredTodos() { + return filters[this.visibility](this.todos) + }, + remaining() { + return this.todos.filter(todo => !todo.done).length + } + }, + methods: { + setLocalStorgae() { + window.localStorage.setItem(STORAGE_KEY, JSON.stringify(this.todos)) + }, + addTodo(e) { + const text = e.target.value + if (text.trim()) { + this.todos.push({ + text, + done: false + }) + this.setLocalStorgae() + } + e.target.value = '' + }, + toggleTodo(val) { + val.done = !val.done + this.setLocalStorgae() + }, + deleteTodo(todo) { + console.log(todo) + this.todos.splice(this.todos.indexOf(todo), 1) + this.setLocalStorgae() + }, + editTodo({ todo, value }) { + console.log(todo, value) + todo.text = value + this.setLocalStorgae() + }, + clearCompleted() { + this.todos = this.todos.filter(todo => !todo.done) + this.setLocalStorgae() + }, + toggleAll({ done }) { + this.todos.forEach(todo => { + todo.done = done + this.setLocalStorgae() + }) + } + }, + filters: { + pluralize: (n, w) => n === 1 ? w : w + 's', + capitalize: s => s.charAt(0).toUpperCase() + s.slice(1) + } +} +</script> + +<style lang="scss"> + @import './index.scss'; +</style> diff --git a/src/views/dashboard/editor/index.vue b/src/views/dashboard/editor/index.vue index c4da0aa8de301acb0ad68a0beafe188903a69896..c72d9fe0566c7c24d9bddbe4461fd0dc7e1c48b1 100644 --- a/src/views/dashboard/editor/index.vue +++ b/src/views/dashboard/editor/index.vue @@ -53,8 +53,8 @@ <wscn-icon-svg icon-class="b" class="dashboard-editor-icon" /> </div> </el-card> - </el-col> + <el-col :span="8"> <pie-chart></pie-chart> </el-col> @@ -62,54 +62,31 @@ <el-col :span="10"> <bar-chart></bar-chart> </el-col> - </el-row> - <el-row> + + <el-row :gutter="20"> <el-col :span="16"> <line-chart></line-chart> </el-col> + <el-col :span="8"> + <todo-list></todo-list> + </el-col> </el-row> - <div class="info-container"> - - <div class="info-wrapper"> - - </div> - </div> - - <!--<div class="clearfix main-dashboard-container"> - - <div class="recent-articles-container"> - <div class="recent-articles-title">最近撸了</div> - <div class="recent-articles-wrapper"> - <template v-if="recentArticles.length!=0"> - <div class="recent-articles-item" v-for="item in recentArticles"> - <span class="recent-articles-status">{{item.status | statusFilter}}</span> - <span class="recent-articles-content" :to="'/article/edit/'+item.id"> - {{item.title}} - </span> - <span class="recent-articles-time">{{item.author}}</span> - </div> - </template> - <template v-else> - <div class="recent-articles-emptyTitle">ä½ å¤ªæ‡’äº†æœ€è¿‘éƒ½æ²¡æœ‰æ’¸</div> - </template> - </div> - </div> - </div>--> </div> </template> <script> import { mapGetters } from 'vuex'; - import PanThumb from 'components/PanThumb'; + import panThumb from 'components/PanThumb'; import pieChart from './pieChart'; import barChart from './barChart'; import lineChart from './lineChart'; import countTo from 'vue-count-to'; + import todoList from 'components/TodoList'; export default { name: 'dashboard-editor', - components: { PanThumb, countTo, pieChart, lineChart, barChart }, + components: { panThumb, countTo, pieChart, lineChart, barChart, todoList }, data() { return { statisticsData: { diff --git a/src/views/login/index.vue b/src/views/login/index.vue index a5a20c79db3c79a5c56b4a62ef1a416c4f64dd10..3f669781cba7abcf586011b5a104b59b3338d99f 100644 --- a/src/views/login/index.vue +++ b/src/views/login/index.vue @@ -73,11 +73,6 @@ showDialog: false } }, - computed: { - ...mapGetters([ - 'auth_type' - ]) - }, methods: { handleLogin() { this.$refs.loginForm.validate(valid => {