Add color picker to change task color to task detail view
This commit is contained in:
parent
8d94bdb081
commit
736fe03b39
4 changed files with 54 additions and 12 deletions
|
@ -2,7 +2,7 @@
|
||||||
<div class="color-picker-container">
|
<div class="color-picker-container">
|
||||||
<verte
|
<verte
|
||||||
v-model="color"
|
v-model="color"
|
||||||
menuPosition="top"
|
:menuPosition="menuPosition"
|
||||||
picker="square"
|
picker="square"
|
||||||
model="hex"
|
model="hex"
|
||||||
:enableAlpha="false"
|
:enableAlpha="false"
|
||||||
|
@ -22,6 +22,7 @@
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
color: '',
|
color: '',
|
||||||
|
lastChangeTimeout: null,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
components: {
|
components: {
|
||||||
|
@ -31,6 +32,10 @@
|
||||||
value: {
|
value: {
|
||||||
required: true,
|
required: true,
|
||||||
},
|
},
|
||||||
|
menuPosition: {
|
||||||
|
type: String,
|
||||||
|
default: 'top',
|
||||||
|
},
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
value(newVal) {
|
value(newVal) {
|
||||||
|
@ -38,15 +43,22 @@
|
||||||
},
|
},
|
||||||
color() {
|
color() {
|
||||||
this.update()
|
this.update()
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
this.color = this.value
|
this.color = this.value
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
update() {
|
update() {
|
||||||
this.$emit('input', this.color)
|
|
||||||
this.$emit('change')
|
if(this.lastChangeTimeout !== null) {
|
||||||
|
clearTimeout(this.lastChangeTimeout)
|
||||||
|
}
|
||||||
|
|
||||||
|
this.lastChangeTimeout = setTimeout(() => {
|
||||||
|
this.$emit('input', this.color)
|
||||||
|
this.$emit('change')
|
||||||
|
}, 500)
|
||||||
},
|
},
|
||||||
reset() {
|
reset() {
|
||||||
// FIXME: I havn't found a way to make it clear to the user the color war reset.
|
// FIXME: I havn't found a way to make it clear to the user the color war reset.
|
||||||
|
|
|
@ -67,6 +67,7 @@ import { faSortUp } from '@fortawesome/free-solid-svg-icons'
|
||||||
import { faList } from '@fortawesome/free-solid-svg-icons'
|
import { faList } from '@fortawesome/free-solid-svg-icons'
|
||||||
import { faEllipsisV } from '@fortawesome/free-solid-svg-icons'
|
import { faEllipsisV } from '@fortawesome/free-solid-svg-icons'
|
||||||
import { faFilter } from '@fortawesome/free-solid-svg-icons'
|
import { faFilter } from '@fortawesome/free-solid-svg-icons'
|
||||||
|
import { faFillDrip } from '@fortawesome/free-solid-svg-icons'
|
||||||
import { faComments } from '@fortawesome/free-regular-svg-icons'
|
import { faComments } from '@fortawesome/free-regular-svg-icons'
|
||||||
import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome'
|
import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome'
|
||||||
|
|
||||||
|
@ -113,6 +114,7 @@ library.add(faSortUp)
|
||||||
library.add(faList)
|
library.add(faList)
|
||||||
library.add(faEllipsisV)
|
library.add(faEllipsisV)
|
||||||
library.add(faFilter)
|
library.add(faFilter)
|
||||||
|
library.add(faFillDrip)
|
||||||
|
|
||||||
Vue.component('icon', FontAwesomeIcon)
|
Vue.component('icon', FontAwesomeIcon)
|
||||||
|
|
||||||
|
|
|
@ -15,7 +15,7 @@ export default class TaskService extends AbstractService {
|
||||||
delete: '/tasks/{id}',
|
delete: '/tasks/{id}',
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
modelFactory(data) {
|
modelFactory(data) {
|
||||||
return new TaskModel(data)
|
return new TaskModel(data)
|
||||||
}
|
}
|
||||||
|
@ -34,9 +34,9 @@ export default class TaskService extends AbstractService {
|
||||||
model.listId = Number(model.listId)
|
model.listId = Number(model.listId)
|
||||||
|
|
||||||
// Convert dates into an iso string
|
// Convert dates into an iso string
|
||||||
model.dueDate = model.dueDate === null ? null : formatISO(new Date(model.dueDate))
|
model.dueDate = model.dueDate ? null : formatISO(new Date(model.dueDate))
|
||||||
model.startDate = model.startDate === null ? null : formatISO(new Date(model.startDate))
|
model.startDate = model.startDate ? null : formatISO(new Date(model.startDate))
|
||||||
model.endDate = model.endDate === null ? null : formatISO(new Date(model.endDate))
|
model.endDate = model.endDate ? null : formatISO(new Date(model.endDate))
|
||||||
model.created = formatISO(model.created)
|
model.created = formatISO(model.created)
|
||||||
model.updated = formatISO(model.updated)
|
model.updated = formatISO(model.updated)
|
||||||
|
|
||||||
|
@ -48,7 +48,7 @@ export default class TaskService extends AbstractService {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make normal timestamps from js dates
|
// Make normal timestamps from js dates
|
||||||
if(model.reminderDates.length > 0) {
|
if (model.reminderDates.length > 0) {
|
||||||
model.reminderDates = model.reminderDates.map(r => {
|
model.reminderDates = model.reminderDates.map(r => {
|
||||||
return formatISO(new Date(r))
|
return formatISO(new Date(r))
|
||||||
})
|
})
|
||||||
|
@ -82,14 +82,14 @@ export default class TaskService extends AbstractService {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Do the same for all related tasks
|
// Do the same for all related tasks
|
||||||
Object.keys(model.relatedTasks).forEach(relationKind => {
|
Object.keys(model.relatedTasks).forEach(relationKind => {
|
||||||
model.relatedTasks[relationKind] = model.relatedTasks[relationKind].map(t => {
|
model.relatedTasks[relationKind] = model.relatedTasks[relationKind].map(t => {
|
||||||
return this.processModel(t)
|
return this.processModel(t)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
// Process all attachments to preven parsing errors
|
// Process all attachments to preven parsing errors
|
||||||
if(model.attachments.length > 0) {
|
if (model.attachments.length > 0) {
|
||||||
const attachmentService = new AttachmentService()
|
const attachmentService = new AttachmentService()
|
||||||
model.attachments.map(a => {
|
model.attachments.map(a => {
|
||||||
return attachmentService.processModel(a)
|
return attachmentService.processModel(a)
|
||||||
|
@ -97,7 +97,7 @@ export default class TaskService extends AbstractService {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Preprocess all labels
|
// Preprocess all labels
|
||||||
if(model.labels.length > 0) {
|
if (model.labels.length > 0) {
|
||||||
const labelService = new LabelService()
|
const labelService = new LabelService()
|
||||||
model.labels = model.labels.map(l => labelService.processModel(l))
|
model.labels = model.labels.map(l => labelService.processModel(l))
|
||||||
}
|
}
|
||||||
|
|
|
@ -147,6 +147,18 @@
|
||||||
@change="saveTask"
|
@change="saveTask"
|
||||||
ref="repeatAfter"/>
|
ref="repeatAfter"/>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="column" v-if="activeFields.color">
|
||||||
|
<!-- Color -->
|
||||||
|
<div class="detail-title">
|
||||||
|
<icon icon="fill-drip"/>
|
||||||
|
Color
|
||||||
|
</div>
|
||||||
|
<color-picker
|
||||||
|
v-model="taskColor"
|
||||||
|
menu-position="bottom"
|
||||||
|
@change="saveTask"
|
||||||
|
ref="color"/>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Labels -->
|
<!-- Labels -->
|
||||||
|
@ -286,6 +298,10 @@
|
||||||
<span class="icon is-small"><icon icon="list"/></span>
|
<span class="icon is-small"><icon icon="list"/></span>
|
||||||
Move task
|
Move task
|
||||||
</a>
|
</a>
|
||||||
|
<a class="button" @click="setFieldActive('color')">
|
||||||
|
<span class="icon is-small"><icon icon="fill-drip"/></span>
|
||||||
|
Set task color
|
||||||
|
</a>
|
||||||
<a class="button is-danger is-outlined noshadow has-no-border" @click="showDeleteModal = true">
|
<a class="button is-danger is-outlined noshadow has-no-border" @click="showDeleteModal = true">
|
||||||
<span class="icon is-small"><icon icon="trash-alt"/></span>
|
<span class="icon is-small"><icon icon="trash-alt"/></span>
|
||||||
Delete task
|
Delete task
|
||||||
|
@ -330,10 +346,12 @@
|
||||||
import Comments from '../../components/tasks/partials/comments'
|
import Comments from '../../components/tasks/partials/comments'
|
||||||
import router from '../../router'
|
import router from '../../router'
|
||||||
import ListSearch from '../../components/tasks/partials/listSearch'
|
import ListSearch from '../../components/tasks/partials/listSearch'
|
||||||
|
import ColorPicker from "../../components/input/colorPicker";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'TaskDetailView',
|
name: 'TaskDetailView',
|
||||||
components: {
|
components: {
|
||||||
|
ColorPicker,
|
||||||
ListSearch,
|
ListSearch,
|
||||||
Reminders,
|
Reminders,
|
||||||
RepeatAfter,
|
RepeatAfter,
|
||||||
|
@ -355,6 +373,13 @@
|
||||||
// The due date is a seperate property in the task to prevent flatpickr from modifying the task model
|
// The due date is a seperate property in the task to prevent flatpickr from modifying the task model
|
||||||
// in store right after updating it from the api resulting in the wrong due date format being saved in the task.
|
// in store right after updating it from the api resulting in the wrong due date format being saved in the task.
|
||||||
dueDate: null,
|
dueDate: null,
|
||||||
|
// We doubled the task color property here because verte does not have a real change property, leading
|
||||||
|
// to the color property change being triggered when the # is removed from it, leading to an update,
|
||||||
|
// which leads in turn to a change... This creates an infinite loop in which the task is updated, changed,
|
||||||
|
// updated, changed, updated and so on.
|
||||||
|
// To prevent this, we put the task color property in a seperate value which is set to the task color
|
||||||
|
// when it is saved and loaded.
|
||||||
|
taskColor: '',
|
||||||
|
|
||||||
showDeleteModal: false,
|
showDeleteModal: false,
|
||||||
taskTitle: '',
|
taskTitle: '',
|
||||||
|
@ -382,6 +407,7 @@
|
||||||
attachments: false,
|
attachments: false,
|
||||||
relatedTasks: false,
|
relatedTasks: false,
|
||||||
moveList: false,
|
moveList: false,
|
||||||
|
color: false,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -425,6 +451,7 @@
|
||||||
.then(r => {
|
.then(r => {
|
||||||
this.$set(this, 'task', r)
|
this.$set(this, 'task', r)
|
||||||
this.taskTitle = this.task.title
|
this.taskTitle = this.task.title
|
||||||
|
this.taskColor = this.task.hexColor
|
||||||
this.setActiveFields()
|
this.setActiveFields()
|
||||||
})
|
})
|
||||||
.catch(e => {
|
.catch(e => {
|
||||||
|
@ -472,6 +499,7 @@
|
||||||
saveTask(undoCallback = null) {
|
saveTask(undoCallback = null) {
|
||||||
|
|
||||||
this.task.dueDate = this.dueDate
|
this.task.dueDate = this.dueDate
|
||||||
|
this.task.hexColor = this.taskColor
|
||||||
|
|
||||||
// If no end date is being set, but a start date and due date,
|
// If no end date is being set, but a start date and due date,
|
||||||
// use the due date as the end date
|
// use the due date as the end date
|
||||||
|
|
Loading…
Add table
Reference in a new issue