import type { Metadata } from "next" import { displayFileName } from "@/lib/drive/display-file-name" import { parseDriveSegments } from "@/lib/drive/drive-url" export type SuiteApp = "mail" | "drive" | "contacts" | "suite" /** Separator between page segment and product name in document titles. */ export const SUITE_TITLE_SEP = " - " export const MAIL_INBOX_DOCUMENT_TITLE = `Boîte mail${SUITE_TITLE_SEP}Ultimail` const DESCRIPTIONS: Record = { mail: "Client mail Ultimail — suite souveraine", drive: "Stockage de fichiers UltiDrive — suite Ultimail", contacts: "Carnet d'adresses — Ulti Suite", suite: "Ultimail, UltiDrive et contacts — interface suite unifiée", } const APP_LABELS: Record = { mail: "Ultimail", drive: "UltiDrive", contacts: "Ulti Suite", suite: "Ulti Suite", } const ICONS: Record, Metadata["icons"]> = { mail: { icon: [ { url: "/brand/ultimail-header-icon.png", sizes: "109x109", type: "image/png" }, { url: "/icon.png", sizes: "32x32", type: "image/png" }, ], apple: [{ url: "/brand/ultimail-header-icon.png", sizes: "180x180", type: "image/png" }], shortcut: "/brand/ultimail-header-icon.png", }, drive: { icon: [ { url: "/ultidrive-mark.svg", type: "image/svg+xml" }, { url: "/drive/favicon-32.png", sizes: "32x32", type: "image/png" }, { url: "/drive/favicon-16.png", sizes: "16x16", type: "image/png" }, ], apple: [{ url: "/drive/apple-touch-icon.png", sizes: "180x180", type: "image/png" }], shortcut: "/ultidrive-mark.svg", }, contacts: { icon: [ { url: "/contacts-mark.svg", type: "image/svg+xml" }, { url: "/icon.png", sizes: "32x32", type: "image/png" }, ], apple: [{ url: "/contacts-mark.svg", type: "image/svg+xml" }], shortcut: "/contacts-mark.svg", }, } type PageMetadataOptions = { app: SuiteApp /** Full document title (no suffix added). */ title?: string /** Short segment only — parent layout `title.template` adds the product suffix. */ titleSegment?: string description?: string /** When true with `title`, use `title` as the full document title. */ absoluteTitle?: boolean } export function formatSuiteDocumentTitle(segment: string, app: SuiteApp): string { return `${segment}${SUITE_TITLE_SEP}${APP_LABELS[app]}` } export function truncateSubjectForTitle(subject: string, maxLen = 48): string { const clean = subject.replace(/\s+/g, " ").trim() if (!clean) return "" if (clean.length <= maxLen) return clean return `${clean.slice(0, maxLen - 1).trimEnd()}…` } export function mailDocumentTitle(subject: string | null | undefined): string { const trimmed = subject?.replace(/\s+/g, " ").trim() if (trimmed) { return formatSuiteDocumentTitle(truncateSubjectForTitle(trimmed), "mail") } return MAIL_INBOX_DOCUMENT_TITLE } export function suiteRootMetadata(): Metadata { return { title: { default: APP_LABELS.suite }, description: DESCRIPTIONS.suite, icons: ICONS.mail, } } export function suitePageMetadata({ app, title, titleSegment, description, absoluteTitle = false, }: PageMetadataOptions): Metadata { const label = APP_LABELS[app] let resolvedTitle: Metadata["title"] if (titleSegment !== undefined) { // Short segment — nearest ancestor `title.template` adds the product suffix once. resolvedTitle = titleSegment } else if (title === undefined) { resolvedTitle = { default: label, template: `%s${SUITE_TITLE_SEP}${label}`, } } else if (absoluteTitle) { resolvedTitle = { absolute: title } } else { // Full title already includes suffix — absolute so root/ancestor templates do not re-apply. resolvedTitle = { absolute: formatSuiteDocumentTitle(title, app) } } const icons = app === "suite" ? ICONS.mail : ICONS[app] const meta: Metadata = { title: resolvedTitle, description: description ?? DESCRIPTIONS[app], icons, } if (app === "drive") { meta.manifest = "/drive/manifest.webmanifest" meta.appleWebApp = { capable: true, title: "UltiDrive", statusBarStyle: "default", } } return meta } export function driveDocumentTitle(segments?: string[]): string { const route = parseDriveSegments(segments) switch (route.view) { case "recent": return "Récents" case "starred": return "Favoris" case "trash": return "Corbeille" case "shared": return route.pathSegments.length > 0 ? displayFileName(route.pathSegments.at(-1)!) : "Partagés avec moi" case "search": return "Recherche" default: if (route.pathSegments.length > 0) { return displayFileName(route.pathSegments.at(-1)!) } return "Mon Drive" } }