ultisuite-client/components/gmail/email-view/email-view-header.tsx
2026-05-20 16:01:08 +02:00

184 lines
5.3 KiB
TypeScript

"use client"
import { useEffect, useRef, type CSSProperties } from "react"
import { Printer, ExternalLink } from "lucide-react"
import { Button } from "@/components/ui/button"
import {
Tooltip,
TooltipContent,
TooltipTrigger,
} from "@/components/ui/tooltip"
import { cn } from "@/lib/utils"
import type { Email } from "@/lib/email-data"
import type { FolderTreeNode, LabelRowItem } from "@/lib/sidebar-nav-data"
import { openConversationPrint } from "@/lib/print-conversation"
import { MailLabelPillStrip } from "@/components/gmail/mail-label-pills"
import {
MAIL_ICON_BTN,
MAIL_PREVIEW_SUBJECT_HEADER_CLASS,
MAIL_TOOLTIP_CONTENT_CLASS,
} from "@/lib/mail-chrome-classes"
import { useTheme } from "next-themes"
import {
emailPreviewSubjectCss,
} from "@/lib/email-preview-dark-styles"
const EMAIL_PREVIEW_IFRAME_STYLE: CSSProperties = {
display: "block",
background: "transparent",
}
function documentIsDark(): boolean {
return document.documentElement.classList.contains("dark")
}
function SandboxedSubject({ text }: { text: string }) {
const iframeRef = useRef<HTMLIFrameElement>(null)
const { resolvedTheme } = useTheme()
useEffect(() => {
const iframe = iframeRef.current
if (!iframe) return
const doc = iframe.contentDocument
if (!doc) return
const isDark = documentIsDark()
doc.open()
doc.write(`<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="Content-Security-Policy" content="default-src 'none'; style-src 'unsafe-inline';">
<style>${emailPreviewSubjectCss(isDark)}</style>
</head>
<body>${text.replace(/</g, "&lt;").replace(/>/g, "&gt;")}</body>
</html>`)
doc.close()
}, [text, resolvedTheme])
return (
<iframe
ref={iframeRef}
sandbox="allow-same-origin"
title="Sujet du message"
className="pointer-events-none w-full border-0 bg-transparent"
style={{ ...EMAIL_PREVIEW_IFRAME_STYLE, height: "32px" }}
tabIndex={-1}
/>
)
}
const LABEL_DISPLAY_NAMES: Record<string, string> = {
inbox: "Boîte de réception",
starred: "Suivis",
snoozed: "En attente",
important: "Important",
sent: "Messages envoyés",
drafts: "Brouillons",
spam: "Spam",
trash: "Corbeille",
}
export interface EmailViewSubjectHeaderProps {
email: Email
isSpamMessage: boolean
onNotSpam?: () => void
onNavigateToLabel?: (label: string) => void
showLabelChip?: (label: string) => boolean
labelBgByText?: Map<string, string>
emailLabelToSidebarFolderId?: Record<string, string>
getNavItemPrefs?: (id: string) => { messages: string }
folderTree?: FolderTreeNode[]
labelRows?: readonly LabelRowItem[]
currentFolderId?: string
}
export function EmailViewSubjectHeader({
email,
isSpamMessage,
onNotSpam,
onNavigateToLabel,
showLabelChip,
labelBgByText,
emailLabelToSidebarFolderId = {},
getNavItemPrefs = () => ({ messages: "show" }),
folderTree,
labelRows,
currentFolderId,
}: EmailViewSubjectHeaderProps) {
return (
<div
className={cn(
"flex items-start gap-3 px-6 py-4 max-sm:px-4",
MAIL_PREVIEW_SUBJECT_HEADER_CLASS
)}
>
<div className="min-w-0 flex-1">
<div className="flex flex-wrap items-center gap-2">
<SandboxedSubject text={email.subject} />
{labelBgByText && onNavigateToLabel ? (
<MailLabelPillStrip
variant="header"
labels={email.labels ?? ["inbox"]}
labelBgByText={labelBgByText}
emailLabelToSidebarFolderId={emailLabelToSidebarFolderId}
getNavItemPrefs={getNavItemPrefs}
labelRows={labelRows}
folderTree={folderTree}
currentFolderId={currentFolderId}
onLabelNavigate={onNavigateToLabel}
showLabel={showLabelChip}
resolveDisplayName={(lab) => LABEL_DISPLAY_NAMES[lab] ?? lab}
showRemoveOnPills
spamChip={
isSpamMessage && onNotSpam ? { onNotSpam } : undefined
}
/>
) : null}
</div>
</div>
<div className="flex shrink-0 items-center gap-1">
<Tooltip>
<TooltipTrigger asChild>
<Button
type="button"
variant="ghost"
size="icon"
className={cn("h-8 w-8", MAIL_ICON_BTN)}
aria-label="Imprimer"
onClick={() => openConversationPrint(email)}
>
<Printer className="h-[18px] w-[18px]" strokeWidth={1.5} />
</Button>
</TooltipTrigger>
<TooltipContent
side="bottom"
className={cn(MAIL_TOOLTIP_CONTENT_CLASS, "text-xs")}
>
Imprimer tout
</TooltipContent>
</Tooltip>
<Tooltip>
<TooltipTrigger asChild>
<Button
variant="ghost"
size="icon"
className={cn("h-8 w-8", MAIL_ICON_BTN)}
aria-label="Ouvrir dans une nouvelle fenêtre"
>
<ExternalLink className="h-[18px] w-[18px]" strokeWidth={1.5} />
</Button>
</TooltipTrigger>
<TooltipContent
side="bottom"
className={cn(MAIL_TOOLTIP_CONTENT_CLASS, "text-xs")}
>
Dans une nouvelle fenêtre
</TooltipContent>
</Tooltip>
</div>
</div>
)
}