diff --git a/components/versions/list-versions.js b/components/versions/list-versions.js index 145b6de..d7c53f1 100644 --- a/components/versions/list-versions.js +++ b/components/versions/list-versions.js @@ -22,6 +22,7 @@ import VersionFilters from './version-filters.js' import CopyButton from './copy-button.js' import ShareButton from './share-button.js' import ExportPdfButton from './export-pdf-button.js' +import PrintButton from './print-button.js' import {formatDate} from '@/lib/format.js' import {compareVersion} from '@/lib/directus.js' import {filterVersions, getFilterStats} from '@/lib/version-utils.js' @@ -128,6 +129,11 @@ function rowContent({ size='small' variant='text' /> + { + 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 print rendering + marked.setOptions({ + breaks: true, // Convert \n to + gfm: true, // GitHub flavored markdown + headerIds: false, // No header IDs needed for print + 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 PrintButton({versionData, size = 'medium', variant = 'outlined'}) { + const [isPrinting, setIsPrinting] = useState(false) + const [snackbar, setSnackbar] = useState({open: false, message: '', severity: 'success'}) + + const handlePrint = async () => { + setIsPrinting(true) + + try { + // Calculate vote status + 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) + + // Create print window + const printWindow = window.open('', '_blank', 'width=800,height=600') + + if (!printWindow) { + throw new Error('Impossible d\'ouvrir la fenêtre d\'impression. Vérifiez que les popups ne sont pas bloqués.') + } + + // Build print-optimized HTML + const printHtml = ` + + + + + + ${versionData.name} - Konstitisyon.la + + + + + 🖨️ Imprimer + ✕ Fermer + + + + ${versionData.name} + + Auteur : @${authorName} + + + Date de création : ${formatDate(versionData.date_created, 'PPpp')} + + + Statut du vote : + ${voteStatus} + + + + + Contenu + + ${renderedContent} + + + + + + + ` + + printWindow.document.write(printHtml) + printWindow.document.close() + + // Auto-focus the print window + printWindow.focus() + + setSnackbar({ + open: true, + message: 'Fenêtre d\'impression ouverte', + severity: 'success' + }) + } catch (error) { + console.error('Erreur lors de l\'impression:', error) + setSnackbar({ + open: true, + message: error.message || 'Une erreur est survenue lors de l\'impression', + severity: 'error' + }) + } finally { + setIsPrinting(false) + } + } + + const handleCloseSnackbar = () => { + setSnackbar(prev => ({...prev, open: false})) + } + + return ( + <> + : } + disabled={isPrinting} + sx={{ + minWidth: size === 'small' ? 'auto' : undefined, + '&:disabled': { + opacity: 0.6 + } + }} + onClick={handlePrint} + > + {isPrinting ? 'Préparation...' : (size === 'small' ? 'Print' : 'Imprimer')} + + + + + {snackbar.message} + + + > + ) +} + +PrintButton.propTypes = { + versionData: PropTypes.object.isRequired, + size: PropTypes.oneOf(['small', 'medium', 'large']), + variant: PropTypes.oneOf(['text', 'outlined', 'contained']) +} diff --git a/components/versions/version-page.js b/components/versions/version-page.js index dc05981..9872951 100644 --- a/components/versions/version-page.js +++ b/components/versions/version-page.js @@ -22,6 +22,7 @@ import Footer from '../footer.js' import VoteButtons from './vote-buttons.js' import CopyButton from './copy-button.js' import ExportPdfButton from './export-pdf-button.js' +import PrintButton from './print-button.js' import VersionComparison from './version-comparison.js' import {getVersion, compareVersion} from '@/lib/directus.js' import {formatDate} from '@/lib/format.js' @@ -224,6 +225,7 @@ export default function VersionPage({session, versionId, viewMode}) { + diff --git a/components/versions/version-timeline.js b/components/versions/version-timeline.js index 7c272a9..d290215 100644 --- a/components/versions/version-timeline.js +++ b/components/versions/version-timeline.js @@ -28,6 +28,7 @@ import VoteButtons from './vote-buttons.js' import CopyButton from './copy-button.js' import ShareButton from './share-button.js' import ExportPdfButton from './export-pdf-button.js' +import PrintButton from './print-button.js' import {formatDate} from '@/lib/format.js' import {compareVersion} from '@/lib/directus.js' @@ -219,6 +220,11 @@ function VersionCard({ size='small' variant='text' /> +