kanban

Minimal kanban with stacked frame

Minimal kanban with stacked frame

Загрузка превью…

src/kanban/c-kanban-4.vue

<!--
  Сетевые unsplash-аватары заменены статичным 1x1 data-URI (PIXEL).
  Доска в покое с фиксированным порядком карточек.
-->
<script setup lang="ts">
import { ref } from "vue"
import { Badge } from "@/components/reui/badge"
import { Frame, FrameDescription, FrameHeader, FramePanel, FrameTitle } from "@/components/reui/frame"
import { Kanban, KanbanBoard, KanbanColumn, KanbanColumnContent, KanbanItem, KanbanItemHandle, KanbanOverlay } from "@/components/reui/kanban"
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar"
import { Progress } from "@/components/ui/progress"

const PIXEL =
  "data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs="

interface Task {
  id: string
  title: string
  assignee: string
  assigneeAvatar: string
  progress: number
}

const columnDescriptions: Record<string, string> = {
  planning: "Tasks being scoped",
  active: "Currently in development",
  completed: "Finished and deployed",
}

const columns = ref<Record<string, Task[]>>({
  planning: [
    { id: "1", title: "Research competitors", assignee: "Alex J.", assigneeAvatar: PIXEL, progress: 20 },
  ],
  active: [
    { id: "2", title: "Build dashboard", assignee: "Sarah C.", assigneeAvatar: PIXEL, progress: 65 },
    { id: "3", title: "API integration", assignee: "David K.", assigneeAvatar: PIXEL, progress: 40 },
  ],
  completed: [
    { id: "4", title: "Setup repository", assignee: "Emma W.", assigneeAvatar: PIXEL, progress: 100 },
  ],
})
</script>

<template>
  <div>
    <Kanban v-model:value="columns" :get-item-value="(item: Task) => item.id">
      <KanbanBoard class="grid auto-rows-fr grid-cols-3">
        <KanbanColumn v-for="(tasks, columnId) in columns" :key="columnId" :value="columnId">
          <Frame stacked spacing="sm" class="h-full">
            <FrameHeader>
              <div class="flex items-center justify-between">
                <FrameTitle class="capitalize">{{ columnId }}</FrameTitle>
                <Badge variant="outline" size="sm">{{ tasks.length }}</Badge>
              </div>
              <FrameDescription>{{ columnDescriptions[columnId] }}</FrameDescription>
            </FrameHeader>
            <KanbanColumnContent :value="columnId" class="flex flex-col gap-2 p-0.5">
              <KanbanItem v-for="task in tasks" :key="task.id" :value="task.id">
                <KanbanItemHandle>
                  <Frame variant="ghost" spacing="xs" class="p-0">
                    <FramePanel class="space-y-3 p-3">
                      <p class="text-sm font-medium">{{ task.title }}</p>
                      <Progress :model-value="task.progress" class="h-1" />
                      <div class="flex items-center justify-between">
                        <div class="flex items-center gap-1.5">
                          <Avatar class="size-5">
                            <AvatarImage :src="task.assigneeAvatar" :alt="task.assignee" />
                            <AvatarFallback class="text-[9px]">{{ task.assignee.charAt(0) }}</AvatarFallback>
                          </Avatar>
                          <span class="text-muted-foreground text-xs">{{ task.assignee }}</span>
                        </div>
                        <span class="text-muted-foreground text-xs">{{ `${task.progress}%` }}</span>
                      </div>
                    </FramePanel>
                  </Frame>
                </KanbanItemHandle>
              </KanbanItem>
            </KanbanColumnContent>
          </Frame>
        </KanbanColumn>
      </KanbanBoard>
      <KanbanOverlay class="bg-muted/10 rounded-md border-2 border-dashed" />
    </Kanban>
  </div>
</template>

Установка

npx shadcn-vue@latest add https://revueui.rootapi.dev/r/c-kanban-4.json

Зависимости реестра

Источник: порт из ReUI (Keenthemes, MIT)