Files
panel/resources/js/views/apps/kanban/KanbanBoardEditDrawer.vue

391 lines
9.7 KiB
Vue
Raw Normal View History

2025-08-04 16:33:07 +03:30
<script setup>
import { Placeholder } from '@tiptap/extension-placeholder'
import { TextAlign } from '@tiptap/extension-text-align'
import { Underline } from '@tiptap/extension-underline'
import { StarterKit } from '@tiptap/starter-kit'
import {
EditorContent,
useEditor,
} from '@tiptap/vue-3'
import { PerfectScrollbar } from 'vue3-perfect-scrollbar'
import { VForm } from 'vuetify/components/VForm'
import avatar1 from '@images/avatars/avatar-1.png'
import avatar2 from '@images/avatars/avatar-2.png'
import avatar3 from '@images/avatars/avatar-3.png'
import avatar4 from '@images/avatars/avatar-4.png'
import avatar5 from '@images/avatars/avatar-5.png'
import avatar6 from '@images/avatars/avatar-6.png'
const props = defineProps({
kanbanItem: {
type: null,
required: false,
default: () => ({
item: {
title: '',
dueDate: '2022-01-01T00:00:00Z',
labels: [],
members: [],
id: 0,
attachments: 0,
commentsCount: 0,
image: '',
comments: '',
},
boardId: 0,
boardName: '',
}),
},
isDrawerOpen: {
type: Boolean,
required: true,
},
})
const emit = defineEmits([
'update:isDrawerOpen',
'update:kanbanItem',
'deleteKanbanItem',
])
const refEditTaskForm = ref()
const labelOptions = [
'UX',
'Image',
'Code Review',
'Dashboard',
'App',
'Charts & Maps',
]
const localKanbanItem = ref(JSON.parse(JSON.stringify(props.kanbanItem.item)))
const handleDrawerModelValueUpdate = val => {
emit('update:isDrawerOpen', val)
if (!val)
refEditTaskForm.value?.reset()
}
// kanban item watcher
watch(() => props.kanbanItem, () => {
localKanbanItem.value = JSON.parse(JSON.stringify(props.kanbanItem.item))
}, { deep: true })
const updateKanbanItem = () => {
refEditTaskForm.value?.validate().then(async valid => {
if (valid.valid) {
emit('update:kanbanItem', {
item: localKanbanItem.value,
boardId: props.kanbanItem.boardId,
boardName: props.kanbanItem.boardName,
})
emit('update:isDrawerOpen', false)
await nextTick()
refEditTaskForm.value?.reset()
}
})
}
// delete kanban item
const deleteKanbanItem = () => {
emit('deleteKanbanItem', {
item: localKanbanItem.value,
boardId: props.kanbanItem.boardId,
boardName: props.kanbanItem.boardName,
})
emit('update:isDrawerOpen', false)
}
// 👉 label/chip color
const resolveLabelColor = {
'UX': 'success',
'Image': 'warning',
'Code Review': 'error',
'Dashboard': 'info',
'App': 'secondary',
'Charts & Maps': 'primary',
}
const users = [
{
img: avatar1,
name: 'John Doe',
},
{
img: avatar2,
name: 'Jane Smith',
},
{
img: avatar3,
name: 'Robert Johnson',
},
{
img: avatar4,
name: 'Lucy Brown',
},
{
img: avatar5,
name: 'Mike White',
},
{
img: avatar6,
name: 'Anna Black',
},
]
const fileAttached = ref()
const editor = useEditor({
content: '',
extensions: [
StarterKit,
TextAlign.configure({
types: [
'heading',
'paragraph',
],
}),
Placeholder.configure({ placeholder: 'Write a Comment...' }),
Underline,
],
})
const config = ref({
altFormat: 'j M, Y',
altInput: true,
dateFormat: 'Y-m-d',
})
</script>
<template>
<VNavigationDrawer
data-allow-mismatch
location="end"
:width="370"
temporary
border="0"
:model-value="props.isDrawerOpen"
@update:model-value="handleDrawerModelValueUpdate"
>
<!-- 👉 Header -->
<AppDrawerHeaderSection
title="Edit Task"
@cancel="$emit('update:isDrawerOpen', false)"
/>
<VDivider />
<PerfectScrollbar
:options="{ wheelPropagation: false }"
style="block-size: calc(100vh - 4rem);"
>
<VForm
v-if="localKanbanItem"
ref="refEditTaskForm"
@submit.prevent="updateKanbanItem"
>
<VCardText class="kanban-editor-drawer">
<VRow>
<VCol cols="12">
<AppTextField
v-model="localKanbanItem.title"
label="Title"
:rules="[requiredValidator]"
/>
</VCol>
<VCol cols="12">
<AppDateTimePicker
v-model="localKanbanItem.dueDate"
label="Due date"
:config="config"
/>
</VCol>
<VCol cols="12">
<AppSelect
v-model="localKanbanItem.labels"
:items="labelOptions"
label="Label"
multiple
eager
>
<template #chip="{ item }">
<VChip :color="resolveLabelColor[item.raw]">
{{ item.raw }}
</VChip>
</template>
</AppSelect>
</VCol>
<VCol cols="12">
<p
class="mb-1 text-body-2 text-high-emphasis"
style="line-height: 15px;"
>
Assigned
</p>
<div>
<VSelect
v-model="localKanbanItem.members"
:items="users"
item-title="name"
item-value="name"
multiple
return-object
variant="plain"
:menu-props="{
offset: 10,
}"
class="assignee-select"
>
<template #selection="{ item }">
<VAvatar size="26">
<VImg :src="item.raw.img" />
<VTooltip activator="parent">
{{ item.raw.name }}
</VTooltip>
</VAvatar>
</template>
<template #prepend-inner>
<IconBtn
size="26"
variant="tonal"
color="secondary"
>
<VIcon
size="20"
icon="tabler-plus"
/>
</IconBtn>
</template>
</VSelect>
</div>
</VCol>
<VCol cols="12">
<VFileInput
v-model="fileAttached"
prepend-icon=""
multiple
variant="outlined"
label="No file chosen"
clearable
>
<template #append>
<VBtn variant="tonal">
Choose
</VBtn>
</template>
</VFileInput>
</VCol>
<VCol cols="12">
<p
class="text-body-2 text-high-emphasis mb-1"
style="line-height: 15px;"
>
COMMENT
</p>
<div class="border rounded px-3 py-2">
<EditorContent :editor="editor" />
<div
v-if="editor"
class="d-flex justify-end flex-wrap gap-x-2"
>
<VIcon
icon="tabler-bold"
:color="editor.isActive('bold') ? 'primary' : 'secondary'"
size="20"
@click="editor.chain().focus().toggleBold().run()"
/>
<VIcon
:color="editor.isActive('underline') ? 'primary' : 'secondary'"
icon="tabler-underline"
size="20"
@click="editor.commands.toggleUnderline()"
/>
<VIcon
:color="editor.isActive('italic') ? 'primary' : 'secondary'"
icon="tabler-italic"
size="20"
@click="editor.chain().focus().toggleItalic().run()"
/>
<VIcon
:color="editor.isActive({ textAlign: 'left' }) ? 'primary' : 'secondary'"
icon="tabler-align-left"
size="20"
@click="editor.chain().focus().setTextAlign('left').run()"
/>
<VIcon
:color="editor.isActive({ textAlign: 'center' }) ? 'primary' : 'secondary'"
icon="tabler-align-center"
size="20"
@click="editor.chain().focus().setTextAlign('center').run()"
/>
<VIcon
:color="editor.isActive({ textAlign: 'right' }) ? 'primary' : 'secondary'"
icon="tabler-align-right"
size="20"
@click="editor.chain().focus().setTextAlign('right').run()"
/>
</div>
</div>
</VCol>
<VCol cols="12">
<VBtn
type="submit"
class="me-4"
>
Update
</VBtn>
<VBtn
color="error"
variant="tonal"
@click="deleteKanbanItem"
>
Delete
</VBtn>
</VCol>
</VRow>
</VCardText>
</VForm>
</PerfectScrollbar>
</VNavigationDrawer>
</template>
<style lang="scss">
.kanban-editor-drawer {
.assignee-select {
.v-field__append-inner {
.v-select__menu-icon {
display: none;
}
}
}
.ProseMirror {
padding: 0;
min-block-size: 7vh !important;
p {
margin-block-end: 0;
}
}
.ProseMirror-focused {
outline: none !important;
}
}
</style>