# Draggable

# Nuevos componentes

Vamos a crear primero el componente tarea

# components/TrelloBoardTask.vue

<script setup lang="ts">
import type { Task, ID } from "@/types";
const props = defineProps<{
  task: Task;
}>();

</script>
<template>
  <div
    :title="task.createdAt.toLocaleString()"
    class="task bg-white p-2 mb-2 rounded shadow-sm w-full"
  >
    <span >
      {{ task.title }}
    </span>
  </div>
</template>
  • Vinculamos :title con la hora de creación.
  • Le damos estilos con las clases Tailwind

# components/DragHandle.vue

Vamos a crear el compomente para arrastrar con un icon de font awesome

<template>
    <span class="drag-handle cursor-move pr-2"><font-awesome-icon icon="fa-solid fa-bars" /></span>  
</template>

# components/RawDisplayer.vue

Con este componente podremos ver los cambios en el array de columnas con sus tareas

<script setup lang="ts">
import { computed } from "vue"

const props = defineProps<{
  title: string
  value: any
}>()

const valueString = computed(() => {
  return JSON.stringify(props.value, null, 2);})

</script>

<template>
  <div>
    <h3>{{ props.title }}</h3>
    <pre>{{ valueString }}</pre>
  </div>
</template>

<style scoped>
pre {
  text-align: start;
}
</style>

# Tareas

# Archivo pages/index.vue

<template>
  <div class="flex gap-4 overflow-x-auto items-start">
    <div v-for="column in columns" :key="column.id" 
    class="column bg-gray-200 p-5 rounded min-w-[250px]">
      <header>
       {{ column.title}} 
      </header>
      <TrelloBoardTask 
        v-for="task in column.tasks"
        :key="task.id" 
        :task="task"/>
    </div>
  </div>  
</template>
  • Añadimos el componente TrelloBoardTask.vue y añadimos un botón para añadir una tarea nueva.

# App.vue

Incluimos una imangen corporativa y un título de página.

  • En el archivo App.vue
  • Añadimos estilos css de Tailwind
  • Un texto de encabezado
  • Añadimos también una imagen o logo.
<template>
  <div class="p-5 h-[100vh] bg-cyan-400 over-flow-auto h-full"> 
    <h1 class="text-2xl text-white flex items-center mb-10">
      <img width="200" class="mr-3" src="/vue.png" alt="Vue.js-ES">
      Trello-Tablero
    </h1>
   <NuxtPage />
  </div>
</template>

# Draggable pages/index.vue

  • Importamos la dependencia draggable
import draggable from "vuedraggable"

# Componente draggable

VueDraggableNext (opens new window)

  • Vamos añadir el componente draggable

  • Uso típico:

    • v-model vincula al array de datos.
    • group permite arrastrar y soltar en diferentes listas.
    • item-key es como un id propio de cada item (columna)
  • Slots

    • template #item cada item (columna) individual, no necesitamos un v-for
    • element será cada uno de los items (column) con su tipo de dato (Column)
<draggable 
  v-model="myArray" 
  group="people" 
  @start="drag=true" 
  @end="drag=false" 
  item-key="id">
  <template #item="{element}">
    <div>{{element.name}}</div>
   </template>
</draggable>

# pages/index.vue

  • :animación a el componente draggable
  • handle a el mismo componente
  • Añadimos el componente RawDisplayer para ver el arrary y los cambios
<template>
  <div>
     <draggable
      v-model="columns"
      group="columns"
      :animation="150"
      handle=".drag-handle"
      item-key="id"
      class="flex gap-4 items-start"
    >
      <template #item="{ element: column }:  { element: Column }">
        <div class="column bg-gray-200 p-5 rounded min-w-[250px]">
         <header class="flex font-bold mb-4 ">
            <drag-handle />
          {{ column.title}} 
          </header>
      <TrelloBoardTask v-for="task in column.tasks" 
      :key="task.id" 
      :task="task" />
      <footer>
        <button class="text-gray-500">+ Add a Card</button>
      </footer>
    </div>
    </template>
    </draggable>
  </div>
  <div>
    <RawDisplayer
    :value="columns" 
    title="Lista" />
</div> 
</template>

# Tareas

# pages/index.vue

<template>
  <div >
    <draggable
      v-model="columns"
      group="columns"
      :animation="150"
      handle=".drag-handle"
      item-key="id"
      class="flex gap-4 items-start"
    >
      <template #item="{ element: column }:  { element: Column }">
        <div class="column bg-gray-200 p-5 rounded min-w-[250px]">
          <header class="flex font-bold mb-4 ">
            <drag-handle />
          {{ column.title}} 
          </header>
          <draggable
            v-model="column.tasks"
            group="tasks"
            :animation="150"
            item-key="id">
            <template #item="{ element: task }: { element: Task }">
              <TrelloBoardTask
              :task="task" 
              />
          </template>
          </draggable>   
          <footer>
            <button class="text-gray-500">+ Add a Card</button>
          </footer>
        </div>
      </template>
    </draggable> 
  </div>  
</template> 

# Clonar Tareas

<script>
import { useKeyModifier } from '@vueuse/core'

const shift = useKeyModifier('Shift', { initial: false })

console.log(shift.value)
</script>

En la parte template elemento draggable añade la tecla shift

:group="{ name: 'tasks', pull: shift ? 'clone' : true }"