diff --git a/components/versions/export-pdf-button.js b/components/versions/export-pdf-button.js
index f6b12f5..d2fc2e7 100644
--- a/components/versions/export-pdf-button.js
+++ b/components/versions/export-pdf-button.js
@@ -7,6 +7,45 @@ import CircularProgress from '@mui/material/CircularProgress'
import PictureAsPdfIcon from '@mui/icons-material/PictureAsPdf'
import {formatDate} from '@/lib/format.js'
+// Helper function to render markdown to HTML
+const renderMarkdownToHtml = async content => {
+ if (!content) {
+ return 'Aucun contenu disponible'
+ }
+
+ // Check if content contains markdown syntax
+ const hasMarkdown = content.includes('**')
+ || content.includes('*')
+ || content.includes('#')
+ || content.includes('[')
+ || content.includes('`')
+ || content.includes('> ')
+ || content.includes('- ')
+ || content.includes('1. ')
+
+ if (!hasMarkdown) {
+ // Simple text with line breaks
+ return content.replaceAll('\n', '
')
+ }
+
+ try {
+ // Dynamic import of markdown parser
+ const {marked} = await import('marked')
+ // Configure marked for better PDF rendering
+ marked.setOptions({
+ breaks: true, // Convert \n to
+ gfm: true, // GitHub flavored markdown
+ headerIds: false, // No header IDs needed for PDF
+ mangle: false // Don't mangle email addresses
+ })
+
+ return marked(content)
+ } catch (error) {
+ console.warn('Failed to parse markdown, falling back to plain text:', error)
+ return content.replaceAll('\n', '
')
+ }
+}
+
export default function ExportPdfButton({versionData, size = 'medium', variant = 'outlined'}) {
const [isExporting, setIsExporting] = useState(false)
@@ -32,12 +71,83 @@ export default function ExportPdfButton({versionData, size = 'medium', variant =
z-index: -1;
`
+ // Add CSS styles for markdown elements
+ const styleElement = document.createElement('style')
+ styleElement.textContent = `
+ .pdf-content h1, .pdf-content h2, .pdf-content h3, .pdf-content h4, .pdf-content h5, .pdf-content h6 {
+ margin: 20px 0 10px 0;
+ font-weight: bold;
+ color: #333;
+ }
+ .pdf-content h1 { font-size: 24px; color: #1976d2; }
+ .pdf-content h2 { font-size: 20px; }
+ .pdf-content h3 { font-size: 18px; }
+ .pdf-content h4 { font-size: 16px; }
+ .pdf-content p { margin: 10px 0; }
+ .pdf-content strong, .pdf-content b { font-weight: bold; }
+ .pdf-content em, .pdf-content i { font-style: italic; }
+ .pdf-content ul, .pdf-content ol {
+ margin: 10px 0;
+ padding-left: 25px;
+ }
+ .pdf-content li { margin: 5px 0; }
+ .pdf-content blockquote {
+ margin: 15px 0;
+ padding: 10px 20px;
+ border-left: 4px solid #1976d2;
+ background-color: #f5f5f5;
+ font-style: italic;
+ }
+ .pdf-content code {
+ background-color: #f5f5f5;
+ padding: 2px 4px;
+ border-radius: 3px;
+ font-family: 'Courier New', monospace;
+ font-size: 13px;
+ }
+ .pdf-content pre {
+ background-color: #f5f5f5;
+ padding: 15px;
+ border-radius: 5px;
+ overflow-x: auto;
+ margin: 15px 0;
+ }
+ .pdf-content pre code {
+ background: none;
+ padding: 0;
+ }
+ .pdf-content a { color: #1976d2; text-decoration: underline; }
+ .pdf-content hr {
+ border: none;
+ border-top: 1px solid #ccc;
+ margin: 20px 0;
+ }
+ .pdf-content table {
+ border-collapse: collapse;
+ margin: 15px 0;
+ width: 100%;
+ }
+ .pdf-content th, .pdf-content td {
+ border: 1px solid #ccc;
+ padding: 8px;
+ text-align: left;
+ }
+ .pdf-content th {
+ background-color: #f5f5f5;
+ font-weight: bold;
+ }
+ `
+ document.head.append(styleElement)
+
const authorName = versionData.user_created?.split('-')[0] || 'Système'
const createdAt = new Date(versionData.date_created)
const threeDaysAgo = new Date(Date.now() - (3 * 24 * 60 * 60 * 1000))
const voteStatus = createdAt < threeDaysAgo ? 'fermé' : 'ouvert'
const voteColor = voteStatus === 'ouvert' ? '#2e7d32' : '#d32f2f'
+ // Render markdown content to HTML
+ const renderedContent = await renderMarkdownToHtml(versionData.delta?.contenu)
+
tempDiv.innerHTML = `