@@ -0,0 +1,756 @@
< template >
< div class = "parc-page" >
<!-- === === === === === === -- >
<!-- FILS D 'ARIANE -->
<!-- ================== -->
<PageSection tone="" content-size="default" class="breadcrum_wp">
<Breadcrumb/>
</PageSection>
<!-- ================== -->
<!-- EN-TêTE -->
<!-- ================== -->
<section class="fiche_header_simple_wp">
<div class="fiche_header_wp_gauche"></div>
<div class="fiche_header_inner">
<div class="fiche_header_titres">
<div>
<DsHeading as="h1" tone="default" textcase="uppercase" class="concert-card__title">
{{ parc_contenus?.header_titre }}
</DsHeading>
</div>
<DsText as="p" align="justify">
{{ parc_contenus?.header_text }}
</DsText>
</div>
<div class="fiche_header_img">
<DsMedia
v-if="parc_contenus?.image_illustration_header?.url"
:src="parc_contenus.image_illustration_header.url"
:alt="parc_contenus.image_illustration_header.alternativeText || ' '"
fit="contain"
ratio="square"
/>
<div v-else class="img_placeholder" aria-hidden="true" />
</div>
</div>
<div class="fiche_header_wp_droite"></div>
</section>
<!-- ================== -->
<!-- DESCRIPTION -->
<!-- ================== -->
<PageSection tone="" content-size="default" padded_size="md" class="fiche_description">
<SectionContent v-if="parc_contenus?.description_generale" class="description_wp">
<StrapiBlocksConvert :blocks="parc_contenus.description_generale" />
</SectionContent>
</PageSection>
<!-- ================== -->
<!-- LES INSTRUMENTS -->
<!-- ================== -->
<PageSection :content="false" padded_size="md">
<Decalage
tone="dark"
title-tone="invert"
position="left"
button-tone="invert"
ensavoirplus-target="texte_cache_1"
ensavoirplus-group="parc-details"
>
<template #title>
LES INSTRUMENTS
</template>
<DsText as="p" tone="invert" align="justify">
Découvrer les 3 000 instruments à la location
</DsText>
</Decalage>
</PageSection>
<PageSection
id="texte_cache_1"
data-ensavoirplus-group="parc-details"
tone=""
content-size="default"
padded_size=""
class="decalage_ensavoirplus--hidden"
>
<div>
<!-- PDF -->
<a
v-if="parc_contenus?.documents?.[0]?.url"
:href="parc_contenus.documents[0].url"
:download="parc_contenus.documents[0].name || true"
class="flex items-center gap-2 px-6 py-2 max-w-[334px] bg-primary-container text-on-primary-container rounded-full font-bold text-sm hover:bg-primary-fixed"
target="_blank"
rel="noopener noreferrer"
>
<span class="material-symbols-outlined text-lg">picture_as_pdf</span>
CATALOGUE DU PARC
<span v-if="parc_contenus.documents[0].size">
(PDF • {{ formatKoToMo(parc_contenus.documents[0].size) }})
</span>
</a>
</div>
<!-- PAR CATEGORIES -->
<section class="space-y-12 mt-16">
<div
v-for="categorie in instruments_categories"
:key="categorie.id"
class="space-y-4"
>
<div class="flex items-center gap-4">
<h3 v-if="categorie.nom_categorie" class="text-2xl font-bold tracking-tight">
{{ categorie.nom_categorie }}
</h3>
<div class="h-[2px] flex-1 bg-surface-container"></div>
</div>
<div class="space-y-4">
<div
class="bg-surface-container-lowest rounded-xl p-8 hover:shadow-xl transition-shadow border border-outline-variant/10"
>
<div class="flex flex-col lg:flex-row gap-8">
<div class="border-surface-container pl-8 grid grid-cols-2 md:grid-cols-5 gap-6 items-start">
<div
v-for="instrument in categorie.instruments_list || []"
:key="instrument.id"
class="flex flex-col gap-3 group"
>
<div class="w-full aspect-[1/1] bg-surface-container-low rounded-lg flex items-center justify-center group-hover:bg-primary-container transition-colors">
<img
v-if="instrument.illustration_instrument?.url"
:src="instrument.illustration_instrument.url"
:alt="instrument.illustration_instrument.alternativeText || instrument.illustration_instrument.caption || instrument.illustration_instrument.name || ' '"
class="w-full aspect-[1/1] object-contain rounded-lg"
>
</div>
<div class="text-center">
<p v-if="instrument.instrument_nom" class="text-xs font-bold uppercase tracking-tighter">
{{ instrument.instrument_nom }}
</p>
</div>
<button
type="button"
class="px-3 py-1.5 bg-surface-container-low text-on-surface-variant rounded-full text-sm font-medium hover:bg-primary-container hover:text-primary transition-colors"
@click="toggleInstrumentDescription(instrument.id)"
>
En savoir plus
</button>
<div v-if="openedInstrumentDescriptions[instrument.id]" class="text-center">
<StrapiBlocksConvert
v-if="instrument.instrument_description"
:blocks="instrument.instrument_description"
/>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</section>
</PageSection>
<!-- ================== -->
<!-- DEVIS -->
<!-- ================== -->
<PageSection :content="false">
<Decalage
tone="brand"
title-tone="invert"
position="right"
button-tone="invert"
ensavoirplus-target="texte_cache_3"
ensavoirplus-group="parc-details"
>
<template #title>
Devis
</template>
<DsText as="p" tone="invert" align="justify">
Formulaire de demande de devis ou d' information sur la location de matériel ou sur l 'organisation d' un événement en salle d 'activités
</DsText>
</Decalage>
</PageSection>
<PageSection
id="texte_cache_3"
data-ensavoirplus-group="parc-details"
tone=""
content-size="default"
padded_size=""
class="mt-16 mb-16 decalage_ensavoirplus--hidden"
>
<div class="fiche_description">
<div class="w-full max-w-3xl rounded-2xl border border-outline-variant/20 bg-surface-container-lowest p-8 shadow-sm">
<div class="mb-8">
<h3 class="text-2xl font-bold tracking-tight">Faire une demande</h3>
<p class="mt-2 text-sm text-on-surface-variant">
Remplissez ce formulaire pour une demande de devis ou d' information . Les champs marqués d ’ un astérisque sont obligatoires .
< / p >
< / div >
< form class = "space-y-6" @submit.prevent ="submitQuoteRequest" >
< div class = "grid grid-cols-1 md:grid-cols-2 gap-6" >
< div class = "space-y-2" >
< label for = "quote-request-type" class = "block text-sm font-medium text-on-surface" >
Type de demande *
< / label >
< select
id = "quote-request-type"
v-model = "quoteForm.requestType"
class = "w-full rounded-xl border border-outline-variant/30 bg-white px-4 py-3 text-sm text-on-surface outline-none transition-colors focus:border-primary"
>
< option value = "" > Choisir un type < / option >
< option value = "location-materiel" > Location de matériel < / option >
< option value = "organisation-salle-activites" > Organisation d ’ un événement en salle d ’ activités < / option >
< / select >
< p v-if = "quoteFormErrors.requestType" class="text-xs text-error" > {{ quoteFormErrors.requestType }} < / p >
< / div >
< div class = "space-y-2" >
< label for = "quote-name" class = "block text-sm font-medium text-on-surface" >
Nom complet *
< / label >
< input
id = "quote-name"
v -model .trim = " quoteForm.name "
type = "text"
class = "w-full rounded-xl border border-outline-variant/30 bg-white px-4 py-3 text-sm text-on-surface outline-none transition-colors focus:border-primary"
placeholder = "Votre nom et prénom"
>
< p v-if = "quoteFormErrors.name" class="text-xs text-error" > {{ quoteFormErrors.name }} < / p >
< / div >
< div class = "space-y-2" >
< label for = "quote-email" class = "block text-sm font-medium text-on-surface" >
Email *
< / label >
< input
id = "quote-email"
v -model .trim = " quoteForm.email "
type = "email"
class = "w-full rounded-xl border border-outline-variant/30 bg-white px-4 py-3 text-sm text-on-surface outline-none transition-colors focus:border-primary"
placeholder = "nom@exemple.fr"
>
< p v-if = "quoteFormErrors.email" class="text-xs text-error" > {{ quoteFormErrors.email }} < / p >
< / div >
< div class = "space-y-2" >
< label for = "quote-phone" class = "block text-sm font-medium text-on-surface" >
Téléphone *
< / label >
< input
id = "quote-phone"
v -model .trim = " quoteForm.phone "
type = "tel"
class = "w-full rounded-xl border border-outline-variant/30 bg-white px-4 py-3 text-sm text-on-surface outline-none transition-colors focus:border-primary"
placeholder = "06 00 00 00 00"
>
< p v-if = "quoteFormErrors.phone" class="text-xs text-error" > {{ quoteFormErrors.phone }} < / p >
< / div >
< div class = "space-y-2" >
< label for = "quote-organisation" class = "block text-sm font-medium text-on-surface" >
Structure / organisme *
< / label >
< input
id = "quote-organisation"
v -model .trim = " quoteForm.organization "
type = "text"
class = "w-full rounded-xl border border-outline-variant/30 bg-white px-4 py-3 text-sm text-on-surface outline-none transition-colors focus:border-primary"
placeholder = "Nom de votre structure"
>
< p v-if = "quoteFormErrors.organization" class="text-xs text-error" > {{ quoteFormErrors.organization }} < / p >
< / div >
< / div >
< div class = "space-y-2" >
< label for = "quote-message" class = "block text-sm font-medium text-on-surface" >
Message *
< / label >
< textarea
id = "quote-message"
v -model .trim = " quoteForm.message "
rows = "6"
class = "w-full rounded-xl border border-outline-variant/30 bg-white px-4 py-3 text-sm text-on-surface outline-none transition-colors focus:border-primary"
placeholder = "Précisez votre besoin, les dates, le matériel ou l’ événement concerné."
> < / textarea >
< p v-if = "quoteFormErrors.message" class="text-xs text-error" > {{ quoteFormErrors.message }} < / p >
< / div >
< div v-if = "quoteSubmitError" class="rounded-xl border border-error/20 bg-error-container/20 px-4 py-3 text-sm text-error" >
{{ quoteSubmitError }}
< / div >
< div v-if = "quoteSubmitSuccess" class="rounded-xl border border-primary/20 bg-primary-container/40 px-4 py-3 text-sm text-on-surface" >
< span v-if = "quoteEmailsSent" > Votre demande a bien été envoyée. Un email de confirmation vous a été adressé. < / span >
< span v-else > Votre demande a bien été enregistrée et transmise à l ’ équipe du Parc. < / span >
< / div >
< div class = "flex items-center gap-4" >
< button
type = "submit"
class = "inline-flex items-center justify-center rounded-full bg-primary px-6 py-3 text-sm font-bold text-on-primary transition-colors hover:bg-primary-dim disabled:cursor-not-allowed disabled:opacity-60"
:disabled = "quoteSubmitting"
>
{ { quoteSubmitting ? 'Envoi en cours...' : 'Envoyer la demande' } }
< / button >
< p class = "text-xs text-on-surface-variant" >
En soumettant ce formulaire , j ’ accepte que les informations saisies soient utilisées dans le cadre de la demande de devis ou d ’ information .
< / p >
< / div >
< / form >
< / div >
< / div >
< / PageSection >
<!-- === === === === === === -- >
<!-- INFOS PRATIQUES -- >
<!-- === === === === === === -- >
< PageSection :content = "false" >
< Decalage tone = "brandreverse" title -tone = " invert " position = "left" button -tone = " invert " ensavoirplus -target = " texte_cache_2 "
ensavoirplus -group = " parc -details " >
< template # title >
Infos pratiques
< / template >
< DsText tone = "invert" as = "p" align = "justify" >
Accès au parc instrumental de l ’ Orchestre national d ’ Île - de - France
< / DsText >
< / Decalage >
< / PageSection >
<!-- === === === === === === -- >
<!-- INFOS PRATIQUES -- >
<!-- PARTIE CACHÉE -- >
<!-- === === === === === === -- >
< div id = "texte_cache_2" data -ensavoirplus -group = " parc -details " class = "decalage_ensavoirplus--hidden" >
< PageSection tone = "" content -size = " default " padded_size = "md" >
< SectionContent class = "fiche_description strapi-blocks" >
< div class = "" >
< h1 > Horaires < / h1 >
< p > De 9 h30 à 12 h et de 14 h à 18 h < / p >
< p > Du lundi au vendredi < / p >
< p > < strong > Uniquement sur rendez - vous < / strong > < / p >
< / div >
< / SectionContent >
< / PageSection >
< PageSection tone = "" content -size = " default " padded_size = "md" >
< SectionContent class = "fiche_description strapi-blocks" >
< div >
< div class = "mb-8" > < iframe src = "https://maps.google.com/maps?width=781&height=538&hl=en&q=1,%20rue%20du%20Capitaine%20Alfred-Dreyfus%20Alfortvillle+(Parc%20instrumental)&t=&z=14&ie=UTF8&iwloc=B&output=embed" width = "600" height = "450" style = "border:0;" allowfullscreen = "" loading = "lazy" referrerpolicy = "no-referrer-when-downgrade" > < / iframe > < / div >
< div >
< h1 > Comment venir ? < / h1 >
< h2 > Accès pour le transport d ’ instruments < / h2 >
< p > Depuis le 1 , rue du Capitaine Alfred - Dreyfus , 94140 Alfortville < / p >
< ul >
< li > Contourner le corps de bâtiment de droite en passant par la circulation du Centre technique municipal . < / li >
< li > Stationner sur le parking du Parc instrumental . < / li >
< / ul >
< section class = "img-gallery_wp" >
< div class = "img-gallery" >
< div class = "ds-media ds-media--" >
< img class = "ds-media__img ds-media__img--cover" src = "/img/photos/acces1.jpg" alt = "" loading = "lazy" decoding = "async" >
< / div >
< / div >
< / section >
< h2 > Accès Évènement public < / h2 >
< p > Rendez - vous au 9 , allée Jean - Baptiste Preux . < / p >
< ul >
< li > Accès au parking par le grand portail coulissant . < / li >
< li > Suivre le cheminement jusqu ’ à la salle d ’ activités . < / li >
< / ul >
< section class = "img-gallery_wp" >
< div class = "img-gallery" >
< div class = "ds-media ds-media--" >
< img class = "ds-media__img ds-media__img--cover" src = "/img/photos/acces2.jpg" alt = "" loading = "lazy" decoding = "async" >
< / div >
< / div >
< / section >
< / div >
< / div >
< / SectionContent >
< / PageSection >
< / div >
<!-- === === === === === === -- >
<!-- CONTACT -- >
<!-- === === === === === === -- >
< PageSection tone = "" content -size = " default " padded_size = "md" class = "contact_spe_wp" >
< ContactSpecifique
titre = "Contacter les régisseurs"
nom = "Stéphane Borsellino / Stéphane Nguyen Phu Khai"
poste = ""
numero = "01 88 15 00 80"
mail = "leparcinstrumental@orchestre-ile.com"
adresse = "1, rue du Capitaine Alfred-Dreyfus 94 140 Alfortvillle"
/ >
< / PageSection >
<!-- === === === === === === -- >
<!-- L 'ORCHESTRE POUR LES PROS -->
<!-- ================== -->
<PageSection padded_size="lg">
<SectionContent>
<SectionTitle tone="" pad="xs">
L' ORCHESTRE POUR LES PROS
< / SectionTitle >
< / SectionContent >
< SectionContent >
< BannierePros / >
< / SectionContent >
< / PageSection >
< / div >
< / template >
< 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'
import DsButton from '@root/design-system/primitives/DsButton.vue'
import logoparc from '/img/logos/logo_le_parc_noir.png'
import catalogue _parc from '/contenus/catalogue-du-parc-instrumental.pdf'
useHead ( {
link : [
{
rel : 'preconnect' ,
href : 'https://fonts.googleapis.com' ,
} ,
{
rel : 'preconnect' ,
href : 'https://fonts.gstatic.com' ,
crossorigin : '' ,
} ,
{
rel : 'stylesheet' ,
href : 'https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;800&display=swap' ,
} ,
{
rel : 'stylesheet' ,
href : 'https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:wght,FILL@100..700,0..1&display=swap' ,
} ,
] ,
} )
//--------------------
// RÉCUPÉRATION DES DONNÉES STRAPI
//--------------------
const parc _strapi = ref ( {
data : {
id : 1 ,
documentId : "parc123456" ,
header _titre : "Un parc riche de plus de 3 000 instruments à la location" ,
header _text : "" ,
image _illustration _header : {
id : 301 ,
documentId : "img123456" ,
name : "parc_header.jpg" ,
alternativeText : "Vue du parc instrumental de l'Orchestre" ,
caption : "Parc instrumental" ,
width : 1600 ,
height : 900 ,
formats : {
thumbnail : {
url : "/"
}
} ,
ext : ".jpg" ,
mime : "image/jpeg" ,
size : 245.8 ,
url : logoparc
} ,
"description_generale" : [
{
"type" : "paragraph" ,
"children" : [
{
"text" : "Le Parc instrumental de l’ Orchestre, dont la mission principale est de faciliter les manifestations musicales en Île-de-France, dispose d’ un catalogue de plus de 3 000 instruments et contribue à plus de 500 manifestations par an (concerts, répétitions, cours, masterclasses...)." ,
"type" : "text"
}
]
} ,
{
"type" : "paragraph" ,
"children" : [
{
"text" : "Il s’ adresse aux municipalités, communautés d’ agglomération, communautés de communes, conservatoires et écoles de musique, ensembles instrumentaux ou vocaux professionnels ou amateurs, organisateurs de concerts (théâtre, festival, association...), structures culturelles ainsi qu’ aux particuliers." ,
"type" : "text"
}
]
} ,
{
"type" : "paragraph" ,
"children" : [
{
"text" : "Situé dans un local industriel, sur 2 niveaux, il offre un espace total de 650m2 dont 400m2 dévolus au stockage des 3 000 instruments." ,
"type" : "text"
}
]
} ,
{
"type" : "paragraph" ,
"children" : [
{
"text" : " Une salle polyvalente dédiée aux activités permet de recevoir des groupes pour de multiples actions culturelles." ,
"type" : "text"
}
]
}
] ,
"documents" : [
{
"id" : 246 ,
"documentId" : "h38c6ppljk084pdgnngcbe0b" ,
"name" : "catalogue-du-parc-instrumental" ,
"alternativeText" : "catalogue-du-parc-instrumental" ,
"caption" : "Catalogue du Parc" ,
"width" : null ,
"height" : null ,
"formats" : null ,
"hash" : "catalogue-du-parc-instrumental" ,
"ext" : ".pdf" ,
"mime" : "application/vnd.openxmlformats-officedocument.wordprocessingml.document" ,
"size" : 2065.92 ,
"url" : catalogue _parc ,
"previewUrl" : null ,
"provider" : "aws-s3" ,
"provider_metadata" : null ,
"createdAt" : "2026-04-20T09:04:05.924Z" ,
"updatedAt" : "2026-04-20T09:04:39.849Z" ,
"publishedAt" : "2026-04-20T09:04:05.924Z" ,
"focalPoint" : null
} ,
]
} ,
meta : { }
} )
const parc _contenus = computed ( ( ) => parc _strapi . value ? . data || null )
const endpointInstruments = "/api/__strapi__/instruments"
const populateInstruments = {
illustration _instrument : true ,
}
const { items : instrumentsItems , refresh : refreshInstruments } = useStrapi (
endpointInstruments ,
{
locale : "fr-FR" ,
populate : populateInstruments ,
pageSize : 500 ,
}
)
onMounted ( ( ) => {
if ( ! instrumentsItems . value ? . length ) {
refreshInstruments ( )
}
} )
const instruments _categories = computed ( ( ) => {
const groups = new Map ( )
for ( const instrument of instrumentsItems . value || [ ] ) {
const categoryName = instrument . instrument _categorie || "Sans catégorie"
if ( ! groups . has ( categoryName ) ) {
groups . set ( categoryName , {
id : categoryName ,
nom _categorie : categoryName ,
instruments _list : [ ] ,
} )
}
groups . get ( categoryName ) . instruments _list . push ( instrument )
}
return Array . from ( groups . values ( ) )
} )
const openedInstrumentDescriptions = ref ( { } )
const quoteForm = reactive ( {
requestType : "" ,
name : "" ,
email : "" ,
phone : "" ,
organization : "" ,
message : "" ,
} )
const quoteFormErrors = reactive ( {
requestType : "" ,
name : "" ,
email : "" ,
phone : "" ,
organization : "" ,
message : "" ,
} )
const quoteSubmitting = ref ( false )
const quoteSubmitSuccess = ref ( false )
const quoteSubmitError = ref ( "" )
const quoteEmailsSent = ref ( false )
function toggleInstrumentDescription ( instrumentId ) {
openedInstrumentDescriptions . value [ instrumentId ] = ! openedInstrumentDescriptions . value [ instrumentId ]
}
function resetQuoteFormErrors ( ) {
quoteFormErrors . requestType = ""
quoteFormErrors . name = ""
quoteFormErrors . email = ""
quoteFormErrors . phone = ""
quoteFormErrors . organization = ""
quoteFormErrors . message = ""
}
function validateQuoteForm ( ) {
resetQuoteFormErrors ( )
let isValid = true
if ( ! quoteForm . requestType ) {
quoteFormErrors . requestType = "Le type de demande est obligatoire."
isValid = false
}
if ( ! quoteForm . name ) {
quoteFormErrors . name = "Le nom est obligatoire."
isValid = false
}
if ( ! quoteForm . email ) {
quoteFormErrors . email = "L’ email est obligatoire."
isValid = false
} else if ( ! /^[^\s@]+@[^\s@]+\.[^\s@]+$/ . test ( quoteForm . email ) ) {
quoteFormErrors . email = "L’ email n’ est pas valide."
isValid = false
}
if ( ! quoteForm . phone ) {
quoteFormErrors . phone = "Le téléphone est obligatoire."
isValid = false
}
if ( ! quoteForm . organization ) {
quoteFormErrors . organization = "La structure est obligatoire."
isValid = false
}
if ( ! quoteForm . message ) {
quoteFormErrors . message = "Le message est obligatoire."
isValid = false
}
return isValid
}
async function submitQuoteRequest ( ) {
quoteSubmitSuccess . value = false
quoteSubmitError . value = ""
quoteEmailsSent . value = false
if ( ! validateQuoteForm ( ) ) {
return
}
quoteSubmitting . value = true
try {
const response = await $fetch ( "/api/parc-demandes" , {
method : "POST" ,
body : {
requestType : quoteForm . requestType ,
name : quoteForm . name ,
email : quoteForm . email ,
phone : quoteForm . phone ,
organization : quoteForm . organization ,
message : quoteForm . message ,
} ,
} )
quoteSubmitSuccess . value = true
quoteEmailsSent . value = Boolean ( response ? . emailsSent )
quoteForm . requestType = ""
quoteForm . name = ""
quoteForm . email = ""
quoteForm . phone = ""
quoteForm . organization = ""
quoteForm . message = ""
resetQuoteFormErrors ( )
} catch ( error ) {
quoteSubmitError . value = error ? . data ? . statusMessage || "L’ envoi de la demande a échoué."
} finally {
quoteSubmitting . value = false
}
}
function formatKoToMo ( sizeInKo ) {
if ( typeof sizeInKo !== "number" ) return ""
return ` ${ ( sizeInKo / 1024 ) . toFixed ( 1 ) } Mo `
}
< / script >
< style lang = "scss" >
. breadcrum _wp {
padding - top : 30 px ;
}
// =======================
// SPÉCIFIQUE À CETTE PAGE
// =======================
. parc - page {
. fiche _description {
display : flex ;
justify - content : center ;
padding - top : 10 px ;
padding - bottom : 10 px ;
padding - left : 10 px ;
padding - right : 10 px ;
> * {
max - width : 640 px ;
display : flex ;
flex - direction : column ;
}
}
. contact _spe _wp {
background - color : var ( -- c - background - jaune - clair ) ;
margin - top : 50 px ;
margin - bottom : 20 px ;
}
}
< / style >