Files
wondif_vue/app/pages/orchestre/discographie.vue
2026-06-14 16:11:51 +02:00

268 lines
9.9 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<div>
<!-- ================== -->
<!-- EN-tête Fond noir -->
<!-- ================== -->
<PageSection tone="dark" content-size="default" class="theme_bandeau--grid">
<div>
<SectionContent pad="xs" class="">
<SectionTitle tone="invert" pad="">
DISCOGRAPHIE
</SectionTitle>
<DsHeading as="h3" tone="invert" class="max-w-[500px]">
Collection Orchestre national dÎle-de-France chez NoMadMusic
</DsHeading>
</SectionContent>
<SectionContent pad="xs" class="">
<DsText tone="invert" size="lg" align="justify" class="theme_bandeau--grid--right--text" >
Cest en 2016 que naît la collaboration fructueuse entre lOrchestre national dÎle-de-France et linnovant label NoMad Music. Depuis nombre denregistrements salués par la critique sont parus parmi lesquels Bel canto amore mio (2016), un album consacré à Manuel De Falla (2017), La Bien-Aimée de Darius Milhaud et LOiseau de feu dIgor Stravinski (2018), Ludwig, un album consacré à Beethoven avec le pianiste Cédric Tiberghien (2018) et un autre dédié à Gustav Mahler avec le baryton Markus Werba (2019). Sont parus en janvier 2021 deux enregistrements sous la direction de Case Scaglione : la Symphonie n°3 « Eroica » de Beethoven et un disque Wagner avec la mezzo Michelle DeYoung et le ténor Simon ONeil.
</DsText>
</SectionContent>
<SectionContent pad="xs" class="">
<DsHeading as="h3" tone="invert">
Collection Solo chez NoMadMusic
</DsHeading>
</SectionContent>
<SectionContent pad="xs" class="">
<DsText tone="invert" size="lg" align="justify" class="theme_bandeau--grid--right--text" >
Solo, la collection discographique créée par lOrchestre national dÎle-de-France, a pour vocation de mettre en valeur la richesse des individualités artistiques qui composent lOrchestre. Au travers de différents enregistrements, à raison dun à deux par saison, des musiciennes et musiciens de lOrchestre peuvent ainsi se produire en solo, en duo ou en petit effectif de musique de chambre et présenter des répertoires variés.
</DsText>
</SectionContent>
</div>
</PageSection>
<!-- ================== -->
<!-- Listes des Disques -->
<!-- ================== -->
<PageSection padded_size="md" content-size="default" class="pl-2 pr-2">
<SectionContent v-if="pending">
<DsText>Chargement des disques...</DsText>
</SectionContent>
<SectionContent v-else-if="error">
<DsText>Impossible de charger les disques pour le moment.</DsText>
</SectionContent>
<SectionContent v-else>
<section
v-for="collection in disquesParCollection"
:key="collection.nom"
class="discographie-collection"
>
<div class="flex items-center gap-4 mb-8">
<h3 class="text-2xl font-bold tracking-tight uppercase">{{ collection.nom }}</h3>
<div class="h-[2px] flex-1 bg-surface-container"></div>
</div>
<div class="flex justify-center">
<section class="flex flex-wrap gap-y-12 gap-x-6 xl:gap-8 2xl:gap-16 mb-16 w-full max-w-[88rem]">
<article
v-for="disque in collection.disques"
:key="disque.id"
class="discographie-disque w-full overflow-hidden rounded-md bg-white shadow-lg xm:max-w-[258px] sm:max-w-[278px] md:max-w-[310px] lg:max-w-[300px] xl:max-w-[345px] 2xl:max-w-[380px]"
>
<div class="relative flex aspect-[3/2] bg-surface-container-low">
<div class="w-[68%] bg-surface-container-lowest">
<img
v-if="disque.illustration"
:src="disque.illustration.url"
:alt="disque.illustration.alternativeText"
class="h-full w-full object-cover"
loading="lazy"
decoding="async"
>
</div>
<div class="discographie-disque__vinyl relative flex-1 bg-[#070707]">
<span
v-if="disque.sortie"
class="absolute right-4 top-4 rounded bg-[#fff3f3] px-2.5 py-1 text-sm font-extrabold text-[#d81938]"
>
{{ disque.sortie }}
</span>
</div>
</div>
<div class="p-5">
<h4 class="mb-1 text-2xl font-extrabold uppercase leading-tight">
{{ disque.titre }}
</h4>
<div v-if="disque.distribution.length" class="discographie-disque__meta mb-4 text-base leading-relaxed">
<StrapiBlocksConvert :blocks="disque.distribution" />
</div>
<div v-if="disque.compositeurs.length" class="discographie-disque__meta mb-5 text-base leading-relaxed">
<StrapiBlocksConvert :blocks="disque.compositeurs" />
</div>
<p v-if="disque.descriptionText" class="mb-5 text-base leading-relaxed">
{{ disque.descriptionText }}
</p>
<a
v-if="disque.lienNomadMusic"
:href="disque.lienNomadMusic"
target="_blank"
rel="noopener noreferrer"
class="flex w-full items-center justify-center gap-3 rounded-md bg-[#E20018] px-5 py-3 text-base font-extrabold text-white transition-colors hover:bg-[#e3061391]"
>
<span class="grid h-4 w-4 place-items-center rounded-full border border-white/80 text-[9px] leading-none">
</span>
<span>NoMadMusic</span>
</a>
<a
v-if="disque.lienAutre"
:href="disque.lienAutre"
target="_blank"
rel="noopener noreferrer"
class="flex w-full items-center justify-center gap-3 rounded-md bg-[#E20018] px-5 py-3 text-base font-extrabold text-white transition-colors hover:bg-[#e3061391]"
>
<span class="grid h-4 w-4 place-items-center rounded-full border border-white/80 text-[9px] leading-none">
</span>
<span>En savoir plus</span>
</a>
</div>
</article>
</section>
</div>
</section>
</SectionContent>
</PageSection>
</div>
</template>
<script setup>
import DsHeading from '@root/design-system/primitives/DsHeading.vue'
import DsText from '@root/design-system/primitives/DsText.vue'
const { items: disquesItems, pending, error } = useStrapi(
"/api/__strapi__/disques",
{
locale: "fr-FR",
sort: "ordre_disque:asc",
fetchAll: true,
populate: {
illustration_disque: true,
},
}
)
const disques = computed(() => {
return disquesItems.value
.map(normalizeDisque)
.sort((a, b) => {
if (a.ordre !== b.ordre) return a.ordre - b.ordre
return a.titre.localeCompare(b.titre, "fr-FR")
})
})
const disquesParCollection = computed(() => {
const collections = new Map()
for (const disque of disques.value) {
const nom = disque.collection || "Autres disques"
if (!collections.has(nom)) {
collections.set(nom, {
nom,
disques: [],
})
}
collections.get(nom).disques.push(disque)
}
return Array.from(collections.values())
})
function normalizeDisque(item) {
return {
id: item.documentId || item.id,
titre: item.titre_disque || "",
collection: item.collection_disque || "",
sortie: item.sortie_disque || "",
distribution: normalizeBlocks(item.distribution_disque),
compositeurs: normalizeBlocks(item.compositeurs_disque),
description: normalizeBlocks(item.description_disque),
descriptionText: blocksToPlainText(item.description_disque),
lienNomadMusic: item.lien_nomadmusic || "",
lienAutre: item.lien_autre || "",
ordre: Number(item.ordre_disque ?? Number.MAX_SAFE_INTEGER),
illustration: normalizeStrapiMedia(item.illustration_disque),
}
}
function normalizeBlocks(blocks) {
return Array.isArray(blocks) ? blocks : []
}
function getFirstBlockLine(blocks) {
const text = blocksToPlainText(blocks)
return text.split("\n").map((line) => line.trim()).find(Boolean) || ""
}
function blocksToPlainText(blocks) {
if (!Array.isArray(blocks)) return ""
return blocks
.map((block) => blockToPlainText(block))
.filter(Boolean)
.join("\n")
.trim()
}
function blockToPlainText(block) {
if (!block || typeof block !== "object") return ""
if (Array.isArray(block.children)) {
return block.children.map(blockToPlainText).join("")
}
return typeof block.text === "string" ? block.text : ""
}
function normalizeStrapiMedia(media) {
if (!media?.url) return null
return {
id: media.id || media.documentId || media.url,
url: media.url,
alternativeText: media.alternativeText || media.caption || "",
}
}
</script>
<style lang="scss">
.discographie-disque {
&__vinyl::before {
content: "";
position: absolute;
inset: 0;
background:
repeating-radial-gradient(
circle at -18% 50%,
rgba(255, 255, 255, 0.13) 0,
rgba(255, 255, 255, 0.13) 1px,
transparent 1px,
transparent 15px
);
opacity: 0.35;
}
&__meta {
.strapi-blocks {
display: grid;
gap: 2px;
}
.strapi-blocks--p {
margin: 0;
}
}
}
</style>