8a9f5ddc7d
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
76 lines
2.5 KiB
TypeScript
76 lines
2.5 KiB
TypeScript
"use client";
|
||
|
||
import { FileText, Paperclip } from "lucide-react";
|
||
import { useState } from "react";
|
||
import { tr } from "@/i18n/tr";
|
||
import type { AttachmentInfo } from "../service";
|
||
import { AttachmentViewer } from "./attachment-viewer";
|
||
|
||
const t = tr.attachments;
|
||
const VISIBLE = 4;
|
||
|
||
/** Ayrıntıda küçük önizleme şeridi (en fazla 4 + "+N"); tıklayınca görüntüleyici açılır. */
|
||
export function AttachmentStrip({ items }: { items: AttachmentInfo[] }) {
|
||
const [viewer, setViewer] = useState<number | null>(null);
|
||
if (!items.length) return null;
|
||
const shown = items.slice(0, VISIBLE);
|
||
const rest = items.length - shown.length;
|
||
|
||
return (
|
||
<div className="flex items-center gap-2">
|
||
<Paperclip className="size-4 shrink-0 text-muted-foreground" aria-hidden />
|
||
<span className="sr-only">{t.count(items.length)}</span>
|
||
<ul className="flex gap-1.5">
|
||
{shown.map((item, i) => (
|
||
<li key={item.id} className="relative">
|
||
<AttachmentThumb item={item} onClick={() => setViewer(i)} />
|
||
{rest > 0 && i === shown.length - 1 ? (
|
||
<button
|
||
type="button"
|
||
onClick={() => setViewer(i + 1)}
|
||
className="absolute inset-0 flex items-center justify-center rounded-md bg-black/55 text-sm font-medium text-white"
|
||
aria-label={`${t.viewerTitle}: ${t.moreCount(rest)}`}
|
||
>
|
||
{t.moreCount(rest)}
|
||
</button>
|
||
) : null}
|
||
</li>
|
||
))}
|
||
</ul>
|
||
<AttachmentViewer
|
||
items={items}
|
||
startIndex={viewer ?? 0}
|
||
open={viewer !== null}
|
||
onOpenChange={(open) => !open && setViewer(null)}
|
||
/>
|
||
</div>
|
||
);
|
||
}
|
||
|
||
export function AttachmentThumb({
|
||
item,
|
||
onClick,
|
||
className = "size-12",
|
||
}: {
|
||
item: AttachmentInfo;
|
||
onClick?: () => void;
|
||
className?: string;
|
||
}) {
|
||
return (
|
||
<button
|
||
type="button"
|
||
onClick={onClick}
|
||
title={item.name}
|
||
aria-label={item.name}
|
||
className={`${className} flex items-center justify-center overflow-hidden rounded-md border bg-muted focus-visible:ring-2 focus-visible:ring-ring focus-visible:outline-none`}
|
||
>
|
||
{item.thumbUrl ? (
|
||
// eslint-disable-next-line @next/next/no-img-element -- yetkili özel dosya
|
||
<img src={item.thumbUrl} alt="" className="size-full object-cover" loading="lazy" />
|
||
) : (
|
||
<FileText className="size-5 text-muted-foreground" aria-hidden />
|
||
)}
|
||
</button>
|
||
);
|
||
}
|