import { cn } from "@/lib/utils" import { labelPillTextClassForTailwindBgUtility } from "@/lib/label-pill-contrast" import { buildInboxCategoryTabIcons } from "@/lib/inbox-category-tabs" type InboxTabBarItem = { id: string label: string icon: string badgeColor: string } import { INBOX_ALL_TAB } from "@/lib/mail-url" import type { Email } from "@/lib/email-data" import type { FolderTreeNode, LabelRowItem } from "@/lib/sidebar-nav-data" import type { MailRouteState } from "@/lib/mail-url" import { formatMailDetailDate } from "@/lib/mail-date" import { MAIL_LIST_ROW_CHECKBOX_CIRCULAR_CLASS, MAIL_LIST_ROW_CHECKBOX_SQUARE_CLASS, } from "@/lib/mail-chrome-classes" export const LIST_PAGE_SIZE = 50 export { PULL_HOLD_HEIGHT, PULL_REFRESH_THRESHOLD, PULL_REFRESH_MAX, PULL_SNAP_BACK_TRANSITION, REFRESH_SPIN_CLASS, PULL_ICON_FADE_MS, PULL_SPINNER_REVEAL_OFFSET, computePullOffset, computeSpinnerRevealProgress, } from "@/hooks/use-mail-list-pull-refresh" export interface EmailListProps { selectedFolder: string inboxTab: string listPage: number openMailId: string | null splitView?: boolean onToggleSidebar?: () => void onMailRouteNavigate: (patch: Partial) => void onSelectFolder?: (folder: string) => void onFolderUnreadCountsChange?: (counts: Record) => void onXsViewChromeChange?: (chrome: import("@/lib/mail-xs-view-chrome").MailXsViewChrome | null) => void } export function collectTreeLabels(nodes: FolderTreeNode[]): string[] { const out: string[] = [] for (const n of nodes) { out.push(n.label) if (n.children?.length) out.push(...collectTreeLabels(n.children)) } return out } export function formatScheduledDateTimeDisplay(iso: string | undefined): string { if (!iso) return "—" return formatMailDetailDate(iso) } export function scheduledIsoToDatetimeLocalValue(iso: string | undefined): string { if (!iso) return "" const d = new Date(iso) if (Number.isNaN(d.getTime())) return "" const p = (n: number) => String(n).padStart(2, "0") return `${d.getFullYear()}-${p(d.getMonth() + 1)}-${p(d.getDate())}T${p(d.getHours())}:${p(d.getMinutes())}` } export function parseDatetimeLocalToIso(value: string): string | null { const d = new Date(value) if (Number.isNaN(d.getTime())) return null return d.toISOString() } export function contextMenuTargetIdsForRow( emailId: string, selectedEmails: string[], selectedFolder: string, pool: Email[] ): string[] { const raw = selectedEmails.includes(emailId) ? selectedEmails : [emailId] if (selectedFolder !== "scheduled") return raw const onlyScheduled = raw.filter((id) => pool.some((e) => e.id === id && e.labels?.includes("scheduled")) ) return onlyScheduled.length > 0 ? onlyScheduled : [emailId] } export function escapeHtml(text: string): string { return text .replace(/&/g, "&") .replace(//g, ">") .replace(/"/g, """) } export function importantSignalIcon(isSpam: boolean, isImportant: boolean): string { if (isSpam) return "mdi:flag-outline" if (isImportant) return "mdi:label-variant" return "mdi:label-variant-outline" } export function buildInboxTabBarItems(labelRows: readonly LabelRowItem[]): InboxTabBarItem[] { return [ ...buildInboxCategoryTabIcons(labelRows), { id: INBOX_ALL_TAB, label: "Tous les messages", icon: "mdi:inbox", badgeColor: "bg-[#0b57d0]", }, ] } export function inboxTabBadgeCountClass(badgeColor: string) { return cn( "shrink-0 rounded-full px-2 py-0.5 text-[11px] font-medium leading-none", badgeColor, labelPillTextClassForTailwindBgUtility(badgeColor) ) } export function inboxTabBadgeDotClass(badgeColor: string) { return cn( "absolute -right-0.5 -top-0.5 size-2 rounded-full ring-2 ring-mail-surface", badgeColor ) } export const CATEGORY_TAB_ICON_CLASS = "h-4 w-4 shrink-0" export function listRowCheckboxClass(circular: boolean) { return circular ? MAIL_LIST_ROW_CHECKBOX_CIRCULAR_CLASS : MAIL_LIST_ROW_CHECKBOX_SQUARE_CLASS } export function listRowQuickHoverTrayToneClass(isSelected: boolean, isRead: boolean) { return isSelected ? "bg-mail-row-selected" : isRead ? "bg-mail-row-read" : "bg-mail-row-unread" }