import { notFound } from 'next/navigation' import { getPublishedNote } from '@/app/actions/notes-publishing' import { Flag, Sparkles } from 'lucide-react' import { format } from 'date-fns' import { fr } from 'date-fns/locale' import { computePublishedSourceHash } from '@/lib/publish/template-render' import { processNoteHtmlForPublish } from '@/lib/publish/process-note-html' import { REWRITE_SHARED_CSS, KATEX_PUBLISH_CSS } from '@/lib/publish/shared-css' export async function generateMetadata({ params }: { params: Promise<{ slug: string }> }) { const { slug } = await params const note = await getPublishedNote(slug) if (!note) return { title: 'Note introuvable — Memento' } return { title: `${note.title || 'Note publiée'} — Memento`, description: note.content?.replace(/<[^>]+>/g, '').slice(0, 160), } } export const revalidate = 60 function estimateReadingTime(html: string): number { const words = html.replace(/<[^>]+>/g, ' ').trim().split(/\s+/).length return Math.max(1, Math.ceil(words / 200)) } /* ─── MAGAZINE ──────────────────────────────────────────────────────────── */ function MagazinePage({ note, bodyHtml, readingTime, slug, isStale }: PageProps) { return ( <>
{/* Header pleine largeur */}
ARTICLE · {note.publishedAt ? format(new Date(note.publishedAt), 'd MMMM yyyy', { locale: fr }) : ''} · {readingTime} min

{note.title || 'Sans titre'}

{note.user?.name && (
{note.user.image && } par {note.user.name}
)}
Memento — Votre mémoire augmentée par l’IA {isStale &&

Le contenu source a évolué depuis la dernière publication.

}
) } /* ─── BRIEF ─────────────────────────────────────────────────────────────── */ function BriefPage({ note, bodyHtml, readingTime, slug, isStale }: PageProps) { return ( <>
Fiche expert · {readingTime} min de lecture {note.publishedAt && <>·{format(new Date(note.publishedAt), 'd MMM yyyy', { locale: fr })}}

{note.title || 'Sans titre'}

{note.user?.name && (
{note.user.image && } {note.user.name}
)}
Memento — Fiche générée par IA {isStale &&

Le contenu source a évolué depuis la publication.

}
) } /* ─── ESSAY ──────────────────────────────────────────────────────────────── */ function EssayPage({ note, bodyHtml, readingTime, slug, isStale }: PageProps) { return ( <>
{note.publishedAt && ( )}

{note.title || 'Sans titre'}

{note.user?.name && (
{note.user.image && }
{note.user.name} {readingTime} min de lecture
)}
Publié sur Memento {isStale &&

Le contenu source a évolué depuis la publication.

}
) } /* ─── SIMPLE (pas d'IA) ─────────────────────────────────────────────────── */ function SimplePage({ note, bodyHtml, readingTime, slug }: PageProps) { return ( <>
Memento Signaler
{note.publishedAt ? format(new Date(note.publishedAt), 'd MMM yyyy', { locale: fr }) : ''} · {readingTime} min de lecture

{note.title || 'Sans titre'}

{note.user?.name && (
{note.user.image && } par {note.user.name}
)}
Memento {' — Votre mémoire augmentée par l\'IA'}
) } /* ─── Types ─────────────────────────────────────────────────────────────── */ type NoteData = NonNullable>> interface PageProps { note: NoteData bodyHtml: string readingTime: number slug: string isStale: boolean } /* ─── Route ──────────────────────────────────────────────────────────────── */ export default async function PublishedNotePage({ params }: { params: Promise<{ slug: string }> }) { const { slug } = await params const note = await getPublishedNote(slug) if (!note) notFound() const usesAiLayout = Boolean(note.publishedContent) const rawHtml = usesAiLayout ? note.publishedContent! : (note.content || '') // Toujours passer par processNoteHtmlForPublish : KaTeX + sanitisation compatible équations const bodyHtml = processNoteHtmlForPublish(rawHtml) const readingSource = usesAiLayout ? note.publishedContent! : (note.content || '') const readingTime = estimateReadingTime(readingSource) const isStale = Boolean( note.publishedSourceHash && computePublishedSourceHash(note.content || '') !== note.publishedSourceHash ) const props: PageProps = { note, bodyHtml, readingTime, slug, isStale } if (!usesAiLayout) return if (note.publishedTemplate === 'brief') return if (note.publishedTemplate === 'essay') return return }