==
<div v-show="isModalOpen" class="task-bg" @click.self="closeModal">
<NuxtPage :key="route.fullPath" />
</div>
=
const isModalOpen = computed(() => {
console.log('sv',route.name);
return route.name === 'tasks-id'
})
=
creud for tasks
https://www.vuemastery.com/courses/build-a-trello-clone-w-nuxt-3/crud-for-tasks
https://github.com/Code-Pop/build-trello-clone-with-nuxt-3/tree/06-end
npm i uuid
used for to generate unique id
so now we are adding new task to that columns
ist create input field on every column
thne create functiin when key enter
after it is called store variables
then it saved to loocal storage
<UInput
v-model="newTaskName"
type="text"
placeholder="Create new task"
icon="i-heroicons-plus-circle-solid"
@keyup.enter="addTask"
/>
=
function addTask() {
boardStore.addTask({
taskName: newTaskName.value,
columnIndex: props.columnIndex
})
newTaskName.value = ''
}
=
function addTask({ columnIndex, taskName }) {
board.value.columns[columnIndex].tasks.push({
id: uuid(),
name: taskName,
description: ''
})
}
=
edit the task in column
<template>
<div class="task-wrapper">
<div class="task-view">
<UInput type="text" v-model="task.name" />
<UTextarea type="text" v-model="task.description" ></UTextarea>
</div>
</div>
to make it beautiful
<UFormGroup label="Name" class="w-full mb-4">
<UInput type="text" v-model="task.name" />
</UFormGroup>
<UFormGroup label="Description" class="w-full mb-4">
<UTextarea v-model="task.description" />
</UFormGroup>
now delete task at view
at [id].vue
function deleteTask() {
console.log('va');
boardStore.deleteTask(route.params.id)
router.push('/')
}
=
<UButton icon="i-heroicons-trash" color="red" @click="deleteTask">
Delete task
</UButton>
=
function deleteTask(taskId) {
console.log(taskId);
for (const column of board.value.columns) {
const taskIndex = column.tasks.findIndex(task => task.id === taskId)
if (taskIndex !== -1) {
column.tasks.splice(taskIndex, 1)
return
}
}
}
=
at boardStore.js
import { v4 as uuid } from 'uuid'
import { defineStore } from 'pinia'
import { useStorage } from '@vueuse/core'
import boardData from '~/data/board.json'
export const useBoardStore = defineStore('boardStore', () => {
const board = useStorage('board', boardData)
/**
* Tasks
*/
const getTask = computed(() => {
return taskId => {
for (const column of board.value.columns) {
const task = column.tasks.find(task => task.id === taskId)
if (task) return task
}
}
})
function addTask({ columnIndex, taskName }) {
board.value.columns[columnIndex].tasks.push({
id: uuid(),
name: taskName,
description: ''
})
}
function deleteTask(taskId) {
console.log(taskId);
for (const column of board.value.columns) {
const taskIndex = column.tasks.findIndex(task => task.id === taskId)
if (taskIndex !== -1) {
column.tasks.splice(taskIndex, 1)
return
}
}
}
/**
* Columns
*/
function addColumn(columnName) {
board.value.columns.push({
name: columnName,
tasks: []
})
}
function deleteColumn(columnIndex) {
board.value.columns.splice(columnIndex, 1)
}
return {
/* State */
board,
/* Getters */
getTask,
/* Actions*/
addColumn,
addTask,
deleteColumn,
deleteTask
}
})
at [id].vue
<script setup>
import { useBoardStore } from '~/stores/boardStore'
const boardStore = useBoardStore()
const route = useRoute()
const router = useRouter()
const task = computed(() => {
return boardStore.getTask(route.params.id)
})
function deleteTask() {
console.log('va');
boardStore.deleteTask(route.params.id)
router.push('/')
}
</script>
<template>
<div class="task-wrapper">
<div class="task-view">
<UFormGroup label="Name" class="w-full mb-4">
<UInput type="text" v-model="task.name" />
</UFormGroup>
<UFormGroup label="Description" class="w-full mb-4">
<UTextarea v-model="task.description" />
</UFormGroup>
<UButton icon="i-heroicons-trash" color="red" @click="deleteTask">
Delete task
</UButton>
</div>
</div>
</template>
=
INDEX.VUE
<script setup>
import { useBoardStore } from '../stores/boardStore'
const boardStore = useBoardStore()
const route = useRoute()
const router = useRouter()
const newColumnName = ref('')
const isModalOpen = computed(() => {
console.log('sv',route.name);
return route.name === 'tasks-id'
})
function addColumn() {
boardStore.addColumn(newColumnName.value)
newColumnName.value = ''
}
function closeModal() {
router.push('/')
}
</script>
<template>
<div class="board-wrapper">
<main class="board">
<BoardColumn
v-for="(column, columnIndex) in boardStore.board.columns"
:key="column.id"
:column="column"
:columnIndex="columnIndex"
/>
<UContainer class="column">
<UInput
v-model="newColumnName"
type="text"
placeholder="Create new column"
icon="i-heroicons-plus-circle-solid"
@keyup.enter="addColumn"
/>
</UContainer>
</main>
<div v-show="isModalOpen" class="task-bg" @click.self="closeModal">
<NuxtPage :key="route.fullPath" />
</div>
</div>
</template>
=
<script setup>
import { useBoardStore } from '../stores/boardStore'
const props = defineProps({
column: {
type: Object,
required: true
},
columnIndex: {
type: Number,
required: true
}
})
const boardStore = useBoardStore()
const router = useRouter()
const editNameState = ref(false)
const newTaskName = ref('')
function addTask() {
boardStore.addTask({
taskName: newTaskName.value,
columnIndex: props.columnIndex
})
newTaskName.value = ''
}
function deleteColumn(columnIndex) {
boardStore.deleteColumn(columnIndex)
}
function goToTask(taskId) {
router.push(`/tasks/${taskId}`)
}
</script>
<template>
<UContainer class="column">
<div class="column-header mb-4">
<div>
<UInput v-if="editNameState" type="text" v-model="column.name" />
<h2 v-else>{{ column.name }}</h2>
</div>
<div>
<UButton
icon="i-heroicons-pencil-square"
class="mr-2"
@click="editNameState = !editNameState"
/>
<UButton
icon="i-heroicons-trash"
color="red"
@click="deleteColumn(columnIndex)"
/>
</div>
</div>
<ul>
<li v-for="task in column.tasks" :key="task.id">
<UCard class="mb-4" @click="goToTask(task.id)">
<strong>{{ task.name }}</strong>
<p>{{ task.description }}</p>
</UCard>
</li>
</ul>
<UInput
v-model="newTaskName"
type="text"
placeholder="Create new task"
icon="i-heroicons-plus-circle-solid"
@keyup.enter="addTask"
/>
</UContainer>
</template>
==
DRAG AND dROP TASKS
https://github.com/Code-Pop/build-trello-clone-with-nuxt-3/tree/07-end
https://www.vuemastery.com/courses/build-a-trello-clone-w-nuxt-3/nuxt-drag-and-drop-tasks
https://developer.mozilla.org/en-US/docs/Web/API/HTML_Drag_and_Drop_API
draggable="true"
boardcolumn
<UCard class="mb-4" @click="goToTask(task.id)" draggable="true">
drag events
drag start, dragstop,dragover,enter,leave
@dragstart="pickUpTask"
@dragend="dragEnd"
@dragenter="dragEnter"
@dragleave="dragLeave"
@dragover="dragOver"
d
function pickUpTask(event){
console.log(event);
}
function dragStop(event)
{
console.log('dragstop',event);
}
function dragEnter(event)
{
console.log('dragEnter',event);
}
function dragEnd(event)
{
console.log('dragEnd',event);
}
function dragOver(event)
{
console.log('dragover',event);
}
function dragLeave(event)
{
console.log('dragLeave',event);
}
=
@drop="dropTask($event)"
@dragenter.prevent
@dragover.prevent
@dragstop="dropTask($event)"
prevent drag enter
preven drag over
prevent drag stop
self prevent
=
function dropTask(event)
{
const fromColumnIndex=event.dataTransfer.getData('from-column-index');
const fromTaskColumnIndex=event.dataTransfer.getData('from-task-index');
console.log(fromColumnIndex,fromTaskColumnIndex);
}
=
function pickUpTask(event,{fromColumnIndex,fromTaskIndex}){
event.dataTransfer.effectAllower='move';
event.dataTransfer.dropEffect='move';
event.dataTransfer.setData('from-column-index',fromColumnIndex);
event.dataTransfer.setData('from-task-index',fromTaskIndex)
}
=
<UContainer
class="column"
@drop="dropTask($event)"
@dragenter.prevent
@dragover.prevent
@dragstop="dropTask($event)"
>
=
<UCard class="mb-4"
@click="goToTask(task.id)"
draggable="true"
@dragstart="pickUpTask"
>
<strong>{{ task.name }}</strong>
<p>{{ task.description }}</p>
</UCard>
=
working code
boardcolumn.vue
function pickupTask(event, { fromColumnIndex, fromTaskIndex }) {
event.dataTransfer.effectAllowed = 'move'
event.dataTransfer.dropEffect = 'move'
event.dataTransfer.setData('from-column-index', fromColumnIndex)
event.dataTransfer.setData('from-task-index', fromTaskIndex)
}
=
function dropTask(event, toColumnIndex) {
const fromColumnIndex = event.dataTransfer.getData('from-column-index')
const fromTaskIndex = event.dataTransfer.getData('from-task-index')
boardStore.moveTask({
taskIndex: fromTaskIndex,
fromColumnIndex,
toColumnIndex
})
}
=
<UContainer
class="column"
@dragenter.prevent
@dragover.prevent
@drop.stop="dropTask($event, columnIndex)"
>
<div class="column-header mb-4">
<div>
<UInput v-if="editNameState" type="text" v-model="column.name" />
<h2 v-else>{{ column.name }}</h2>
</div>
<div>
<UButton
icon="i-heroicons-pencil-square"
class="mr-2"
@click="editNameState = !editNameState"
/>
<UButton
icon="i-heroicons-trash"
color="red"
@click="deleteColumn(columnIndex)"
/>
</div>
</div>
<ul>
<li v-for="(task, taskIndex) in column.tasks" :key="task.id">
<UCard
class="mb-4"
@click="goToTask(task.id)"
draggable="true"
@dragstart="
pickupTask($event, {
fromColumnIndex: columnIndex,
fromTaskIndex: taskIndex
})
"
>
<strong>{{ task.name }}</strong>
<p>{{ task.description }}</p>
</UCard>
</li>
</ul>
<UInput
v-model="newTaskName"
type="text"
placeholder="Create new task"
icon="i-heroicons-plus-circle-solid"
@keyup.enter="addTask"
/>
</UContainer>
=
boardstore.js
function moveTask({ taskIndex, fromColumnIndex, toColumnIndex }) {
const task = board.value.columns[fromColumnIndex].tasks.splice(
taskIndex,
1
)[0]
board.value.columns[toColumnIndex].tasks.push(task)
}
=
boardstore.js
import { v4 as uuid } from 'uuid'
import { defineStore } from 'pinia'
import { useStorage } from '@vueuse/core'
import boardData from '~/data/board.json'
export const useBoardStore = defineStore('boardStore', () => {
const board = useStorage('board', boardData)
/**
* Tasks
*/
const getTask = computed(() => {
return taskId => {
for (const column of board.value.columns) {
const task = column.tasks.find(task => task.id === taskId)
if (task) return task
}
}
})
function moveTask({ taskIndex, fromColumnIndex, toColumnIndex }) {
const task = board.value.columns[fromColumnIndex].tasks.splice(
taskIndex,
1
)[0]
board.value.columns[toColumnIndex].tasks.push(task)
}
function addTask({ columnIndex, taskName }) {
board.value.columns[columnIndex].tasks.push({
id: uuid(),
name: taskName,
description: ''
})
}
function deleteTask(taskId) {
for (const column of board.value.columns) {
const taskIndex = column.tasks.findIndex(task => task.id === taskId)
if (taskIndex !== -1) {
column.tasks.splice(taskIndex, 1)
return
}
}
}
/**
* Columns
*/
function addColumn(columnName) {
board.value.columns.push({
name: columnName,
tasks: []
})
}
function deleteColumn(columnIndex) {
board.value.columns.splice(columnIndex, 1)
}
return {
/* State */
board,
/* Getters */
getTask,
moveTask,
/* Actions*/
addColumn,
addTask,
deleteColumn,
deleteTask
}
})
boardcolumn.vue
<script setup>
import { useBoardStore } from '../stores/boardStore'
const props = defineProps({
column: {
type: Object,
required: true
},
columnIndex: {
type: Number,
required: true
}
})
const boardStore = useBoardStore()
const router = useRouter()
const editNameState = ref(false)
const newTaskName = ref('')
function addTask() {
boardStore.addTask({
taskName: newTaskName.value,
columnIndex: props.columnIndex
})
newTaskName.value = ''
}
function deleteColumn(columnIndex) {
boardStore.deleteColumn(columnIndex)
}
function dropTask(event, toColumnIndex) {
const fromColumnIndex = event.dataTransfer.getData('from-column-index')
const fromTaskIndex = event.dataTransfer.getData('from-task-index')
boardStore.moveTask({
taskIndex: fromTaskIndex,
fromColumnIndex,
toColumnIndex
})
}
function goToTask(taskId) {
router.push(`/tasks/${taskId}`)
}
function pickupTask(event, { fromColumnIndex, fromTaskIndex }) {
event.dataTransfer.effectAllowed = 'move'
event.dataTransfer.dropEffect = 'move'
event.dataTransfer.setData('from-column-index', fromColumnIndex)
event.dataTransfer.setData('from-task-index', fromTaskIndex)
}
</script>
<template>
<UContainer
class="column"
@dragenter.prevent
@dragover.prevent
@drop.stop="dropTask($event, columnIndex)"
>
<div class="column-header mb-4">
<div>
<UInput v-if="editNameState" type="text" v-model="column.name" />
<h2 v-else>{{ column.name }}</h2>
</div>
<div>
<UButton
icon="i-heroicons-pencil-square"
class="mr-2"
@click="editNameState = !editNameState"
/>
<UButton
icon="i-heroicons-trash"
color="red"
@click="deleteColumn(columnIndex)"
/>
</div>
</div>
<ul>
<li v-for="(task, taskIndex) in column.tasks" :key="task.id">
<UCard
class="mb-4"
@click="goToTask(task.id)"
draggable="true"
@dragstart="
pickupTask($event, {
fromColumnIndex: columnIndex,
fromTaskIndex: taskIndex
})
"
>
<strong>{{ task.name }}</strong>
<p>{{ task.description }}</p>
</UCard>
</li>
</ul>
<UInput
v-model="newTaskName"
type="text"
placeholder="Create new task"
icon="i-heroicons-plus-circle-solid"
@keyup.enter="addTask"
/>
</UContainer>
</template>
=
==
dRAG And Drop COlumns
<UContainer
class="column"
draggable="true"
@dragstart.self="pickupColumn($event, columnIndex)"
function pickupColumn(event, fromColumnIndex) {
event.dataTransfer.effectAllowed = 'move'
event.dataTransfer.dropEffect = 'move'
event.dataTransfer.setData('type', 'column')
event.dataTransfer.setData('from-column-index', fromColumnIndex)
}
=
function dropItem(event, toColumnIndex) {
const type = event.dataTransfer.getData('type')
const fromColumnIndex = event.dataTransfer.getData('from-column-index')
if (type === 'task') {
const fromTaskIndex = event.dataTransfer.getData('from-task-index')
boardStore.moveTask({
taskIndex: fromTaskIndex,
fromColumnIndex,
toColumnIndex
})
} else if (type === 'column') {
boardStore.moveColumn({
fromColumnIndex,
toColumnIndex
})
}
}
=
move column in boardstore .js
function moveColumn({ fromColumnIndex, toColumnIndex }) {
const column = board.value.columns.splice(fromColumnIndex, 1)[0]
board.value.columns.splice(toColumnIndex, 0, column)
}
full code
boardstore.js
import { v4 as uuid } from 'uuid'
import { defineStore } from 'pinia'
import { useStorage } from '@vueuse/core'
import boardData from '~/data/board.json'
export const useBoardStore = defineStore('boardStore', () => {
const board = useStorage('board', boardData)
/**
* Tasks
*/
const getTask = computed(() => {
return taskId => {
for (const column of board.value.columns) {
const task = column.tasks.find(task => task.id === taskId)
if (task) return task
}
}
})
function addTask({ columnIndex, taskName }) {
board.value.columns[columnIndex].tasks.push({
id: uuid(),
name: taskName,
description: ''
})
}
function deleteTask(taskId) {
for (const column of board.value.columns) {
const taskIndex = column.tasks.findIndex(task => task.id === taskId)
if (taskIndex !== -1) {
column.tasks.splice(taskIndex, 1)
return
}
}
}
function moveTask({ taskIndex, fromColumnIndex, toColumnIndex }) {
const task = board.value.columns[fromColumnIndex].tasks.splice(
taskIndex,
1
)[0]
board.value.columns[toColumnIndex].tasks.push(task)
}
/**
* Columns
*/
function addColumn(columnName) {
board.value.columns.push({
name: columnName,
tasks: []
})
}
function deleteColumn(columnIndex) {
board.value.columns.splice(columnIndex, 1)
}
function moveColumn({ fromColumnIndex, toColumnIndex }) {
const column = board.value.columns.splice(fromColumnIndex, 1)[0]
board.value.columns.splice(toColumnIndex, 0, column)
}
return {
/* State */
board,
/* Getters */
getTask,
/* Actions*/
addColumn,
addTask,
deleteColumn,
deleteTask,
moveColumn,
moveTask
}
})
boardcolumn.vue
<script setup>
import { useBoardStore } from '../stores/boardStore'
const props = defineProps({
column: {
type: Object,
required: true
},
columnIndex: {
type: Number,
required: true
}
})
const boardStore = useBoardStore()
const router = useRouter()
const editNameState = ref(false)
const newTaskName = ref('')
function addTask() {
boardStore.addTask({
taskName: newTaskName.value,
columnIndex: props.columnIndex
})
newTaskName.value = ''
}
function deleteColumn(columnIndex) {
boardStore.deleteColumn(columnIndex)
}
function dropItem(event, toColumnIndex) {
const type = event.dataTransfer.getData('type')
const fromColumnIndex = event.dataTransfer.getData('from-column-index')
if (type === 'task') {
const fromTaskIndex = event.dataTransfer.getData('from-task-index')
boardStore.moveTask({
taskIndex: fromTaskIndex,
fromColumnIndex,
toColumnIndex
})
} else if (type === 'column') {
boardStore.moveColumn({
fromColumnIndex,
toColumnIndex
})
}
}
function goToTask(taskId) {
router.push(`/tasks/${taskId}`)
}
function pickupColumn(event, fromColumnIndex) {
event.dataTransfer.effectAllowed = 'move'
event.dataTransfer.dropEffect = 'move'
event.dataTransfer.setData('type', 'column')
event.dataTransfer.setData('from-column-index', fromColumnIndex)
}
function pickupTask(event, { fromColumnIndex, fromTaskIndex }) {
event.dataTransfer.effectAllowed = 'move'
event.dataTransfer.dropEffect = 'move'
event.dataTransfer.setData('type', 'task')
event.dataTransfer.setData('from-column-index', fromColumnIndex)
event.dataTransfer.setData('from-task-index', fromTaskIndex)
}
</script>
<template>
<UContainer
class="column"
draggable="true"
@dragstart.self="pickupColumn($event, columnIndex)"
@dragenter.prevent
@dragover.prevent
@drop.stop="dropItem($event, columnIndex)"
>
<div class="column-header mb-4">
<div>
<UInput v-if="editNameState" type="text" v-model="column.name" />
<h2 v-else>{{ column.name }}</h2>
</div>
<div>
<UButton
icon="i-heroicons-pencil-square"
class="mr-2"
@click="editNameState = !editNameState"
/>
<UButton
icon="i-heroicons-trash"
color="red"
@click="deleteColumn(columnIndex)"
/>
</div>
</div>
<ul>
<li v-for="(task, taskIndex) in column.tasks" :key="task.id">
<UCard
class="mb-4"
@click="goToTask(task.id)"
draggable="true"
@dragstart="
pickupTask($event, {
fromColumnIndex: columnIndex,
fromTaskIndex: taskIndex
})
"
>
<strong>{{ task.name }}</strong>
<p>{{ task.description }}</p>
</UCard>
</li>
</ul>
<UInput
v-model="newTaskName"
type="text"
placeholder="Create new task"
icon="i-heroicons-plus-circle-solid"
@keyup.enter="addTask"
/>
</UContainer>
</template>
=
boardcolumn.vue
@drop.stop="dropItem($event, { toColumnIndex: columnIndex })"
<UContainer
class="column"
draggable="true"
@dragstart.self="pickupColumn($event, columnIndex)"
@dragenter.prevent
@dragover.prevent
@drop.stop="dropItem($event, { toColumnIndex: columnIndex })"
>
=
<UCard
class="mb-4"
@click="goToTask(task.id)"
draggable="true"
@dragstart="
pickupTask($event, {
fromColumnIndex: columnIndex,
fromTaskIndex: taskIndex
})
"
@drop.stop="
dropItem($event, {
toColumnIndex: columnIndex,
toTaskIndex: taskIndex
})
"
=
function moveTask({
fromTaskIndex,
toTaskIndex,
fromColumnIndex,
toColumnIndex
}) {
const task = board.value.columns[fromColumnIndex].tasks.splice(
fromTaskIndex,
1
)[0]
board.value.columns[toColumnIndex].tasks.splice(toTaskIndex, 0, task)
}
=
bonus with next steps
nuxt ui
uinotification (toast notifcication)
command panel
const toast = useToast()
=
function deleteTask() {
toast.add({
title: 'Task deleted',
description: `${task.value.name} has been deleted.`,
icon: 'i-heroicons-trash',
color: 'red'
})
boardStore.deleteTask(route.params.id)
router.push('/')
}
=
in app.vue
<script setup>
const route = useRoute();
console.log(route.name);
</script>
<template>
<Html class="bg-emerald-500">
<div>
<NuxtPage />
</div>
<UNotifications />
</Html>
</template>
=
delete [id].vue
const toast = useToast()
function deleteTask() {
toast.add({
title: 'Task deleted',
description: `${task.value.name} has been deleted.`,
icon: 'i-heroicons-trash',
color: 'red'
})
boardStore.deleteTask(route.params.id)
router.push('/')
}
=
No comments:
Post a Comment