fix: corriger toutes les erreurs de lint restantes (263 -> 0)

This commit is contained in:
2026-07-04 14:34:50 +04:00
parent b193914c57
commit 454eefbe58
33 changed files with 210 additions and 159 deletions
+2 -2
View File
@@ -20,7 +20,7 @@ async function jwennAwtis(slug) {
} }
export async function generateMetadata(props) { export async function generateMetadata(props) {
const params = await props.params; const params = await props.params
const {slug} = params const {slug} = params
const anAwtis = await jwennAwtis(slug) const anAwtis = await jwennAwtis(slug)
@@ -64,7 +64,7 @@ export async function generateMetadata(props) {
} }
export default async function AwtisPajSlug(props) { export default async function AwtisPajSlug(props) {
const params = await props.params; const params = await props.params
const {slug} = params const {slug} = params
const anAwtis = await jwennAwtis(slug) const anAwtis = await jwennAwtis(slug)
+1 -1
View File
@@ -63,7 +63,7 @@ async function jwennDone(paj) {
} }
export default async function AwitsPaj(props) { export default async function AwitsPaj(props) {
const searchParams = await props.searchParams; const searchParams = await props.searchParams
const {paj} = searchParams const {paj} = searchParams
const {pajTotal, awtisPouChakPaj, pajParsed} = await jwennDone(paj || 1) const {pajTotal, awtisPouChakPaj, pajParsed} = await jwennDone(paj || 1)
+1 -1
View File
@@ -78,7 +78,7 @@ export default async function RootLayout({children}) {
) )
return ( return (
<html lang='fr' suppressHydrationWarning> <html suppressHydrationWarning lang='fr'>
<body> <body>
{plausibleUrl {plausibleUrl
? <PlausibleProvider src={plausibleUrl}>{inner}</PlausibleProvider> ? <PlausibleProvider src={plausibleUrl}>{inner}</PlausibleProvider>
+1 -2
View File
@@ -7,7 +7,6 @@ import Statistik from '../components/akey/statistik'
import Akey from '../components/akey' import Akey from '../components/akey'
import AnVedette from '../components/akey/an-vedette' import AnVedette from '../components/akey/an-vedette'
import okiLogo from '../public/logo-512x512.png'
import Footer from '../components/footer' import Footer from '../components/footer'
import Aso from '../components/akey/aso' import Aso from '../components/akey/aso'
@@ -26,7 +25,7 @@ export default async function Page() {
return ( return (
<Box sx={{display: 'flex', flexDirection: 'column', minHeight: '100vh'}}> <Box sx={{display: 'flex', flexDirection: 'column', minHeight: '100vh'}}>
<Akey logo={okiLogo} /> <Akey />
<Container sx={{flexGrow: 100}}> <Container sx={{flexGrow: 100}}>
{dernierTeks && <AnVedette teks={dernierTeks} />} {dernierTeks && <AnVedette teks={dernierTeks} />}
<Statistik statistik={statistik} /> <Statistik statistik={statistik} />
+4 -4
View File
@@ -21,10 +21,10 @@ async function jwennAnTeks(slug) {
} }
export async function generateMetadata(props) { export async function generateMetadata(props) {
const params = await props.params; const params = await props.params
const {slug} = params const {slug} = params
const anTeks = await jwennAnTeks(slug) const anTeks = await jwennAnTeks(slug)
const awtis = anTeks?.artistes?.length === 1 ? anTeks?.artistes[0].alias : getAlias(anTeks.artistes, anTeks.prioriteArtistes) const awtis = anTeks?.artistes?.length === 1 ? anTeks?.artistes[0].alias : getAlias(anTeks.artistes, anTeks.prioriteArtistes)
const title = `PAWÒL-NU | ${awtis} - ${anTeks.titre}` const title = `PAWÒL-NU | ${awtis} - ${anTeks.titre}`
@@ -67,12 +67,12 @@ export async function generateMetadata(props) {
} }
export default async function AnPawolPaj(props) { export default async function AnPawolPaj(props) {
const params = await props.params; const params = await props.params
const {slug} = params const {slug} = params
const anTeks = await jwennAnTeks(slug) const anTeks = await jwennAnTeks(slug)
const {couverture} = anTeks const {couverture} = anTeks
const teksKuvetiFormat = formatKuveti(couverture) const teksKuvetiFormat = formatKuveti(couverture)
const jsonLd = { const jsonLd = {
'@context': 'http://schema.org', '@context': 'http://schema.org',
+5
View File
@@ -1,4 +1,5 @@
import {Suspense} from 'react' import {Suspense} from 'react'
import PropTypes from 'prop-types'
import TeksDrawerLoader from '../../components/teks/teks-drawer-loader' import TeksDrawerLoader from '../../components/teks/teks-drawer-loader'
import {CurrentTrackProvider} from '../../components/teks/current-track-context' import {CurrentTrackProvider} from '../../components/teks/current-track-context'
import Loading from './loading' import Loading from './loading'
@@ -50,3 +51,7 @@ export default function PawolLayout({children}) {
</CurrentTrackProvider> </CurrentTrackProvider>
) )
} }
PawolLayout.propTypes = {
children: PropTypes.node.isRequired
}
+1 -1
View File
@@ -1,5 +1,5 @@
export default function robots() { export default function robots() {
const isProduction = process.env.NODE_ENV === 'production'; const isProduction = process.env.NODE_ENV === 'production'
if (!isProduction) { if (!isProduction) {
return { return {
+1 -1
View File
@@ -14,7 +14,7 @@ export default function Sipote() {
<Box sx={{display: 'flex', marginTop: 10, flexDirection: 'column', minHeight: '100vh'}}> <Box sx={{display: 'flex', marginTop: 10, flexDirection: 'column', minHeight: '100vh'}}>
<Box sx={{flexGrow: 1, marginBottom: 10}}> <Box sx={{flexGrow: 1, marginBottom: 10}}>
<Container> <Container>
<Typography gutterBottom sx={{fontWeight: 'bold', textAlign:'center' }} variant='h4' component='h1'> <Typography gutterBottom sx={{fontWeight: 'bold', textAlign: 'center'}} variant='h4' component='h1'>
Soutenir ORGANISATION KA INTERNATIONALE ! Soutenir ORGANISATION KA INTERNATIONALE !
</Typography> </Typography>
<Paper sx={{padding: 2, marginTop: 3}}> <Paper sx={{padding: 2, marginTop: 3}}>
+7 -7
View File
@@ -69,13 +69,13 @@ export default function ThemeRegistry(props) {
return ( return (
<> <>
<InitColorSchemeScript attribute='class' /> <InitColorSchemeScript attribute='class' />
<NextAppDirEmotionCacheProvider options={{key: 'mui'}}> <NextAppDirEmotionCacheProvider options={{key: 'mui'}}>
<ThemeProvider theme={theme}> <ThemeProvider theme={theme}>
<CssBaseline enableColorScheme /> <CssBaseline enableColorScheme />
<ChanjeTem /> <ChanjeTem />
{children} {children}
</ThemeProvider> </ThemeProvider>
</NextAppDirEmotionCacheProvider> </NextAppDirEmotionCacheProvider>
</> </>
) )
} }
+2 -2
View File
@@ -36,10 +36,10 @@ export default function AnVedette({teks}) {
<Box sx={{position: 'relative', width: '100%', aspectRatio: {xs: '1 / 1', sm: '16 / 9'}, maxHeight: {sm: 420}}}> <Box sx={{position: 'relative', width: '100%', aspectRatio: {xs: '1 / 1', sm: '16 / 9'}, maxHeight: {sm: 420}}}>
{fmt?.url ? ( {fmt?.url ? (
<Image <Image
src={`${IMAGE_URL}${fmt.url}`}
alt={titre}
fill fill
priority priority
src={`${IMAGE_URL}${fmt.url}`}
alt={titre}
placeholder='blur' placeholder='blur'
blurDataURL={BLUR_DATA_URL} blurDataURL={BLUR_DATA_URL}
sizes='(max-width: 600px) 100vw, 800px' sizes='(max-width: 600px) 100vw, 800px'
+1 -10
View File
@@ -1,13 +1,8 @@
import PropTypes from 'prop-types'
import Container from '@mui/material/Container' import Container from '@mui/material/Container'
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 Button from '@mui/material/Button'
import Image from 'next/image'
import Link from 'next/link'
export default function Akey({logo}) { export default function Akey() {
return ( return (
<Box sx={{flexGrow: 1, marginBottom: 3, marginTop: 7}}> <Box sx={{flexGrow: 1, marginBottom: 3, marginTop: 7}}>
<Container align='center'> <Container align='center'>
@@ -25,7 +20,3 @@ export default function Akey({logo}) {
</Box> </Box>
) )
} }
Akey.propTypes = {
logo: PropTypes.object.isRequired
}
+10 -9
View File
@@ -72,7 +72,8 @@ export default function AwtisDetay({anAwtis}) {
position: 'relative', position: 'relative',
flexShrink: 0, flexShrink: 0,
mb: 2, mb: 2,
}}> }}
>
{photoUrl ? ( {photoUrl ? (
<Image <Image
src={photoUrl} src={photoUrl}
@@ -94,8 +95,8 @@ export default function AwtisDetay({anAwtis}) {
{rezoSosyal?.length > 0 && ( {rezoSosyal?.length > 0 && (
<Box sx={{display: 'flex', gap: 0.75, flexWrap: 'wrap', justifyContent: 'center', mb: 1.5}}> <Box sx={{display: 'flex', gap: 0.75, flexWrap: 'wrap', justifyContent: 'center', mb: 1.5}}>
{rezoSosyal.map((rezo, i) => ( {rezoSosyal.map(rezo => (
<SocialButton key={i} rezo={rezo} /> <SocialButton key={rezo.url} rezo={rezo} />
))} ))}
</Box> </Box>
)} )}
@@ -149,9 +150,9 @@ export default function AwtisDetay({anAwtis}) {
<Link href={`/paroles/${titrePhare.slug}`} style={{display: 'block', height: '100%'}}> <Link href={`/paroles/${titrePhare.slug}`} style={{display: 'block', height: '100%'}}>
<Box sx={{position: 'relative', minHeight: 130, height: '100%'}}> <Box sx={{position: 'relative', minHeight: 130, height: '100%'}}>
<Image <Image
fill
src={coverUrl} src={coverUrl}
alt={titrePhare.titre} alt={titrePhare.titre}
fill
placeholder='blur' placeholder='blur'
blurDataURL={BLUR_DATA_URL} blurDataURL={BLUR_DATA_URL}
sizes='200px' sizes='200px'
@@ -163,7 +164,7 @@ export default function AwtisDetay({anAwtis}) {
)} )}
<Grid size={{xs: 12, sm: coverUrl ? 8 : 12}}> <Grid size={{xs: 12, sm: coverUrl ? 8 : 12}}>
<CardContent> <CardContent>
<Typography variant='subtitle1' sx={{fontWeight: 700}} gutterBottom> <Typography gutterBottom variant='subtitle1' sx={{fontWeight: 700}}>
<Link href={`/paroles/${titrePhare.slug}`} style={{color: 'inherit', textDecoration: 'none'}}> <Link href={`/paroles/${titrePhare.slug}`} style={{color: 'inherit', textDecoration: 'none'}}>
{titrePhare.titre} {titrePhare.titre}
</Link> </Link>
@@ -172,8 +173,8 @@ export default function AwtisDetay({anAwtis}) {
Écouter sur Écouter sur
</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 => (
<StreamButton key={i} lyen={lyen} /> <StreamButton key={lyen.url} lyen={lyen} />
))} ))}
</Box> </Box>
</CardContent> </CardContent>
@@ -202,7 +203,7 @@ export default function AwtisDetay({anAwtis}) {
})} })}
</AccordionDetails> </AccordionDetails>
</Accordion> </Accordion>
) : paroles.length === 0 ? ( ) : (paroles.length === 0 ? (
<Typography textAlign='center' variant='body1' color='text.secondary'> <Typography textAlign='center' variant='body1' color='text.secondary'>
Aucune parole pour le moment Aucune parole pour le moment
</Typography> </Typography>
@@ -213,7 +214,7 @@ export default function AwtisDetay({anAwtis}) {
<MizikLyen anPawol={paroles[0]} kuveti={formatKuveti(paroles[0].couverture, 'thumbnail')} /> <MizikLyen anPawol={paroles[0]} kuveti={formatKuveti(paroles[0].couverture, 'thumbnail')} />
</Paper> </Paper>
</Box> </Box>
)} ))}
</Grid> </Grid>
</Grid> </Grid>
+1 -2
View File
@@ -19,7 +19,6 @@ import {formatKuveti} from '../../lib/kuveti'
import AwtisBiyografi from './awtis-biyografi' import AwtisBiyografi from './awtis-biyografi'
const PREFIX = 'awtis-kat' const PREFIX = 'awtis-kat'
const SITE_URL = process.env.NEXT_PUBLIC_SITE_URL || 'http://localhost:3001'
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 EXCLUSIVE_LABEL = process.env.NEXT_PUBLIC_EXCLUSIVE_ARTIST_LABEL || 'OKI Exclusif' const EXCLUSIVE_LABEL = process.env.NEXT_PUBLIC_EXCLUSIVE_ARTIST_LABEL || 'OKI Exclusif'
@@ -84,7 +83,7 @@ export default function AwtisKat({artiste}) {
component='img' component='img'
alt={alias} alt={alias}
image={`${photo?.url ? `${IMAGE_URL}${formatKuveti(photo, 'thumbnail')?.url}` : noImageUrl}`} image={`${photo?.url ? `${IMAGE_URL}${formatKuveti(photo, 'thumbnail')?.url}` : noImageUrl}`}
loading='lazy' loading='lazy'
title={alias} title={alias}
/> />
<CardContent> <CardContent>
+15 -18
View File
@@ -5,7 +5,6 @@ import {useRouter} from 'next/navigation'
import TextField from '@mui/material/TextField' import TextField from '@mui/material/TextField'
import Autocomplete from '@mui/material/Autocomplete' import Autocomplete from '@mui/material/Autocomplete'
import Avatar from '@mui/material/Avatar' import Avatar from '@mui/material/Avatar'
import CircularProgress from '@mui/material/CircularProgress'
import Container from '@mui/material/Container' import Container from '@mui/material/Container'
import {jwennToutAwtis} from '../../lib/oki-api' import {jwennToutAwtis} from '../../lib/oki-api'
@@ -29,7 +28,7 @@ export default function ChecheAwtis() {
(async () => { (async () => {
try { try {
const {data} = await jwennToutAwtis() const {data} = await jwennToutAwtis()
const filteredData = data.map(artiste => { const filteredData = data.map(artiste => {
const firstLetter = artiste.alias[0].toUpperCase() const firstLetter = artiste.alias[0].toUpperCase()
return { return {
@@ -50,15 +49,13 @@ export default function ChecheAwtis() {
} }
}, [loading]) }, [loading])
const sortedOptions = useMemo(() => { const sortedOptions = useMemo(() => [...options].sort((a, b) =>
return [...options].sort((a, b) => -b.firstLetter.localeCompare(a.firstLetter)
-b.firstLetter.localeCompare(a.firstLetter) ), [options])
);
}, [options]);
return ( return (
<Container <Container
sx={{ display: 'flex', justifyContent: 'center', marginBottom: 3 }} sx={{display: 'flex', justifyContent: 'center', marginBottom: 3}}
> >
<Autocomplete <Autocomplete
autoHighlight autoHighlight
@@ -70,35 +67,35 @@ export default function ChecheAwtis() {
noOptionsText='Aucun résultat' noOptionsText='Aucun résultat'
id='cheche-awtis' id='cheche-awtis'
options={sortedOptions} options={sortedOptions}
groupBy={(option) => option?.firstLetter} groupBy={option => option?.firstLetter}
getOptionLabel={(option) => option?.alias} getOptionLabel={option => option?.alias}
renderOption={(props, option) => { renderOption={(optionProps, option) => {
const {key, ...rest} = props; const {key, ...rest} = optionProps
return ( return (
<li key={key} {...rest}> <li key={key} {...rest}>
<Avatar <Avatar
style={{ marginRight: 8 }} style={{marginRight: 8}}
alt={option?.alias} alt={option?.alias}
src={`${IMAGE_URL}${formatKuveti(option?.photo, 'thumbnail')?.url || ''}`} src={`${IMAGE_URL}${formatKuveti(option?.photo, 'thumbnail')?.url || ''}`}
/> />
{option?.alias} {option?.alias}
</li> </li>
); )
}} }}
sx={{ width: 300 }} sx={{width: 300}}
renderInput={(params) => ( renderInput={params => (
<TextField <TextField
{...params} {...params}
label='Rechercher un artiste' label='Rechercher un artiste'
slotProps={{ slotProps={{
...params.slotProps, ...params.slotProps,
htmlInput: { ...params.slotProps.htmlInput }, htmlInput: {...params.slotProps.htmlInput},
}} }}
/> />
)} )}
onChange={(event, newValue) => { onChange={(event, newValue) => {
router.push(`/awtis/${newValue.slug}`); router.push(`/awtis/${newValue.slug}`)
}} }}
onOpen={() => setOpen(true)} onOpen={() => setOpen(true)}
onClose={() => setOpen(false)} onClose={() => setOpen(false)}
+25 -17
View File
@@ -1,5 +1,6 @@
'use client' 'use client'
import PropTypes from 'prop-types'
import Chip from '@mui/material/Chip' import Chip from '@mui/material/Chip'
import IconButton from '@mui/material/IconButton' import IconButton from '@mui/material/IconButton'
import Tooltip from '@mui/material/Tooltip' import Tooltip from '@mui/material/Tooltip'
@@ -11,23 +12,23 @@ import {
} from '@icons-pack/react-simple-icons' } from '@icons-pack/react-simple-icons'
const SOCIAL_CONFIG = { const SOCIAL_CONFIG = {
Mastodon: {label: 'Mastodon', bg: '#6364FF', color: '#fff', Icon: Mastodon}, Mastodon: {label: 'Mastodon', bg: '#6364FF', color: '#fff', Icon: Mastodon},
Peertube: {label: 'PeerTube', bg: '#F2690D', color: '#fff', Icon: Peertube}, Peertube: {label: 'PeerTube', bg: '#F2690D', color: '#fff', Icon: Peertube},
Pixelfed: {label: 'Pixelfed', bg: '#11D49D', color: '#fff', Icon: null}, Pixelfed: {label: 'Pixelfed', bg: '#11D49D', color: '#fff', Icon: null},
Funkwhale: {label: 'Funkwhale', bg: '#E01B60', color: '#fff', Icon: null}, Funkwhale: {label: 'Funkwhale', bg: '#E01B60', color: '#fff', Icon: null},
Bluesky: {label: 'Bluesky', bg: '#0085FF', color: '#fff', Icon: null}, Bluesky: {label: 'Bluesky', bg: '#0085FF', color: '#fff', Icon: null},
Instagram: {label: 'Instagram', bg: '#E4405F', color: '#fff', Icon: Instagram}, Instagram: {label: 'Instagram', bg: '#E4405F', color: '#fff', Icon: Instagram},
Youtube: {label: 'YouTube', bg: '#FF0000', color: '#fff', Icon: Youtube}, Youtube: {label: 'YouTube', bg: '#FF0000', color: '#fff', Icon: Youtube},
Tiktok: {label: 'TikTok', bg: '#000000', color: '#fff', Icon: Tiktok}, Tiktok: {label: 'TikTok', bg: '#000000', color: '#fff', Icon: Tiktok},
Spotify: {label: 'Spotify', bg: '#1DB954', color: '#fff', Icon: Spotify}, Spotify: {label: 'Spotify', bg: '#1DB954', color: '#fff', Icon: Spotify},
Deezer: {label: 'Deezer', bg: '#EF5466', color: '#fff', Icon: Deezer}, Deezer: {label: 'Deezer', bg: '#EF5466', color: '#fff', Icon: Deezer},
Applemusic: {label: 'Apple Music', bg: '#FC3C44', color: '#fff', Icon: Applemusic}, Applemusic: {label: 'Apple Music', bg: '#FC3C44', color: '#fff', Icon: Applemusic},
Bandcamp: {label: 'Bandcamp', bg: '#1DA0C3', color: '#fff', Icon: Bandcamp}, Bandcamp: {label: 'Bandcamp', bg: '#1DA0C3', color: '#fff', Icon: Bandcamp},
Soundcloud: {label: 'SoundCloud', bg: '#FF5500', color: '#fff', Icon: Soundcloud}, Soundcloud: {label: 'SoundCloud', bg: '#FF5500', color: '#fff', Icon: Soundcloud},
Facebook: {label: 'Facebook', bg: '#1877F2', color: '#fff', Icon: Facebook}, Facebook: {label: 'Facebook', bg: '#1877F2', color: '#fff', Icon: Facebook},
Twitter: {label: 'X / Twitter', bg: '#000000', color: '#fff', Icon: Twitter}, Twitter: {label: 'X / Twitter', bg: '#000000', color: '#fff', Icon: Twitter},
Linktree: {label: 'Linktree', bg: '#43E660', color: '#000', Icon: null}, Linktree: {label: 'Linktree', bg: '#43E660', color: '#000', Icon: null},
SiteWeb: {label: 'Site web', bg: '#555555', color: '#fff', Icon: null}, SiteWeb: {label: 'Site web', bg: '#555555', color: '#fff', Icon: null},
} }
export function SocialButton({rezo}) { export function SocialButton({rezo}) {
@@ -59,15 +60,22 @@ export function SocialButton({rezo}) {
return ( return (
<Tooltip title={rezo.url}> <Tooltip title={rezo.url}>
<Chip <Chip
clickable
label={config.label} label={config.label}
component='a' component='a'
href={rezo.url} href={rezo.url}
target='_blank' target='_blank'
rel='noopener noreferrer' rel='noopener noreferrer'
clickable
size='small' size='small'
sx={{bgcolor: config.bg, color: config.color, fontWeight: 600}} sx={{bgcolor: config.bg, color: config.color, fontWeight: 600}}
/> />
</Tooltip> </Tooltip>
) )
} }
SocialButton.propTypes = {
rezo: PropTypes.shape({
plateforme: PropTypes.string.isRequired,
url: PropTypes.string.isRequired
}).isRequired
}
+2 -2
View File
@@ -57,7 +57,7 @@ export default function LicenseModal({license, sourceOriginale, remixes}) {
<DialogContent dividers> <DialogContent dividers>
{sourceOriginale && ( {sourceOriginale && (
<Box sx={{mb: 3}}> <Box sx={{mb: 3}}>
<Typography variant='overline' color='text.secondary' display='block' gutterBottom> <Typography gutterBottom variant='overline' color='text.secondary' display='block'>
Basé sur Basé sur
</Typography> </Typography>
<Link href={`/paroles/${sourceOriginale.slug}`} underline='hover' color='inherit'> <Link href={`/paroles/${sourceOriginale.slug}`} underline='hover' color='inherit'>
@@ -76,7 +76,7 @@ export default function LicenseModal({license, sourceOriginale, remixes}) {
)} )}
{remixes && ( {remixes && (
<Box sx={{mb: 3}}> <Box sx={{mb: 3}}>
<Typography variant='overline' color='text.secondary' display='block' gutterBottom> <Typography gutterBottom variant='overline' color='text.secondary' display='block'>
Déclinaisons Déclinaisons
</Typography> </Typography>
{remixes.map(remix => ( {remixes.map(remix => (
+25 -10
View File
@@ -70,12 +70,14 @@ export default function FilesList({files}) {
useEffect(() => { useEffect(() => {
const audioFiles = files.filter(f => f.mime.startsWith('audio')) const audioFiles = files.filter(f => f.mime.startsWith('audio'))
if (audioFiles.length === 0) return if (audioFiles.length === 0) {
return
}
let cancelled = false let cancelled = false
async function fetchAllMeta() { async function fetchAllMeta() {
const mm = await import('music-metadata-browser') const mm = await import('music-metadata-browser') // eslint-disable-line node/no-unsupported-features/es-syntax
const results = {} const results = {}
await Promise.all( await Promise.all(
audioFiles.map(async file => { audioFiles.map(async file => {
@@ -98,7 +100,9 @@ export default function FilesList({files}) {
} }
}) })
) )
if (!cancelled) setAudioMeta(results) if (!cancelled) {
setAudioMeta(results)
}
} }
fetchAllMeta() fetchAllMeta()
@@ -121,7 +125,8 @@ export default function FilesList({files}) {
fontWeight: 'bold', fontWeight: 'bold',
letterSpacing: '0.05rem', letterSpacing: '0.05rem',
textTransform: 'uppercase', textTransform: 'uppercase',
}}>{isHaute ? 'Haute' : 'Faible'}</Typography> }}
>{isHaute ? 'Haute' : 'Faible'}</Typography>
) )
} }
@@ -150,12 +155,16 @@ export default function FilesList({files}) {
} }
useEffect(() => () => { useEffect(() => () => {
Object.values(controllersRef.current).forEach(c => c.abort()) for (const c of Object.values(controllersRef.current)) {
c.abort()
}
}, []) }, [])
const handleClick = async (e, url, fileName, fileId) => { const handleClick = async (e, url, fileName, fileId) => {
e.stopPropagation() e.stopPropagation()
if (fileId in downloading) return if (fileId in downloading) {
return
}
const controller = new AbortController() const controller = new AbortController()
controllersRef.current[fileId] = controller controllersRef.current[fileId] = controller
@@ -163,14 +172,18 @@ export default function FilesList({files}) {
setDownloading(prev => ({...prev, [fileId]: 0})) setDownloading(prev => ({...prev, [fileId]: 0}))
try { try {
const response = await fetch(url, {signal: controller.signal}) const response = await fetch(url, {signal: controller.signal})
const contentLength = +response.headers.get('content-length') const contentLength = Number(response.headers.get('content-length'))
const reader = response.body.getReader() const reader = response.body.getReader()
const chunks = [] const chunks = []
let received = 0 let received = 0
while (true) { for (;;) {
// eslint-disable-next-line no-await-in-loop -- chaque chunk dépend du précédent, la lecture est intrinsèquement séquentielle
const {done, value} = await reader.read() const {done, value} = await reader.read()
if (done) break if (done) {
break
}
chunks.push(value) chunks.push(value)
received += value.length received += value.length
if (contentLength) { if (contentLength) {
@@ -186,7 +199,9 @@ export default function FilesList({files}) {
a.click() a.click()
URL.revokeObjectURL(blobUrl) URL.revokeObjectURL(blobUrl)
} catch (error) { } catch (error) {
if (error.name !== 'AbortError') throw error if (error.name !== 'AbortError') {
throw error
}
} finally { } finally {
delete controllersRef.current[fileId] delete controllersRef.current[fileId]
setDownloading(prev => { setDownloading(prev => {
+2 -2
View File
@@ -48,10 +48,10 @@ export default function KitsDialog({kits}) {
<DialogTitle>Télécharger un kit</DialogTitle> <DialogTitle>Télécharger un kit</DialogTitle>
<DialogContent dividers> <DialogContent dividers>
<List> <List>
{kits.map((kit, index) => { {kits.map(kit => {
const PlatformIcon = PLATFORM_ICON[kit.plateforme] ?? CloudDownloadIcon const PlatformIcon = PLATFORM_ICON[kit.plateforme] ?? CloudDownloadIcon
return ( return (
<ListItem key={index} disablePadding> <ListItem key={kit.url} disablePadding>
<ListItemButton component='a' href={kit.url} target='_blank' rel='noopener noreferrer'> <ListItemButton component='a' href={kit.url} target='_blank' rel='noopener noreferrer'>
<ListItemIcon> <ListItemIcon>
<PlatformIcon /> <PlatformIcon />
+3 -2
View File
@@ -70,7 +70,8 @@ export default function Navigasyon() {
<Appdiv> <Appdiv>
<div className={classes.root}> <div className={classes.root}>
<AppBar style={{zIndex: 1, boxShadow: 'none'}} position='fixed' color='default'> <AppBar style={{zIndex: 1, boxShadow: 'none'}} position='fixed' color='default'>
{selectedTab !== undefined && <Tabs {selectedTab !== undefined && (
<Tabs
allowScrollButtonsMobile allowScrollButtonsMobile
scrollButtons scrollButtons
centered={Boolean(!isMobile)} centered={Boolean(!isMobile)}
@@ -91,7 +92,7 @@ export default function Navigasyon() {
<Tab icon={<MusicNoteIcon />} aria-label='Paroles' {...a11yProps(2)} /> <Tab icon={<MusicNoteIcon />} aria-label='Paroles' {...a11yProps(2)} />
<Tab icon={<RecordVoiceOverIcon />} aria-label='Artistes' {...a11yProps(3)} /> <Tab icon={<RecordVoiceOverIcon />} aria-label='Artistes' {...a11yProps(3)} />
</Tabs> </Tabs>
} )}
</AppBar> </AppBar>
</div> </div>
</Appdiv> </Appdiv>
-2
View File
@@ -4,8 +4,6 @@ import ArrowRightAltIcon from '@mui/icons-material/ArrowRightAlt'
import CGUDialog from '../cgu/cgu-dialog' import CGUDialog from '../cgu/cgu-dialog'
const CGU_PDF_LINK = process.env.NEXT_PUBLIC_CGU_DOWNLOAD_LINK
export default function Presantasyon() { export default function Presantasyon() {
const [open, setOpen] = useState(false) const [open, setOpen] = useState(false)
+16 -8
View File
@@ -1,18 +1,19 @@
'use client' 'use client'
import PropTypes from 'prop-types'
import Button from '@mui/material/Button' import Button from '@mui/material/Button'
import OpenInNewIcon from '@mui/icons-material/OpenInNew' import OpenInNewIcon from '@mui/icons-material/OpenInNew'
import {Spotify, Applemusic, Deezer, Tidal, Youtubemusic, Amazon, Soundcloud} from '@icons-pack/react-simple-icons' import {Spotify, Applemusic, Deezer, Tidal, Youtubemusic, Amazon, Soundcloud} from '@icons-pack/react-simple-icons'
export const PLATFORM_CONFIG = { export const PLATFORM_CONFIG = {
Spotify: {label: 'Spotify', bg: '#1DB954', color: '#fff', Icon: Spotify}, Spotify: {label: 'Spotify', bg: '#1DB954', color: '#fff', Icon: Spotify},
Applemusic: {label: 'Apple Music', bg: '#FC3C44', color: '#fff', Icon: Applemusic}, Applemusic: {label: 'Apple Music', bg: '#FC3C44', color: '#fff', Icon: Applemusic},
Deezer: {label: 'Deezer', bg: '#EF5466', color: '#fff', Icon: Deezer}, Deezer: {label: 'Deezer', bg: '#EF5466', color: '#fff', Icon: Deezer},
Tidal: {label: 'Tidal', bg: '#000000', color: '#fff', Icon: Tidal}, Tidal: {label: 'Tidal', bg: '#000000', color: '#fff', Icon: Tidal},
Qobuz: {label: 'Qobuz', bg: '#00245B', color: '#fff', Icon: null}, Qobuz: {label: 'Qobuz', bg: '#00245B', color: '#fff', Icon: null},
Youtubemusic: {label: 'YouTube Music', bg: '#FF0000', color: '#fff', Icon: Youtubemusic}, Youtubemusic: {label: 'YouTube Music', bg: '#FF0000', color: '#fff', Icon: Youtubemusic},
Amazon: {label: 'Amazon Music', bg: '#00A8E1', color: '#fff', Icon: Amazon}, Amazon: {label: 'Amazon Music', bg: '#00A8E1', color: '#fff', Icon: Amazon},
Soundcloud: {label: 'SoundCloud', bg: '#FF5500', color: '#fff', Icon: Soundcloud}, Soundcloud: {label: 'SoundCloud', bg: '#FF5500', color: '#fff', Icon: Soundcloud},
} }
export function StreamButton({lyen}) { export function StreamButton({lyen}) {
@@ -39,3 +40,10 @@ export function StreamButton({lyen}) {
</Button> </Button>
) )
} }
StreamButton.propTypes = {
lyen: PropTypes.shape({
plateforme: PropTypes.string.isRequired,
url: PropTypes.string.isRequired
}).isRequired
}
+1 -1
View File
@@ -20,7 +20,7 @@ const getMizikFiltered = (paroles, filter) => {
const filteredTitre = paroles.filter(({titre}) => { const filteredTitre = paroles.filter(({titre}) => {
const deburredTit = deburr(titre) const deburredTit = deburr(titre)
return deburredTit.toLowerCase().includes(deburr(filter.toLowerCase())) return deburredTit.toLowerCase().includes(deburr(filter.toLowerCase()))
}) })
const filteredAlias = paroles.filter(({artistes}) => { const filteredAlias = paroles.filter(({artistes}) => {
const aliasLis = artistes.map(({alias}) => deburr(alias)).join(', ') const aliasLis = artistes.map(({alias}) => deburr(alias)).join(', ')
+20 -14
View File
@@ -21,7 +21,7 @@ const pulse = keyframes`
` `
const SlideUp = forwardRef(function SlideUp(props, ref) { const SlideUp = forwardRef(function SlideUp(props, ref) {
return <Slide direction='up' ref={ref} {...props} /> return <Slide ref={ref} direction='up' {...props} />
}) })
function toEmbedUrl(url) { function toEmbedUrl(url) {
@@ -31,6 +31,7 @@ function toEmbedUrl(url) {
if (match) { if (match) {
return `${u.origin}/videos/embed/${match[1]}?title=0&warningTitle=0&peertubeLink=0&controlBar=1` return `${u.origin}/videos/embed/${match[1]}?title=0&warningTitle=0&peertubeLink=0&controlBar=1`
} }
return url return url
} catch { } catch {
return url return url
@@ -45,7 +46,9 @@ export default function KaraokeModal({url, desktopUrl, titre, artistes}) {
const activeUrl = (!isMobile && desktopUrl) ? desktopUrl : url const activeUrl = (!isMobile && desktopUrl) ? desktopUrl : url
useEffect(() => { useEffect(() => {
if (!open) setLoaded(false) if (!open) {
setLoaded(false)
}
}, [open]) }, [open])
return ( return (
@@ -55,13 +58,13 @@ export default function KaraokeModal({url, desktopUrl, titre, artistes}) {
color='primary' color='primary'
size={isMobile ? 'medium' : 'large'} size={isMobile ? 'medium' : 'large'}
aria-label='karaoké' aria-label='karaoké'
onClick={() => setOpen(true)}
sx={{ sx={{
position: 'fixed', position: 'fixed',
bottom: {xs: 24, sm: 32}, bottom: {xs: 24, sm: 32},
right: {xs: 24, sm: 32}, right: {xs: 24, sm: 32},
zIndex: 1050, zIndex: 1050,
}} }}
onClick={() => setOpen(true)}
> >
<MicIcon /> <MicIcon />
</Fab> </Fab>
@@ -69,7 +72,6 @@ export default function KaraokeModal({url, desktopUrl, titre, artistes}) {
<Dialog <Dialog
open={open} open={open}
onClose={() => setOpen(false)}
slots={{transition: SlideUp}} slots={{transition: SlideUp}}
maxWidth={false} maxWidth={false}
sx={{ sx={{
@@ -102,6 +104,7 @@ export default function KaraokeModal({url, desktopUrl, titre, artistes}) {
} }
} }
}} }}
onClose={() => setOpen(false)}
> >
{/* Header superposé en gradient */} {/* Header superposé en gradient */}
<Box sx={{ <Box sx={{
@@ -118,7 +121,8 @@ export default function KaraokeModal({url, desktopUrl, titre, artistes}) {
alignItems: 'flex-start', alignItems: 'flex-start',
justifyContent: 'space-between', justifyContent: 'space-between',
pointerEvents: 'none', pointerEvents: 'none',
}}> }}
>
<Box sx={{pointerEvents: 'none'}}> <Box sx={{pointerEvents: 'none'}}>
{titre && ( {titre && (
<Typography variant='subtitle1' sx={{color: '#fff', fontWeight: 700, lineHeight: 1.2, textShadow: '0 1px 4px rgba(0,0,0,0.5)'}}> <Typography variant='subtitle1' sx={{color: '#fff', fontWeight: 700, lineHeight: 1.2, textShadow: '0 1px 4px rgba(0,0,0,0.5)'}}>
@@ -133,7 +137,6 @@ export default function KaraokeModal({url, desktopUrl, titre, artistes}) {
</Box> </Box>
<IconButton <IconButton
size='small' size='small'
onClick={() => setOpen(false)}
aria-label='fermer' aria-label='fermer'
sx={{ sx={{
pointerEvents: 'auto', pointerEvents: 'auto',
@@ -143,6 +146,7 @@ export default function KaraokeModal({url, desktopUrl, titre, artistes}) {
border: '1px solid rgba(255,255,255,0.12)', border: '1px solid rgba(255,255,255,0.12)',
'&:hover': {bgcolor: 'rgba(255,255,255,0.25)'}, '&:hover': {bgcolor: 'rgba(255,255,255,0.25)'},
}} }}
onClick={() => setOpen(false)}
> >
<CloseIcon fontSize='small' /> <CloseIcon fontSize='small' />
</IconButton> </IconButton>
@@ -166,7 +170,8 @@ export default function KaraokeModal({url, desktopUrl, titre, artistes}) {
alignItems: 'center', alignItems: 'center',
justifyContent: 'center', justifyContent: 'center',
gap: 1.5, gap: 1.5,
}}> }}
>
<MicIcon sx={{fontSize: 44, color: 'rgba(255,255,255,0.55)', animation: `${pulse} 1.6s ease-in-out infinite`}} /> <MicIcon sx={{fontSize: 44, color: 'rgba(255,255,255,0.55)', animation: `${pulse} 1.6s ease-in-out infinite`}} />
<Typography <Typography
variant='caption' variant='caption'
@@ -187,27 +192,28 @@ export default function KaraokeModal({url, desktopUrl, titre, artistes}) {
transform: 'translateX(-50%)', transform: 'translateX(-50%)',
height: '100%', height: '100%',
aspectRatio: '16 / 9', aspectRatio: '16 / 9',
}}> }}
>
<iframe <iframe
src={toEmbedUrl(activeUrl)}
onLoad={() => setLoaded(true)}
style={{width: '100%', height: '100%', border: 'none', display: 'block', opacity: loaded ? 1 : 0, transition: 'opacity 0.4s ease'}}
allowFullScreen allowFullScreen
src={toEmbedUrl(activeUrl)}
style={{width: '100%', height: '100%', border: 'none', display: 'block', opacity: loaded ? 1 : 0, transition: 'opacity 0.4s ease'}}
allow='autoplay; fullscreen' allow='autoplay; fullscreen'
sandbox='allow-same-origin allow-scripts allow-popups allow-forms' sandbox='allow-same-origin allow-scripts allow-popups allow-forms'
title='Karaoké' title='Karaoké'
onLoad={() => setLoaded(true)}
/> />
</Box> </Box>
) : ( ) : (
/* Vidéo 16:9 desktop : player remplit exactement le dialog paysage */ /* Vidéo 16:9 desktop : player remplit exactement le dialog paysage */
<iframe <iframe
src={toEmbedUrl(activeUrl)}
onLoad={() => setLoaded(true)}
style={{width: '100%', height: '100%', border: 'none', display: 'block', opacity: loaded ? 1 : 0, transition: 'opacity 0.4s ease'}}
allowFullScreen allowFullScreen
src={toEmbedUrl(activeUrl)}
style={{width: '100%', height: '100%', border: 'none', display: 'block', opacity: loaded ? 1 : 0, transition: 'opacity 0.4s ease'}}
allow='autoplay; fullscreen' allow='autoplay; fullscreen'
sandbox='allow-same-origin allow-scripts allow-popups allow-forms' sandbox='allow-same-origin allow-scripts allow-popups allow-forms'
title='Karaoké' title='Karaoké'
onLoad={() => setLoaded(true)}
/> />
)} )}
</Box> </Box>
+13 -5
View File
@@ -30,9 +30,10 @@ function createAudio(src) {
function parseLrc(text) { function parseLrc(text) {
const lines = [] const lines = []
for (const raw of text.split('\n')) { for (const raw of text.split('\n')) {
const match = raw.match(/^\[(\d{2}):(\d{2})[.:]\d+\](.*)$/) const match = raw.match(/^\[(\d{2}):(\d{2})[.:]\d+](.*)$/)
if (match) { if (match) {
lines.push({time: parseInt(match[1]) * 60 + parseInt(match[2]), text: match[3].trim()}) const time = (Number.parseInt(match[1], 10) * 60) + Number.parseInt(match[2], 10)
lines.push({time, text: match[3].trim()})
} }
} }
@@ -145,6 +146,7 @@ export default function Lekte({audio, url, parole}) {
setPosition(0) setPosition(0)
el.currentTime = 0 el.currentTime = 0
} }
el.addEventListener('loadedmetadata', onLoaded) el.addEventListener('loadedmetadata', onLoaded)
el.addEventListener('ended', onEnded) el.addEventListener('ended', onEnded)
return () => { return () => {
@@ -154,7 +156,10 @@ export default function Lekte({audio, url, parole}) {
}, [audio]) }, [audio])
useEffect(() => { useEffect(() => {
if (!parole?.pawol?.url) return if (!parole?.pawol?.url) {
return
}
fetch(new URL(parole.pawol.url, IMAGE_URL).toString()) fetch(new URL(parole.pawol.url, IMAGE_URL).toString())
.then(r => r.text()) .then(r => r.text())
.then(text => setLrcLines(parseLrc(text))) .then(text => setLrcLines(parseLrc(text)))
@@ -162,7 +167,7 @@ export default function Lekte({audio, url, parole}) {
}, [parole?.pawol?.url]) }, [parole?.pawol?.url])
const activeIndex = lrcLines const activeIndex = lrcLines
? lrcLines.reduce((last, line, i) => line.time <= position ? i : last, -1) ? lrcLines.findLastIndex(line => line.time <= position)
: -1 : -1
const handleChangePosition = value => { const handleChangePosition = value => {
@@ -317,7 +322,10 @@ export default function Lekte({audio, url, parole}) {
{[-1, 0, 1].map(offset => { {[-1, 0, 1].map(offset => {
const idx = activeIndex + offset const idx = activeIndex + offset
const line = lrcLines[idx] const line = lrcLines[idx]
if (!line) return <Box key={offset} sx={{height: offset === 0 ? 28 : 20}} /> if (!line) {
return <Box key={offset} sx={{height: offset === 0 ? 28 : 20}} />
}
return ( return (
<Typography <Typography
key={offset} key={offset}
+1 -1
View File
@@ -51,9 +51,9 @@ export default function TeksKat({parole}) {
<Box sx={{position: 'relative', height: 240}}> <Box sx={{position: 'relative', height: 240}}>
{couverture?.url ? ( {couverture?.url ? (
<Image <Image
fill
src={`${IMAGE_URL}${formatKuveti(couverture, 'thumbnail')?.url}`} src={`${IMAGE_URL}${formatKuveti(couverture, 'thumbnail')?.url}`}
alt={titre} alt={titre}
fill
placeholder='blur' placeholder='blur'
blurDataURL={BLUR_DATA_URL} blurDataURL={BLUR_DATA_URL}
sizes='(max-width: 600px) 100vw, (max-width: 900px) 50vw, 33vw' sizes='(max-width: 600px) 100vw, (max-width: 900px) 50vw, 33vw'
+6 -6
View File
@@ -183,7 +183,7 @@ export default function Teks({parole}) {
<i>parole soumise par {parole.user.username}</i> <i>parole soumise par {parole.user.username}</i>
</Typography> </Typography>
)} )}
{parole?.userAdmin&& !parole.user && ( {parole?.userAdmin && !parole.user && (
<Typography style={{marginBottom: '1.5em'}} display='block' variant='caption'> <Typography style={{marginBottom: '1.5em'}} display='block' variant='caption'>
<i>parole soumise par {parole.userAdmin.firstname}</i> <i>parole soumise par {parole.userAdmin.firstname}</i>
</Typography> </Typography>
@@ -220,8 +220,8 @@ export default function Teks({parole}) {
Écouter sur Écouter sur
</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 => (
<StreamButton key={i} lyen={lyen} /> <StreamButton key={lyen.url} lyen={lyen} />
))} ))}
</Box> </Box>
</Box> </Box>
@@ -229,11 +229,10 @@ export default function Teks({parole}) {
</Box> </Box>
<Box sx={{maxWidth: 700, margin: '0 auto'}} className={classes.gridText}> <Box sx={{maxWidth: 700, margin: '0 auto'}} className={classes.gridText}>
<Tabs <Tabs
value={tab}
onChange={(event, value) => setTab(value)}
variant='scrollable'
scrollButtons scrollButtons
allowScrollButtonsMobile allowScrollButtonsMobile
value={tab}
variant='scrollable'
centered={langArray.length === 0} centered={langArray.length === 0}
slots={{ slots={{
startScrollButtonIcon: ArrowBackIosNewIcon, startScrollButtonIcon: ArrowBackIosNewIcon,
@@ -255,6 +254,7 @@ export default function Teks({parole}) {
} }
} }
}} }}
onChange={(event, value) => setTab(value)}
> >
<Tab label='Transcription' /> <Tab label='Transcription' />
{langArray.map(({title}) => ( {langArray.map(({title}) => (
+5
View File
@@ -1,7 +1,12 @@
'use client' 'use client'
import PropTypes from 'prop-types'
import NextTopLoader from 'nextjs-toploader' import NextTopLoader from 'nextjs-toploader'
export default function TopLoader({color}) { export default function TopLoader({color}) {
return <NextTopLoader color={color} /> return <NextTopLoader color={color} />
} }
TopLoader.propTypes = {
color: PropTypes.string.isRequired
}
+14 -14
View File
@@ -1,25 +1,25 @@
import { dirname } from "path"; import {dirname} from 'node:path'
import { fileURLToPath } from "url"; import {fileURLToPath} from 'node:url'
import { FlatCompat } from "@eslint/eslintrc"; import {FlatCompat} from '@eslint/eslintrc'
const __filename = fileURLToPath(import.meta.url); const __filename = fileURLToPath(import.meta.url)
const __dirname = dirname(__filename); const __dirname = dirname(__filename)
const compat = new FlatCompat({ const compat = new FlatCompat({
baseDirectory: __dirname, baseDirectory: __dirname,
}); })
const eslintConfig = [ const eslintConfig = [
...compat.extends("next/core-web-vitals"), ...compat.extends('next/core-web-vitals'),
{ {
ignores: [ ignores: [
"node_modules/**", 'node_modules/**',
".next/**", '.next/**',
"out/**", 'out/**',
"build/**", 'build/**',
"next-env.d.ts", 'next-env.d.ts',
], ],
}, },
]; ]
export default eslintConfig; export default eslintConfig
+11 -5
View File
@@ -1,15 +1,21 @@
const SIZE_ORDER = { const SIZE_ORDER = {
large: ['large', 'medium', 'small'], large: ['large', 'medium', 'small'],
medium: ['medium', 'small', 'large'], medium: ['medium', 'small', 'large'],
small: ['small', 'medium', 'large'], small: ['small', 'medium', 'large'],
thumbnail: ['thumbnail', 'small', 'medium', 'large'], thumbnail: ['thumbnail', 'small', 'medium', 'large'],
} }
export const formatKuveti = (kuveti, preferred = 'large') => { export const formatKuveti = (kuveti, preferred = 'large') => {
if (!kuveti) return null if (!kuveti) {
return null
}
const order = SIZE_ORDER[preferred] ?? SIZE_ORDER.large const order = SIZE_ORDER[preferred] ?? SIZE_ORDER.large
for (const size of order) { for (const size of order) {
if (kuveti.formats?.[size]) return kuveti.formats[size] if (kuveti.formats?.[size]) {
return kuveti.formats[size]
}
} }
return kuveti return kuveti
} }
+3 -2
View File
@@ -186,6 +186,7 @@ async function jwennTouSlug(endpoint) {
encodeValuesOnly: true encodeValuesOnly: true
}) })
// eslint-disable-next-line no-await-in-loop -- pagination séquentielle, chaque page dépend du nombre de résultats de la précédente
const {data} = await request(`/${endpoint}?${query}`, headers) const {data} = await request(`/${endpoint}?${query}`, headers)
slugs.push(...data.map(({slug}) => slug)) slugs.push(...data.map(({slug}) => slug))
hasMore = data.length === pageSize hasMore = data.length === pageSize
@@ -223,9 +224,9 @@ export async function jwennAnVedette() {
const query = qs.stringify({ const query = qs.stringify({
populate: ['artistes', 'couverture'], populate: ['artistes', 'couverture'],
filters: { filters: {
isNewRelease: { $eq: true } isNewRelease: {$eq: true}
}, },
pagination: { limit: 1 } pagination: {limit: 1}
}, { }, {
encodeValuesOnly: true encodeValuesOnly: true
}) })
-4
View File
@@ -1,16 +1,12 @@
import YouTubeIcon from '@mui/icons-material/YouTube' import YouTubeIcon from '@mui/icons-material/YouTube'
import TelegramIcon from '@mui/icons-material/Telegram' import TelegramIcon from '@mui/icons-material/Telegram'
import PeertubeIcon from './icons/peertube'
import XmppIcon from './icons/xmpp'
import XIcon from './icons/x' import XIcon from './icons/x'
import GiteaIcon from './icons/gitea' import GiteaIcon from './icons/gitea'
import BlueskyIcon from './icons/bluesky' import BlueskyIcon from './icons/bluesky'
const gitURL = process.env.NEXT_PUBLIC_GIT || 'https://labola.o-k-i.net/ORGANISATION-KA-INTERNATIONALE/pawol.nu' const gitURL = process.env.NEXT_PUBLIC_GIT || 'https://labola.o-k-i.net/ORGANISATION-KA-INTERNATIONALE/pawol.nu'
const blueskyUrl = process.env.NEXT_PUBLIC_BLUESKY_URL || 'https://bsky.app/profile/organisationka.bsky.social' const blueskyUrl = process.env.NEXT_PUBLIC_BLUESKY_URL || 'https://bsky.app/profile/organisationka.bsky.social'
const xmppContact = process.env.NEXT_PUBLIC_XMPP || 'oki@xmpp.cz'
const gadeUsername = process.env.NEXT_PUBLIC_GADE_USERNAME || 'oki'
const youtubeUsername = process.env.NEXT_PUBLIC_YOUTUBE_USERNAME || 'OrganisationKInternationaleOKi' const youtubeUsername = process.env.NEXT_PUBLIC_YOUTUBE_USERNAME || 'OrganisationKInternationaleOKi'
const tiwtterUsername = process.env.NEXT_PUBLIC_TWITTER_USERNAME || 'OrganisationKA' const tiwtterUsername = process.env.NEXT_PUBLIC_TWITTER_USERNAME || 'OrganisationKA'
const telegramGroup = process.env.NEXT_PUBLIC_TELEGRAM_GROUP || 'OrganisationKA' const telegramGroup = process.env.NEXT_PUBLIC_TELEGRAM_GROUP || 'OrganisationKA'
+10 -3
View File
@@ -11,13 +11,20 @@ function buildRemotePatterns() {
const [hostname, port] = entry.split(':') const [hostname, port] = entry.split(':')
const isLocal = hostname === 'localhost' || hostname === '127.0.0.1' const isLocal = hostname === 'localhost' || hostname === '127.0.0.1'
const pattern = {protocol: isLocal ? 'http' : 'https', hostname, pathname: '/uploads/**'} const pattern = {protocol: isLocal ? 'http' : 'https', hostname, pathname: '/uploads/**'}
if (port) pattern.port = port if (port) {
pattern.port = port
}
return pattern return pattern
}) })
if (!raw.includes('localhost')) if (!raw.includes('localhost')) {
patterns.push({protocol: 'http', hostname: 'localhost', port: '1337', pathname: '/uploads/**'}) patterns.push({protocol: 'http', hostname: 'localhost', port: '1337', pathname: '/uploads/**'})
if (!raw.includes('127.0.0.1')) }
if (!raw.includes('127.0.0.1')) {
patterns.push({protocol: 'http', hostname: '127.0.0.1', port: '1337', pathname: '/uploads/**'}) patterns.push({protocol: 'http', hostname: '127.0.0.1', port: '1337', pathname: '/uploads/**'})
}
return patterns return patterns
} }
+1 -1
View File
@@ -1 +1 @@
import '@testing-library/jest-dom/vitest' import '@testing-library/jest-dom/vitest' // eslint-disable-line import/no-unassigned-import