ultisuite-client/components/gmail/mail-folder-stack-indicator.tsx

146 lines
3.8 KiB
TypeScript

"use client"
import { Fragment, useMemo } from "react"
import { Icon } from "@iconify/react"
import type { FolderTreeNode } from "@/lib/sidebar-nav-maps"
import type { LabelRowItem } from "@/lib/sidebar-nav-data"
import { breadcrumbItemsForVisitKey } from "@/lib/mail-folder-display"
import { resolveMailNavIcon } from "@/lib/mail-nav-icons"
import { cn } from "@/lib/utils"
type MailFolderStackIndicatorProps = {
currentKey: string
folderTree: FolderTreeNode[]
folderIdToLabel: Record<string, string>
labelRows?: readonly LabelRowItem[]
className?: string
onNavigate?: (visitKey: string) => void
}
function MailNavIconGlyph({
visitKey,
folderTree,
labelRows,
}: {
visitKey: string
folderTree: FolderTreeNode[]
labelRows?: readonly LabelRowItem[]
}) {
const resolved = useMemo(
() => resolveMailNavIcon(visitKey, folderTree, labelRows),
[visitKey, folderTree, labelRows]
)
if (resolved.kind === "folder") {
return (
<Icon
icon={resolved.icon}
className="size-4 shrink-0"
style={{ color: resolved.color }}
aria-hidden
/>
)
}
if (resolved.kind === "iconify") {
return (
<Icon
icon={resolved.icon}
className="size-4 shrink-0 text-[#5f6368]"
aria-hidden
/>
)
}
const { Icon: LucideIcon } = resolved
return (
<LucideIcon
className="size-4 shrink-0 text-[#5f6368]"
strokeWidth={1.5}
aria-hidden
/>
)
}
export function MailFolderStackIndicator({
currentKey,
folderTree,
folderIdToLabel,
labelRows,
className,
onNavigate,
}: MailFolderStackIndicatorProps) {
const items = useMemo(
() =>
breadcrumbItemsForVisitKey(
currentKey,
folderTree,
folderIdToLabel,
labelRows
),
[currentKey, folderTree, folderIdToLabel, labelRows]
)
const ariaLabel = items.map((i) => i.label).join(" · ")
return (
<nav
aria-label={`Fil d'Ariane : ${ariaLabel}`}
className={cn(
"flex max-w-[min(360px,calc(100vw-1rem))] items-center",
"border-t border-r border-[#dadce0]/90",
"bg-white/78 px-3.5 py-2.5 text-sm font-medium leading-snug text-[#3c4043]",
"rounded-tr-2xl shadow-sm backdrop-blur-md",
className
)}
>
<span className="flex min-w-0 items-center gap-1.5">
{items.map((item, i) => {
const isCurrent = item.visitKey === currentKey
const segmentClass = cn(
"flex min-w-0 items-center gap-1.5 rounded-sm outline-none",
onNavigate &&
!isCurrent &&
"cursor-pointer hover:bg-[#f1f3f4] focus-visible:ring-2 focus-visible:ring-[#0b57d0]/40",
onNavigate && isCurrent && "cursor-default"
)
const content = (
<>
<MailNavIconGlyph
visitKey={item.visitKey}
folderTree={folderTree}
labelRows={labelRows}
/>
<span className="truncate">{item.label}</span>
</>
)
return (
<Fragment key={`${item.visitKey}-${i}`}>
{i > 0 ? (
<span
className="shrink-0 text-xs leading-none text-[#9aa0a6]"
aria-hidden
>
·
</span>
) : null}
{onNavigate ? (
<button
type="button"
className={segmentClass}
aria-current={isCurrent ? "page" : undefined}
onClick={() => onNavigate(item.visitKey)}
>
{content}
</button>
) : (
<span className={segmentClass}>{content}</span>
)}
</Fragment>
)
})}
</span>
</nav>
)
}