ultisuite-client/components/gmail/email-view/message-attachments.tsx
2026-05-20 18:22:36 +02:00

174 lines
6.7 KiB
TypeScript

"use client"
import {
Info,
HardDrive,
File,
FileText,
Image as ImageIcon,
} from "lucide-react"
import {
Tooltip,
TooltipContent,
TooltipTrigger,
} from "@/components/ui/tooltip"
import { cn } from "@/lib/utils"
import type { EmailAttachment, EmailAttachmentKind } from "@/lib/email-data"
import {
attachmentPreviewTooltip,
resolveAttachmentKind,
shouldUseAttachmentPillsInPreview,
} from "@/lib/attachment-display"
import { MAIL_TOOLTIP_CONTENT_CLASS } from "@/lib/mail-chrome-classes"
function MessageAttachmentCard({ name, kind }: { name: string; kind: EmailAttachmentKind }) {
return (
<>
<div className="relative flex h-[132px] shrink-0 flex-col items-center justify-center bg-linear-to-b from-muted to-muted/70 dark:from-[#3c4043] dark:to-[#303134]">
{kind === "image" ? (
<ImageIcon className="size-11 text-[#9aa0a6]" strokeWidth={1.25} aria-hidden />
) : kind === "pdf" ? (
<div
className="rounded border border-border bg-mail-surface px-4 py-5 shadow-sm"
aria-hidden
>
<span className="text-[11px] font-bold leading-none text-[#d93025]">PDF</span>
</div>
) : (
<File className="size-11 text-[#9aa0a6]" strokeWidth={1.25} aria-hidden />
)}
</div>
<div className="flex min-h-[38px] items-center gap-2 border-t border-border bg-muted px-2 py-1.5">
{kind === "pdf" ? (
<FileText className="size-4 shrink-0 text-[#d93025]" strokeWidth={1.5} aria-hidden />
) : kind === "image" ? (
<ImageIcon className="size-4 shrink-0 text-[#1a73e8]" strokeWidth={1.5} aria-hidden />
) : (
<File className="size-4 shrink-0 text-[#5f6368]" strokeWidth={1.5} aria-hidden />
)}
<span className="min-w-0 flex-1 truncate text-xs leading-tight text-[#3c4043]">
{name}
</span>
</div>
</>
)
}
function MessageAttachmentPill({
name,
kind,
sizeBytes,
}: {
name: string
kind: EmailAttachmentKind
sizeBytes?: number
}) {
const tip = attachmentPreviewTooltip(name, sizeBytes)
return (
<Tooltip>
<TooltipTrigger asChild>
<button
type="button"
className="inline-flex max-w-[min(100%,320px)] min-w-0 shrink-0 items-center gap-2 rounded-full border border-border bg-muted py-1.5 pl-2.5 pr-3 text-left text-sm text-foreground shadow-sm transition hover:border-border hover:bg-accent hover:shadow focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring"
>
{kind === "pdf" ? (
<FileText className="size-4 shrink-0 text-[#d93025]" strokeWidth={1.5} aria-hidden />
) : kind === "image" ? (
<ImageIcon className="size-4 shrink-0 text-[#1a73e8]" strokeWidth={1.5} aria-hidden />
) : (
<File className="size-4 shrink-0 text-[#5f6368]" strokeWidth={1.5} aria-hidden />
)}
<span className="min-w-0 truncate font-medium">{name}</span>
</button>
</TooltipTrigger>
<TooltipContent side="bottom" className={cn(MAIL_TOOLTIP_CONTENT_CLASS, "max-w-xs whitespace-pre-line text-xs")}>
{tip}
</TooltipContent>
</Tooltip>
)
}
export function MessageAttachmentsSection({ attachments }: { attachments: EmailAttachment[] }) {
const n = attachments.length
if (n === 0) return null
const summary = n === 1 ? "Une pièce jointe" : `${n} pièces jointes`
const asPills = shouldUseAttachmentPillsInPreview(attachments)
return (
<div className="mt-4 border-t border-border px-4 pb-4 pl-[68px] pt-4 max-sm:pl-4 max-sm:pr-4">
<div className="mb-3 flex min-w-0 flex-wrap items-center justify-between gap-x-3 gap-y-2">
<div className="flex min-w-0 max-w-[min(100%,28rem)] items-center gap-1 text-sm text-muted-foreground">
<span className="min-w-0 truncate">
{summary}
<span aria-hidden> · </span>
<span>Analysé par VirusTotal</span>
</span>
<Tooltip delayDuration={400}>
<TooltipTrigger asChild>
<button
type="button"
className="flex h-7 w-7 shrink-0 items-center justify-center rounded-full text-muted-foreground hover:bg-accent"
aria-label="Informations sur l'analyse VirusTotal des pièces jointes"
>
<Info className="size-4" strokeWidth={1.75} />
</button>
</TooltipTrigger>
<TooltipContent side="bottom" className={cn(MAIL_TOOLTIP_CONTENT_CLASS, "max-w-xs text-xs")}>
VirusTotal analyse les pièces jointes et les compare à une base de signatures pour
repérer les virus et logiciels malveillants.
</TooltipContent>
</Tooltip>
</div>
<button
type="button"
className="flex shrink-0 items-center gap-2 rounded-md py-1 pl-1 pr-2 text-sm font-medium text-primary hover:bg-accent"
aria-label="Ajouter à UltiDrive"
>
<HardDrive className="size-[18px] shrink-0" strokeWidth={1.5} aria-hidden />
Ajouter à UltiDrive
</button>
</div>
<div
className={
asPills
? "flex flex-wrap gap-2 pb-1"
: "flex flex-nowrap gap-3 overflow-x-auto overflow-y-hidden pb-1 [-webkit-overflow-scrolling:touch]"
}
role="list"
aria-label="Pièces jointes"
>
{attachments.map((att, index) => {
const kind = resolveAttachmentKind(att.name, att.kind)
const tip = attachmentPreviewTooltip(att.name, att.sizeBytes)
if (asPills) {
return (
<div key={`${att.name}-${index}`} className="shrink-0" role="listitem">
<MessageAttachmentPill name={att.name} kind={kind} sizeBytes={att.sizeBytes} />
</div>
)
}
return (
<div key={`${att.name}-${index}`} className="shrink-0" role="listitem">
<Tooltip>
<TooltipTrigger asChild>
<button
type="button"
className="flex w-[200px] flex-col overflow-hidden rounded border border-border bg-mail-surface text-left shadow-sm transition hover:border-border hover:shadow-md focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring"
>
<MessageAttachmentCard name={att.name} kind={kind} />
</button>
</TooltipTrigger>
<TooltipContent side="bottom" className={cn(MAIL_TOOLTIP_CONTENT_CLASS, "max-w-xs whitespace-pre-line text-xs")}>
{tip}
</TooltipContent>
</Tooltip>
</div>
)
})}
</div>
</div>
)
}