finalisation home page

This commit is contained in:
2026-02-06 20:20:01 +01:00
parent 91c1b03a2f
commit d9ac2b4cc5
45 changed files with 1892 additions and 148 deletions

View File

@@ -0,0 +1,266 @@
<!-- Utilisé pour : -->
<!-- Index.vue / Encart PROS bas de page -->
<template>
<div class="banniere_pros_wp">
<div class="studio_img">
<DsMedia src="/contenus/studio_img_1.webp" alt="Image du studio pro" ratio="16-9" />
</div>
<div class="banniere_pros--description studio_description">
<div>
<img src="/img/logos/logo_le_studio_noir.png" alt="Logo du studio pro" width="200">
</div>
<DsHeading as="h5" tone="default" class="banniere_pros--description--titre">
On enregistre au studio !
</DsHeading>
<DsText as="p" tone="default" :clamp="3">
Un grand studio modulaire ouvert à tous les professionnels aux portes de Paris
</DsText>
</div>
<div class="parc_img">
<DsMedia src="/contenus/studio_img_2.webp" alt="Image du studio pro" ratio="16-9" />
</div>
<div class="banniere_pros--description parc_description">
<div>
<img src="/img/logos/logo_le_parc_noir.png" alt="Logo du parc instrumental pro" width="150">
</div>
<DsHeading as="h5" tone="default" class="banniere_pros--description--titre">
+ de 3 000 instruments en location
</DsHeading>
<DsText as="p" tone="default" :clamp="3">
Location dinstruments de musique pour les professionnels et les amateurs
</DsText>
</div>
</div>
</template>
<script setup>
import DsMedia from '@root/design-system/primitives/DsMedia.vue'
import DsText from '@root/design-system/primitives/DsText.vue'
import DsHeading from '@root/design-system/primitives/DsHeading.vue'
</script>
<style lang="scss">
.banniere_pros_wp {
display: grid;
}
@media (max-width: 599px) {
.banniere_pros_wp {
padding-left: 10px;
}
}
@media (min-width: 500px) {
.banniere_pros_wp {
row-gap: 50px;
}
}
@media (max-width: 399px) {
.banniere_pros_wp {
grid-template-columns: 30px 240px;
grid-template-rows: 130px 60px 130px 42px 111px 70px 140px;
//justify-content: center;
.ds-media--16-9 {
aspect-ratio: 4 / 3;
}
}
}
@media (min-width: 400px) {
.banniere_pros_wp {
grid-template-columns: 80px 290px;
grid-template-rows: 150px 60px 130px 42px 170px 70px 140px;
//justify-content: center;
.ds-media--16-9 {
aspect-ratio: 4 / 3;
}
}
}
@media (min-width: 500px) {
.banniere_pros_wp {
grid-template-columns: 150px 270px 40px 40px;
grid-template-rows: auto;
//justify-content: center;
align-items: center;
.ds-media--16-9 {
aspect-ratio: 16 / 9;
}
}
}
@media (min-width: 600px) {
.banniere_pros_wp {
grid-template-columns: 220px 250px 40px 40px;
grid-template-rows: auto;
//justify-content: center;
align-items: center;
.ds-media--16-9 {
aspect-ratio: 16 / 9;
}
}
}
@media (min-width: 700px) {
.banniere_pros_wp {
grid-template-columns: 220px 250px 40px 40px;
grid-template-rows: auto;
//justify-content: center;
align-items: center;
.ds-media--16-9 {
aspect-ratio: 16 / 9;
}
}
}
@media (min-width: 800px) {
.banniere_pros_wp {
grid-template-columns: 100px 190px 20px 40px 110px 140px 160px;
grid-template-rows: auto;
align-items: center;
.ds-media--16-9 {
aspect-ratio: 4 / 3;
}
}
}
@media (min-width: 900px) {
.banniere_pros_wp {
grid-template-columns: 130px 190px 40px 30px 160px 130px 169px;
grid-template-rows: auto;
align-items: center;
.ds-media--16-9 {
aspect-ratio: 4 / 3;
}
}
}
@media (min-width: 1000px) {
.banniere_pros_wp {
grid-template-columns: 160px 200px 90px 50px 160px 150px 150px;
grid-template-rows: auto;
align-items: center;
.ds-media--16-9 {
aspect-ratio: 16 / 9;
}
}
}
@media (min-width: 1100px) {
.banniere_pros_wp {
grid-template-columns: 200px 200px 100px 50px 200px 150px 150px;
grid-template-rows: auto;
align-items: center;
.ds-media--16-9 {
aspect-ratio: 16 / 9;
}
}
}
@media (min-width: 1200px) {
.banniere_pros_wp {
grid-template-columns: 230px 200px 100px 50px 230px 150px 150px;
grid-template-rows: auto;
align-items: center;
.ds-media--16-9 {
aspect-ratio: 16 / 9;
}
}
}
@media (min-width: 1300px) {
.banniere_pros_wp {
grid-template-columns: 270px 200px 100px 50px 270px 150px 150px;
grid-template-rows: auto;
align-items: center;
.ds-media--16-9 {
aspect-ratio: 16 / 9;
}
}
}
@media (min-width: 1400px) {
.banniere_pros_wp {
grid-template-columns: 320px 200px 100px 50px 320px 150px 150px;
grid-template-rows: auto;
align-items: center;
.ds-media--16-9 {
aspect-ratio: 16 / 9;
}
}
}
/* IMAGES */
.studio_img {
grid-column: 1 / 3;
grid-row: 1;
z-index: 1;
}
@media (max-width: 499px) {
.studio_img {
grid-column: 1 / 3;
grid-row: 1/2;
z-index: 1;
}
}
.parc_img {
grid-column: 4 / 7;
grid-row: 1;
z-index: 1;
}
@media (max-width: 799px) {
.parc_img {
grid-column: 1 / 3;
grid-row: 2;
z-index: 1;
}
}
@media (max-width: 499px) {
.parc_img {
grid-column: 1 / 3;
grid-row: 5/6;
z-index: 1;
}
}
/* DESCRIPTIONS (au-dessus des images) */
.studio_description {
grid-column: 2 / 5;
grid-row: 1;
z-index: 2;
}
@media (max-width: 499px) {
.studio_description {
grid-column: 2;
grid-row: 2/4;
z-index: 2;
}
}
.parc_description {
grid-column: 6 / 8;
grid-row: 1;
z-index: 2;
}
@media (max-width: 799px) {
.parc_description {
grid-column: 2 / 5;
grid-row: 2;
z-index: 2;
}
}
@media (max-width: 499px) {
.parc_description {
grid-column: 2;
grid-row: 6/8;
z-index: 2;
}
}
.banniere_pros--description {
background-color: var(--c-background-blanc-casse);
padding: 17px;
max-height: 170px;
&--titre {
font-size: 18px;
}
}
</style>

View File

@@ -0,0 +1,242 @@
<!-- Utilisé pour : -->
<!-- Index.vue / Tous à l'orchestre -->
<!-- Permet de filtrer des contenus grâce à des boutons -->
<template>
<!-- FILTRES -->
<SectionContent pad="xs" class="theme_tao--filters" role="tablist">
<DsButton
v-for="f in filters"
:key="f.key"
textColor="invert"
size="aplati"
borderColor="invert"
:aria-pressed="activeFilter === f.key"
:class="{ 'is-active': activeFilter === f.key }"
@click="activeFilter = f.key"
>
{{ f.label }}
</DsButton>
</SectionContent>
<!-- CARTES HORIZONTALES -->
<SectionContent class="theme_tao--cardlist">
<HorizontalCards
aria-label="Posts Instagram ONDIF"
hint-key="tao-cardlist-hint-seen"
:peek="30"
:fade-width="64"
:reset-key="activeFilter"
reset-behavior="smooth"
:reset-delay-ms="0"
>
<DsCard
v-for="card in filteredCards"
:key="card.id"
class="theme_tao--cardlist--card"
>
<div class="theme_tao--cardlist--card--wp">
<!-- Image -->
<div class="theme_tao--cardlist--card--img">
<NuxtImg :src="card.imgSrc" :alt="card.imgAlt" />
</div>
<!-- Content -->
<div class="theme_tao--cardlist--card--content">
<DsHeading as="h5" tone="default">
{{ card.title }}
</DsHeading>
<DsText as="p" tone="default" :clamp="6">
<span v-html="card.descriptionHtml" />
</DsText>
</div>
</div>
</DsCard>
</HorizontalCards>
</SectionContent>
</template>
<script setup>
import { ref, computed, watch, nextTick } from 'vue'
import DsCard from '@root/design-system/components/DsCard.vue'
import DsHeading from '@root/design-system/primitives/DsHeading.vue'
import DsButton from '@root/design-system/primitives/DsButton.vue'
import SectionContent from '../components/section/SectionContent.vue'
import DsText from '@root/design-system/primitives/DsText.vue'
//--------------------------------------------------------------------------
// Filtres
//--------------------------------------------------------------------------
// Variable qui contient les catégories qui permettront de filtrer
const filters = [
{ key: 'famille', label: 'Famille' },
{ key: 'lieux', label: 'Lieux' },
{ key: 'ateliers', label: 'Ateliers' },
{ key: 'musique', label: 'Musique' },
]
// variable pour donner le filtre actif
// filtre par défaut : le premier
const activeFilter = ref(filters[0].key)
//--------------------------------------------------------------------------
// CONTENUS DES CARTES
//--------------------------------------------------------------------------
const cards = ref([
{
id: 'insta-1',
imgSrc: '/contenus/insta_ondif_1.jpg',
imgAlt: 'le titre du post',
title: "[Y'A PAS QUE LES ÂNES QUI MANGENT DU SON]",
descriptionHtml: `Tu as moins de 28 ans ? Paie 6 € la place dès 3 concerts de lOrchestre à la Philharmonie de Paris<br>
🔴 Ile de France | Ministère de la culture<br>
🎨 Agence belleville.eu`,
tags: ['musique','famille'],
},
{
id: 'insta-2',
imgSrc: '/contenus/insta_ondif_2.jpg',
imgAlt: 'le titre du post',
title: " Tous à lorchestre ! Un début de saison qui fait vibrer lOndif 🎶",
descriptionHtml: `Des lycéens conquis par Rachmaninov aux premières rencontres à Montereau, des petites oreilles émerveillées aux ateliers de Marly-la-Ville, sans oublier la musique portée jusqu'aux hôpitaux.<br>
Et plus de 250 choristes rassemblés pour le "Chantons avec" Alice Swing !<br>
Quelle énergie ❤️`,
tags: ['famille', 'ateliers', 'musique', 'lieux'],
},
{
id: 'insta-3',
imgSrc: '/contenus/insta_ondif_3.jpg',
imgAlt: 'le titre du post',
title: "L'Orchestre en résidence à Montereau",
descriptionHtml: `Notre équipe a rencontré les élèves de Montereau pour un premier atelier au Conservatoire municipal de musique Gaston Litaize`,
tags: ['lieux', 'ateliers', 'famille'],
},
{
id: 'insta-3',
imgSrc: '/contenus/insta_ondif_3.jpg',
imgAlt: 'le titre du post',
title: "L'Orchestre en résidence à Montereau",
descriptionHtml: `Notre équipe a rencontré les élèves de Montereau pour un premier atelier au Conservatoire municipal de musique Gaston Litaize`,
tags: ['lieux', 'ateliers', 'famille'],
},
{
id: 'insta-3',
imgSrc: '/contenus/insta_ondif_3.jpg',
imgAlt: 'le titre du post',
title: "L'Orchestre en résidence à Montereau",
descriptionHtml: `Notre équipe a rencontré les élèves de Montereau pour un premier atelier au Conservatoire municipal de musique Gaston Litaize`,
tags: ['lieux', 'ateliers', 'famille'],
},
{
id: 'insta-3',
imgSrc: '/contenus/insta_ondif_3.jpg',
imgAlt: 'le titre du post',
title: "L'Orchestre en résidence à Montereau",
descriptionHtml: `Notre équipe a rencontré les élèves de Montereau pour un premier atelier au Conservatoire municipal de musique Gaston Litaize`,
tags: ['lieux', 'ateliers', 'famille'],
},
])
//--------------------------------------------------------------------------
// Computed : cartes filtrées
//--------------------------------------------------------------------------
const filteredCards = computed(() => {
return cards.value.filter(card =>
card.tags.includes(activeFilter.value)
)
})
</script>
<style lang="scss">
.theme_tao {
margin-bottom: 50px;
&--description {
max-width: 800px;
}
&--txt {
margin-bottom: 35px;
}
&--filters {
display: flex;
flex-wrap: wrap;
column-gap: 10px;
row-gap: 14px;
.is-active {
background-color: var(--c-surface);
color: var(--c-backgroud-brandreverse);
}
}
&--cardlist {
margin-top: 20px;
&--card {
background-color: var(--c-surface);
border-radius: 10px;
//padding: 50px;
padding: clamp(18px, 2.4vw, 32px);
&--wp {
display: flex;
flex-direction: column;
align-items: center;
}
&--img {
max-width: 280px;
overflow: hidden;
img {
max-height: 280px;
}
@media (min-width: 400px) {
img {
max-height: 350px;
}
}
}
&--content {
max-width: 320px;
padding-top: 20px;
}
}
&--card {
/* base: mobile-first */
width: clamp(260px, 81vw, 360px);
}
@media (min-width: 400px) {
&--card {
width: clamp(260px, 80vw, 360px);
}
}
@media (min-width: 500px) {
&--card {
width: clamp(280px, 63vw, 460px);
}
}
@media (min-width: 700px) {
&--card {
width: clamp(280px, 60vw, 460px);
}
}
@media (min-width: 1024px) {
&--card {
width: clamp(320px, 33vw, 520px);
}
}
@media (min-width: 1440px) {
&--card {
width: clamp(360px, 28vw, 560px);
}
}
}
}
</style>

View File

@@ -1,6 +1,6 @@
<template>
<NewsletterCta />
<PageSection tone="brand" :padded="false" content-size="default" padt="sm" padb="sm" class="footer">
<PageSection tone="brand" content-size="default" padt="sm" padb="sm" class="footer">
<div class="footer--inner">
<SectionContent pad="xs" class="footer--logo">
<NuxtImg :src="logoDefault" :alt="brand.logoAlt" class="logo-img" />
@@ -26,19 +26,19 @@
<div class="nav--item nav--social">
<a class="social" href="...">
<NuxtImg :src="logoInstagram" alt="logo Instagram" height="37" width="37" class="social__icon" />
<NuxtImg :src="logoInstagram" alt="logo Instagram" height="30" width="30" class="social__icon" />
<span class="social__label">Instagram</span>
</a>
<a class="social" href="...">
<NuxtImg :src="logoyt" alt="logo You Tube" height="28" width="37" class="social__icon" />
<NuxtImg :src="logoyt" alt="logo You Tube" height="30" width="35" class="social__icon" />
<span class="social__label">YouTube</span>
</a>
<a class="social" href="...">
<NuxtImg :src="logofacebook" alt="logo Facebook" height="37" width="35" class="social__icon" />
<NuxtImg :src="logofacebook" alt="logo Facebook" height="30" width="28" class="social__icon" />
<span class="social__label">Facebook</span>
</a>
<a class="social" href="...">
<NuxtImg :src="logolinkedin" alt="logo LinkedIn" height="37" width="37" class="social__icon" />
<NuxtImg :src="logolinkedin" alt="logo LinkedIn" height="30" width="30" class="social__icon" />
<span class="social__label">LinkedIn</span>
</a>
@@ -51,7 +51,7 @@
</div>
</PageSection>
<PageSection :padded="false" content-size="default" padt="sm" padb="sm">
<PageSection content-size="default" padt="sm" padb="sm">
<SectionContent>
<div class="footer_logos">
<div><img class="footer_logos--img" :src="logoPrefet" height="80" alt="logo Préfet de la région d'Île-de-France" /></div>
@@ -60,7 +60,7 @@
</div>
</SectionContent>
</PageSection>
<PageSection :padded="false" content-size="default" padt="sm" padb="sm">
<PageSection content-size="default" padt="sm" padb="sm">
<SectionContent>
<div class="footer_mentions">
<div class="footer_mentions--item">© Orchestre national dÎle-de-France - 2026</div>
@@ -145,7 +145,7 @@
display: block;
padding: 4px;
border-radius: 5px;
background-color: rgb(255 255 255 / 83%);
background-color: rgb(255 255 255 / 60%);
}
}
}

View File

@@ -0,0 +1,303 @@
<!-- app/components/HorizontalCards.vue -->
<!-- Faire défiler des cartes qui se déplacent horizontalement -->
<!-- Les cartes sont dans le composant qui appelle celui-çi, donc cela vaut pour tous types de cartes-->
<template>
<!-- Root: classe is-scrolled pour piloter fade + hint -->
<div
class="hc"
:class="[
rootClass,
{ 'is-scrolled': hasScrolled }
]"
>
<!-- Optional title slot -->
<div v-if="$slots.title" class="hc__header">
<slot name="title" />
</div>
<!-- Hint icon (micro affordance) -->
<div v-if="showHint" class="hc__hint" aria-hidden="true">
<span class="hc__hint-icon">{{ hintIcon }}</span>
</div>
<div v-if="showHint" class="hc__hint--left" aria-hidden="true">
<span class="hc__hint-icon">{{ hintIcon }}</span>
</div>
<!-- Scroller -->
<div
ref="scroller"
class="hc__scroller"
:class="scrollerClass"
tabindex="0"
role="region"
:aria-label="ariaLabel"
@scroll.passive="onScroll"
>
<div class="hc__track" :class="trackClass">
<!-- Cards -->
<slot />
</div>
</div>
</div>
</template>
<script setup>
import { onMounted, onBeforeUnmount, ref, computed, watch, nextTick } from 'vue'
const props = defineProps({
ariaLabel: { type: String, default: 'Horizontal content' },
/** Active lanimation "nudge" une seule fois (localStorage) */
nudgeOnce: { type: Boolean, default: true },
hintKey: { type: String, default: 'horizontal-cards-hint-seen' },
/** Nudge settings */
nudgePx: { type: Number, default: 48 },
nudgeDelayMs: { type: Number, default: 350 },
nudgeReturnDelayMs: { type: Number, default: 450 },
/** UI affordances */
showHint: { type: Boolean, default: true },
hintIcon: { type: String, default: '⇆' },
/** Peek: % de padding-right du scroller pour montrer la carte suivante */
peek: { type: Number, default: 30 }, // 2540 conseillé
/** Fade (px) : largeur du dégradé */
fadeWidth: { type: Number, default: 64 },
/** Classes hooks */
rootClass: { type: [String, Array, Object], default: '' },
scrollerClass: { type: [String, Array, Object], default: '' },
trackClass: { type: [String, Array, Object], default: '' },
// Reset scroll (ex: changement de filtre)
resetKey: { type: [String, Number], default: null },
resetBehavior: { type: String, default: 'smooth' }, // 'smooth' ou 'auto'
resetDelayMs: { type: Number, default: 0 },
})
const scroller = ref(null)
const hasScrolled = ref(false)
let t = null
const cssVars = computed(() => ({
'--hc-peek': `${props.peek}%`,
'--hc-fade-w': `${props.fadeWidth}px`
}))
const markSeen = () => {
try { localStorage.setItem(props.hintKey, '1') } catch (_) {}
}
const isSeen = () => {
try { return localStorage.getItem(props.hintKey) === '1' } catch (_) { return true }
}
const onScroll = () => {
if (!hasScrolled.value) {
hasScrolled.value = true
markSeen()
}
if (t) clearTimeout(t)
t = setTimeout(() => {}, 80)
}
onMounted(() => {
const el = scroller.value
if (!el) return
// Inject vars on root element
// (Vue naime pas style binding + class binding sur le root via computed uniquement,
// donc on set ici pour être sûr)
el.closest('.hc')?.style?.setProperty('--hc-peek', `${props.peek}%`)
el.closest('.hc')?.style?.setProperty('--hc-fade-w', `${props.fadeWidth}px`)
if (!props.nudgeOnce) return
if (isSeen()) return
const reduce = window.matchMedia?.('(prefers-reduced-motion: reduce)')?.matches
if (reduce) return
const canScroll = el.scrollWidth > el.clientWidth + 4
if (!canScroll) return
setTimeout(() => {
el.scrollBy({ left: props.nudgePx, behavior: 'smooth' })
setTimeout(() => {
el.scrollBy({ left: -props.nudgePx, behavior: 'smooth' })
markSeen()
}, props.nudgeReturnDelayMs)
}, props.nudgeDelayMs)
})
onBeforeUnmount(() => {
if (t) clearTimeout(t)
})
// Pour revenir à la première carte sur changement de filtre
const resetToStart = async () => {
const el = scroller.value
if (!el) return
await nextTick()
// Important : si tu changes le contenu + transition, un petit délai peut aider
const run = () => el.scrollTo({ left: 0, behavior: props.resetBehavior })
if (props.resetDelayMs > 0) {
setTimeout(run, props.resetDelayMs)
} else {
run()
}
}
watch(
() => props.resetKey,
(nv, ov) => {
// si cest la première fois (ov === null) tu peux choisir de reset ou pas
if (nv === ov) return
resetToStart()
}
)
</script>
<style lang="scss">
/* ==========================================================================
HorizontalCards (no lib)
- scroll-snap
- peek (last card cut)
- fade right
- hint icon
- nudge once (JS minimal)
========================================================================== */
.hc {
position: relative;
/* Vars (fallbacks) */
--hc-peek: 30%;
--hc-fade-w: 64px;
}
/* Title slot */
.hc__header {
margin-bottom: 0.75rem;
}
/* Hint icon */
.hc__hint {
pointer-events: none;
position: absolute;
right: 10px;
top: 50%;
transform: translateY(-50%);
display: grid;
place-items: center;
width: 34px;
height: 34px;
border-radius: 999px;
background: rgba(255, 255, 255, 0.9);
box-shadow: 0 6px 18px rgba(0,0,0,0.12);
opacity: 1;
transition: opacity 180ms ease, transform 180ms ease;
z-index: 2;
}
.hc__hint--left {
pointer-events: none;
position: absolute;
left: 10px;
top: 50%;
transform: translateY(-50%);
display: grid;
place-items: center;
width: 34px;
height: 34px;
border-radius: 999px;
background: rgba(255, 255, 255, 0.9);
box-shadow: 0 6px 18px rgba(0,0,0,0.12);
opacity: 1;
transition: opacity 180ms ease, transform 180ms ease;
z-index: 2;
}
.hc__hint-icon {
font-size: 18px;
line-height: 1;
}
/* Scroller */
.hc__scroller {
overflow-x: auto;
overflow-y: hidden;
-webkit-overflow-scrolling: touch;
scroll-snap-type: x mandatory;
// Cacher la barre de défilement horizontal
/* Firefox */
scrollbar-width: none;
/* IE / Edge legacy */
-ms-overflow-style: none;
/* WebKit (Chrome, Safari, Edge Chromium) */
&::-webkit-scrollbar {
display: none;
}
/* ✅ peek */
padding: 0.25rem var(--hc-peek) 0.25rem 0;
outline: none;
/* Fade right */
&::after {
content: '';
pointer-events: none;
position: absolute;
top: 0;
right: 0;
width: var(--hc-fade-w);
height: 100%;
background: linear-gradient(
to left,
rgb(172 207 207 / 59%),
rgba(172, 207, 207, 0)
);
opacity: 1;
transition: opacity 180ms ease;
z-index: 1;
}
&:focus-visible {
outline: 2px solid currentColor;
outline-offset: 6px;
}
}
/* Track */
.hc__track {
display: flex;
flex-wrap: nowrap;
gap: 20px;
align-items: stretch;
}
/* Snap + “rail-friendly” defaults for children */
.hc__track > * {
flex: 0 0 auto;
scroll-snap-align: start;
}
/* After first scroll: calm UI */
.hc.is-scrolled {
.hc__hint, .hc__hint--left {
background: rgba(172, 207, 207, 0.9);
//opacity: 0;
transform: translateY(-50%) scale(0.96);
}
.hc__scroller::after {
opacity: 0.55;
}
}
</style>

View File

@@ -1,6 +1,6 @@
<template>
<div class="newslettercta">
<PageSection tone="brandreverse" :padded="false" content-size="default" padb="xs">
<PageSection tone="brandreverse" content-size="default" padb="xs">
<SectionTitle as="h1" tone="invert" pad="xs">
NEWSLETTER
</SectionTitle>
@@ -42,10 +42,8 @@
.newslettercta__content {
display: grid;
grid-template-columns: minmax(0, 1fr);
align-items: center;
row-gap: 15px;
column-gap: 15px;
column-gap: 25px;
padding-right: 10px;
.newslettercta__content_text {
@@ -53,12 +51,18 @@
}
.newslettercta__button {
grid-column: 1;
justify-self: start;
justify-self: center;
}
@media (min-width: 1000px) {
.newslettercta__button {
justify-self: center;
margin-top: -10px;
}
}
}
@media (max-width: 300px) {
.newslettercta__content {
padding-left: calc(var(--section-title-pl, var(--sp-45)) - 20px);
padding-left: calc(var(--sp-45) - 20px);
}
}
@media (min-width: 500px) {

View File

@@ -0,0 +1,75 @@
<template>
<DsCard class="square-card">
<div class="square-card__grid">
<!-- Image -->
<div class="square-card__media">
<DsMedia :src="imgSrc" :alt="imgAlt" ratio="square" />
</div>
<!-- Content -->
<div class="square-card__content">
<DsHeading as="h5" tone="default" class="square-card__title">
{{ title }}
</DsHeading>
<!-- Description -->
<DsText as="p" tone="default" :clamp="3" class="square-card__description">
{{ description }}
</DsText>
</div>
</div>
</DsCard>
</template>
<script setup>
import DsCard from '@root/design-system/components/DsCard.vue'
import DsMedia from '@root/design-system/primitives/DsMedia.vue'
import DsHeading from '@root/design-system/primitives/DsHeading.vue'
import DsText from '@root/design-system/primitives/DsText.vue'
import DsButtonArrow from '@root/design-system/primitives/DsButtonArrow.vue'
defineProps({
id: { type: [String, Number], required: true },
title: { type: String, required: true },
url: { type: String, required: true },
description: { type: String, default: '' },
imgSrc: { type: String, default: '' },
imgAlt: { type: String, default: '' },
})
</script>
<style lang="scss">
.square-card__grid {
display: grid;
align-items: start;
}
.square-card__content {
display: grid;
gap: var(--sp-6);
max-width: 518px;
padding-left: 22px;
padding-right: 20px;
padding-top: 13px;
padding-bottom: 10px;
background: white;
max-width: 85%;
justify-self: center;
position: relative;
margin-top: -50px;
}
.square-card__meta {
margin-top: calc(var(--sp-4) * -1);
}
.square-card__description {
margin-top: 10px;
margin-bottom: 20px;
}
.square-card__actions {
margin-top: auto;
}
</style>

View File

@@ -0,0 +1,108 @@
<template>
<div class="square-card-list">
<slot />
</div>
</template>
<style lang="scss">
.square-card-list {
display: flex;
flex-wrap: wrap;
gap: var(--gap-cards);
justify-content: flex-start;
}
@media (max-width: 572px) {
.square-card-list {
justify-content: center;
}
}
// Afficher seulement 1 cards < 600px
@media (max-width: 599px) {
.square-card-list > .square-card:nth-child(2) {
display: none;
}
.square-card-list > .square-card:nth-child(3) {
display: none;
}
}
// Afficher seulement 2 cards < 900px
@media (max-width: 799px) {
.square-card-list > .square-card:nth-child(n+3) {
display: none;
}
}
// Taille des cards
@media (max-width: 599px) {
.square-card-list > .square-card {
max-width: 260px;
flex: 1 1 260px;
max-width: 90%;
}
}
@media (min-width: 600px) {
.square-card-list > .square-card {
max-width: 260px;
flex: 1 1 260px;
}
}
@media (min-width: 700px) {
.square-card-list > .square-card {
max-width: 280px;
flex: 1 1 280px;
}
}
@media (min-width: 800px) {
.square-card-list > .square-card {
max-width: 280px;
flex: 1 1 280px;
}
}
@media (min-width: 900px) {
.square-card-list > .square-card {
max-width: 260px;
flex: 1 1 260px;
}
}
@media (min-width: 1000px) {
.square-card-list > .square-card {
max-width: 280px;
flex: 1 1 280px;
}
}
@media (min-width: 1100px) {
.square-card-list > .square-card {
max-width: 300px;
flex: 1 1 300px;
}
}
@media (min-width: 1200px) {
.square-card-list > .square-card {
max-width: 258px;
flex: 1 1 258px;
}
}
@media (min-width: 1300px) {
.square-card-list > .square-card {
max-width: 283px;
flex: 1 1 283px;
}
}
@media (min-width: 1400px) {
// style appliqué au composant enfant via sa classe
.square-card-list > .square-card {
max-width: 308px;
flex: 1 1 308px;
}
}
</style>

View File

@@ -0,0 +1,74 @@
<template>
<DsCard class="textleft-card">
<div class="textleft-card__grid">
<!-- Content -->
<div class="textleft-card__content">
<DsHeading as="h5" tone="default" class="textleft-card__title">
{{ title }}
</DsHeading>
<!-- Description -->
<DsText as="p" tone="default" :clamp="3" class="textleft-card__description">
{{ description }}
</DsText>
<!-- Actions -->
<div class="concert-card__actions">
<DsButtonArrow :to="`/concerts/${id}`" variant="secondary">
Découvrir
</DsButtonArrow>
</div>
</div>
</div>
</DsCard>
</template>
<script setup>
import DsCard from '@root/design-system/components/DsCard.vue'
import DsMedia from '@root/design-system/primitives/DsMedia.vue'
import DsHeading from '@root/design-system/primitives/DsHeading.vue'
import DsText from '@root/design-system/primitives/DsText.vue'
import DsButtonArrow from '@root/design-system/primitives/DsButtonArrow.vue'
defineProps({
id: { type: [String, Number], required: true },
title: { type: String, required: true },
url: { type: String, required: true },
description: { type: String, default: '' },
})
</script>
<style lang="scss">
.textleft-card__grid {
display: grid;
align-items: start;
}
.textleft-card__content {
display: grid;
gap: var(--sp-6);
max-width: 518px;
padding-left: 10px;
padding-right: 20px;
padding-top: 3px;
background: white;
border-left: 2px solid;
&:hover {
border-left-color: var(--c-brand_rouge);
}
}
.textleft-card__meta {
margin-top: calc(var(--sp-4) * -1);
}
.textleft-card__description {
margin-top: 10px;
margin-bottom: 20px;
}
.textleft-card__actions {
margin-top: auto;
}
</style>

View File

@@ -0,0 +1,108 @@
<template>
<div class="textleft-card-list">
<slot />
</div>
</template>
<style lang="scss">
.textleft-card-list {
display: flex;
flex-wrap: wrap;
gap: var(--gap-cards);
justify-content: flex-start;
}
@media (max-width: 572px) {
.textleft-card-list {
justify-content: center;
}
}
// Afficher seulement 1 cards < 600px
@media (max-width: 599px) {
.textleft-card-list > .textleft-card:nth-child(2) {
display: none;
}
.textleft-card-list > .textleft-card:nth-child(3) {
display: none;
}
}
// Afficher seulement 2 cards < 900px
@media (max-width: 799px) {
.textleft-card-list > .textleft-card:nth-child(3) {
display: none;
}
}
// Taille des cards
@media (max-width: 599px) {
.textleft-card-list > .textleft-card {
max-width: 260px;
flex: 1 1 260px;
max-width: 90%;
}
}
@media (min-width: 600px) {
.textleft-card-list > .textleft-card {
max-width: 247px;
flex: 1 1 247px;
}
}
@media (min-width: 700px) {
.textleft-card-list > .textleft-card {
max-width: 280px;
flex: 1 1 280px;
}
}
@media (min-width: 800px) {
.textleft-card-list > .textleft-card {
max-width: 231px;
flex: 1 1 231px;
}
}
@media (min-width: 900px) {
.textleft-card-list > .textleft-card {
max-width: 258px;
flex: 1 1 258px;
}
}
@media (min-width: 1000px) {
.textleft-card-list > .textleft-card {
max-width: 288px;
flex: 1 1 288px;
}
}
@media (min-width: 1100px) {
.textleft-card-list > .textleft-card {
max-width: 311px;
flex: 1 1 311px;
}
}
@media (min-width: 1200px) {
.textleft-card-list > .textleft-card {
max-width: 334px;
flex: 1 1 334px;
}
}
@media (min-width: 1300px) {
.textleft-card-list > .textleft-card {
max-width: 367px;
flex: 1 1 367px;
}
}
@media (min-width: 1400px) {
// style appliqué au composant enfant via sa classe
.textleft-card-list > .textleft-card {
max-width: 400px;
flex: 1 1 400px;
}
}
</style>

View File

@@ -1,11 +1,10 @@
<script setup>
import logoDefault from '/img/logos/logo_orchestre_red.svg'
import agendaRouge from '@/assets/img/icones/agenda_rouge.svg'
import ticket from '@/assets/img/icones/ticket_black.svg'
import mobile_agenda_icon from '@/assets/img/icones/agenda_rouge_fonce_blanc.svg'
import mobile_ticket from '@/assets/img/icones/ticket_white.svg'
import ticket from '@/assets/img/icones/ticket_noir.svg'
import mobile_agenda_icon from '@/assets/img/icones/agenda_blanc_non_opaque.svg'
import mobile_ticket from '@/assets/img/icones/ticket_blanc.svg'
const { brand } = useAppConfig()
</script>
<template>
@@ -18,17 +17,31 @@
<img :src="agendaRouge" alt="icone agenda" />
</template>
<template #ticket>
<img class="img_ticket" :src="ticket" alt="icone ticket" />
<img class="img_ticket_desktop" :src="ticket" alt="icone ticket" />
</template>
<template #mobile_agenda_icon>
<img :src="mobile_agenda_icon" alt="icone ticket" />
</template>
<template #mobile_ticket>
<img :src="mobile_ticket" alt="icone ticket" />
<img class="img_ticket_mob" :src="mobile_ticket" alt="icone ticket" />
</template>
</HeaderNav>
</template>
<style lang="scss">
.img_ticket_desktop {
max-height: 26px;
margin-top: 4px;
margin-left: -11px;
}
.img_ticket_mob {
max-height: 37px;
margin-top: 9px;
margin-left: -11px;
}
</style>

View File

@@ -32,7 +32,7 @@
<nav class="header_nav_cont" aria-label="Primary navigation">
<!-- Desktop nav -->
<ul class="header_nav header_nav--desktop">
<li class="header_nav_item brandontext_bold">
<li class="header_nav_item">
L'Orchestre
<ul class="header_nav_sub_menu">
<li class="header_nav_sub_menu_item"><NuxtLink to="/">Nos missions</NuxtLink></li>
@@ -56,7 +56,7 @@
</ul>
</li>
<li class="header_nav_item brandontext_bold">
<li class="header_nav_item">
Éducation et médiation
<ul class="header_nav_sub_menu">
<li class="header_nav_sub_menu_item"><NuxtLink to="/">Petite enfance</NuxtLink></li>
@@ -156,7 +156,7 @@
>
<ul class="header_drawer_inner">
<li
class="header_drawer_link brandontext_bold"
class="header_drawer_link"
:class="{ 'is-open': activeDrawer === 'orchestre' }"
@click="toggleDrawer('orchestre')"
>
@@ -188,7 +188,7 @@
</li>
<li
class="header_drawer_link brandontext_bold"
class="header_drawer_link"
:class="{ 'is-open': activeDrawer === 'education' }"
@click="toggleDrawer('education')"
>
@@ -217,15 +217,17 @@
</ul>
</li>
<NuxtLink class="header_drawer_link icon_mobile_agenda" to="/agenda" @click="close">
<!-- ICÔNE injectée -->
<slot name="mobile_agenda_icon" />
</NuxtLink>
<NuxtLink class="header_drawer_link icon_mobile_ticket" to="/agenda" @click="close">
<!-- ICÔNE injectée -->
<slot name="mobile_ticket" />
</NuxtLink>
<li class="icon_mobile">
<NuxtLink class="header_drawer_link icon_mobile_agenda" to="/agenda" @click="close">
<!-- ICÔNE injectée -->
<slot name="mobile_agenda_icon" />
</NuxtLink>
<NuxtLink class="header_drawer_link icon_mobile_ticket" to="/agenda" @click="close">
<!-- ICÔNE injectée -->
<slot name="mobile_ticket" />
</NuxtLink>
</li>
</ul>
</div>
@@ -262,6 +264,12 @@
</script>
<style lang="scss">
.icon_mobile {
display: flex;
column-gap: 20px;
padding-left: 3px;
}
.icon_mobile_agenda {
width: 35px;
margin-top: 10px;

View File

@@ -7,12 +7,12 @@
<template>
<header>
<div class="bg-orbs" aria-hidden="true">
<span class="orb orb--1" />
<span class="orb orb--2" />
<span class="orb orb--3" />
<span class="orb orb--4" />
<span class="orb orb--5" />
<span class="orb orb--6" />
<!-- <span class="orb orb--1" /> -->
<!-- <span class="orb orb--2" /> -->
<!-- <span class="orb orb--3" /> -->
<!-- <span class="orb orb--4" /> -->
<!-- <span class="orb orb--5" /> -->
<!-- <span class="orb orb--6" /> -->
</div>
<div class="header_layout" :class="`header--${theme}`">
<slot />

View File

@@ -8,12 +8,14 @@
<section
class="page-section"
:class="[
`page-section--overflow--${overflow}`,
`page-section--${tone}`,
{ 'page-section--padded': padded }
{ 'page-section--padded': padded },
`page-section--padded--${padded_size}`
]"
>
<!-- Si content == true -->
<PageSectionInner v-if="content" :size="contentSize" :padt="padt" :padb="padb">
<PageSectionInner v-if="content" :size="contentSize" :padt="padt" :padb="padb" :position="position" :overflow="overflow">
<slot />
</PageSectionInner>
@@ -28,11 +30,13 @@
<script setup>
defineProps({
tone: { type: String, default: 'default' }, // default / brand / muted / dark…
padded: { type: Boolean, default: true }, // padding vertical
padded_size: { type: String, default: '' }, // none | sm | md | lg
contentSize: { type: String, default: 'default'}, // narrow/default/wide
content: { type: Boolean, default: true }, // contenu contraint ou full
padb : { type: String, default: '' }, // props pour PageSectionInner
padt : { type: String, default: '' } // props pour PageSectionInner
padt : { type: String, default: '' }, // props pour PageSectionInner
position : { type: String, default: '' },
overflow : { type: String, default: '' }
})
</script>
@@ -41,6 +45,9 @@
position: relative;
width: 100%;
//min-height: var(--sp-200);
&--overflow--hidden {
overflow: hidden;
}
/* tons = arrière-plan section */
&--default { background: transparent; }
@@ -50,8 +57,14 @@
// padding en haut et en bas
&--padded {
padding-top: 30px;
padding-bottom: 50px;
&--md {
padding-top: 30px;
padding-bottom: 50px;
}
&--lg {
padding-top: 30px;
padding-bottom: 120px;
}
}
}

View File

@@ -2,7 +2,7 @@
Des templates peuvent avoir toutes la même marge de page et d'autres, par ex, être full page -->
<template>
<div class="page-section--inner" :class="[`page-section--inner--${size}`,`page-section--inner--padb--${padb}`,`page-section--inner--padt--${padt}`]">
<div class="page-section--inner" :class="[`page-section--inner--${size}`,`page-section--inner--padb--${padb}`,`page-section--inner--padt--${padt}`,`page-section--inner--position--${position}`,`page-section--inner--overflow--${overflow}`]">
<slot />
</div>
</template>
@@ -11,7 +11,8 @@
defineProps({
size: { type: String, default: 'default' }, // default / wide / narrow
padb : { type: String, default: '' },
padt : { type: String, default: '' }
padt : { type: String, default: '' },
position : { type: String, dafault : ''}
})
</script>
@@ -25,7 +26,9 @@
// respiration sur les côtés avec marges minimale ( surtout utile pour mobiles)
&--position--relative {
position: relative;
}
// limite de largeur quand on veut une largeur plus petit (pour les articles par exemple)
&--narrow {
@@ -37,7 +40,7 @@
/* mobile / small screens */
@media (max-width: 700px) {
padding-inline: var(--page-padding-mobile);
//padding-inline: var(--page-padding-mobile);
}
@media (min-width: 0px) {

View File

@@ -29,30 +29,44 @@
&--tone-brandreverse { background: var(--c-backgroud-brandreverse); }
&--pad-xs {
padding-top: var(--sp-32);
//padding-top: var(--sp-32);
padding-bottom: var(--sp-16);
padding-left: var(--sp-45);
padding-right: var(--sp-8);
}
&--pad-sm {
padding-top: var(--sp-32);
//padding-top: var(--sp-32);
padding-bottom: var(--sp-16);
padding-left: var(--sp-45);
padding-right: var(--sp-8);
}
&--pad-md {
padding-top: var(--sp-80);
//padding-top: var(--sp-80);
padding-bottom: var(--sp-180);
padding-left: var(--sp-45);
padding-right: var(--sp-8);
}
&--pad-lg {
padding-top: var(--sp-80);
//padding-top: var(--sp-80);
padding-bottom: var(--sp-180);
padding-left: var(--sp-45);
padding-right: var(--sp-8);
}
}
@media (max-width: 400px) {
.section-content {
&--pad-xs {
//padding-bottom: calc(var(--sp-16) * 0.5);
padding-left: calc(var(--sp-45) * 0.5);
//padding-right: calc(var(--sp-8) * 0.5);
}
}
}
@media (max-width: 300px) {
.section-title {
padding-left: calc(var(--section-title-pl, var(--sp-45)) - 20px);
padding-left: calc(var(--sp-45) - 20px);
}
}

View File

@@ -45,10 +45,17 @@
padding-left: var(--sp-45);
}
}
@media (max-width: 400px) {
.section-title {
&--pad-xs {
padding-left: calc(var(--sp-45) * 0.5);
}
}
}
@media (max-width: 300px) {
.section-title {
padding-left: calc(var(--section-title-pl, var(--sp-45)) - 20px);
padding-left: calc(var(--sp-45) - 20px);
}
}