From 4a8b15e7be196ebbb3a267cfb5b07cd58619929d Mon Sep 17 00:00:00 2001 From: konrad Date: Sat, 5 Sep 2020 20:16:17 +0000 Subject: [PATCH] Favorite tasks (#236) Add loading spinner when updating a task Show favorites namespace if the favorited task is the first favorite Show the list favorited tasks belong to Fix task width Add method to mark a function as favorite Make favorite clickable Format Hide favorite button when not hovered Add button to mark a task as favorite Co-authored-by: kolaente Reviewed-on: https://kolaente.dev/vikunja/frontend/pulls/236 --- .../tasks/partials/singleTaskInList.vue | 36 ++++- src/main.js | 2 + src/models/task.js | 9 +- src/store/modules/namespaces.js | 6 + src/styles/components/tasks.scss | 126 +++++++++++------- src/views/list/views/List.vue | 21 +-- 6 files changed, 138 insertions(+), 62 deletions(-) diff --git a/src/components/tasks/partials/singleTaskInList.vue b/src/components/tasks/partials/singleTaskInList.vue index 17ceee86..df50dd20 100644 --- a/src/components/tasks/partials/singleTaskInList.vue +++ b/src/components/tasks/partials/singleTaskInList.vue @@ -1,5 +1,5 @@ diff --git a/src/main.js b/src/main.js index 5f6a2816..3acf6f57 100644 --- a/src/main.js +++ b/src/main.js @@ -54,6 +54,7 @@ import { faCalendarAlt } from '@fortawesome/free-regular-svg-icons' import { faCloudDownloadAlt } from '@fortawesome/free-solid-svg-icons' import { faCloudUploadAlt } from '@fortawesome/free-solid-svg-icons' import { faPercent } from '@fortawesome/free-solid-svg-icons' +import { faStar as faStarSolid } from '@fortawesome/free-solid-svg-icons' import { faStar } from '@fortawesome/free-regular-svg-icons' import { faAlignLeft } from '@fortawesome/free-solid-svg-icons' import { faPaperclip } from '@fortawesome/free-solid-svg-icons' @@ -119,6 +120,7 @@ library.add(faFilter) library.add(faFillDrip) library.add(faKeyboard) library.add(faSave) +library.add(faStarSolid) Vue.component('icon', FontAwesomeIcon) diff --git a/src/models/task.js b/src/models/task.js index c754fb64..8d65b334 100644 --- a/src/models/task.js +++ b/src/models/task.js @@ -1,4 +1,4 @@ -import AbstractModel from './abstractModel'; +import AbstractModel from './abstractModel' import UserModel from './user' import LabelModel from './label' import AttachmentModel from './attachment' @@ -95,6 +95,7 @@ export default class TaskModel extends AbstractModel { attachments: [], identifier: '', index: 0, + isFavorite: false, createdBy: UserModel, created: null, @@ -167,7 +168,7 @@ export default class TaskModel extends AbstractModel { return } - const {state} = await navigator.permissions.request({name: 'notifications'}); + const {state} = await navigator.permissions.request({name: 'notifications'}) if (state !== 'granted') { console.debug('Notification permission not granted, not showing notifications') return @@ -191,11 +192,11 @@ export default class TaskModel extends AbstractModel { actions: [ { action: 'mark-as-done', - title: 'Done' + title: 'Done', }, { action: 'show-task', - title: 'Show task' + title: 'Show task', }, ], }) diff --git a/src/store/modules/namespaces.js b/src/store/modules/namespaces.js index 0c60d62e..b9d7c696 100644 --- a/src/store/modules/namespaces.js +++ b/src/store/modules/namespaces.js @@ -93,5 +93,11 @@ export default { return Promise.reject(e) }) }, + loadNamespacesIfFavoritesDontExist(ctx) { + // The first namespace should be the one holding all favorites + if(ctx.state.namespaces[0].id !== -2) { + return ctx.dispatch('loadNamespaces') + } + }, }, } \ No newline at end of file diff --git a/src/styles/components/tasks.scss b/src/styles/components/tasks.scss index dd1a1f3b..90378560 100644 --- a/src/styles/components/tasks.scss +++ b/src/styles/components/tasks.scss @@ -22,66 +22,86 @@ padding: 0.5rem 1rem; border-bottom: 1px solid darken(#fff, 10%); transition: background-color $transition; + align-items: center; + cursor: pointer; &:hover { background-color: darken($light-background, 3); } - span:not(.tag) { - width: 100%; + .tasktext, + &.tasktext { + vertical-align: top; + white-space: nowrap; + text-overflow: ellipsis; + overflow: hidden; display: inline-block; - cursor: pointer; + width: 100%; - .tasktext, - &.tasktext { - vertical-align: top; - white-space: nowrap; - text-overflow: ellipsis; - overflow: hidden; - display: inline-block; - max-width: calc(#{$desktop} - 27px - 2rem); // The max width of the outer container minus the padding - width: calc(100% - 2rem); // The max width of the outer container minus the padding + .overdue { + color: $red; + } + } - @media screen and (max-width: $desktop) { - max-width: calc(100vw - 27px - 2rem - 1.5rem - 3rem); // 1.5rem is the padding of the tasks container, 3rem is the padding of .app-container - } + .task-list { + width: auto; + color: lighten($grey, 25%); + font-size: .9em; + white-space: nowrap; + } - .overdue { - color: $red; - } + .fancycheckbox span { + display: none; + } - .task-list { - width: auto; - color: lighten($grey, 25%); - font-size: .9em; - vertical-align: text-bottom; - } + .tag { + margin: 0 0.5em; + } + + .avatar { + border-radius: 50%; + vertical-align: bottom; + margin-left: 5px; + height: 27px; + width: 27px; + } + + a { + color: $text; + transition: color ease $transition-duration; + + &:hover { + color: darken($text, 40%); + } + } + + .favorite { + opacity: 0; + text-align: center; + width: 27px; + transition: opacity $transition, color $transition; + + &:hover { + color: $orange; } - .fancycheckbox span { + &.is-favorite { + opacity: 1; + color: $orange; + } + } + + &:hover .favorite { + opacity: 1; + } + + .fancycheckbox { + height: 18px; + padding-top: 0; + + span { display: none; } - - .tag { - margin: 0 0.5em; - } - - .avatar { - border-radius: 50%; - vertical-align: bottom; - margin-left: 5px; - height: 27px; - width: 27px; - } - - a { - color: $text; - transition: color ease $transition-duration; - - &:hover { - color: darken($text, 40%); - } - } } .tasktext.done { @@ -107,6 +127,15 @@ width: 24px; cursor: pointer; } + + &.loader-container.is-loading:after { + top: calc(50% - 1em); + left: calc(50% - 1em); + width: 2em; + height: 2em; + border-left-color: $grey-light; + border-bottom-color: $grey-light; + } } .task:last-child { @@ -242,3 +271,8 @@ } } } + +.is-max-width-desktop .tasks .task { + width: 100%; + max-width: $desktop; +} diff --git a/src/views/list/views/List.vue b/src/views/list/views/List.vue index 2ac67e73..2b03a3f2 100644 --- a/src/views/list/views/List.vue +++ b/src/views/list/views/List.vue @@ -84,17 +84,18 @@
-
- -
- -
+ +
+
+