diff --git a/components/versions/version-timeline.js b/components/versions/version-timeline.js
new file mode 100644
index 0000000..7d5bac7
--- /dev/null
+++ b/components/versions/version-timeline.js
@@ -0,0 +1,317 @@
+import {useRef, useState} from 'react'
+import PropTypes from 'prop-types'
+import Box from '@mui/material/Box'
+import Typography from '@mui/material/Typography'
+import Card from '@mui/material/Card'
+import CardContent from '@mui/material/CardContent'
+import CardActions from '@mui/material/CardActions'
+import Button from '@mui/material/Button'
+import Chip from '@mui/material/Chip'
+import Avatar from '@mui/material/Avatar'
+import Divider from '@mui/material/Divider'
+import Timeline from '@mui/lab/Timeline'
+import TimelineItem from '@mui/lab/TimelineItem'
+import TimelineSeparator from '@mui/lab/TimelineSeparator'
+import TimelineConnector from '@mui/lab/TimelineConnector'
+import TimelineContent from '@mui/lab/TimelineContent'
+import TimelineDot from '@mui/lab/TimelineDot'
+import TimelineOppositeContent from '@mui/lab/TimelineOppositeContent'
+import AccessTimeIcon from '@mui/icons-material/AccessTime'
+import CheckCircleIcon from '@mui/icons-material/CheckCircle'
+import ErrorIcon from '@mui/icons-material/Error'
+import EditIcon from '@mui/icons-material/Edit'
+import SessionExpired from '../session/session-expired.js'
+import VersionDialog from './version-dialog.js'
+import {formatDate} from '@/lib/format.js'
+import {compareVersion} from '@/lib/directus.js'
+
+function getVersionStatus(version, index, totalVersions) {
+ // Logic to determine version status based on position and data
+ if (index === 0) {
+ return 'current' // Most recent
+ }
+
+ if (index === totalVersions - 1) {
+ return 'initial' // First version
+ }
+
+ return 'archived' // Intermediate versions
+}
+
+function getStatusConfig(status) {
+ switch (status) {
+ case 'current': {
+ return {
+ color: '#1976D2',
+ bgColor: '#E3F2FD',
+ icon: ,
+ label: 'En cours',
+ chipColor: 'primary'
+ }
+ }
+
+ case 'published': {
+ return {
+ color: '#2E7D32',
+ bgColor: '#E8F5E9',
+ icon: ,
+ label: 'Publié',
+ chipColor: 'success'
+ }
+ }
+
+ case 'archived': {
+ return {
+ color: '#757575',
+ bgColor: '#F5F5F5',
+ icon: ,
+ label: 'Archivé',
+ chipColor: 'default'
+ }
+ }
+
+ case 'outdated': {
+ return {
+ color: '#D32F2F',
+ bgColor: '#F9E8E8',
+ icon: ,
+ label: 'Obsolète',
+ chipColor: 'error'
+ }
+ }
+
+ default: {
+ return {
+ color: '#757575',
+ bgColor: '#F5F5F5',
+ icon: ,
+ label: 'Archivé',
+ chipColor: 'default'
+ }
+ }
+ }
+}
+
+function VersionCard({
+ version,
+ index,
+ totalVersions,
+ accessToken,
+ userId,
+ countdownRef,
+ setError,
+ setIsErrorAlertOpen,
+ setIsOpenComparison,
+ setVersionCompare
+}) {
+ const status = getVersionStatus(version, index, totalVersions)
+ const statusConfig = getStatusConfig(status)
+ const userDisplayName = version.user_created?.split('-')[0] || 'Système'
+
+ const handleCompareClick = async () => {
+ const comparisonData = await compareVersion({
+ accessToken,
+ userId,
+ versionId: version.id,
+ countdownRef,
+ setError,
+ setIsErrorAlertOpen
+ })
+
+ if (comparisonData) {
+ setVersionCompare({...comparisonData, versionId: version.id})
+ setIsOpenComparison(true)
+ }
+ }
+
+ // Estimate content preview (first 100 chars)
+ const contentPreview = version?.delta?.contenu
+ ? version.delta.contenu.slice(0, 100) + (version.delta.contenu.length > 100 ? '...' : '')
+ : 'Contenu non disponible'
+
+ return (
+
+
+
+
+
+ {statusConfig.icon}
+
+
+
+ {version.name}
+
+
+ par @{userDisplayName}
+
+
+
+
+
+
+
+ {contentPreview}
+
+
+
+
+ {formatDate(version.date_created, 'PPpp')}
+
+
+ {/* Placeholder for vote count - would need API enhancement */}
+
+
+
+
+
+
+
+
+
+
+
+
+ )
+}
+
+export default function VersionTimeline({
+ collection,
+ data,
+ accessToken,
+ userId,
+ setError,
+ setIsErrorAlertOpen
+}) {
+ const countdownRef = useRef()
+ const [isOpenComparison, setIsOpenComparison] = useState(false)
+ const [versionCompare, setVersionCompare] = useState(null)
+
+ const versionData = data.find(({id}) => id === versionCompare?.versionId)
+
+ return (
+ <>
+
+
+ Historique des versions - {collection}
+
+
+
+ {data.map((version, index) => (
+
+
+
+ {formatDate(version.date_created, 'dd/MM/yyyy')}
+
+
+
+ {formatDate(version.date_created, 'HH:mm')}
+
+
+
+
+
+ {index === 0 ? : }
+
+ {index < data.length - 1 && }
+
+
+
+
+
+
+ ))}
+
+
+
+ {isOpenComparison && (
+
+ )}
+
+
+ >
+ )
+}
+
+VersionTimeline.propTypes = {
+ collection: PropTypes.oneOf(['titres', 'articles']).isRequired,
+ data: PropTypes.array.isRequired,
+ accessToken: PropTypes.string.isRequired,
+ userId: PropTypes.string.isRequired,
+ setError: PropTypes.func.isRequired,
+ setIsErrorAlertOpen: PropTypes.func.isRequired
+}
+
+VersionCard.propTypes = {
+ version: PropTypes.object.isRequired,
+ index: PropTypes.number.isRequired,
+ totalVersions: PropTypes.number.isRequired,
+ accessToken: PropTypes.string.isRequired,
+ userId: PropTypes.string.isRequired,
+ countdownRef: PropTypes.object.isRequired,
+ setError: PropTypes.func.isRequired,
+ setIsErrorAlertOpen: PropTypes.func.isRequired,
+ setIsOpenComparison: PropTypes.func.isRequired,
+ setVersionCompare: PropTypes.func.isRequired
+}