Add image handling
This commit is contained in:
88
src/components/sort/SortableImage.tsx
Normal file
88
src/components/sort/SortableImage.tsx
Normal file
@ -0,0 +1,88 @@
|
||||
'use client';
|
||||
|
||||
import { useSortable } from '@dnd-kit/sortable';
|
||||
import { CSS } from '@dnd-kit/utilities';
|
||||
import clsx from 'clsx';
|
||||
import { CheckCircle, Circle, GripVertical } from 'lucide-react';
|
||||
import NextImage from 'next/image';
|
||||
import Link from 'next/link';
|
||||
|
||||
type SortableCardItemProps = {
|
||||
id: string;
|
||||
item: {
|
||||
id: string;
|
||||
name: string;
|
||||
fileKey: string;
|
||||
altText: string;
|
||||
published?: boolean;
|
||||
creationDate?: Date | string;
|
||||
};
|
||||
};
|
||||
|
||||
export function SortableImage({ id, item }: SortableCardItemProps) {
|
||||
const { attributes, listeners, setNodeRef, transform, transition } = useSortable({ id });
|
||||
|
||||
const style = {
|
||||
transform: CSS.Transform.toString(transform),
|
||||
transition,
|
||||
};
|
||||
|
||||
const href = `/portfolio/edit/${item.id}`;
|
||||
|
||||
let dateDisplay = null;
|
||||
if (item.creationDate instanceof Date) {
|
||||
dateDisplay = item.creationDate.toLocaleDateString('de-DE');
|
||||
} else if (typeof item.creationDate === 'string') {
|
||||
const parsed = new Date(item.creationDate);
|
||||
if (!isNaN(parsed.getTime())) {
|
||||
dateDisplay = parsed.toLocaleDateString('de-DE');
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<div
|
||||
ref={setNodeRef}
|
||||
style={style}
|
||||
{...attributes}
|
||||
className="relative cursor-grab active:cursor-grabbing"
|
||||
>
|
||||
<div
|
||||
{...listeners}
|
||||
className="absolute top-2 left-2 z-20 text-muted-foreground bg-white/70 rounded-full p-1"
|
||||
title="Drag to reorder"
|
||||
>
|
||||
<GripVertical className="w-4 h-4" />
|
||||
</div>
|
||||
|
||||
<Link href={href}>
|
||||
<div className="group rounded-lg border overflow-hidden hover:shadow-md transition-shadow bg-background relative">
|
||||
<div className="relative aspect-[4/3] w-full bg-muted items-center justify-center">
|
||||
<NextImage
|
||||
src={`/api/image/thumbnail/${item.fileKey}.webp`}
|
||||
alt={item.altText ? item.altText : "Image"}
|
||||
fill
|
||||
className={clsx("object-cover transition duration-300")}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Content */}
|
||||
<div className="p-4 text-center">
|
||||
<h2 className="text-lg font-semibold truncate">{item.name}</h2>
|
||||
{dateDisplay && (
|
||||
<p className="text-xs text-muted-foreground mt-1">{dateDisplay}</p>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Status icon in bottom-left corner */}
|
||||
<div className="absolute bottom-2 left-2 z-10 bg-white/80 rounded-full p-1">
|
||||
{item.published ? (
|
||||
<CheckCircle className="w-4 h-4 text-green-600" />
|
||||
) : (
|
||||
<Circle className="w-4 h-4 text-muted-foreground" />
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</Link>
|
||||
</div>
|
||||
);
|
||||
}
|
Reference in New Issue
Block a user