146 lines
4.2 KiB
TypeScript
146 lines
4.2 KiB
TypeScript
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<MailRouteState>) => void
|
|
onSelectFolder?: (folder: string) => void
|
|
onFolderUnreadCountsChange?: (counts: Record<string, number>) => 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, ">")
|
|
.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"
|
|
}
|