kanban thumbnails
Deploy / deploy (push) Successful in 2m30s

This commit is contained in:
twotalesanimation
2026-05-24 18:36:22 +02:00
parent 5c452a7512
commit 0723bea4ee
4 changed files with 35 additions and 5 deletions
@@ -41,7 +41,7 @@ export default async function KanbanPage({
where: { projectId: id }, where: { projectId: id },
orderBy: [{ status: "asc" }, { sortOrder: "asc" }], orderBy: [{ status: "asc" }, { sortOrder: "asc" }],
include: { include: {
shot: { select: { id: true, shotCode: true } }, shot: { select: { id: true, shotCode: true, thumbnailUrl: true } },
asset: { select: { id: true, assetCode: true, name: true } }, asset: { select: { id: true, assetCode: true, name: true } },
assignedArtist: { assignedArtist: {
select: { id: true, name: true, email: true, image: true }, select: { id: true, name: true, email: true, image: true },
@@ -55,6 +55,8 @@ export default async function KanbanPage({
versionNumber: true, versionNumber: true,
approvalStatus: true, approvalStatus: true,
createdAt: true, createdAt: true,
thumbnailUrl: true,
posterUrl: true,
}, },
}, },
}, },
+2 -2
View File
@@ -60,14 +60,14 @@ async function getProject(id: string) {
tasks: { tasks: {
orderBy: [{ status: "asc" }, { sortOrder: "asc" }], orderBy: [{ status: "asc" }, { sortOrder: "asc" }],
include: { include: {
shot: { select: { id: true, shotCode: true } }, shot: { select: { id: true, shotCode: true, thumbnailUrl: true } },
asset: { select: { id: true, assetCode: true, name: true } }, asset: { select: { id: true, assetCode: true, name: true } },
assignedArtist: { select: { id: true, name: true, email: true, image: true } }, assignedArtist: { select: { id: true, name: true, email: true, image: true } },
_count: { select: { versions: true } }, _count: { select: { versions: true } },
versions: { versions: {
take: 1, take: 1,
orderBy: { versionNumber: "desc" }, orderBy: { versionNumber: "desc" },
select: { id: true, versionNumber: true, approvalStatus: true, createdAt: true }, select: { id: true, versionNumber: true, approvalStatus: true, createdAt: true, thumbnailUrl: true, posterUrl: true },
}, },
}, },
}, },
+3 -1
View File
@@ -42,7 +42,7 @@ interface KanbanTask {
status: TaskStatus; status: TaskStatus;
priority: string; priority: string;
dueDate: Date | null; dueDate: Date | null;
shot?: { shotCode: string } | null; shot?: { shotCode: string; thumbnailUrl?: string | null } | null;
asset?: { assetCode: string; name: string } | null; asset?: { assetCode: string; name: string } | null;
assignedArtist?: { assignedArtist?: {
id: string; id: string;
@@ -56,6 +56,8 @@ interface KanbanTask {
versionNumber: number; versionNumber: number;
approvalStatus: string; approvalStatus: string;
createdAt: Date; createdAt: Date;
thumbnailUrl?: string | null;
posterUrl?: string | null;
}[]; }[];
} }
+27 -1
View File
@@ -14,6 +14,7 @@ import {
XCircle, XCircle,
Clock, Clock,
GripVertical, GripVertical,
Film,
} from "lucide-react"; } from "lucide-react";
import { TaskStatus, TaskType } from "@prisma/client"; import { TaskStatus, TaskType } from "@prisma/client";
import { TASK_STATUS_CONFIG, TASK_TYPE_LABELS } from "./TaskCard"; import { TASK_STATUS_CONFIG, TASK_TYPE_LABELS } from "./TaskCard";
@@ -33,7 +34,7 @@ interface KanbanTask {
status: TaskStatus; status: TaskStatus;
priority: string; priority: string;
dueDate: Date | null; dueDate: Date | null;
shot?: { shotCode: string } | null; shot?: { shotCode: string; thumbnailUrl?: string | null } | null;
asset?: { assetCode: string; name: string } | null; asset?: { assetCode: string; name: string } | null;
assignedArtist?: { id: string; name: string | null; email: string; image: string | null } | null; assignedArtist?: { id: string; name: string | null; email: string; image: string | null } | null;
_count?: { versions: number }; _count?: { versions: number };
@@ -42,6 +43,8 @@ interface KanbanTask {
versionNumber: number; versionNumber: number;
approvalStatus: string; approvalStatus: string;
createdAt: Date; createdAt: Date;
thumbnailUrl?: string | null;
posterUrl?: string | null;
}[]; }[];
} }
@@ -68,6 +71,13 @@ export function KanbanCard({ task, isDragOverlay = false }: KanbanCardProps) {
const contextCode = task.shot?.shotCode ?? task.asset?.assetCode; const contextCode = task.shot?.shotCode ?? task.asset?.assetCode;
// Resolve thumbnail: prefer latest version thumbnail, then shot thumbnail
const thumbnail =
latestVersion?.thumbnailUrl ??
latestVersion?.posterUrl ??
task.shot?.thumbnailUrl ??
null;
return ( return (
<div <div
ref={setNodeRef} ref={setNodeRef}
@@ -94,6 +104,22 @@ export function KanbanCard({ task, isDragOverlay = false }: KanbanCardProps) {
)} )}
</div> </div>
{/* Thumbnail */}
{thumbnail ? (
<div className="w-full aspect-video rounded-md overflow-hidden bg-zinc-800">
<img
src={thumbnail}
alt={contextCode ?? task.title}
className="w-full h-full object-cover"
loading="lazy"
/>
</div>
) : contextCode && task.shot ? (
<div className="w-full aspect-video rounded-md bg-zinc-800 flex items-center justify-center">
<Film className="h-5 w-5 text-zinc-700" />
</div>
) : null}
{/* Title */} {/* Title */}
<Link <Link
href={`/tasks/${task.id}`} href={`/tasks/${task.id}`}