2020-03-23 22:24:14 +00:00
|
|
|
|
<template>
|
2023-09-07 11:43:03 +00:00
|
|
|
|
<div>
|
2023-09-06 16:31:30 +00:00
|
|
|
|
<div
|
2023-09-07 11:43:03 +00:00
|
|
|
|
:class="{'is-loading': taskService.loading}"
|
2024-02-06 17:29:17 +00:00
|
|
|
|
class="task loader-container single-task"
|
2023-11-27 11:47:26 +00:00
|
|
|
|
@mouseup.stop.self="openTaskDetail"
|
|
|
|
|
@mousedown.stop.self="focusTaskLink"
|
|
|
|
|
ref="taskContainerRef"
|
|
|
|
|
tabindex="-1"
|
2022-11-01 10:43:01 +00:00
|
|
|
|
>
|
2023-09-07 11:43:03 +00:00
|
|
|
|
<fancycheckbox
|
|
|
|
|
:disabled="(isArchived || disabled) && !canMarkAsDone"
|
|
|
|
|
@update:model-value="markAsDone"
|
|
|
|
|
v-model="task.done"
|
|
|
|
|
/>
|
|
|
|
|
|
|
|
|
|
<ColorBubble
|
2023-09-29 18:46:02 +00:00
|
|
|
|
v-if="!showProjectSeparately && projectColor !== '' && currentProject?.id !== task.projectId"
|
2023-09-07 11:43:03 +00:00
|
|
|
|
:color="projectColor"
|
|
|
|
|
class="mr-1"
|
|
|
|
|
/>
|
|
|
|
|
|
|
|
|
|
<div
|
|
|
|
|
:class="{ 'done': task.done, 'show-project': showProject && project}"
|
|
|
|
|
class="tasktext"
|
2023-11-27 11:47:26 +00:00
|
|
|
|
@mouseup.stop.self="openTaskDetail"
|
|
|
|
|
@mousedown.stop.self="focusTaskLink"
|
2023-09-07 11:43:03 +00:00
|
|
|
|
>
|
2021-01-15 20:04:48 +00:00
|
|
|
|
<span>
|
2020-08-01 13:17:10 +00:00
|
|
|
|
<router-link
|
2023-04-12 09:13:55 +00:00
|
|
|
|
v-if="showProject && typeof project !== 'undefined'"
|
2022-11-13 21:04:57 +00:00
|
|
|
|
:to="{ name: 'project.list', params: { projectId: task.projectId } }"
|
2023-09-29 07:19:17 +00:00
|
|
|
|
class="task-project mr-1"
|
2022-09-15 11:56:14 +00:00
|
|
|
|
:class="{'mr-2': task.hexColor !== ''}"
|
2023-09-06 16:31:30 +00:00
|
|
|
|
v-tooltip="$t('task.detail.belongsToProject', {project: project.title})"
|
|
|
|
|
>
|
2022-11-13 21:04:57 +00:00
|
|
|
|
{{ project.title }}
|
2020-08-01 13:17:10 +00:00
|
|
|
|
</router-link>
|
2020-05-11 14:52:58 +00:00
|
|
|
|
|
2022-09-15 11:56:14 +00:00
|
|
|
|
<ColorBubble
|
|
|
|
|
v-if="task.hexColor !== ''"
|
2022-11-01 10:43:01 +00:00
|
|
|
|
:color="getHexColor(task.hexColor)"
|
2022-09-15 11:56:14 +00:00
|
|
|
|
class="mr-1"
|
|
|
|
|
/>
|
2023-09-06 13:58:52 +00:00
|
|
|
|
|
2023-09-29 07:32:00 +00:00
|
|
|
|
<priority-label :priority="task.priority" :done="task.done" class="pr-2"/>
|
2023-09-06 16:31:30 +00:00
|
|
|
|
|
|
|
|
|
<router-link
|
|
|
|
|
:to="taskDetailRoute"
|
|
|
|
|
class="task-link"
|
|
|
|
|
ref="taskLink"
|
|
|
|
|
tabindex="-1"
|
|
|
|
|
>
|
|
|
|
|
{{ task.title }}
|
|
|
|
|
</router-link>
|
2021-01-15 20:04:48 +00:00
|
|
|
|
</span>
|
2020-05-11 14:52:58 +00:00
|
|
|
|
|
2023-09-07 11:43:03 +00:00
|
|
|
|
<labels
|
|
|
|
|
v-if="task.labels.length > 0"
|
|
|
|
|
class="labels ml-2 mr-1"
|
|
|
|
|
:labels="task.labels"
|
|
|
|
|
/>
|
2022-11-01 10:43:01 +00:00
|
|
|
|
|
2023-09-07 11:43:03 +00:00
|
|
|
|
<assignee-list
|
|
|
|
|
v-if="task.assignees.length > 0"
|
|
|
|
|
:assignees="task.assignees"
|
|
|
|
|
:avatar-size="25"
|
|
|
|
|
class="ml-1"
|
|
|
|
|
:inline="true"
|
|
|
|
|
/>
|
2022-11-01 10:43:01 +00:00
|
|
|
|
|
2023-09-07 11:43:03 +00:00
|
|
|
|
<!-- FIXME: use popup -->
|
|
|
|
|
<BaseButton
|
|
|
|
|
v-if="+new Date(task.dueDate) > 0"
|
|
|
|
|
class="dueDate"
|
|
|
|
|
@click.prevent.stop="showDefer = !showDefer"
|
|
|
|
|
v-tooltip="formatDateLong(task.dueDate)"
|
2022-05-10 23:14:38 +00:00
|
|
|
|
>
|
2023-09-07 11:43:03 +00:00
|
|
|
|
<time
|
|
|
|
|
:datetime="formatISO(task.dueDate)"
|
|
|
|
|
:class="{'overdue': task.dueDate <= new Date() && !task.done}"
|
|
|
|
|
class="is-italic"
|
|
|
|
|
:aria-expanded="showDefer ? 'true' : 'false'"
|
|
|
|
|
>
|
|
|
|
|
– {{ $t('task.detail.due', {at: dueDateFormatted}) }}
|
|
|
|
|
</time>
|
|
|
|
|
</BaseButton>
|
|
|
|
|
<CustomTransition name="fade">
|
|
|
|
|
<defer-task v-if="+new Date(task.dueDate) > 0 && showDefer" v-model="task" ref="deferDueDate"/>
|
|
|
|
|
</CustomTransition>
|
|
|
|
|
|
|
|
|
|
<span>
|
2022-11-13 21:04:57 +00:00
|
|
|
|
<span class="project-task-icon" v-if="task.attachments.length > 0">
|
2020-12-30 21:20:33 +00:00
|
|
|
|
<icon icon="paperclip"/>
|
|
|
|
|
</span>
|
2023-12-11 21:35:09 +00:00
|
|
|
|
<span class="project-task-icon" v-if="!isEditorContentEmpty(task.description)">
|
2020-12-30 21:20:33 +00:00
|
|
|
|
<icon icon="align-left"/>
|
|
|
|
|
</span>
|
2022-11-13 21:04:57 +00:00
|
|
|
|
<span class="project-task-icon" v-if="task.repeatAfter.amount > 0">
|
2021-11-01 16:06:03 +00:00
|
|
|
|
<icon icon="history"/>
|
|
|
|
|
</span>
|
2020-12-30 21:20:33 +00:00
|
|
|
|
</span>
|
2022-11-01 10:43:01 +00:00
|
|
|
|
|
2023-09-07 11:43:03 +00:00
|
|
|
|
<checklist-summary :task="task"/>
|
|
|
|
|
</div>
|
2022-11-01 10:43:01 +00:00
|
|
|
|
|
2023-03-28 11:45:16 +00:00
|
|
|
|
<ProgressBar
|
2023-09-07 11:43:03 +00:00
|
|
|
|
v-if="task.percentDone > 0"
|
2023-03-28 11:45:16 +00:00
|
|
|
|
:value="task.percentDone * 100"
|
|
|
|
|
is-small
|
|
|
|
|
/>
|
2023-09-07 11:43:03 +00:00
|
|
|
|
|
2023-09-29 18:46:02 +00:00
|
|
|
|
<ColorBubble
|
|
|
|
|
v-if="showProjectSeparately && projectColor !== '' && currentProject?.id !== task.projectId"
|
|
|
|
|
:color="projectColor"
|
|
|
|
|
class="mr-1"
|
|
|
|
|
/>
|
|
|
|
|
|
2023-09-07 11:43:03 +00:00
|
|
|
|
<router-link
|
2023-09-29 18:46:02 +00:00
|
|
|
|
v-if="showProjectSeparately"
|
2023-09-07 11:43:03 +00:00
|
|
|
|
:to="{ name: 'project.list', params: { projectId: task.projectId } }"
|
|
|
|
|
class="task-project"
|
|
|
|
|
v-tooltip="$t('task.detail.belongsToProject', {project: project.title})"
|
|
|
|
|
>
|
|
|
|
|
{{ project.title }}
|
|
|
|
|
</router-link>
|
2022-11-01 10:43:01 +00:00
|
|
|
|
|
2023-09-07 11:43:03 +00:00
|
|
|
|
<BaseButton
|
|
|
|
|
:class="{'is-favorite': task.isFavorite}"
|
|
|
|
|
@click="toggleFavorite"
|
|
|
|
|
class="favorite"
|
|
|
|
|
>
|
|
|
|
|
<icon icon="star" v-if="task.isFavorite"/>
|
|
|
|
|
<icon :icon="['far', 'star']" v-else/>
|
|
|
|
|
</BaseButton>
|
|
|
|
|
<slot/>
|
|
|
|
|
</div>
|
|
|
|
|
<template v-if="typeof task.relatedTasks?.subtask !== 'undefined'">
|
|
|
|
|
<template v-for="subtask in task.relatedTasks.subtask">
|
|
|
|
|
<template v-if="getTaskById(subtask.id)">
|
|
|
|
|
<single-task-in-project
|
|
|
|
|
:key="subtask.id"
|
|
|
|
|
:the-task="getTaskById(subtask.id)"
|
|
|
|
|
:disabled="disabled"
|
|
|
|
|
:can-mark-as-done="canMarkAsDone"
|
|
|
|
|
:all-tasks="allTasks"
|
2023-09-07 11:47:52 +00:00
|
|
|
|
class="subtask-nested"
|
2023-09-07 11:43:03 +00:00
|
|
|
|
/>
|
|
|
|
|
</template>
|
|
|
|
|
</template>
|
|
|
|
|
</template>
|
2023-03-28 11:13:29 +00:00
|
|
|
|
</div>
|
2020-03-23 22:24:14 +00:00
|
|
|
|
</template>
|
|
|
|
|
|
2022-11-01 10:43:01 +00:00
|
|
|
|
<script setup lang="ts">
|
2023-06-20 12:39:59 +00:00
|
|
|
|
import {ref, watch, shallowReactive, onMounted, onBeforeUnmount, computed} from 'vue'
|
2022-11-01 10:43:01 +00:00
|
|
|
|
import {useI18n} from 'vue-i18n'
|
2022-02-15 12:07:59 +00:00
|
|
|
|
|
2023-09-04 12:00:22 +00:00
|
|
|
|
import TaskModel, {getHexColor} from '@/models/task'
|
2022-09-06 09:36:01 +00:00
|
|
|
|
import type {ITask} from '@/modelTypes/ITask'
|
2022-11-01 10:43:01 +00:00
|
|
|
|
|
|
|
|
|
import PriorityLabel from '@/components/tasks/partials/priorityLabel.vue'
|
|
|
|
|
import Labels from '@/components/tasks/partials//labels.vue'
|
|
|
|
|
import DeferTask from '@/components/tasks/partials//defer-task.vue'
|
|
|
|
|
import ChecklistSummary from '@/components/tasks/partials/checklist-summary.vue'
|
|
|
|
|
|
2023-03-28 11:45:16 +00:00
|
|
|
|
import ProgressBar from '@/components/misc/ProgressBar.vue'
|
2022-05-10 23:14:38 +00:00
|
|
|
|
import BaseButton from '@/components/base/BaseButton.vue'
|
2022-11-01 10:43:01 +00:00
|
|
|
|
import Fancycheckbox from '@/components/input/fancycheckbox.vue'
|
|
|
|
|
import ColorBubble from '@/components/misc/colorBubble.vue'
|
2022-11-12 18:24:02 +00:00
|
|
|
|
import CustomTransition from '@/components/misc/CustomTransition.vue'
|
2022-11-01 10:43:01 +00:00
|
|
|
|
|
|
|
|
|
import TaskService from '@/services/task'
|
|
|
|
|
|
2021-01-17 10:36:57 +00:00
|
|
|
|
import {closeWhenClickedOutside} from '@/helpers/closeWhenClickedOutside'
|
2022-06-23 00:58:00 +00:00
|
|
|
|
import {formatDateSince, formatISO, formatDateLong} from '@/helpers/time/formatDate'
|
2022-11-01 10:43:01 +00:00
|
|
|
|
import {success} from '@/message'
|
|
|
|
|
|
2022-11-13 21:04:57 +00:00
|
|
|
|
import {useProjectStore} from '@/stores/projects'
|
2022-09-24 13:20:40 +00:00
|
|
|
|
import {useBaseStore} from '@/stores/base'
|
2022-09-23 10:55:53 +00:00
|
|
|
|
import {useTaskStore} from '@/stores/tasks'
|
2023-09-04 11:03:39 +00:00
|
|
|
|
import AssigneeList from '@/components/tasks/partials/assigneeList.vue'
|
2023-09-04 12:00:22 +00:00
|
|
|
|
import {useIntervalFn} from '@vueuse/core'
|
2023-09-04 18:14:00 +00:00
|
|
|
|
import {playPopSound} from '@/helpers/playPop'
|
|
|
|
|
import {useAuthStore} from '@/stores/auth'
|
2023-12-11 21:35:09 +00:00
|
|
|
|
import {isEditorContentEmpty} from '@/helpers/editorContentEmpty'
|
2020-03-23 22:24:14 +00:00
|
|
|
|
|
2023-06-20 12:39:59 +00:00
|
|
|
|
const {
|
|
|
|
|
theTask,
|
|
|
|
|
isArchived = false,
|
|
|
|
|
showProject = false,
|
|
|
|
|
disabled = false,
|
|
|
|
|
canMarkAsDone = true,
|
2023-09-07 11:43:03 +00:00
|
|
|
|
allTasks = [],
|
2023-06-20 12:39:59 +00:00
|
|
|
|
} = defineProps<{
|
|
|
|
|
theTask: ITask,
|
|
|
|
|
isArchived?: boolean,
|
|
|
|
|
showProject?: boolean,
|
|
|
|
|
disabled?: boolean,
|
|
|
|
|
canMarkAsDone?: boolean,
|
2023-09-07 11:43:03 +00:00
|
|
|
|
allTasks?: ITask[],
|
2023-06-20 12:39:59 +00:00
|
|
|
|
}>()
|
2022-11-01 10:43:01 +00:00
|
|
|
|
|
2023-09-07 11:43:03 +00:00
|
|
|
|
function getTaskById(taskId: number): ITask | undefined {
|
|
|
|
|
if (typeof allTasks === 'undefined' || allTasks.length === 0) {
|
|
|
|
|
return null
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return allTasks.find(t => t.id === taskId)
|
|
|
|
|
}
|
|
|
|
|
|
2022-11-01 10:43:01 +00:00
|
|
|
|
const emit = defineEmits(['task-updated'])
|
|
|
|
|
|
|
|
|
|
const {t} = useI18n({useScope: 'global'})
|
|
|
|
|
|
|
|
|
|
const taskService = shallowReactive(new TaskService())
|
|
|
|
|
const task = ref<ITask>(new TaskModel())
|
|
|
|
|
const showDefer = ref(false)
|
|
|
|
|
|
|
|
|
|
watch(
|
2023-06-20 12:39:59 +00:00
|
|
|
|
() => theTask,
|
2022-11-01 10:43:01 +00:00
|
|
|
|
newVal => {
|
|
|
|
|
task.value = newVal
|
2020-09-05 20:35:52 +00:00
|
|
|
|
},
|
2022-11-01 10:43:01 +00:00
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
onMounted(() => {
|
2023-06-20 13:24:02 +00:00
|
|
|
|
task.value = theTask
|
2022-11-01 10:43:01 +00:00
|
|
|
|
document.addEventListener('click', hideDeferDueDatePopup)
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
onBeforeUnmount(() => {
|
|
|
|
|
document.removeEventListener('click', hideDeferDueDatePopup)
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
const baseStore = useBaseStore()
|
2022-11-13 21:04:57 +00:00
|
|
|
|
const projectStore = useProjectStore()
|
2022-11-01 10:43:01 +00:00
|
|
|
|
const taskStore = useTaskStore()
|
|
|
|
|
|
2023-04-12 09:13:55 +00:00
|
|
|
|
const project = computed(() => projectStore.projects[task.value.projectId])
|
|
|
|
|
const projectColor = computed(() => project.value ? project.value?.hexColor : '')
|
2022-11-01 10:43:01 +00:00
|
|
|
|
|
2023-09-29 18:46:02 +00:00
|
|
|
|
const showProjectSeparately = computed(() => !showProject && currentProject.value?.id !== task.value.projectId && project.value)
|
|
|
|
|
|
2022-11-13 21:04:57 +00:00
|
|
|
|
const currentProject = computed(() => {
|
|
|
|
|
return typeof baseStore.currentProject === 'undefined' ? {
|
2022-11-01 10:43:01 +00:00
|
|
|
|
id: 0,
|
|
|
|
|
title: '',
|
2022-11-13 21:04:57 +00:00
|
|
|
|
} : baseStore.currentProject
|
2022-02-15 12:07:59 +00:00
|
|
|
|
})
|
2022-11-01 10:43:01 +00:00
|
|
|
|
|
|
|
|
|
const taskDetailRoute = computed(() => ({
|
|
|
|
|
name: 'task.detail',
|
|
|
|
|
params: {id: task.value.id},
|
|
|
|
|
// TODO: re-enable opening task detail in modal
|
|
|
|
|
// state: { backdropView: router.currentRoute.value.fullPath },
|
|
|
|
|
}))
|
|
|
|
|
|
2023-09-04 12:00:22 +00:00
|
|
|
|
function updateDueDate() {
|
|
|
|
|
if (!task.value.dueDate) {
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
dueDateFormatted.value = formatDateSince(task.value.dueDate)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const dueDateFormatted = ref('')
|
|
|
|
|
useIntervalFn(updateDueDate, 60_000, {
|
|
|
|
|
immediateCallback: true,
|
|
|
|
|
})
|
|
|
|
|
onMounted(updateDueDate)
|
|
|
|
|
|
2022-11-01 10:43:01 +00:00
|
|
|
|
|
|
|
|
|
async function markAsDone(checked: boolean) {
|
|
|
|
|
const updateFunc = async () => {
|
|
|
|
|
const newTask = await taskStore.update(task.value)
|
|
|
|
|
task.value = newTask
|
2023-09-04 18:14:00 +00:00
|
|
|
|
if (checked && useAuthStore().settings.frontendSettings.playSoundWhenDone) {
|
|
|
|
|
playPopSound()
|
|
|
|
|
}
|
2022-11-01 10:43:01 +00:00
|
|
|
|
emit('task-updated', newTask)
|
|
|
|
|
success({
|
|
|
|
|
message: task.value.done ?
|
|
|
|
|
t('task.doneSuccess') :
|
|
|
|
|
t('task.undoneSuccess'),
|
|
|
|
|
}, [{
|
2023-03-08 09:43:46 +00:00
|
|
|
|
title: t('task.undo'),
|
2022-11-01 10:43:01 +00:00
|
|
|
|
callback: () => undoDone(checked),
|
|
|
|
|
}])
|
2024-01-15 22:33:02 +00:00
|
|
|
|
updateDueDate()
|
2022-11-01 10:43:01 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (checked) {
|
|
|
|
|
setTimeout(updateFunc, 300) // Delay it to show the animation when marking a task as done
|
|
|
|
|
} else {
|
|
|
|
|
await updateFunc() // Don't delay it when un-marking it as it doesn't have an animation the other way around
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function undoDone(checked: boolean) {
|
|
|
|
|
task.value.done = !task.value.done
|
|
|
|
|
markAsDone(!checked)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async function toggleFavorite() {
|
2023-05-30 09:37:45 +00:00
|
|
|
|
task.value = await taskStore.toggleFavorite(task.value)
|
2022-11-01 10:43:01 +00:00
|
|
|
|
emit('task-updated', task.value)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const deferDueDate = ref<typeof DeferTask | null>(null)
|
2023-09-04 12:00:22 +00:00
|
|
|
|
|
2022-11-01 10:43:01 +00:00
|
|
|
|
function hideDeferDueDatePopup(e) {
|
|
|
|
|
if (!showDefer.value) {
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
closeWhenClickedOutside(e, deferDueDate.value.$el, () => {
|
|
|
|
|
showDefer.value = false
|
|
|
|
|
})
|
|
|
|
|
}
|
2023-09-06 16:31:30 +00:00
|
|
|
|
|
|
|
|
|
const taskLink = ref<HTMLElement | null>(null)
|
2023-11-27 11:47:26 +00:00
|
|
|
|
const taskContainerRef = ref<HTMLElement | null>(null)
|
2023-09-07 11:43:03 +00:00
|
|
|
|
|
2023-11-27 11:47:26 +00:00
|
|
|
|
function hasTextSelected() {
|
2023-09-06 16:31:30 +00:00
|
|
|
|
const isTextSelected = window.getSelection().toString()
|
2023-11-27 11:47:26 +00:00
|
|
|
|
return !(typeof isTextSelected === 'undefined' || isTextSelected === '' || isTextSelected === '\n')
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function openTaskDetail() {
|
|
|
|
|
if (!hasTextSelected()) {
|
2023-09-06 16:31:30 +00:00
|
|
|
|
taskLink.value.$el.click()
|
|
|
|
|
}
|
|
|
|
|
}
|
2023-11-27 11:47:26 +00:00
|
|
|
|
|
|
|
|
|
function focusTaskLink() {
|
|
|
|
|
if (!hasTextSelected()) {
|
|
|
|
|
taskContainerRef.value.focus()
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-03-23 22:24:14 +00:00
|
|
|
|
</script>
|
2021-10-18 12:22:47 +00:00
|
|
|
|
|
|
|
|
|
<style lang="scss" scoped>
|
|
|
|
|
.task {
|
|
|
|
|
display: flex;
|
|
|
|
|
flex-wrap: wrap;
|
|
|
|
|
padding: .4rem;
|
|
|
|
|
transition: background-color $transition;
|
|
|
|
|
align-items: center;
|
|
|
|
|
cursor: pointer;
|
|
|
|
|
border-radius: $radius;
|
|
|
|
|
border: 2px solid transparent;
|
2023-03-04 16:13:31 +00:00
|
|
|
|
|
2021-10-18 12:22:47 +00:00
|
|
|
|
&:hover {
|
2021-11-22 21:12:54 +00:00
|
|
|
|
background-color: var(--grey-100);
|
2021-10-18 12:22:47 +00:00
|
|
|
|
}
|
|
|
|
|
|
2023-09-06 16:31:30 +00:00
|
|
|
|
&:focus-within, &:focus {
|
|
|
|
|
box-shadow: 0 0 0 2px hsla(var(--primary-hsl), 0.5);
|
|
|
|
|
|
|
|
|
|
a.task-link {
|
|
|
|
|
box-shadow: none;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-10-18 12:22:47 +00:00
|
|
|
|
.tasktext,
|
|
|
|
|
&.tasktext {
|
|
|
|
|
text-overflow: ellipsis;
|
2023-06-23 12:28:06 +00:00
|
|
|
|
word-wrap: break-word;
|
|
|
|
|
word-break: break-word;
|
|
|
|
|
display: -webkit-box;
|
|
|
|
|
hyphens: auto;
|
|
|
|
|
-webkit-line-clamp: 4;
|
|
|
|
|
-webkit-box-orient: vertical;
|
2021-10-18 12:22:47 +00:00
|
|
|
|
overflow: hidden;
|
2023-09-04 12:00:22 +00:00
|
|
|
|
|
2021-10-18 12:22:47 +00:00
|
|
|
|
flex: 1 0 50%;
|
|
|
|
|
|
2022-05-10 23:15:08 +00:00
|
|
|
|
.dueDate {
|
|
|
|
|
display: inline-block;
|
|
|
|
|
margin-left: 5px;
|
|
|
|
|
}
|
|
|
|
|
|
2021-10-18 12:22:47 +00:00
|
|
|
|
.overdue {
|
2021-11-22 21:12:54 +00:00
|
|
|
|
color: var(--danger);
|
2021-10-18 12:22:47 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-11-13 21:04:57 +00:00
|
|
|
|
.task-project {
|
2021-10-18 12:22:47 +00:00
|
|
|
|
width: auto;
|
2021-11-22 21:12:54 +00:00
|
|
|
|
color: var(--grey-400);
|
2021-10-18 12:22:47 +00:00
|
|
|
|
font-size: .9rem;
|
|
|
|
|
white-space: nowrap;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.avatar {
|
|
|
|
|
border-radius: 50%;
|
|
|
|
|
vertical-align: bottom;
|
|
|
|
|
margin-left: 5px;
|
|
|
|
|
height: 27px;
|
|
|
|
|
width: 27px;
|
|
|
|
|
}
|
|
|
|
|
|
2022-11-13 21:04:57 +00:00
|
|
|
|
.project-task-icon {
|
2021-10-18 12:22:47 +00:00
|
|
|
|
margin-left: 6px;
|
|
|
|
|
|
|
|
|
|
&:not(:first-of-type) {
|
|
|
|
|
margin-left: 8px;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
2023-03-28 11:13:29 +00:00
|
|
|
|
a {
|
|
|
|
|
color: var(--text);
|
|
|
|
|
transition: color ease $transition-duration;
|
|
|
|
|
|
|
|
|
|
&:hover {
|
|
|
|
|
color: var(--grey-900);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-10-18 12:22:47 +00:00
|
|
|
|
.favorite {
|
2023-03-04 16:13:31 +00:00
|
|
|
|
opacity: 1;
|
2021-10-18 12:22:47 +00:00
|
|
|
|
text-align: center;
|
|
|
|
|
width: 27px;
|
|
|
|
|
transition: opacity $transition, color $transition;
|
|
|
|
|
|
|
|
|
|
&:hover {
|
2021-11-22 21:12:54 +00:00
|
|
|
|
color: var(--warning);
|
2021-10-18 12:22:47 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
&.is-favorite {
|
|
|
|
|
opacity: 1;
|
2021-11-22 21:12:54 +00:00
|
|
|
|
color: var(--warning);
|
2021-10-18 12:22:47 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-03-04 16:13:31 +00:00
|
|
|
|
@media(hover: hover) and (pointer: fine) {
|
2024-02-06 17:29:17 +00:00
|
|
|
|
& .favorite {
|
2023-03-04 16:13:31 +00:00
|
|
|
|
opacity: 0;
|
|
|
|
|
}
|
|
|
|
|
|
2024-02-06 17:29:17 +00:00
|
|
|
|
&:hover .favorite {
|
2023-03-04 16:13:31 +00:00
|
|
|
|
opacity: 1;
|
|
|
|
|
}
|
2021-10-18 12:22:47 +00:00
|
|
|
|
}
|
2023-09-07 11:43:03 +00:00
|
|
|
|
|
2023-09-06 16:31:30 +00:00
|
|
|
|
.favorite:focus {
|
|
|
|
|
opacity: 1;
|
|
|
|
|
}
|
2023-09-07 11:43:03 +00:00
|
|
|
|
|
2021-10-20 12:33:36 +00:00
|
|
|
|
:deep(.fancycheckbox) {
|
2021-10-18 12:22:47 +00:00
|
|
|
|
height: 18px;
|
|
|
|
|
padding-top: 0;
|
|
|
|
|
padding-right: .5rem;
|
|
|
|
|
|
|
|
|
|
span {
|
|
|
|
|
display: none;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.tasktext.done {
|
|
|
|
|
text-decoration: line-through;
|
2021-11-22 21:12:54 +00:00
|
|
|
|
color: var(--grey-500);
|
2021-10-18 12:22:47 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
span.parent-tasks {
|
2021-11-22 21:12:54 +00:00
|
|
|
|
color: var(--grey-500);
|
2021-10-18 12:22:47 +00:00
|
|
|
|
width: auto;
|
|
|
|
|
}
|
|
|
|
|
|
2022-11-13 21:04:57 +00:00
|
|
|
|
.show-project .parent-tasks {
|
2022-12-02 17:05:48 +00:00
|
|
|
|
padding-left: .25rem;
|
|
|
|
|
}
|
|
|
|
|
|
2021-10-18 12:22:47 +00:00
|
|
|
|
.remove {
|
2021-11-22 21:12:54 +00:00
|
|
|
|
color: var(--danger);
|
2021-10-18 12:22:47 +00:00
|
|
|
|
}
|
|
|
|
|
|
2023-09-04 12:00:22 +00:00
|
|
|
|
input[type='checkbox'] {
|
2021-10-18 12:22:47 +00:00
|
|
|
|
vertical-align: middle;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.settings {
|
|
|
|
|
float: right;
|
|
|
|
|
width: 24px;
|
|
|
|
|
cursor: pointer;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
&.loader-container.is-loading:after {
|
|
|
|
|
top: calc(50% - 1rem);
|
|
|
|
|
left: calc(50% - 1rem);
|
|
|
|
|
width: 2rem;
|
|
|
|
|
height: 2rem;
|
2021-11-22 21:12:54 +00:00
|
|
|
|
border-left-color: var(--grey-300);
|
|
|
|
|
border-bottom-color: var(--grey-300);
|
2021-10-18 12:22:47 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
2023-09-07 11:47:52 +00:00
|
|
|
|
|
|
|
|
|
.subtask-nested {
|
|
|
|
|
margin-left: 1.75rem;
|
|
|
|
|
}
|
2023-03-04 16:13:31 +00:00
|
|
|
|
</style>
|