This commit is contained in:
2026-02-20 21:55:35 +01:00
parent 329b43e07c
commit c258a436a0
13 changed files with 1340 additions and 817 deletions

View File

@@ -1,13 +1,309 @@
<template>
<div>
<!-- ================== -->
<!-- Fond noir -->
<!-- ================== -->
<PageSection tone="dark" content-size="default" class="theme_bandeau--grid">
<SectionContent pad="xs" class="theme_bandeau--grid--left">
<SectionTitle tone="invert" pad="">
LES MUSICIENS
</SectionTitle>
<DsHeading as="h3" tone="invert">
95 musiciens engagés Partout et pour tous en Île-de-France !
</DsHeading>
</SectionContent>
<SectionContent pad="xs" class="theme_bandeau--grid--right">
<DsText tone="invert" size="lg" class="theme_bandeau--grid--right--text" >
Les 95 musiciennes et musiciens proposent chaque saison plus de 120 concerts dans des salles et théâtres, des lieux culturels et des espaces atypiques de la région francilienne. Porté par une forte mission territoriale, lorchestre sengage à rendre la musique symphonique accessible à toutes et tous, en la faisant vivre au plus près des habitants grâce notamment à des actions culturelles, pédagogiques et participatives au cœur du territoire.
</DsText>
</SectionContent>
</PageSection>
<!-- ================== -->
<!-- Listes des musiciens -->
<!-- ================== -->
<!-- ================== -->
<!-- DIRECTION -->
<!-- ================== -->
<PageSection padded_size="md" content-size="default" class="musiciens_list_section remonter_artistes_list">
<section v-if="pending" aria-busy="true" aria-live="polite">
<DsText as="p" tone="default">Chargement des artistes...</DsText>
</section>
<section v-else-if="error">
<DsText as="p" tone="default">Impossible de charger les artistes.</DsText>
</section>
<section v-else-if="artistesDirection.length" class="musiciens_list">
<article v-for="a in artistesDirection" :key="a.id" class="musicien_card">
<DsMedia
v-if="a.image?.url"
:src="a.image.url"
:alt="a.image.alternativeText || a.nom_artiste_ondif || ''"
ratio="square"
/>
<DsHeading as="h4" tone="default" class="musicien_card_nom">
<NuxtLink :to="`/orchestre/artiste-${a.slug_artiste_ondif}`">
{{ a.nom_artiste_ondif }}
</NuxtLink>
</DsHeading>
<DsText
v-if="a.postesLabel"
as="p"
tone="default"
size="md"
class="musicien_card_postes"
>
{{ a.postesLabel }}
</DsText>
</article>
</section>
<section v-else>
<DsText as="p" tone="default">Aucun artiste pour la direction.</DsText>
</section>
</PageSection>
<!-- ================== -->
<!-- MUSICIENS -->
<!-- ================== -->
<PageSection padded_size="md" content-size="default" class="musiciens_list_section musiciens_list_wp">
<section v-if="pending" aria-busy="true" aria-live="polite">
<DsText as="p" tone="default">Chargement des artistes...</DsText>
</section>
<section v-else-if="error">
<DsText as="p" tone="default">Impossible de charger les artistes.</DsText>
</section>
<section v-else-if="artistesAutres.length" class="musiciens_list">
<article v-for="a in artistesAutres" :key="a.id" class="musicien_card">
<DsMedia
v-if="a.image?.url"
:src="a.image.url"
:alt="a.image.alternativeText || a.nom_artiste_ondif || ''"
ratio="square"
/>
<DsHeading as="h4" tone="default" class="musicien_card_nom">
<NuxtLink :to="`/orchestre/artiste-${a.slug_artiste_ondif}`">
{{ a.nom_artiste_ondif }}
</NuxtLink>
</DsHeading>
<DsText
v-if="a.postesLabel"
as="p"
tone="default"
size="md"
class="musicien_card_postes"
>
{{ a.postesLabel }}
</DsText>
</article>
</section>
<section v-else>
<DsText as="p" tone="default">Aucun autre artiste trouvé.</DsText>
</section>
</PageSection>
</div>
</template>
<script lang="ts" setup>
<script setup>
import DsHeading from '@root/design-system/primitives/DsHeading.vue'
import DsText from '@root/design-system/primitives/DsText.vue'
import DsMedia from '@root/design-system/primitives/DsMedia.vue'
const runtimeConfig = useRuntimeConfig()
const saisonFiltre = computed(() => String(runtimeConfig.public.saison || '').trim())
const artistesFilters = computed(() => {
if (!saisonFiltre.value) return null
return {
saisons_artiste_ondif: {
nom_saison: {
$eq: saisonFiltre.value,
},
},
}
})
//--------------------
// DONNÉES POUR LES ARTISTES
//--------------------
const { artistes, pending, error } = useArtistes({
locale: "fr-FR",
sort: "ordre_artiste_ondif:asc",
populate: {
saisons_artiste_ondif: true,
image_illustration_artiste_ondif: true,
postes_artiste_ondif: true,
},
filters: artistesFilters,
})
const artistesDisplay = computed(() => {
return (artistes.value || []).map((artiste) => ({
...artiste,
image: getArtisteImage(artiste),
postesLabel: getPostesLabel(artiste),
}))
})
const postesDirection = [
"direction",
"cheffe assistante",
"chef assistante",
]
const artistesDirection = computed(() =>
artistesDisplay.value.filter((a) => isDirectionArtist(a))
)
const artistesAutres = computed(() =>
artistesDisplay.value.filter((a) => !isDirectionArtist(a))
)
function getArtisteImage(artiste) {
const media = artiste?.image_illustration_artiste_ondif
const rows = extractStrapiList(media)
if (rows.length) return rows[0]
if (media && typeof media === "object" && media.url) return media
return null
}
function getPostesLabel(artiste) {
const postes = extractStrapiList(artiste?.postes_artiste_ondif)
return postes
.map((p) => p?.nom_poste)
.filter(Boolean)
.join(", ")
}
function isDirectionArtist(artiste) {
const postes = extractStrapiList(artiste?.postes_artiste_ondif)
.map((p) => String(p?.nom_poste || "").trim().toLowerCase())
.filter(Boolean)
return postes.some((poste) => postesDirection.includes(poste))
}
function extractStrapiList(value) {
if (!value) return []
if (Array.isArray(value)) return value.map(normalizeStrapiItem).filter(Boolean)
if (value?.data) {
const rows = Array.isArray(value.data) ? value.data : [value.data]
return rows.map(normalizeStrapiItem).filter(Boolean)
}
if (typeof value === "object") return [normalizeStrapiItem(value)].filter(Boolean)
return []
}
function normalizeStrapiItem(item) {
if (!item || typeof item !== "object") return null
if (item.attributes && typeof item.attributes === "object") {
return { id: item.id, ...item.attributes }
}
return item
}
</script>
<style>
<style lang="scss">
</style>
.remonter_artistes_list {
transform: translateY(-90px);
}
.theme_bandeau--grid {
> .page-section--inner {
padding-top: 70px;
padding-bottom: 150px;
display: flex;
flex-wrap: wrap;
column-gap: 120px;
row-gap: 30px;
}
&--left {
max-width: 40%;
h1 {
padding-bottom: 20px;
}
}
&--right {
max-width: 60%;
&--text {
max-width: 500px;
}
}
}
.musiciens_list_wp {
// parce que le bloc du dessus à un transform: translateY(-170px); alors cela laisse un espace vide que l'on comble avec ce margin-top négatif
margin-top: -120px;
}
.musiciens_list {
display: grid;
grid-template-columns: repeat(3, minmax(0, 1fr));
gap: 28px;
}
.musicien_card {
display: flex;
flex-direction: column;
gap: 10px;
}
.musicien_card_nom {
margin-top: 8px;
margin-left: 5px;
&:hover {
color: var(--c-brand_rouge);
}
}
.musicien_card_postes {
margin-left: 5px;
text-transform: lowercase;
&::first-letter {
text-transform: uppercase;
}
}
@media (max-width: 980px) {
.musiciens_list {
grid-template-columns: repeat(2, minmax(0, 1fr));
}
}
@media (max-width: 400px) {
.musiciens_list {
grid-template-columns: 1fr;
padding-left: 5px;
padding-right: 5px;
}
}
@media (max-width: 600px) {
.musiciens_list {
padding-left: 5px;
padding-right: 5px;
}
}
</style>