87 lines
3.1 KiB
TypeScript
87 lines
3.1 KiB
TypeScript
'use client';
|
|
|
|
import type { ChatMessage } from '@/lib/api';
|
|
import { MediaImageSkeleton } from '@/components/ui/media-image-skeleton';
|
|
import { parseChatMediaMetadata } from '@/lib/chat-media-album';
|
|
import { cn } from '@/lib/utils';
|
|
|
|
interface ChatMediaAlbumGridProps {
|
|
messages: ChatMessage[];
|
|
mediaUrls: Record<string, { blobUrl?: string; status?: string } | undefined>;
|
|
className?: string;
|
|
onImageClick?: (message: ChatMessage, index: number) => void;
|
|
}
|
|
|
|
function tileClass(count: number, index: number) {
|
|
if (count === 1) return 'col-span-2 row-span-2';
|
|
if (count === 2) return 'col-span-1 row-span-2';
|
|
if (count === 3) {
|
|
if (index === 0) return 'col-span-1 row-span-2';
|
|
return 'col-span-1 row-span-1';
|
|
}
|
|
if (count === 4) return 'col-span-1 row-span-1';
|
|
if (count === 5) {
|
|
if (index === 0) return 'col-span-2 row-span-2';
|
|
return 'col-span-1 row-span-1';
|
|
}
|
|
if (count >= 6) {
|
|
if (index === 0) return 'col-span-2 row-span-2';
|
|
return 'col-span-1 row-span-1';
|
|
}
|
|
return 'col-span-1 row-span-1';
|
|
}
|
|
|
|
export function ChatMediaAlbumGrid({ messages, mediaUrls, className, onImageClick }: ChatMediaAlbumGridProps) {
|
|
const imageMessages = messages.filter((message) => message.type === 'IMAGE' && message.storageKey);
|
|
const fileMessages = messages.filter((message) => message.type === 'FILE' && message.storageKey);
|
|
const count = imageMessages.length;
|
|
|
|
if (!count && fileMessages.length) {
|
|
return (
|
|
<div className={cn('space-y-2', className)}>
|
|
{fileMessages.map((message) => (
|
|
<div key={message.id} className="rounded-xl bg-black/5 px-3 py-2 text-sm">
|
|
{message.content || parseChatMediaMetadata(message.metadataJson).fileName || 'Файл'}
|
|
</div>
|
|
))}
|
|
</div>
|
|
);
|
|
}
|
|
|
|
return (
|
|
<div
|
|
className={cn(
|
|
'grid max-w-[320px] grid-cols-2 gap-0.5 overflow-hidden rounded-2xl',
|
|
count === 1 ? 'grid-rows-1' : count === 2 ? 'grid-rows-2' : 'grid-rows-3 auto-rows-[96px]',
|
|
className
|
|
)}
|
|
>
|
|
{imageMessages.map((message, index) => {
|
|
const media = message.storageKey ? mediaUrls[message.storageKey] : undefined;
|
|
const hiddenCount = count > 6 && index === 5 ? count - 6 : 0;
|
|
const isLoading = !media?.blobUrl || media.status === 'loading';
|
|
return (
|
|
<button
|
|
key={message.id}
|
|
type="button"
|
|
className={cn('relative overflow-hidden bg-[#dfe4ea]', tileClass(Math.min(count, 6), index))}
|
|
onClick={() => onImageClick?.(message, index)}
|
|
>
|
|
{isLoading ? (
|
|
<MediaImageSkeleton className="h-full min-h-[96px] w-full rounded-none" rounded="none" />
|
|
) : (
|
|
// eslint-disable-next-line @next/next/no-img-element
|
|
<img src={media.blobUrl} alt="" className="h-full w-full object-cover" />
|
|
)}
|
|
{hiddenCount > 0 ? (
|
|
<div className="absolute inset-0 flex items-center justify-center bg-black/45 text-2xl font-semibold text-white">
|
|
+{hiddenCount}
|
|
</div>
|
|
) : null}
|
|
</button>
|
|
);
|
|
})}
|
|
</div>
|
|
);
|
|
}
|