Compare commits

..

3 Commits

Author SHA1 Message Date
cedric 35e1a3a010 fix: typo StreamButton
Déploiement FRONT PROD / check (push) Successful in 2m8s
Déploiement FRONT PROD / deploy (push) Successful in 21s
2026-06-22 18:52:14 +04:00
cedric 9949efd0c1 feat: otimize images on awtis-detay 2026-06-22 18:51:57 +04:00
cedric 972e41d528 feat: optimize paroles images 2026-06-22 18:48:26 +04:00
4 changed files with 61 additions and 60 deletions
+38 -38
View File
@@ -1,6 +1,7 @@
'use client' 'use client'
import {useState} from 'react' import {useState} from 'react'
import Image from 'next/image'
import Link from 'next/link' import Link from 'next/link'
import PropTypes from 'prop-types' import PropTypes from 'prop-types'
import Accordion from '@mui/material/Accordion' import Accordion from '@mui/material/Accordion'
@@ -9,14 +10,12 @@ import AccordionSummary from '@mui/material/AccordionSummary'
import Box from '@mui/material/Box' import Box from '@mui/material/Box'
import Button from '@mui/material/Button' import Button from '@mui/material/Button'
import CardActionArea from '@mui/material/CardActionArea' import CardActionArea from '@mui/material/CardActionArea'
import CardMedia from '@mui/material/CardMedia'
import Chip from '@mui/material/Chip' import Chip from '@mui/material/Chip'
import Container from '@mui/material/Container' import Container from '@mui/material/Container'
import Grid from '@mui/material/Grid' import Grid from '@mui/material/Grid'
import Paper from '@mui/material/Paper' import Paper from '@mui/material/Paper'
import Card from '@mui/material/Card' import Card from '@mui/material/Card'
import CardContent from '@mui/material/CardContent' import CardContent from '@mui/material/CardContent'
import Avatar from '@mui/material/Avatar'
import Typography from '@mui/material/Typography' import Typography from '@mui/material/Typography'
import {green} from '@mui/material/colors' import {green} from '@mui/material/colors'
import ExpandMoreIcon from '@mui/icons-material/ExpandMore' import ExpandMoreIcon from '@mui/icons-material/ExpandMore'
@@ -24,40 +23,15 @@ import KeyboardBackspaceIcon from '@mui/icons-material/KeyboardBackspace'
import VerifiedIcon from '@mui/icons-material/Verified' import VerifiedIcon from '@mui/icons-material/Verified'
import {formatKuveti} from '../../lib/kuveti' import {formatKuveti} from '../../lib/kuveti'
import {PLATFORM_CONFIG, StreamButtonComponent} from '../streaming-buttons' import {StreamButton} from '../streaming-buttons'
import AwtisBiyografi from './awtis-biyografi' import AwtisBiyografi from './awtis-biyografi'
import MizikLyen from './mizik-lyen' import MizikLyen from './mizik-lyen'
const IMAGE_URL = process.env.NEXT_PUBLIC_API_URL_ROOT || 'http://localhost:1337' const IMAGE_URL = process.env.NEXT_PUBLIC_API_URL_ROOT || 'http://localhost:1337'
const noImageUrl = 'https://place-hold.it/140x140?text=Indisponible' const BLUR_DATA_URL = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNsYAAAAAYAAjCB0C8AAAAASUVORK5CYII='
const sortTeks = paroles => paroles.sort((a, b) => a.titre.localeCompare(b.titre, 'fr', {sensitivity: 'base'})) const sortTeks = paroles => paroles.sort((a, b) => a.titre.localeCompare(b.titre, 'fr', {sensitivity: 'base'}))
function StreamButton({lyen}) {
const config = PLATFORM_CONFIG[lyen.plateforme] || {label: lyen.plateforme, bg: '#555', color: '#fff', Icon: null}
const PlatformIcon = config.Icon
return (
<Button
href={lyen.url}
target='_blank'
rel='noopener noreferrer'
size='small'
startIcon={PlatformIcon ? <PlatformIcon size={16} color={config.color} /> : null}
endIcon={<OpenInNewIcon sx={{fontSize: 11}} />}
sx={{
bgcolor: config.bg,
color: config.color,
fontWeight: 700,
fontSize: '0.72rem',
textTransform: 'none',
'&:hover': {bgcolor: config.bg, opacity: 0.85},
}}
>
{config.label}
</Button>
)
}
export default function AwtisDetay({anAwtis}) { export default function AwtisDetay({anAwtis}) {
const [esByografiOuve, meteEsByografiOuve] = useState(false) const [esByografiOuve, meteEsByografiOuve] = useState(false)
const {alias, biographie, paroles, photo, isOKIAwtis, titrePhare} = anAwtis const {alias, biographie, paroles, photo, isOKIAwtis, titrePhare} = anAwtis
@@ -70,6 +44,10 @@ export default function AwtisDetay({anAwtis}) {
? `${IMAGE_URL}${titrePhare.couverture.formats?.small?.url || titrePhare.couverture.formats?.thumbnail?.url || titrePhare.couverture.url}` ? `${IMAGE_URL}${titrePhare.couverture.formats?.small?.url || titrePhare.couverture.formats?.thumbnail?.url || titrePhare.couverture.url}`
: null : null
const photoUrl = photo?.url
? `${IMAGE_URL}${photo.formats?.small?.url || photo.formats?.thumbnail?.url || photo.url}`
: null
return ( return (
<Container> <Container>
<Box sx={{mt: 8, mb: 2}}> <Box sx={{mt: 8, mb: 2}}>
@@ -79,11 +57,28 @@ export default function AwtisDetay({anAwtis}) {
</Box> </Box>
<Box sx={{display: 'flex', justifyContent: 'center', mb: 2}}> <Box sx={{display: 'flex', justifyContent: 'center', mb: 2}}>
<Avatar <Box sx={{
src={photo?.url ? `${IMAGE_URL}${photo?.formats?.small?.url || photo?.formats?.thumbnail?.url || photo?.url}` : noImageUrl} width: 200, height: 200,
borderRadius: '50%',
border: `2px solid ${green[500]}`,
overflow: 'hidden',
position: 'relative',
flexShrink: 0,
}}>
{photoUrl ? (
<Image
src={photoUrl}
alt={`Photo ${alias}`} alt={`Photo ${alias}`}
sx={{width: 200, height: 200, border: `2px solid ${green[500]}`}} width={200}
height={200}
placeholder='blur'
blurDataURL={BLUR_DATA_URL}
style={{objectFit: 'cover', width: '100%', height: '100%'}}
/> />
) : (
<Box sx={{width: '100%', height: '100%', bgcolor: 'grey.300'}} />
)}
</Box>
</Box> </Box>
{isOKIAwtis && ( {isOKIAwtis && (
@@ -95,7 +90,7 @@ export default function AwtisDetay({anAwtis}) {
sx={{bgcolor: '#FFD700', color: '#000', fontWeight: 700, '& .MuiChip-icon': {color: '#000'}}} sx={{bgcolor: '#FFD700', color: '#000', fontWeight: 700, '& .MuiChip-icon': {color: '#000'}}}
/> />
<Typography variant='caption' sx={{color: 'text.secondary', textAlign: 'center'}}> <Typography variant='caption' sx={{color: 'text.secondary', textAlign: 'center'}}>
Musiques publiées en exclusivité sur PAWÒL-NU, avant toute sortie sur les plateformes de streaming. Paroles publiées en exclusivité sur PAWÒL-NU, avant toute sortie sur les plateformes de streaming.
</Typography> </Typography>
</Box> </Box>
)} )}
@@ -123,12 +118,17 @@ export default function AwtisDetay({anAwtis}) {
<Grid container> <Grid container>
{coverUrl && ( {coverUrl && (
<Grid size={{xs: 12, sm: 4}}> <Grid size={{xs: 12, sm: 4}}>
<CardMedia <Box sx={{position: 'relative', minHeight: 140, height: '100%'}}>
component='img' <Image
image={coverUrl} src={coverUrl}
alt={titrePhare.titre} alt={titrePhare.titre}
sx={{height: '100%', minHeight: 140, objectFit: 'cover'}} fill
placeholder='blur'
blurDataURL={BLUR_DATA_URL}
sizes='200px'
style={{objectFit: 'cover'}}
/> />
</Box>
</Grid> </Grid>
)} )}
<Grid size={{xs: 12, sm: coverUrl ? 8 : 12}}> <Grid size={{xs: 12, sm: coverUrl ? 8 : 12}}>
@@ -141,7 +141,7 @@ export default function AwtisDetay({anAwtis}) {
</Typography> </Typography>
<Box sx={{display: 'flex', flexWrap: 'wrap', gap: 1}}> <Box sx={{display: 'flex', flexWrap: 'wrap', gap: 1}}>
{titrePhare.streamAudio.map((lyen, i) => ( {titrePhare.streamAudio.map((lyen, i) => (
<StreamButtonComponent key={i} lyen={lyen} /> <StreamButton key={i} lyen={lyen} />
))} ))}
</Box> </Box>
</CardContent> </CardContent>
+1 -1
View File
@@ -15,7 +15,7 @@ export const PLATFORM_CONFIG = {
Soundcloud: {label: 'SoundCloud', bg: '#FF5500', color: '#fff', Icon: Soundcloud}, Soundcloud: {label: 'SoundCloud', bg: '#FF5500', color: '#fff', Icon: Soundcloud},
} }
export function StreamButtonComponent({lyen}) { export function StreamButton({lyen}) {
const config = PLATFORM_CONFIG[lyen.plateforme] ?? {label: lyen.plateforme, bg: '#555', color: '#fff', Icon: null} const config = PLATFORM_CONFIG[lyen.plateforme] ?? {label: lyen.plateforme, bg: '#555', color: '#fff', Icon: null}
const PlatformIcon = config.Icon const PlatformIcon = config.Icon
return ( return (
+14 -13
View File
@@ -9,7 +9,6 @@ import Card from '@mui/material/Card'
import CardActionArea from '@mui/material/CardActionArea' import CardActionArea from '@mui/material/CardActionArea'
import CardContent from '@mui/material/CardContent' import CardContent from '@mui/material/CardContent'
import CardMedia from '@mui/material/CardMedia'
import Typography from '@mui/material/Typography' import Typography from '@mui/material/Typography'
import Box from '@mui/material/Box' import Box from '@mui/material/Box'
import Grid from '@mui/material/Grid' import Grid from '@mui/material/Grid'
@@ -23,20 +22,15 @@ const IMAGE_URL = process.env.NEXT_PUBLIC_API_URL_ROOT || 'http://localhost:1337
const classes = { const classes = {
root: `${PREFIX}-root`, root: `${PREFIX}-root`,
media: `${PREFIX}-media`
} }
const StyledGrid = styled(Grid)({ const StyledGrid = styled(Grid)({
[`& .${classes.root}`]: { [`& .${classes.root}`]: {
maxWidth: 345 maxWidth: 345
}, },
[`& .${classes.media}`]: {
height: 240,
objectFit: 'contain'
}
}) })
const noImageUrl = 'https://place-hold.it/140x140?text=Indisponible' const BLUR_DATA_URL = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNsYAAAAAYAAjCB0C8AAAAASUVORK5CYII='
export default function TeksKat({parole}) { export default function TeksKat({parole}) {
const router = useRouter() const router = useRouter()
@@ -53,14 +47,21 @@ export default function TeksKat({parole}) {
<StyledGrid size={{xs: 12, sm: 6, md: 4}}> <StyledGrid size={{xs: 12, sm: 6, md: 4}}>
<Card className={classes.root}> <Card className={classes.root}>
<CardActionArea onClick={() => handleClick(slug)}> <CardActionArea onClick={() => handleClick(slug)}>
<CardMedia <Box sx={{position: 'relative', height: 240}}>
className={classes.media} {couverture?.url ? (
component='img' <Image
src={`${IMAGE_URL}${couverture.formats?.thumbnail?.url || couverture.url}`}
alt={titre} alt={titre}
image={couverture?.url ? `${IMAGE_URL}${couverture.formats?.thumbnail?.url || couverture.url}` : noImageUrl} fill
title={titre} placeholder='blur'
loading='lazy' blurDataURL={BLUR_DATA_URL}
sizes='(max-width: 600px) 100vw, (max-width: 900px) 50vw, 33vw'
style={{objectFit: 'contain'}}
/> />
) : (
<Box sx={{width: '100%', height: '100%', bgcolor: 'grey.300'}} />
)}
</Box>
<CardContent> <CardContent>
<Box sx={{display: 'flex', alignItems: 'center'}}> <Box sx={{display: 'flex', alignItems: 'center'}}>
<Typography display='inline' style={{marginRight: 5}} variant='h6' component='h2'> <Typography display='inline' style={{marginRight: 5}} variant='h6' component='h2'>
+2 -2
View File
@@ -20,7 +20,7 @@ import {formatKuveti} from '../../lib/kuveti'
import LicenseModal from '../cc/license-modal' import LicenseModal from '../cc/license-modal'
import FilesDialog from '../files/files-dialog' import FilesDialog from '../files/files-dialog'
import {StreamButtonComponent} from '../streaming-buttons' import {StreamButton} from '../streaming-buttons'
import EntegreMizik from './entegre-mizik' import EntegreMizik from './entegre-mizik'
import OkiMizik from './oki-mizik' import OkiMizik from './oki-mizik'
import DiferansDialog from './diferans-dialog' import DiferansDialog from './diferans-dialog'
@@ -225,7 +225,7 @@ export default function Teks({parole}) {
</Typography> </Typography>
<Box sx={{display: 'flex', flexWrap: 'wrap', justifyContent: 'center', gap: 1}}> <Box sx={{display: 'flex', flexWrap: 'wrap', justifyContent: 'center', gap: 1}}>
{parole.streamAudio.map((lyen, i) => ( {parole.streamAudio.map((lyen, i) => (
<StreamButtonComponent key={i} lyen={lyen} /> <StreamButton key={i} lyen={lyen} />
))} ))}
</Box> </Box>
</Box> </Box>