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" | "agenda" | "meet" | "admin" | "compte" | "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 UltiSuite", contacts: "Carnet d'adresses — UltiSuite", agenda: "Agenda partagé, invitations et disponibilités — UltiSuite", meet: "Visioconférence chiffrée intégrée à la suite — UltiMeet", admin: "Console d'administration — UltiSuite", compte: "Réglages du compte — UltiSuite", suite: "Ultimail, UltiDrive et contacts — interface suite unifiée", } const APP_LABELS: Record = { mail: "Ultimail", drive: "UltiDrive", contacts: "UltiSuite", agenda: "Agenda", meet: "UltiMeet", admin: "Administration", compte: "Compte Ulti", suite: "UltiSuite", } const ICONS: Record = { suite: { icon: [ { url: "/ultisuite-mark.svg", type: "image/svg+xml" }, { url: "/ultisuite-32.png", sizes: "32x32", type: "image/png" }, ], apple: [{ url: "/ultisuite-180.png", sizes: "180x180", type: "image/png" }], shortcut: "/ultisuite-mark.svg", }, admin: { icon: [{ url: "/admin-mark.svg", type: "image/svg+xml" }], apple: [{ url: "/admin-mark.svg", type: "image/svg+xml" }], shortcut: "/admin-mark.svg", }, mail: { icon: [ { url: "/ultimail-mark.svg", type: "image/svg+xml" }, { url: "/icon.png", sizes: "32x32", type: "image/png" }, ], apple: [{ url: "/apple-icon.png", sizes: "180x180", type: "image/png" }], shortcut: "/ultimail-mark.svg", }, 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", }, compte: { icon: [{ url: "/compte-mark.svg", type: "image/svg+xml" }], apple: [{ url: "/compte-mark.svg", type: "image/svg+xml" }], shortcut: "/compte-mark.svg", }, agenda: { icon: [ { url: "/agenda-mark.svg", type: "image/svg+xml" }, { url: "/icon.png", sizes: "32x32", type: "image/png" }, ], apple: [{ url: "/agenda-mark.svg", type: "image/svg+xml" }], shortcut: "/agenda-mark.svg", }, meet: { icon: [ { url: "/ultimeet-mark.svg", type: "image/svg+xml" }, { url: "/icon.png", sizes: "32x32", type: "image/png" }, ], apple: [{ url: "/ultimeet-mark.svg", type: "image/svg+xml" }], shortcut: "/ultimeet-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: APP_LABELS.suite, description: DESCRIPTIONS.suite, icons: ICONS.suite, } } 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 = 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" case "org": return route.pathSegments.length > 0 ? displayFileName(route.pathSegments.at(-1)!) : "Dossier d'organisation" case "mount": return route.pathSegments.length > 0 ? displayFileName(route.pathSegments.at(-1)!) : "Volume monté" default: if (route.pathSegments.length > 0) { return displayFileName(route.pathSegments.at(-1)!) } return "Mon Drive" } }