feat(ui): ek ekleme alanı, carousel görüntüleyici, ekstre sayfası ve mutabakat penceresi
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,75 @@
|
||||
"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>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user