diff --git a/memento-note/app/(public)/p/[slug]/page.tsx b/memento-note/app/(public)/p/[slug]/page.tsx index 85fceb2..24e1557 100644 --- a/memento-note/app/(public)/p/[slug]/page.tsx +++ b/memento-note/app/(public)/p/[slug]/page.tsx @@ -1,6 +1,6 @@ import { notFound } from 'next/navigation' import { getPublishedNote } from '@/app/actions/notes-publishing' -import { FileText, Calendar, Clock, Flag } from 'lucide-react' +import { Calendar, Clock, Flag } from 'lucide-react' import { format } from 'date-fns' import katex from 'katex' @@ -16,97 +16,81 @@ export async function generateMetadata({ params }: { params: Promise<{ slug: str export const revalidate = 60 -function renderMathInHtml(html: string): string { - let result = html - result = result.replace(/]*data-type="math-equation"[^>]*data-latex="([^"]*)"[^>]*><\/div>/g, (_, latex) => { - try { - return `
${katex.renderToString(decodeHtml(latex), { displayMode: true, throwOnError: false })}
` - } catch { return `
${latex}
` } - }) - result = result.replace(/]*data-type="inline-math"[^>]*data-latex="([^"]*)"[^>]*>.*?<\/span>/g, (_, latex) => { - try { - return katex.renderToString(decodeHtml(latex), { displayMode: false, throwOnError: false }) - } catch { return latex } - }) - return result -} - function decodeHtml(text: string): string { - return text.replace(/"/g, '"').replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/'/g, "'") + const map: Record = { '"': '"', '&': '&', '<': '<', '>': '>', ''': "'" } + return text.replace(/&[a-z#0-9]+;/gi, m => map[m] || m) } function processContent(html: string): string { - let result = renderMathInHtml(html) - // Render callouts + let result = html + + // KaTeX block math + result = result.replace(/]*data-type="math-equation"[^>]*data-latex="([^"]*)"[^>]*><\/div>/g, (_, latex) => { + try { return `
${katex.renderToString(decodeHtml(latex), { displayMode: true, throwOnError: false })}
` } + catch { return `
${latex}
` } + }) + // KaTeX inline math + result = result.replace(/]*data-type="inline-math"[^>]*data-latex="([^"]*)"[^>]*>.*?<\/span>/g, (_, latex) => { + try { return katex.renderToString(decodeHtml(latex), { displayMode: false, throwOnError: false }) } + catch { return latex } + }) + // Callouts result = result.replace(/]*data-type="callout-block"[^>]*data-callout-type="([^"]*)"[^>]*>/g, (_, type) => { - const colors: Record = { + const c: Record = { info: '#eff6ff|#3b82f6', warning: '#fffbeb|#f59e0b', tip: '#faf5ff|#8b5cf6', success: '#f0fdf4|#22c55e', danger: '#fef2f2|#ef4444', } - const [bg, border] = (colors[type] || colors.info).split('|') + const [bg, border] = (c[type] || c.info).split('|') return `
` }) - // Close callouts - result = result.replace(/<\/div>(\s*<\/div>)/g, '$1') - // Outline blocks — remove (they don't work without the editor) + // Remove outline blocks (need editor JS) result = result.replace(/]*data-type="outline-block"[^>]*><\/div>/g, '') - // Link preview searchable text + // Remove link preview searchable text result = result.replace(/]*class="link-preview-searchable"[^>]*>[\s\S]*?<\/div>/g, '') - // Remove buttons (delete/unwrap) + // Remove editor buttons result = result.replace(/]*>[\s\S]*?<\/button>/g, '') + // Remove contentEditable attributes + result = result.replace(/contenteditable="[^"]*"/gi, '') + return result } function estimateReadingTime(html: string): number { - const text = html.replace(/<[^>]+>/g, ' ').trim() - const words = text.split(/\s+/).length + const words = html.replace(/<[^>]+>/g, ' ').trim().split(/\s+/).length return Math.max(1, Math.ceil(words / 200)) } export default async function PublishedNotePage({ params }: { params: Promise<{ slug: string }> }) { const { slug } = await params const note = await getPublishedNote(slug) - if (!note) notFound() const processedContent = processContent(note.content || '') const readingTime = estimateReadingTime(note.content || '') return ( - - - - - - - + <> + {/* KaTeX + fonts CSS */} + + + + +
{/* Top bar */} {/* Article */}
- {/* Meta */}
{note.publishedAt ? format(new Date(note.publishedAt), 'd MMM yyyy') : ''} @@ -115,58 +99,30 @@ export default async function PublishedNotePage({ params }: { params: Promise<{ {readingTime} min de lecture
- {/* Title */} -

+

{note.title || 'Sans titre'}

- {/* Author */} {note.user?.name && (
- {note.user.image && ( - - )} + {note.user.image && } par {note.user.name}
)} - {/* Divider */}
- {/* Content */} -
+
- {/* Custom styles injected */}
{/* Footer */} -
+ ) }