diff --git a/components/files/files-dialog.js b/components/files/files-dialog.js
new file mode 100644
index 0000000..59d70aa
--- /dev/null
+++ b/components/files/files-dialog.js
@@ -0,0 +1,52 @@
+import {useState} from 'react'
+import PropTypes from 'prop-types'
+import Button from '@mui/material/Button'
+import Dialog from '@mui/material/Dialog'
+import DialogActions from '@mui/material/DialogActions'
+import DialogContent from '@mui/material/DialogContent'
+import useMediaQuery from '@mui/material/useMediaQuery'
+import {useTheme} from '@mui/material/styles'
+
+import DownloadForOfflineIcon from '@mui/icons-material/DownloadForOffline'
+import FilesList from './files-list'
+
+export default function FilesDialog({files}) {
+ const [open, setOpen] = useState(false)
+ const theme = useTheme()
+ const fullScreen = useMediaQuery(theme.breakpoints.down('md'))
+
+ const handleClickOpen = () => {
+ setOpen(true)
+ }
+
+ const handleClose = () => {
+ setOpen(false)
+ }
+
+ return (
+ <>
+ } sx={{marginBottom: 2}} variant='outlined' onClick={handleClickOpen}>
+ Télécharger
+
+
+ >
+ )
+}
+
+FilesDialog.propTypes = {
+ files: PropTypes.array.isRequired
+}
diff --git a/components/files/files-list.js b/components/files/files-list.js
new file mode 100644
index 0000000..3c0ba78
--- /dev/null
+++ b/components/files/files-list.js
@@ -0,0 +1,248 @@
+import PropTypes from 'prop-types'
+import List from '@mui/material/List'
+import ListSubheader from '@mui/material/ListSubheader'
+import Typography from '@mui/material/Typography'
+import Box from '@mui/material/Box'
+import {useTheme, useColorScheme, styled} from '@mui/material/styles'
+import Table from '@mui/material/Table'
+import TableHead from '@mui/material/TableHead'
+import TableBody from '@mui/material/TableBody'
+import TableCell, {tableCellClasses} from '@mui/material/TableCell'
+import TableRow from '@mui/material/TableRow'
+import TableContainer from '@mui/material/TableContainer'
+import Paper from '@mui/material/Paper'
+import FileSaver from 'file-saver'
+import DescriptionIcon from '@mui/icons-material/Description'
+import LibraryMusicIcon from '@mui/icons-material/LibraryMusic'
+import {Link} from '@mui/material'
+
+const apiUrl = process.env.NEXT_PUBLIC_API_URL_ROOT || 'http://localhost:1337'
+
+const StyledTableCell = styled(TableCell)(({theme}) => ({
+ [`&.${tableCellClasses.head}`]: {
+ backgroundColor: theme.palette.common.black,
+ color: theme.palette.common.white,
+ },
+ [`&.${tableCellClasses.body}`]: {
+ fontSize: 14,
+ },
+}))
+
+const StyledTableRow = styled(TableRow)(({theme}) => ({
+ '&:nth-of-type(odd)': {
+ backgroundColor: theme.palette.action.hover,
+ },
+ '&:last-child td, &:last-child th': {
+ border: 0,
+ },
+}))
+
+function formatSize(size) {
+ if (size < 1000) {
+ return Math.round(size) + ' Kb'
+ }
+
+ const mbSize = size / 1000
+ return Math.round(mbSize) + ' Mb'
+}
+
+export default function FilesList({files}) {
+ const theme = useTheme()
+ const {mode} = useColorScheme()
+
+ const musicFiles = files.filter(file => file.attributes.mime.startsWith('audio'))
+ const pdfFiles = files.filter(file => file.attributes.mime === 'application/pdf')
+
+ const sortedMusicFiles = musicFiles.sort((a, b) => {
+ const extensionOrder = {
+ '.flac': 0,
+ '.ogg': 1,
+ '.aac': 2,
+ '.mp3': 3
+ }
+ return extensionOrder[a.attributes.ext.toLowerCase()] - extensionOrder[b.attributes.ext.toLowerCase()]
+ })
+
+ const handleClick = (e, url, fileName) => {
+ e.stopPropagation()
+ FileSaver.saveAs(url, fileName)
+ }
+
+ const getQuality = (extension, caption) => {
+ switch (extension) {
+ case '.ogg':
+ case '.aac':
+ case '.mp3':
+ return (
+ Faible
+ )
+ case '.flac':
+ if (caption === 'MAX') {
+ return (
+ {caption}
+ )
+ }
+
+ if (caption === 'HAUTE') {
+ return (
+ {caption}
+ )
+ }
+
+ return (
+ Haute
+ )
+
+ default:
+ return
+ }
+ }
+
+ return (
+ <>
+ {musicFiles.length > 0 && (
+
+
+
+
+ Musiques
+
+
+
+
+ MAX : Jusqu’à 24-bit, 96 kHz, ≃ 3000 kbps (flac)
HAUTE : 16 bits, ≃ 900 kbps (flac)
FAIBLE : 320 kbps (ogg / aac / mp3)
+
+
+ QUALITÉ
+
+
+
+
+ {sortedMusicFiles.map(file => (
+
+
+ {getQuality(file.attributes.ext.toLowerCase(), file?.attributes?.caption?.toUpperCase())}
+
+
+ handleClick(e, `${apiUrl}${file.attributes.url}`, file.attributes.name)}
+ >
+ {file.attributes.name}
+
+ ({formatSize(file.attributes.size)})
+
+
+ ))}
+
+
+
+
+ )}
+
+ {pdfFiles.length > 0 && (
+
+
+
+
+ Paroles
+
+
+
+
+
+
+ LANGUE
+
+
+
+
+ {pdfFiles.map(file => (
+
+
+
+ {file.attributes.caption}
+
+
+
+ handleClick(e, `${apiUrl}${file.attributes.url}`, file.attributes.name)}
+ >
+ {file.attributes.name}
+
+ ({formatSize(file.attributes.size)})
+
+
+ ))}
+
+
+
+
+ )}
+ >
+ )
+}
+
+FilesList.propTypes = {
+ files: PropTypes.array.isRequired
+}
diff --git a/components/teks/teks.js b/components/teks/teks.js
index 515fcf3..6dc349e 100644
--- a/components/teks/teks.js
+++ b/components/teks/teks.js
@@ -16,6 +16,7 @@ import ExplicitIcon from '@mui/icons-material/Explicit'
import {formatJsonString, getAlias} from '../../lib/utils/format'
import LicenseModal from '../cc/license-modal'
+import FilesDialog from '../files/files-dialog'
import EntegreMizik from './entegre-mizik'
import OkiMizik from './oki-mizik'
import DiferansDialog from './diferans-dialog'
@@ -183,6 +184,9 @@ export default function Teks({parole}) {
)}
+ {parole?.files?.data && (
+
+ )}
{(parole.okiMizikID || parole.streamAudio.length > 0 || parole.gadeEmbed) && (