Files
IdP/apps/frontend/components/chat/chat-media-album-grid.tsx
2026-06-29 12:17:25 +03:00

85 lines
3.0 KiB
TypeScript

'use client';
import type { ChatMessage } from '@/lib/api';
import { parseChatMediaMetadata } from '@/lib/chat-media-album';
import { cn } from '@/lib/utils';
interface ChatMediaAlbumGridProps {
messages: ChatMessage[];
mediaUrls: Record<string, { blobUrl?: 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;
return (
<button
key={message.id}
type="button"
className={cn('relative overflow-hidden bg-[#dfe4ea]', tileClass(Math.min(count, 6), index))}
onClick={() => onImageClick?.(message, index)}
>
{media?.blobUrl ? (
// eslint-disable-next-line @next/next/no-img-element
<img src={media.blobUrl} alt="" className="h-full w-full object-cover" />
) : (
<div className="flex h-full min-h-[96px] items-center justify-center text-xs text-[#667085]"></div>
)}
{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>
);
}