update a lot of change since a while

This commit is contained in:
2026-01-22 10:29:36 +01:00
parent a4dcb95d83
commit e1c1475f10
78 changed files with 4200 additions and 534 deletions

View File

@@ -1,5 +1,8 @@
export default defineAppConfig({
title: "Orchestre national d'Île-de-France - ONDIF",
brand: {
logoAlt: "Orchestre National dÎle-de-France",
},
theme: {
primaryColor: '#6c63ff',
},

View File

@@ -1,15 +1,17 @@
<template>
<div>
<NuxtLoadingIndicator/>
<div class="app">
<!-- improves perceived performance / une barre fine en haut de la page lors des chargements -->
<NuxtLoadingIndicator />
<!-- improves accessibility / car tu navigues sans rechargement, annonce les changements de page aux lecteurs décran -->
<NuxtRouteAnnouncer />
<!-- NuxtPage c'est là que Nuxt trouve les templates des pages à afficher en fonction de l'URL saisie -->
<NuxtPage />
<!-- on va gérer 2 layout, car on a 2 header différents -->
<NuxtLayout>
<NuxtPage />
</NuxtLayout>
<!-- <NuxtWelcome /> -->
</div>
</template>

Binary file not shown.

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 640"><!--!Font Awesome Pro 7.1.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2025 Fonticons, Inc.--><path opacity=".4" d="M64 320C64 337.7 78.3 352 96 352L466.7 352L498.7 320L466.7 288L96 288C78.3 288 64 302.3 64 320z"/><path d="M566.6 297.4C579.1 309.9 579.1 330.2 566.6 342.7L406.6 502.7C394.1 515.2 373.8 515.2 361.3 502.7C348.8 490.2 348.8 469.9 361.3 457.4L498.7 320L361.4 182.6C348.9 170.1 348.9 149.8 361.4 137.3C373.9 124.8 394.2 124.8 406.7 137.3L566.7 297.3z"/></svg>

After

Width:  |  Height:  |  Size: 605 B

View File

@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="448px" height="384px" viewBox="0 0 448 384" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>Group</title>
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="Extra-Large-Copy" transform="translate(-3206, -1360)" fill="#000000">
<g id="Group" transform="translate(3110, 1232)">
<path d="M96,320 C96,302.3 110.3,288 128,288 L512,288 C529.7,288 544,302.3 544,320 C544,337.7 529.7,352 512,352 L128,352 C110.3,352 96,337.7 96,320 Z" id="Path" fill-rule="nonzero" opacity="0.4"></path>
<path d="M544,160 C544,142.3 529.7,128 512,128 L128,128 C110.3,128 96,142.3 96,160 C96,177.7 110.3,192 128,192 L512,192 C529.7,192 544,177.7 544,160 Z M544,480 C544,462.3 529.7,448 512,448 L128,448 C110.3,448 96,462.3 96,480 C96,497.7 110.3,512 128,512 L512,512 C529.7,512 544,497.7 544,480 Z" id="Shape" fill-rule="nonzero"></path>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.0 KiB

View File

@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="448px" height="384px" viewBox="0 0 448 384" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>Group</title>
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="Extra-Large-Copy" transform="translate(-2896, -2170)" fill="#FFFFFF">
<g id="Group" transform="translate(2800, 2042)">
<path d="M512,288 C529.7,288 544,302.3 544,320 C544,337.7 529.7,352 512,352 L128,352 C110.3,352 96,337.7 96,320 C96,302.3 110.3,288 128,288 L512,288 Z M512,128 C529.7,128 544,142.3 544,160 C544,177.7 529.7,192 512,192 L128,192 C110.3,192 96,177.7 96,160 C96,142.3 110.3,128 128,128 Z M544,480 C544,462.3 529.7,448 512,448 L128,448 C110.3,448 96,462.3 96,480 C96,497.7 110.3,512 128,512 L512,512 C529.7,512 544,497.7 544,480 Z" id="Shape" fill-rule="nonzero"></path>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 969 B

View File

@@ -0,0 +1,25 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="419px" height="315px" viewBox="0 0 419 315" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>noun-tickets-956198</title>
<g id="billetterie" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="500" transform="translate(-16, 0)">
<g id="noun-tickets-956198" transform="translate(16.8607, 0)">
<polygon id="Path" fill="#E30613" fill-rule="nonzero" points="143.329055 222.711266 138.691691 210.354443 147.213974 207.1581 151.851338 219.514922"></polygon>
<polygon id="Path" fill="#E30613" fill-rule="nonzero" points="119.057451 132.068566 123.691645 144.425389 115.169362 147.621732 110.535168 135.26491"></polygon>
<polygon id="Path" fill="#E30613" fill-rule="nonzero" points="132.976854 169.56076 124.454571 172.753934 119.823546 160.397112 128.345829 157.203937"></polygon>
<polygon id="Path" fill="#E30613" fill-rule="nonzero" points="142.613989 194.44992 134.091707 197.643095 129.460681 185.286272 137.982964 182.093098"></polygon>
<path d="M252.092168,149.25452 L262.557317,177.012069 L321.713562,154.714209 L311.248414,126.956659 L252.092168,149.25452 Z M268.020256,165.636024 L263.925611,155.170876 L306.242873,139.242788 L310.337517,149.707936 L268.020256,165.636024 Z" id="Shape" fill="#E30613" fill-rule="nonzero"></path>
<path d="M327.174064,109.665884 L301.692536,42.3205116 L146.978327,100.565861 L172.459855,167.911233 L327.174064,109.665884 Z M296.683826,54.1507856 L315.341352,104.660424 L177.46369,156.535188 L158.806164,106.02555 L296.683826,54.1507856 Z" id="Shape" fill="#000000" fill-rule="nonzero"></path>
<polygon id="Path" fill="#000000" fill-rule="nonzero" points="186.371133 206.25663 183.177958 197.734347 246.666851 173.934849 249.860026 182.457131"></polygon>
<polygon id="Path" fill="#000000" fill-rule="nonzero" points="175.791411 178.76723 239.273804 154.961231 242.470147 163.483514 178.987755 187.289513"></polygon>
<polygon id="Path" fill="#000000" fill-rule="nonzero" points="193.399903 225.85593 190.206729 217.333647 234.095509 200.882261 237.288684 209.404544"></polygon>
<polygon id="Path" fill="#000000" fill-rule="nonzero" points="66.4432439 165.961054 90.2492426 229.443447 81.72696 232.63979 57.9209612 169.157397"></polygon>
<polygon id="Path" fill="#000000" fill-rule="nonzero" points="88.854052 166.692371 105.308688 210.574651 96.7864055 213.770995 80.3317693 169.888715"></polygon>
<path d="M266.198464,272.115803 L329.449273,273.02678 L329.903169,243.450689 L266.65236,242.539712 L266.198464,272.115803 Z M275.755967,252.093152 L320.805916,253.004129 L320.805916,264.380174 L275.755967,263.469196 L275.755967,252.093152 Z" id="Shape" fill="#E30613" fill-rule="nonzero"></path>
<polygon id="Path" fill="#000000" fill-rule="nonzero" points="252.287186 272.944629 184.490835 271.913066 184.6305 262.813042 252.426852 263.844606"></polygon>
<polygon id="Path" fill="#000000" fill-rule="nonzero" points="231.135869 293.307749 184.269815 292.593569 184.40948 283.493546 231.275534 284.207726"></polygon>
<path d="M355.386655,0 L111.029214,91.9184416 L112.847999,96.0130864 C113.758977,98.7428495 113.758977,101.929605 112.394103,104.202213 C111.029222,106.931977 109.207267,108.753931 106.477585,110.118732 C101.018058,112.394591 94.6473109,109.207754 92.372102,103.748309 L90.5533162,99.6536644 L0,133.327569 L36.4041558,230.251471 L35.0392742,308.518659 L131.508134,309.88354 L131.508134,305.331822 C131.508134,299.415304 136.513756,294.410007 142.429949,294.410007 C148.346142,294.410007 153.351765,299.415629 153.351765,305.331822 L153.351765,309.88354 L415.000794,314.432089 L417.730557,141.516209 L408.630534,141.516209 L355.386655,0 Z M11.8301033,138.787746 L85.5460607,111.030197 C89.1868013,116.489723 95.5569801,120.13022 102.381794,120.13022 C103.292772,120.13022 104.20058,120.13022 105.111558,119.676324 L106.022535,122.406087 L114.669142,119.219251 L113.758164,116.489487 C116.945001,114.213628 119.217691,111.483865 121.039564,108.30036 C122.404446,104.65962 123.315423,101.01896 122.85835,97.3785449 L328.537239,20.4756698 L382.688024,165.634001 L176.554094,242.536876 C172.913353,237.077349 166.543174,233.436853 159.71836,233.436853 C158.807383,233.436853 157.899574,233.436853 156.988597,233.890749 L156.077619,232.071963 L147.431013,235.258799 L147.884909,237.077585 C144.698072,239.353444 142.425382,242.083207 140.603509,245.266712 C139.238627,248.907453 138.32765,252.548112 138.784723,256.188528 L65.0687658,283.946077 L11.8301033,138.787746 Z M342.645485,189.751614 L342.188411,223.879748 L254.820388,222.514866 L342.645485,189.751614 Z M381.779079,304.877187 L161.993894,301.69035 C160.175108,294.40895 154.712494,288.495763 147.430932,286.673971 L147.430932,284.855185 L138.330908,284.855185 L138.330908,286.673971 C131.049508,288.492757 125.136322,293.955371 123.314529,301.236934 L44.5931122,299.872052 L45.0470083,253.911206 L60.5176165,295.320822 L138.331388,266.198147 L138.331388,270.749865 L147.431411,270.749865 L147.431411,262.560738 L150.618247,261.195856 L148.799462,257.101212 C147.888484,254.371448 147.888484,251.184693 149.253358,248.912084 C150.618239,246.636225 152.440194,244.360366 155.169876,242.995566 C160.629402,240.719707 167.00015,243.906544 169.275359,249.365989 L171.094145,253.460633 L184.288731,248.455011 L184.288731,250.73087 L252.090771,251.641848 L252.090771,242.541824 L202.034549,241.630847 L230.702994,230.709031 L350.378985,232.527817 L351.289962,185.658513 L383.599554,173.828239 L381.779079,304.877187 Z M336.2749,17.2907754 L350.380382,11.8312491 L404.531168,156.98958 L390.425685,162.449106 L336.2749,17.2907754 Z M405.896293,305.332228 L390.879914,304.878332 L392.6987,170.641004 L407.715079,165.181478 L405.896293,305.332228 Z" id="Shape" fill="#000000" fill-rule="nonzero"></path>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 6.0 KiB

View File

@@ -0,0 +1,25 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="419px" height="315px" viewBox="0 0 419 315" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>noun-tickets-956198</title>
<g id="billetterie" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="ticket-blanc" transform="translate(-16, 0)">
<g id="noun-tickets-956198" transform="translate(16.8607, 0)">
<polygon id="Path" fill-opacity="0.85" fill="#E30613" fill-rule="nonzero" points="143.329055 222.711266 138.691691 210.354443 147.213974 207.1581 151.851338 219.514922"></polygon>
<polygon id="Path" fill-opacity="0.85" fill="#E30613" fill-rule="nonzero" points="119.057451 132.068566 123.691645 144.425389 115.169362 147.621732 110.535168 135.26491"></polygon>
<polygon id="Path" fill-opacity="0.85" fill="#E30613" fill-rule="nonzero" points="132.976854 169.56076 124.454571 172.753934 119.823546 160.397112 128.345829 157.203937"></polygon>
<polygon id="Path" fill-opacity="0.85" fill="#E30613" fill-rule="nonzero" points="142.613989 194.44992 134.091707 197.643095 129.460681 185.286272 137.982964 182.093098"></polygon>
<path d="M252.092168,149.25452 L262.557317,177.012069 L321.713562,154.714209 L311.248414,126.956659 L252.092168,149.25452 Z M268.020256,165.636024 L263.925611,155.170876 L306.242873,139.242788 L310.337517,149.707936 L268.020256,165.636024 Z" id="Shape" fill-opacity="0.727347847" fill="#E30613" fill-rule="nonzero"></path>
<path d="M327.174064,109.665884 L301.692536,42.3205116 L146.978327,100.565861 L172.459855,167.911233 L327.174064,109.665884 Z M296.683826,54.1507856 L315.341352,104.660424 L177.46369,156.535188 L158.806164,106.02555 L296.683826,54.1507856 Z" id="Shape" fill-opacity="0.727347847" fill="#FFFFFF" fill-rule="nonzero"></path>
<polygon id="Path" fill-opacity="0.727347847" fill="#FFFFFF" fill-rule="nonzero" points="186.371133 206.25663 183.177958 197.734347 246.666851 173.934849 249.860026 182.457131"></polygon>
<polygon id="Path" fill-opacity="0.727347847" fill="#FFFFFF" fill-rule="nonzero" points="175.791411 178.76723 239.273804 154.961231 242.470147 163.483514 178.987755 187.289513"></polygon>
<polygon id="Path" fill-opacity="0.727347847" fill="#FFFFFF" fill-rule="nonzero" points="193.399903 225.85593 190.206729 217.333647 234.095509 200.882261 237.288684 209.404544"></polygon>
<polygon id="Path" fill-opacity="0.727347847" fill="#FFFFFF" fill-rule="nonzero" points="66.4432439 165.961054 90.2492426 229.443447 81.72696 232.63979 57.9209612 169.157397"></polygon>
<polygon id="Path" fill-opacity="0.727347847" fill="#FFFFFF" fill-rule="nonzero" points="88.854052 166.692371 105.308688 210.574651 96.7864055 213.770995 80.3317693 169.888715"></polygon>
<path d="M266.198464,272.115803 L329.449273,273.02678 L329.903169,243.450689 L266.65236,242.539712 L266.198464,272.115803 Z M275.755967,252.093152 L320.805916,253.004129 L320.805916,264.380174 L275.755967,263.469196 L275.755967,252.093152 Z" id="Shape" fill-opacity="0.727347847" fill="#E30613" fill-rule="nonzero"></path>
<polygon id="Path" fill-opacity="0.727347847" fill="#FFFFFF" fill-rule="nonzero" points="252.287186 272.944629 184.490835 271.913066 184.6305 262.813042 252.426852 263.844606"></polygon>
<polygon id="Path" fill="#FFFFFF" fill-rule="nonzero" points="231.135869 293.307749 184.269815 292.593569 184.40948 283.493546 231.275534 284.207726"></polygon>
<path d="M355.386655,0 L111.029214,91.9184416 L112.847999,96.0130864 C113.758977,98.7428495 113.758977,101.929605 112.394103,104.202213 C111.029222,106.931977 109.207267,108.753931 106.477585,110.118732 C101.018058,112.394591 94.6473109,109.207754 92.372102,103.748309 L90.5533162,99.6536644 L0,133.327569 L36.4041558,230.251471 L35.0392742,308.518659 L131.508134,309.88354 L131.508134,305.331822 C131.508134,299.415304 136.513756,294.410007 142.429949,294.410007 C148.346142,294.410007 153.351765,299.415629 153.351765,305.331822 L153.351765,309.88354 L415.000794,314.432089 L417.730557,141.516209 L408.630534,141.516209 L355.386655,0 Z M11.8301033,138.787746 L85.5460607,111.030197 C89.1868013,116.489723 95.5569801,120.13022 102.381794,120.13022 C103.292772,120.13022 104.20058,120.13022 105.111558,119.676324 L106.022535,122.406087 L114.669142,119.219251 L113.758164,116.489487 C116.945001,114.213628 119.217691,111.483865 121.039564,108.30036 C122.404446,104.65962 123.315423,101.01896 122.85835,97.3785449 L328.537239,20.4756698 L382.688024,165.634001 L176.554094,242.536876 C172.913353,237.077349 166.543174,233.436853 159.71836,233.436853 C158.807383,233.436853 157.899574,233.436853 156.988597,233.890749 L156.077619,232.071963 L147.431013,235.258799 L147.884909,237.077585 C144.698072,239.353444 142.425382,242.083207 140.603509,245.266712 C139.238627,248.907453 138.32765,252.548112 138.784723,256.188528 L65.0687658,283.946077 L11.8301033,138.787746 Z M342.645485,189.751614 L342.188411,223.879748 L254.820388,222.514866 L342.645485,189.751614 Z M381.779079,304.877187 L161.993894,301.69035 C160.175108,294.40895 154.712494,288.495763 147.430932,286.673971 L147.430932,284.855185 L138.330908,284.855185 L138.330908,286.673971 C131.049508,288.492757 125.136322,293.955371 123.314529,301.236934 L44.5931122,299.872052 L45.0470083,253.911206 L60.5176165,295.320822 L138.331388,266.198147 L138.331388,270.749865 L147.431411,270.749865 L147.431411,262.560738 L150.618247,261.195856 L148.799462,257.101212 C147.888484,254.371448 147.888484,251.184693 149.253358,248.912084 C150.618239,246.636225 152.440194,244.360366 155.169876,242.995566 C160.629402,240.719707 167.00015,243.906544 169.275359,249.365989 L171.094145,253.460633 L184.288731,248.455011 L184.288731,250.73087 L252.090771,251.641848 L252.090771,242.541824 L202.034549,241.630847 L230.702994,230.709031 L350.378985,232.527817 L351.289962,185.658513 L383.599554,173.828239 L381.779079,304.877187 Z M336.2749,17.2907754 L350.380382,11.8312491 L404.531168,156.98958 L390.425685,162.449106 L336.2749,17.2907754 Z M405.896293,305.332228 L390.879914,304.878332 L392.6987,170.641004 L407.715079,165.181478 L405.896293,305.332228 Z" id="Shape" fill="#FFFFFF" fill-rule="nonzero"></path>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 164 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

View File

@@ -10,4 +10,8 @@ $rouge_transparent: #e3061391;
$vert: green;
$bleu_fonce: #0056b3;
$bleu_clair: #007bff;
$bleu_clair: #007bff;

View File

@@ -1,81 +1,76 @@
@font-face {
font-family: 'brandontext_black_italic';
src: url('~/assets/fonts/brandontext_black_italic.woff2') format('woff2');
}
@font-face {
font-family: 'brandontext_black';
src: url('~/assets/fonts/brandontext_black.woff2') format('woff2');
}
@font-face {
font-family: 'brandontext_bold_italic';
src: url('~/assets/fonts/brandontext_bold_italic.woff2') format('woff2');
src: url('@/assets/fonts/brandontext_boldItalic.woff2') format('woff2');
}
@font-face {
font-family: 'brandontext_bold';
src: url('~/assets/fonts/brandontext_bold.woff2') format('woff2');
}
@font-face {
font-family: 'brandontext_light_italic';
src: url('~/assets/fonts/brandontext_light_italic.woff2') format('woff2');
}
@font-face {
font-family: 'brandontext_light';
src: url('~/assets/fonts/brandontext_light.woff2') format('woff2');
src: url('@/assets/fonts/brandontext_bold.woff2') format('woff2');
}
@font-face {
font-family: 'brandontext_medium_italic';
src: url('~/assets/fonts/brandontext_medium_italic.woff2') format('woff2');
src: url('@/assets/fonts/brandontext_mediumItalic.woff2') format('woff2');
}
@font-face {
font-family: 'brandontext_medium';
src: url('~/assets/fonts/brandontext_medium.woff2') format('woff2');
src: url('@/assets/fonts/brandontext_medium.woff2') format('woff2');
}
@font-face {
font-family: 'brandontext_regular_italic';
src: url('~/assets/fonts/brandontext_regular_italic.woff2') format('woff2');
src: url('@/assets/fonts/brandontext_regularItalic.woff2') format('woff2');
}
@font-face {
font-family: 'brandontext_regular';
src: url('~/assets/fonts/brandontext_regular.woff2') format('woff2');
src: url('@/assets/fonts/brandontext_regular.woff2') format('woff2');
}
@font-face {
font-family: 'brandontext_thin_italic';
src: url('~/assets/fonts/brandontext_thin_italic.woff2') format('woff2');
}
@font-face {
font-family: 'brandontext_thin';
src: url('~/assets/fonts/brandontext_thin.woff2') format('woff2');
}
@font-face {
font-family: 'barlow_medium';
src: url('~/assets/fonts/barlow_medium.ttf') format('truetype');
src: url('@/assets/fonts/barlow_medium.ttf') format('truetype');
}
@font-face {
font-family: 'barlow_semibold';
src: url('~/assets/fonts/barlow_semibold.ttf') format('truetype');
src: url('@/assets/fonts/barlow_semibold.ttf') format('truetype');
}
@font-face {
font-family: 'barlow_regular';
src: url('~/assets/fonts/barlow_regular.ttf') format('truetype');
src: url('@/assets/fonts/barlow_regular.ttf') format('truetype');
}
@font-face {
font-family: 'barlow_light';
src: url('~/assets/fonts/barlow_light.ttf') format('truetype');
src: url('@/assets/fonts/barlow_light.ttf') format('truetype');
}
@font-face {
font-family: 'barlow_extrabold';
src: url('~/assets/fonts/barlow_extrabold.ttf') format('truetype');
src: url('@/assets/fonts/barlow_extrabold.ttf') format('truetype');
}
@font-face {
font-family: 'barlow_bold';
src: url('~/assets/fonts/barlow_bold.ttf') format('truetype');
src: url('@/assets/fonts/barlow_bold.ttf') format('truetype');
}
@font-face {
font-family: 'barlow_black';
src: url('~/assets/fonts/barlow_black.ttf') format('truetype');
src: url('@/assets/fonts/barlow_black.ttf') format('truetype');
}
@font-face {
font-family: "Roboto Flex";
src: url("@/assets/fonts/robotoflex.ttf") format("truetype");
font-weight: 100 1000;
font-stretch: 25% 151%;
font-style: oblique 0deg 10deg;
font-display: swap;
}
.brandontext_bold {
font-family: brandontext_bold !important;
}
}
.roboto_regular {
font-family: Roboto Flex;
font-weight: 400
}
.roboto_semibold {
font-family: Roboto Flex;
font-weight: 600
}

View File

@@ -2,6 +2,9 @@
margin: 0;
padding: 0;
}
*, *::before, *::after {
box-sizing: border-box;
}
h1, h2, h3, h4, h5, h6 {
font-size: inherit;

View File

@@ -19,3 +19,10 @@
.height_33 {
height: 33px;
}
.margin_left_-20 {
margin-left: -20px;
}
.padding_top_1 {
padding-top: 1px;
}

View File

@@ -1,9 +0,0 @@
@use 'colors' as *;
h1 {
color: red;
}
p {
color: $vert;
}

View File

@@ -1,214 +0,0 @@
@use '../base/colors' as *;
@use '../layout/media_queries';
.header_full {
display: grid;
grid-template-rows: 130px auto auto;
@include media_queries.media_min(tablet_600) {
grid-template-columns: 1fr 500px 1fr;
}
@include media_queries.media_min(tablet_900) {
grid-template-columns: 1fr 890px 1fr;
}
@include media_queries.media_min(desktop_1000) {
grid-template-columns: auto 980px auto;
}
@include media_queries.media_min(desktop_1100) {
grid-template-columns: auto 1090px auto;
}
@include media_queries.media_min(desktop_1200) {
grid-template-columns: auto 1160px auto;
}
@include media_queries.media_min(desktop_1300) {
grid-template-columns: 1fr 1250px 1fr;
}
@include media_queries.media_min(desktop_1500) {
grid-template-columns: 1fr 1420px 1fr;
}
@include media_queries.media_min(desktop_1800) {
grid-template-columns: 1fr 1700px 1fr;
}
nav {
color: $blanc;
a {
color: $blanc;
}
}
.header_navigation {
grid-column: 2;
grid-row: 1;
z-index: 10;
}
.obscur {
grid-column: 1 / -1;
grid-row: 1;
z-index: 5;
//background-color: #0000007a;
background-color: rgba(0,0,0,.4);
}
.header-img_cont {
grid-column: 1 / -1;
grid-row: 1 / -1;
}
.header-img_text {
grid-column: 2;
grid-row: 3;
color: $blanc;
width: 650px;
margin-left: 80px;
margin-bottom: 150px;
.header-img_titre {
margin-bottom: 10px;
text-transform: uppercase;
font-family: 'barlow_black';
font-size: 50px;
}
.header-img_description {
margin-bottom: 20px;
font-family: 'barlow_regular';
font-size: 20px;
}
.decouvrir {
display: flex;
.decouvrir_icone {
margin-top: 2px;
margin-right: 5px;
}
.decouvrir_texte {
font-family: 'barlow_regular';
font-size: 18px;
}
}
}
}
.header_full_2 {
display: grid;
@include media_queries.media_min(tablet_600) {
grid-template-rows: 117px auto auto;
}
@include media_queries.media_min(tablet_900) {
grid-template-rows: 117px auto auto;
}
@include media_queries.media_min(desktop_1800) {
grid-template-rows: 130px auto auto;
}
@include media_queries.media_min(tablet_600) {
grid-template-columns: 1fr 500px 1fr;
}
@include media_queries.media_min(tablet_900) {
grid-template-columns: 1fr 890px 1fr;
}
@include media_queries.media_min(desktop_1000) {
grid-template-columns: auto 980px auto;
}
@include media_queries.media_min(desktop_1100) {
grid-template-columns: auto 1090px auto;
}
@include media_queries.media_min(desktop_1200) {
grid-template-columns: auto 1160px auto;
}
@include media_queries.media_min(desktop_1300) {
grid-template-columns: 1fr 1250px 1fr;
}
@include media_queries.media_min(desktop_1500) {
grid-template-columns: 1fr 1420px 1fr;
}
@include media_queries.media_min(desktop_1800) {
grid-template-columns: 1fr 1700px 1fr;
}
nav {
color: $noir;
a {
color: $noir;
}
}
.header_navigation {
grid-column: 2;
grid-row: 1;
z-index: 10;
}
.obscur {
grid-column: 1 / -1;
grid-row: 1;
z-index: 5;
background-color: rgb(255 255 255 / 98%);
}
.header-img_cont {
grid-column: 1 / -1;
grid-row: 1 / -1;
}
.header-img_text {
grid-column: 2;
grid-row: 3;
color: $blanc;
width: 650px;
margin-left: 80px;
margin-bottom: 150px;
.header-img_titre {
display: inline-block;
background-color: $rouge_transparent;
padding-bottom: 5px;
padding-left: 10px;
padding-right: 10px;
text-transform: uppercase;
font-family: 'barlow_black';
font-size: 50px;
}
.header-img_description {
display: inline-block;
background-color: $rouge_transparent;
padding-bottom: 20px;
padding-top: 5px;
padding-left: 10px;
padding-right: 10px;
font-family: 'barlow_regular';
font-size: 20px;
}
.decouvrir {
display: flex;
.decouvrir_icone {
display: inline-block;
background-color: $rouge_transparent;
padding-top: 2px;
padding-left: 10px;
padding-right: 5px;
padding-bottom: 5px;
}
.decouvrir_texte {
display: inline-block;
background-color: $rouge_transparent;
padding-bottom: 5px;
font-family: 'barlow_regular';
font-size: 18px;
padding-right: 10px;
}
}
}
}

View File

@@ -0,0 +1,129 @@
@use '../base/colors' as *;
@use '../layout/media_queries';
/* thème clair */
.header_layout.header--light {
--header-text-color: #{$noir};
}
/* thème sombre */
.header_layout.header--dark {
--header-text-color: #{$blanc};
}
.header_layout {
display: grid;
grid-template-rows: 130px auto auto;
@include media_queries.media_max(tablet_700) {
grid-template-columns: 10px minmax(0, 1fr) 10px;
}
@include media_queries.media_min(tablet_700) {
grid-template-columns: 10px minmax(0, 1fr) 10px;
}
@include media_queries.media_min(tablet_800) {
grid-template-columns: 10px minmax(0, 1fr) 10px;
}
@include media_queries.media_min(tablet_900) {
grid-template-columns: 15px minmax(0, 1fr) 15px;
}
@include media_queries.media_min(desktop_1000) {
grid-template-columns: auto 980px auto;
}
@include media_queries.media_min(desktop_1100) {
grid-template-columns: auto 1090px auto;
}
@include media_queries.media_min(desktop_1200) {
grid-template-columns: auto 1160px auto;
}
@include media_queries.media_min(desktop_1300) {
grid-template-columns: 1fr 1250px 1fr;
}
@include media_queries.media_min(desktop_1500) {
grid-template-columns: 1fr 1420px 1fr;
}
@include media_queries.media_min(desktop_1800) {
grid-template-columns: 1fr 1700px 1fr;
}
nav {
color: var(--header-text-color);
a {
color: var(--header-text-color);
}
}
.header_navigation {
grid-column: 2;
grid-row: 1;
z-index: 10;
}
.obscur {
grid-column: 1 / -1;
grid-row: 1;
z-index: 5;
//background-color: #0000007a;
background-color: rgba(0,0,0,.4);
}
.header-img_cont {
grid-column: 1 / -1;
grid-row: 1 / -1;
}
.header-img_text {
grid-column: 2;
grid-row: 3;
color: $blanc;
margin-left: 80px;
margin-bottom: 150px;
@include media_queries.media_max(tablet_800) {
width: 500px;
}
@include media_queries.media_min(tablet_800) {
width: 650px;
}
.header-img_titre {
margin-bottom: 10px;
text-transform: uppercase;
font-family: 'barlow_black';
@include media_queries.media_max(tablet_800) {
font-size: 40px;
}
@include media_queries.media_min(tablet_800) {
font-size: 50px;
}
}
.header-img_description {
margin-bottom: 20px;
font-family: 'barlow_regular';
@include media_queries.media_max(tablet_800) {
font-size: 18px;
}
@include media_queries.media_min(tablet_800) {
font-size: 20px;
}
}
.decouvrir {
display: flex;
.decouvrir_icone {
margin-top: 2px;
margin-right: 5px;
}
.decouvrir_texte {
font-family: 'barlow_regular';
font-size: 18px;
}
}
}
}

View File

@@ -8,11 +8,53 @@
font-family: 'brandontext_regular';
font-size: 16px;
.header_nav_item {
.header_nav_topbar_item {
list-style: none;
cursor: pointer;
margin-right: 30px;
&:last-child {
margin-right: 0px;
}
position: relative;
cursor: pointer;
&:hover {
.header_nav_topbar_submenu {
visibility: visible;
/* Pour l'effet de transition */
opacity: 1;
}
}
}
.header_nav_topbar_submenu {
position: absolute;
left: 0;
z-index: 2;
width: 187px;
visibility:hidden;
/* Pour l'effet de transition */
opacity: 0;
transition: visibility 0.2s,opacity 0.2s cubic-bezier(0.4, 0, 1, 1);
padding-top: 10px;
padding-left: 9px;
padding-right: 16px;
padding-bottom: 5px;
text-align: left;
background-color: rgba(255, 255, 255, 0.95);
border-radius: 3px;
.header_nav_topbar_submenu_item {
list-style: none;
font-family: 'brandontext_regular';
font-size: 15px;
padding-bottom: 2px;
&:hover {
a {
color: var(--c-brand_rouge);
}
}
}
}
.header_nav_lang {
display: flex;
@@ -29,12 +71,16 @@
display: grid;
grid-template-rows: 1fr;
grid-template-columns: 1fr;
@include media_queries.media_min(tablet_600) {
@include media_queries.media_min(tablet_701) {
grid-template-columns: 140px 1fr;
}
}
@include media_queries.media_min(tablet_800) {
grid-template-columns: 140px 1fr;
}
@include media_queries.media_min(tablet_900) {
grid-template-columns: 140px 1fr;
grid-template-columns: 171px 1fr;
}
@include media_queries.media_min(desktop_1000) {
grid-template-columns: 200px 1fr;
@@ -51,16 +97,65 @@
}
.header_nav_logo {
margin-top: -17px;
@include media_queries.media_min(tablet_700) {
margin-top: -7px;
}
@include media_queries.media_min(tablet_800) {
margin-top: -7px;
}
@include media_queries.media_min(tablet_900) {
margin-top: -17px;
}
@include media_queries.media_max(tablet_700) {
width: 166px;
margin-left: 43px;
}
@include media_queries.media_max(phone_500) {
margin-left: 0px;
}
@include media_queries.media_max(phone_300) {
margin-left: 0px;
}
}
.header_nav_cont {
margin-left: 30px;
margin-right: 30px;
@include media_queries.media_max(tablet_800) {
margin-left: 40px;
margin-right: 20px;
}
@include media_queries.media_min(tablet_800) {
margin-left: 25px;
margin-right: 25px;
}
@include media_queries.media_min(tablet_900) {
margin-left: 30px;
margin-right: 30px;
}
@include media_queries.media_max(tablet_700) {
margin-top: -9px;
}
.header_nav {
display: flex;
row-gap: 13px;
justify-content: center;
@include media_queries.media_min(tablet_700) {
justify-content: flex-start;
}
@include media_queries.media_min(tablet_800) {
justify-content: center;
}
flex-wrap: wrap;
text-wrap-mode: nowrap;
font-family: 'brandontext_regular';
@@ -81,8 +176,23 @@
}
.header_nav_item {
margin-right: 34px;
@include media_queries.media_min(tablet_600) {
position: relative;
cursor: pointer;
&:hover {
.header_nav_sub_menu {
visibility: visible;
/* Pour l'effet de transition */
opacity: 1;
}
}
list-style: none;
&:nth-child(5) {
margin-right: 10px;
}
@include media_queries.media_min(tablet_701) {
margin-right: 20px;
}
@include media_queries.media_min(tablet_900) {
@@ -100,24 +210,51 @@
&:last-child {
margin-right: 0px;
}
}
.header_nav_sub_menu {
position: absolute;
left: 0;
z-index: 2;
visibility:hidden;
/* Pour l'effet de transition */
opacity: 0;
transition: visibility 0.2s,opacity 0.2s cubic-bezier(0.4, 0, 1, 1);
padding-top: 10px;
padding-left: 9px;
padding-right: 16px;
padding-bottom: 5px;
text-align: left;
background-color: rgba(255, 255, 255, 0.93);
border-radius: 3px;
.header_nav_sub_menu_item {
list-style: none;
font-family: 'brandontext_regular';
font-size: 18px;
padding-bottom: 2px;
&:hover {
a {
color: var(--c-brand_rouge);
}
}
}
}
.header_nav_icones {
display: flex;
}
.nav_icone {
display: flex;
.nav_icone_img {
margin-right: 6px;
@include media_queries.media_min(tablet_600) {
margin-top: 1px;
}
@include media_queries.media_min(tablet_900) {
margin-top: 1px;
}
@include media_queries.media_min(desktop_1800) {
margin-top: 2px;
}
img {
@include media_queries.media_max(tablet_600) {
width: 83%;
}
@include media_queries.media_min(tablet_600) {
width: 83%;
}
@@ -128,9 +265,195 @@
width: 100%;
}
}
}
.nav_icone_img--agenda {
margin-right: 13px;
@include media_queries.media_min(tablet_600) {
margin-top: 1px;
}
@include media_queries.media_min(tablet_900) {
margin-top: 2px;
}
@include media_queries.media_min(desktop_1800) {
margin-top: 2px;
}
}
.nav_icone_img--ticket {
width: 46px;
margin-top: -4px;
}
}
}
}
/* accessibilité pour que les écran est le message "ouvrir le menu" mais non visible sur l'écran en mode normal*/
.sr-only {
position: absolute;
width: 1px; height: 1px;
padding: 0; margin: -1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
white-space: nowrap;
border: 0;
}
/* Par défaut : desktop visible, mobile caché */
.header_nav--desktop { display: flex; }
.header_nav--mobile { display: none; }
.header_nav--mobile-icons { display: none; }
.header_drawer { display: none; }
/* ✅ Mobile < 700px : on inverse */
@media (max-width: 700px) {
.header_nav--desktop { display: none; }
.header_nav--mobile {
display: flex;
justify-content: flex-end;
margin-top: -21px;
}
.header_nav--mobile-icons {
display: none;
@include media_queries.media_min(phone_400) {
display: flex;
}
justify-content: flex-end;
margin-top: -23px;
margin-right: 60px;
}
.hamburger_black {
background-color: $noir;
}
.hamburger_white {
background-color: $blanc;
}
.header_burger {
position: relative;
background: transparent;
border: 0;
cursor: pointer;
width: 27px;
padding: 8px;
font-size: 26px;
line-height: 1;
img {
width: 31px;
}
.burger_line {
position: absolute;
left: 0;
width: 100%;
height: 3px;
transition:
transform 0.25s ease,
opacity 0.2s ease,
top 0.25s ease;
}
.burger_line:nth-child(1) { top: 0; }
.burger_line:nth-child(2) { top: 8px; }
.burger_line:nth-child(3) { top: 16px; }
&.is-open {
.burger_line:nth-child(1) {
top: 8px;
transform: rotate(45deg);
}
.burger_line:nth-child(2) {
opacity: 0;
}
.burger_line:nth-child(3) {
top: 8px;
transform: rotate(-45deg);
}
}
}
.header_drawer {
display: block;
width: 100%;
position: absolute;
left: 0;
border-top: 1px solid rgba(0,0,0,.1);
background-color: rgba(0, 0, 0, 0.9);
margin-top: 47px;
padding-bottom: 10px;
padding-right: 10px;
padding-left: 40px;
}
.header_drawer[data-open="false"] {
display: none;
}
.header_drawer_inner {
display: flex;
flex-direction: column;
gap: 12px;
padding: 12px 0;
}
.header_drawer_link {
text-decoration: none;
color: $blanc;
padding: 6px 0;
font-size: 26px;
position: relative;
cursor: pointer;
&.is-open {
.header_drawer_sub_menu {
display: block;
visibility: visible;
opacity: 1;
}
}
list-style: none;
}
.header_drawer_sub_menu {
display: none;
max-width: 300px;
//position: absolute;
left: 0;
z-index: 2;
visibility:hidden;
/* Pour l'effet de transition */
opacity: 0;
transition: visibility 0.2s,opacity 0.2s cubic-bezier(0.4, 0, 1, 1);
margin-top: 10px;
margin-left: 20px;
padding-top: 10px;
padding-left: 9px;
padding-right: 16px;
padding-bottom: 5px;
text-align: left;
background-color: rgba(255, 255, 255, 0.93);
border-radius: 3px;
}
.header_drawer_sub_menu_item {
list-style: none;
font-family: 'brandontext_regular';
font-size: 18px;
padding-bottom: 2px;
&:hover {
a {
color: var(--c-brand_rouge);
}
}
}
}
}

View File

@@ -0,0 +1,33 @@
.bg-orbs {
position: absolute;
inset: 0;
z-index: 0;
transform: translateZ(0);
overflow: hidden;
}
.orb {
position: absolute;
border-radius: 999px;
filter: blur(3px);
opacity: 0.30;
will-change: transform;
transform: translate3d(0,0,0);
//background: radial-gradient(circle, rgba(255,255,255,0.20), rgba(255,255,255,0) 60%);
background: red;
}
.orb--1 { width: 100px; height: 100px; top: 2%; left: 18%; animation: orb1 6s ease-in-out infinite alternate; }
.orb--2 { width: 320px; height: 320px; top: 6%; left: 72%; animation: orb2 6s ease-in-out infinite alternate; }
@keyframes orb1 { to { transform: translate3d(30px, 18px, 0); } }
@keyframes orb2 { to { transform: translate3d(-26px, 34px, 0); } }
@keyframes orb3 { to { transform: translate3d(22px, -28px, 0); } }
@keyframes orb4 { to { transform: translate3d(34px, -14px, 0); } }
@keyframes orb5 { to { transform: translate3d(-18px, -18px, 0); } }
@keyframes orb6 { to { transform: translate3d(-34px, 12px, 0); } }
@media (prefers-reduced-motion: reduce) {
.orb { animation: none !important; }
}

View File

@@ -1,4 +1,13 @@
.page-enter-active,
.app {
min-height: 100vh;
display: flex;
flex-direction: column;
}
// Pour que main occupe toute la place de la page et que le footer soit en bas (au cas où le main n'occupe pas toute la hauteur de la page
#main-content {
flex: 1;
}
.page-enter-active,
.page-leave-active {
transition: all 0.4s ease;
}

View File

@@ -8,6 +8,7 @@ $breakpoints: (
"tablet_600": 600px,
"tablet_640": 640px,
"tablet_700": 700px,
"tablet_701": 701px,
"tablet_800": 800px,
"tablet_900": 900px,
"desktop_1000": 1000px,

View File

@@ -1,13 +1,19 @@
@use 'base/reset';
/* à remplacer par Design system */
@use 'base/colors';
@use 'base/text';
@use 'base/button';
@use 'base/img';
@use 'base/fonts';
@use 'base/spaces';
/* Design system */
@use "@root/design-system/tokens/index" as *;
@use 'layout/layout';
@use 'layout/media_queries';
@use 'component/header_full';
@use 'component/header_nav';
@use 'component/_header_layout';
@use 'component/header_nav';
@use 'component/orbites';

193
app/components/Footer.vue Normal file
View File

@@ -0,0 +1,193 @@
<template>
<NewsletterCta />
<PageSection tone="brand" :padded="false" 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" />
</SectionContent>
<SectionContent pad="xs">
<div class="footer--grid">
<div class="footer--grid--orchestre">
<div class="nav--item">L'équipe</div>
<div class="nav--item">Nous contacter</div>
</div>
<div class="footer--grid--nav1">
<div class="nav--title">Nous soutenir</div>
<div class="nav--item">Mécénat</div>
<div class="nav--item">XXXX</div>
</div>
<div class="footer--grid--nav2">
<div class="nav--title">Rejoignez-nous</div>
<div class="nav--item">Recrutement</div>
<div class="nav--item">Académie d'Orchestre</div>
</div>
<div class="footer--grid--social">
<div class="nav--title">Nos réseaux</div>
<div class="nav--item nav--social">
<a class="social" href="...">
<NuxtImg :src="logoInstagram" alt="logo Instagram" height="37" width="37" 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" />
<span class="social__label">YouTube</span>
</a>
<a class="social" href="...">
<NuxtImg :src="logofacebook" alt="logo Facebook" height="37" width="35" 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" />
<span class="social__label">LinkedIn</span>
</a>
</div>
</div>
</div>
</SectionContent pad="xs">
</div>
</PageSection>
<PageSection :padded="false" 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>
<div><img class="footer_logos--img" :src="logoIdf" height="80" alt="logo Région Île-de-France" /></div>
<div><img class="footer_logos--img" :src="logoParis" height="80" alt="logo Région Paris" /></div>
</div>
</SectionContent>
</PageSection>
<PageSection :padded="false" 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>
<div class="footer_mentions--item">Conditions générales de vente</div>
<div class="footer_mentions--item">Mentions légales</div>
</div>
</SectionContent>
</PageSection>
</template>
<script setup>
import logoDefault from '/img/logos/logo_orchestre_red.svg'
import logoInstagram from '/img/icones/instagram_gradient.svg'
import logoyt from '/img/icones/youtube_play_rouge.svg'
import logofacebook from '/img/icones/facebook_rond_bleu.svg'
import logolinkedin from '/img/icones/linkedin_bleu.png'
import logoPrefet from '@/assets/img/logos/logo_pref_idf.webp'
import logoIdf from '@/assets/img/logos/logo_region_idf.webp'
import logoParis from '@/assets/img/logos/logo_region_paris.webp'
const { brand } = useAppConfig()
</script>
<style lang="scss">
.footer {
color: var(--c-text-invert);
font-family: var(--font-roboto);
font-weight: var(--fw-extralight);
&--logo {
max-width: 250px;
img {
filter: invert(100%) sepia(96%) saturate(18%) hue-rotate(237deg) brightness(127%) contrast(105%);
}
}
&--grid {
display: grid;
@media (max-width: 400px) {
grid-template-columns: 1fr;
row-gap: 20px;
}
@media (min-width: 400px) {
grid-template-columns: 1fr 1fr;
column-gap: 30px;
row-gap: 40px;
}
@media (min-width: 900px) {
grid-template-columns: 1.2fr 1fr 1fr 1fr;
column-gap: 50px;
row-gap: 50px;
}
align-items: start;
margin-top: 20px;
}
.nav {
&--title {
padding-bottom: 12px;
font-weight: var(--fw-black);
}
&--item {
padding-bottom: 6px;
}
&--social {
display: grid;
grid-template-columns: max-content max-content;
column-gap: 5px;
row-gap: 6px;
align-items: center;
.social {
display: contents;
&__icon {
display: block;
padding: 4px;
border-radius: 5px;
background-color: rgb(255 255 255 / 83%);
}
}
}
}
}
.footer_logos {
display: flex;
flex-wrap: wrap;
justify-content: center;
column-gap: 15px;
row-gap: 20px;
&--img {
object-fit: contain;
max-height: 70px;
@media (max-width: 300px) {
max-width: 210px;
}
@media (min-width: 300px) {
max-width: 290px;
}
@media (min-width: 400px) {
max-width: 390px;
}
@media (min-width: 900px) {
max-width: 390px;
}
}
}
.footer_mentions {
display: flex;
flex-wrap: wrap;
justify-content: center;
column-gap: 15px;
row-gap: 12px;
font-family: var(--font-roboto);
font-weight: var(--fw-medium);
font-size: 12px;
}
</style>

View File

@@ -0,0 +1,73 @@
<template>
<div class="newslettercta">
<PageSection tone="brandreverse" :padded="false" content-size="default" padb="xs">
<SectionTitle as="h1" tone="invert" pad="xs">
NEWSLETTER
</SectionTitle>
<SectionContent pad="xs" class="newslettercta__content">
<div class="newslettercta__content_text">
<DsText as="p" tone="invert">
Recevez l'actualité des concerts de l'Orchestre national d'Île-de-France par infolettre !
</DsText>
</div>
<div class="newslettercta__button">
<DsButton
href="https://eb686efa.sibforms.com/serve/MUIFAP2a1WdNgM9e0cv4B5b_QwHC_QzCXtnwSoUEWllWVV1Kxq7vbzbRVWoIagXviq-jYQHuKv0-AN8cmEggeJnUds8C4VumwkC0dCTD0kQPVZ8nXWhXG5ABFo4EEys6OY-C_qQW4iUnWeq8cFA8X3dRaLj_q410BX_yvp6E8o5eOklPWsKkZnmXI1Qc31WqegQhTTkp_Z0Jhbg="
target="_blank"
rel="noopener noreferrer"
textColor="invert"
borderColor="invert"
>
Restez informé
</DsButton>
</div>
</SectionContent>
</PageSection>
</div>
</template>
<script setup>
import DsText from '@root/design-system/primitives/DsText.vue'
import DsButton from '@root/design-system/primitives/DsButton.vue'
</script>
<style lang="scss">
.newslettercta {
margin-bottom: 30px;
}
.newslettercta__content {
display: grid;
grid-template-columns: minmax(0, 1fr);
align-items: center;
row-gap: 15px;
column-gap: 15px;
padding-right: 10px;
.newslettercta__content_text {
grid-column: 1;
}
.newslettercta__button {
grid-column: 1;
justify-self: start;
}
}
@media (max-width: 300px) {
.newslettercta__content {
padding-left: calc(var(--section-title-pl, var(--sp-45)) - 20px);
}
}
@media (min-width: 500px) {
.newslettercta__content {
grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
.newslettercta__button {
grid-column: 2;
}
}
}
</style>

View File

@@ -1,30 +0,0 @@
<template>
<NuxtLink :to="to" :class="['btn', variantClass]">
<slot />
</NuxtLink>
</template>
<script setup>
// defineProps() sert à déclarer les propriétés (props) que ton composant peut recevoir depuis lextérieur.
// “Ce composant attend certains paramètres quon lui passera.”
const props = defineProps({
to: {
type: String,
required: true
},
variant: {
type: String,
default: 'primary'
}
})
// la fonction computed sert a se synchroniser chaque fois que la props variant change, ce rend dynamique la mise à jour de la variable, cela s'appelle une propriété calculée
const variantClass = computed(() => {
return `btn--${props.variant}`
})
</script>
<style>
</style>

View File

@@ -0,0 +1,88 @@
<template>
<DsCard class="concert-card">
<div class="concert-card__grid">
<!-- Image -->
<div class="concert-card__media">
<DsMedia :src="imageUrl" :alt="imageAlt" ratio="square" />
</div>
<!-- Content -->
<div class="concert-card__content">
<DsHeading as="h4" tone="default" class="concert-card__title">
{{ title }}
</DsHeading>
<!-- Meta : date + lieu -->
<div class="concert-card__meta">
<DsHeading as="h5" tone="default">
{{ venue }}
</DsHeading>
<DsHeading as="h6" tone="default">
<time :datetime="dateISO">{{ dateLabel }}</time>
</DsHeading>
</div>
<!-- Description -->
<DsText as="p" tone="default" :clamp="3" class="concert-card__description">
{{ description }}
</DsText>
<!-- Actions -->
<div class="concert-card__actions">
<DsButtonArrow :to="`/concerts/${id}`" variant="secondary">
Réserver
</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 },
venue: { type: String, required: true },
dateISO: { type: String, required: true }, // ex: "2026-01-15T20:00:00+01:00"
dateLabel: { type: String, required: true }, // ex: "Jeu. 15 jan. 2026 — 20h"
description: { type: String, default: '' },
imageUrl: { type: String, default: '' },
imageAlt: { type: String, default: '' },
})
</script>
<style lang="scss">
.concert-card__grid {
display: grid;
gap: var(--sp-16);
align-items: start;
}
.concert-card__content {
display: grid;
gap: var(--sp-6);
max-width: 518px;
padding-left: 5px;
padding-right: 5px;
}
.concert-card__meta {
margin-top: calc(var(--sp-4) * -1);
}
.concert-card__description {
margin-top: 10px;
margin-bottom: 20px;
}
.concert-card__actions {
margin-top: auto;
}
</style>

View File

@@ -0,0 +1,126 @@
<template>
<div class="concert-card-list">
<slot />
</div>
</template>
<style lang="scss">
.concert-card-list {
display: flex;
flex-wrap: wrap;
gap: var(--gap-cards);
justify-content: center;
}
// Afficher seulement 1 cards < 600px
@media (max-width: 599px) {
.concert-card-list > .concert-card:nth-child(2) {
display: none;
}
.concert-card-list > .concert-card:nth-child(3) {
display: none;
}
}
// Afficher seulement 2 cards < 900px
@media (max-width: 899px) {
.concert-card-list > .concert-card:nth-child(3) {
display: none;
}
}
// Taille des cards
@media (max-width: 599px) {
.concert-card-list > .concert-card {
flex: 1 1 260px;
max-width: 90%;
}
}
@media (min-width: 600px) {
.concert-card-list > .concert-card {
flex: 1 1 260px;
}
.concert-card-list > .concert-card:first-child {
flex: 2 1 280px;
}
}
@media (min-width: 700px) {
.concert-card-list > .concert-card {
flex: 1 1 280px;
}
.concert-card-list > .concert-card:first-child {
flex: 2 1 300px;
}
}
@media (min-width: 800px) {
.concert-card-list > .concert-card {
flex: 1 1 280px;
}
.concert-card-list > .concert-card:first-child {
flex: 2 1 300px;
}
}
@media (min-width: 900px) {
.concert-card-list > .concert-card {
flex: 1 1 260px;
}
.concert-card-list > .concert-card:first-child {
flex: 2 1 300px;
}
}
@media (min-width: 1000px) {
.concert-card-list > .concert-card {
flex: 1 1 280px;
}
.concert-card-list > .concert-card:first-child {
flex: 2 1 340px;
}
}
@media (min-width: 1100px) {
.concert-card-list > .concert-card {
flex: 1 1 300px;
}
.concert-card-list > .concert-card:first-child {
flex: 2 1 380px;
}
}
@media (min-width: 1200px) {
.concert-card-list > .concert-card {
flex: 1 1 320px;
}
.concert-card-list > .concert-card:first-child {
flex: 2 1 400px;
}
}
@media (min-width: 1300px) {
.concert-card-list > .concert-card {
flex: 1 1 340px;
}
.concert-card-list > .concert-card:first-child {
flex: 2 1 440px;
}
}
@media (min-width: 1400px) {
// style appliqué au composant enfant via sa classe
.concert-card-list > .concert-card {
flex: 1 1 360px;
}
//règle spécifique après la règle générale
.concert-card-list > .concert-card:first-child {
flex: 2 1 480px;
}
}
</style>

View File

@@ -0,0 +1,13 @@
<script setup>
defineProps({
burgerColor: { type: String, default: 'hamburger_black' }
})
</script>
<template>
<span class="burger">
<span :class="['burger_line', burgerColor]"></span>
<span :class="['burger_line', burgerColor]"></span>
<span :class="['burger_line', burgerColor]"></span>
</span>
</template>

View File

@@ -0,0 +1,34 @@
<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'
const { brand } = useAppConfig()
</script>
<template>
<HeaderNav burger-color="hamburger_black">
<template #logo>
<NuxtImg :src="logoDefault" :alt="brand.logoAlt" class="logo-img" />
</template>
<template #agenda-icon>
<img :src="agendaRouge" alt="icone agenda" />
</template>
<template #ticket>
<img class="img_ticket" :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" />
</template>
</HeaderNav>
</template>
<style lang="scss">
</style>

View File

@@ -0,0 +1,57 @@
<script setup>
import logoFull from '/img/logos/logo_blanc_rouge.png'
import agendaNoir from '@/assets/img/icones/agenda_rouge_fonce_blanc.svg'
import ticket from '@/assets/img/icones/ticket_white.svg'
import mobile_agenda_icon from '@/assets/img/icones/agenda_rouge_fonce_blanc.svg'
import mobile_ticket from '@/assets/img/icones/ticket_white.svg'
const { brand } = useAppConfig()
</script>
<template>
<HeaderNav burger-color="hamburger_white">
<template #logo>
<NuxtImg :src="logoFull" :alt="brand.logoAlt" class="logo-img" />
</template>
<template #agenda-icon>
<img :src="agendaNoir" alt="icone agenda" />
</template>
<template #ticket>
<img :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" />
</template>
</HeaderNav>
<div class="obscur"></div>
<div class="header-img_cont">
<NuxtImg
src="/img/photos/zaho.jpg"
placeholder
preset="full"
alt="L'orchestre National d'Île-de-france en concert - vue d'ensemble"
class="header-img"
/>
</div>
<div class="header-img_text">
<div class="header-img_titre">ZAHO DE SAGAZAN</div>
<div class="header-img_description">Accompagnée par lOrchestre national dÎle-de-France dirigé par Dylan Corlay, Zaho de Sagazan revisite les chansons de son premier album pour les plonger dans une toute nouvelle dimension !</div>
<div class="decouvrir"><div class="decouvrir_icone"><img src="@/assets/img/icones/fleche_gris_blanc.svg" alt="icone flèche"></div><div class="decouvrir_texte">Découvrir</div></div>
</div>
</template>

View File

@@ -0,0 +1,278 @@
<template>
<div class="header_navigation">
<div class="height_10"></div>
<ul class="header_navigation_topbar" aria-label="Language selector">
<li class="header_nav_topbar_item">
Professionnels
<ul class="header_nav_topbar_submenu">
<li class="header_nav_topbar_submenu_item"><NuxtLink to="/">Programmer l'Orchestre</NuxtLink></li>
<li class="header_nav_topbar_submenu_item"><NuxtLink to="/">Le studio et les espaces</NuxtLink></li>
<li class="header_nav_topbar_submenu_item"><NuxtLink to="/">Louer des instruments</NuxtLink></li>
<li class="header_nav_topbar_submenu_item"><NuxtLink to="/">Recrutement / Concours</NuxtLink></li>
<li class="header_nav_topbar_submenu_item"><NuxtLink to="/">Espace candidats</NuxtLink></li>
<li class="header_nav_topbar_submenu_item"><NuxtLink to="/">Presse</NuxtLink></li>
</ul>
</li>
<li class="header_nav_topbar_item header_nav_lang">
<div class="header_nav_lang_item">FR</div>
<div class="header_nav_lang_item">/</div>
<div class="header_nav_lang_item">EN</div>
</li>
</ul>
<div class="height_20"></div>
<div class="header_navigation_main">
<div class="header_nav_logo">
<!-- LOGO injecté -->
<slot name="logo" />
</div>
<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">
L'Orchestre
<ul class="header_nav_sub_menu">
<li class="header_nav_sub_menu_item"><NuxtLink to="/">Nos missions</NuxtLink></li>
<li class="header_nav_sub_menu_item"><NuxtLink to="/">Direction musicale</NuxtLink></li>
<li class="header_nav_sub_menu_item"><NuxtLink to="/">Les musiciens</NuxtLink></li>
<li class="header_nav_sub_menu_item"><NuxtLink to="/">Les artistes invités</NuxtLink></li>
<li class="header_nav_sub_menu_item"><NuxtLink to="/">Discographie</NuxtLink></li>
<li class="header_nav_sub_menu_item"><NuxtLink to="/">Nos partenaires</NuxtLink></li>
<li class="header_nav_sub_menu_item"><NuxtLink to="/">Nous soutenir</NuxtLink></li>
</ul>
</li>
<li class="header_nav_item">
Concerts
<ul class="header_nav_sub_menu">
<li class="header_nav_sub_menu_item"><NuxtLink to="/">Saison</NuxtLink></li>
<li class="header_nav_sub_menu_item"><NuxtLink to="/">Jeune public</NuxtLink></li>
<li class="header_nav_sub_menu_item"><NuxtLink to="/">Concert mode d'emploi</NuxtLink></li>
<li class="header_nav_sub_menu_item"><NuxtLink to="/">ONDIF MAG</NuxtLink></li>
<li class="header_nav_sub_menu_item"><NuxtLink to="/">ONDIF LIVE !</NuxtLink></li>
</ul>
</li>
<li class="header_nav_item brandontext_bold">
Éducation et médiation
<ul class="header_nav_sub_menu">
<li class="header_nav_sub_menu_item"><NuxtLink to="/">Petite enfance</NuxtLink></li>
<li class="header_nav_sub_menu_item"><NuxtLink to="/">Scolaires</NuxtLink></li>
<li class="header_nav_sub_menu_item"><NuxtLink to="/">Champ social</NuxtLink></li>
<li class="header_nav_sub_menu_item"><NuxtLink to="/">Insertion professionnelle</NuxtLink></li>
<li class="header_nav_sub_menu_item"><NuxtLink to="/">Pratiques amateurs</NuxtLink></li>
<li class="header_nav_sub_menu_item"><NuxtLink to="/">Ressources pédagogiques</NuxtLink></li>
</ul>
</li>
<li class="header_nav_item">
Mécénat
<ul class="header_nav_sub_menu">
<li class="header_nav_sub_menu_item"><NuxtLink to="/">Entreprises</NuxtLink></li>
<li class="header_nav_sub_menu_item"><NuxtLink to="/">Les projets</NuxtLink></li>
<li class="header_nav_sub_menu_item"><NuxtLink to="/">Particuliers</NuxtLink></li>
<li class="header_nav_sub_menu_item"><NuxtLink to="/">Ils nous font confiance</NuxtLink></li>
</ul>
</li>
<li class="header_nav_item header_nav_icones">
<div class="">
<NuxtLink to="/agenda">
<div class="nav_icone">
<div class="nav_icone_img nav_icone_img--agenda">
<!-- ICÔNE injectée -->
<span class="sr-only">Agenda</span>
<slot name="agenda-icon" />
</div>
</div>
</NuxtLink>
</div>
<div class=" padding_top_1">
<NuxtLink to="/agenda">
<div class="nav_icone">
<div class="nav_icone_img nav_icone_img--ticket">
<!-- ICÔNE injectée -->
<span class="sr-only">billeterie</span>
<slot name="ticket" />
</div>
</div>
</NuxtLink>
</div>
</li>
</ul>
<!-- Mobile nav -->
<div class="header_nav--mobile">
<button
class="header_burger"
type="button"
:class="{ 'is-open': isOpen }"
:aria-expanded="isOpen ? 'true' : 'false'"
aria-controls="mobile-menu"
@click="toggle"
>
<span class="sr-only">{{ isOpen ? 'Fermer le menu' : 'Ouvrir le menu' }}</span>
<!-- icone hamburger injecté -->
<BurgerIcon :burger-color="burgerColor" />
</button>
</div>
<!-- Mobile icons -->
<div class="header_nav header_nav--mobile-icons">
<div class="header_nav_item">
<NuxtLink to="/agenda">
<div class="nav_icone">
<div class="nav_icone_img nav_icone_img--agenda">
<!-- ICÔNE injectée -->
<span class="sr-only">Agenda</span>
<slot name="agenda-icon" />
</div>
</div>
</NuxtLink>
</div>
<div class="header_nav_item padding_top_1">
<NuxtLink to="/agenda">
<div class="nav_icone">
<div class="nav_icone_img nav_icone_img--ticket">
<!-- ICÔNE injectée -->
<span class="sr-only">billeterie</span>
<slot name="ticket" />
</div>
</div>
</NuxtLink>
</div>
</div>
<!-- Mobile drawer -->
<div
id="mobile-menu"
class="header_drawer"
:data-open="isOpen ? 'true' : 'false'"
>
<ul class="header_drawer_inner">
<li
class="header_drawer_link brandontext_bold"
:class="{ 'is-open': activeDrawer === 'orchestre' }"
@click="toggleDrawer('orchestre')"
>
L'Orchestre
<ul class="header_drawer_sub_menu">
<li class="header_drawer_sub_menu_item"><NuxtLink to="/">Nos missions</NuxtLink></li>
<li class="header_drawer_sub_menu_item"><NuxtLink to="/">Direction musicale</NuxtLink></li>
<li class="header_drawer_sub_menu_item"><NuxtLink to="/">Les musiciens</NuxtLink></li>
<li class="header_drawer_sub_menu_item"><NuxtLink to="/">Les artistes invités</NuxtLink></li>
<li class="header_drawer_sub_menu_item"><NuxtLink to="/">Discographie</NuxtLink></li>
<li class="header_drawer_sub_menu_item"><NuxtLink to="/">Nos partenaires</NuxtLink></li>
<li class="header_drawer_sub_menu_item"><NuxtLink to="/">Nous soutenir</NuxtLink></li>
</ul>
</li>
<li
class="header_drawer_link"
:class="{ 'is-open': activeDrawer === 'concerts' }"
@click="toggleDrawer('concerts')"
>
Concerts
<ul class="header_drawer_sub_menu">
<li class="header_drawer_sub_menu_item"><NuxtLink to="/">Saison</NuxtLink></li>
<li class="header_drawer_sub_menu_item"><NuxtLink to="/">Jeune public</NuxtLink></li>
<li class="header_drawer_sub_menu_item"><NuxtLink to="/">Concert mode d'emploi</NuxtLink></li>
<li class="header_drawer_sub_menu_item"><NuxtLink to="/">ONDIF MAG</NuxtLink></li>
<li class="header_drawer_sub_menu_item"><NuxtLink to="/">ONDIF LIVE !</NuxtLink></li>
</ul>
</li>
<li
class="header_drawer_link brandontext_bold"
:class="{ 'is-open': activeDrawer === 'education' }"
@click="toggleDrawer('education')"
>
Éducation et médiation
<ul class="header_drawer_sub_menu">
<li class="header_drawer_sub_menu_item"><NuxtLink to="/">Petite enfance</NuxtLink></li>
<li class="header_drawer_sub_menu_item"><NuxtLink to="/">Scolaires</NuxtLink></li>
<li class="header_drawer_sub_menu_item"><NuxtLink to="/">Champ social</NuxtLink></li>
<li class="header_drawer_sub_menu_item"><NuxtLink to="/">Insertion professionnelle</NuxtLink></li>
<li class="header_drawer_sub_menu_item"><NuxtLink to="/">Pratiques amateurs</NuxtLink></li>
<li class="header_drawer_sub_menu_item"><NuxtLink to="/">Ressources pédagogiques</NuxtLink></li>
</ul>
</li>
<li
class="header_drawer_link"
:class="{ 'is-open': activeDrawer === 'mecenat' }"
@click="toggleDrawer('mecenat')"
>
Mécénat
<ul class="header_drawer_sub_menu">
<li class="header_drawer_sub_menu_item"><NuxtLink to="/">Entreprises</NuxtLink></li>
<li class="header_drawer_sub_menu_item"><NuxtLink to="/">Les projets</NuxtLink></li>
<li class="header_drawer_sub_menu_item"><NuxtLink to="/">Particuliers</NuxtLink></li>
<li class="header_drawer_sub_menu_item"><NuxtLink to="/">Ils nous font confiance</NuxtLink></li>
</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>
</ul>
</div>
</nav>
</div>
<div class="height_25"></div>
</div>
</template>
<script setup>
import { ref } from 'vue'
import { useRoute } from 'vue-router'
import { watch } from 'vue'
defineProps({
burgerColor: { type: String, default: 'hamburger_black' }
})
const isOpen = ref(false)
const activeDrawer = ref(null)
const toggle = () => (isOpen.value = !isOpen.value)
const close = () => (isOpen.value = false)
const toggleDrawer = (key) => {
activeDrawer.value = activeDrawer.value === key ? null : key
}
// ✅ ferme automatiquement le mobile drawer si on navigue
const route = useRoute()
watch(() => route.fullPath, () => {
close()
activeDrawer.value = null
})
</script>
<style lang="scss">
.icon_mobile_agenda {
width: 35px;
margin-top: 10px;
img {
width: 100%
}
}
.icon_mobile_ticket {
width: 61px;
img {
width: 100%
}
}
</style>

View File

@@ -0,0 +1,21 @@
<script setup>
defineProps({
theme: { type: String, default: 'dark' }
})
</script>
<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" />
</div>
<div class="header_layout" :class="`header--${theme}`">
<slot />
</div>
</header>
</template>

View File

@@ -1,77 +0,0 @@
<script setup>
defineProps({
logoSrc: {
type: String,
required: true
},
logoAlt: {
type: String,
required: true
},
imgAgendaSrc: {
type: String,
required: true
}
})
</script>
<template>
<div class="header_navigation">
<div class="height_10"></div>
<nav class="header_navigation_topbar">
<div class="header_nav_item">Professionnels</div>
<div class="header_nav_item header_nav_lang">
<div class="header_nav_lang_item">FR</div>
<div class="header_nav_lang_item">/</div>
<div class="header_nav_lang_item">EN</div>
</div>
</nav>
<div class="height_20"></div>
<div class="header_navigation_main">
<div class="header_nav_logo">
<NuxtImg
:src="logoSrc"
:alt="logoAlt"
class="logo-img"
/>
</div>
<nav class="header_nav_cont">
<div class="header_nav">
<div class="header_nav_item brandontext_bold">
<NuxtLink to="/">L'Orchestre</NuxtLink>
</div>
<div class="header_nav_item">
<NuxtLink to="/agenda">Concerts</NuxtLink>
</div>
<div class="header_nav_item brandontext_bold">
<NuxtLink to="/agenda">Éducation et médiation</NuxtLink>
</div>
<div class="header_nav_item">
<NuxtLink to="/agenda">Mécénat</NuxtLink>
</div>
<div class="header_nav_item">
<NuxtLink to="/agenda">
<div class="nav_icone">
<div class="nav_icone_img"><img :src="imgAgendaSrc" alt="icone agenda"></div>
<div>Agenda</div>
</div>
</NuxtLink>
</div>
</div>
</nav>
</div>
<div class="height_25"></div>
</div>
</template>
<style>
</style>

View File

@@ -1,36 +0,0 @@
<script setup>
import agenda from '@/assets/img/icones/agenda_rouge_fonce_blanc.svg'
</script>
<template>
<div class="header_full">
<header_content
logo-src="/img/logos/logo_blanc_rouge.png"
logo-alt="Logo de l'orchestre National d'Île-de-france en concert"
:img-agenda-src="agenda"
/>
<div class="obscur"></div>
<div class="header-img_cont">
<NuxtImg
src="/img/photos/zaho.jpg"
placeholder
preset="full"
alt="L'orchestre National d'Île-de-france en concert - vue d'ensemble"
class="header-img"
/>
</div>
<div class="header-img_text">
<div class="header-img_titre">ZAHO DE SAGAZAN</div>
<div class="header-img_description">Accompagnée par lOrchestre national dÎle-de-France dirigé par Dylan Corlay, Zaho de Sagazan revisite les chansons de son premier album pour les plonger dans une toute nouvelle dimension !</div>
<div class="decouvrir"><div class="decouvrir_icone"><img src="@/assets/img/icones/fleche_gris_blanc.svg" alt="icone flèche"></div><div class="decouvrir_texte">Découvrir</div></div>
</div>
</div>
</template>

View File

@@ -0,0 +1,59 @@
<!--
La section par défaut fait la largeur de la page.
On peut mettre de la couleur ou pas.
C'est le contenu de la section (PageSectionInner) qui aura une marge.
Et avec "content" à "false" on peut dire aussi qu'on n'utilise pas le PageSectionInner, au cas où...
-->
<template>
<section
class="page-section"
:class="[
`page-section--${tone}`,
{ 'page-section--padded': padded }
]"
>
<!-- Si content == true -->
<PageSectionInner v-if="content" :size="contentSize" :padt="padt" :padb="padb">
<slot />
</PageSectionInner>
<!-- Si content == false -->
<template v-else>
<slot />
</template>
</section>
</template>
<script setup>
defineProps({
tone: { type: String, default: 'default' }, // default / brand / muted / dark…
padded: { type: Boolean, default: true }, // padding vertical
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
})
</script>
<style lang="scss">
.page-section {
position: relative;
width: 100%;
//min-height: var(--sp-200);
/* tons = arrière-plan section */
&--default { background: transparent; }
&--brand { background: var(--c-brand_rouge);}
&--dark { background: var(--c-backgroud-black); }
&--brandreverse { background: var(--c-backgroud-brandreverse); }
// padding en haut et en bas
&--padded {
padding-top: 30px;
padding-bottom: 50px;
}
}
</style>

View File

@@ -0,0 +1,99 @@
<!-- Pour gérer tous les types de main dans les différents templates de page
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}`]">
<slot />
</div>
</template>
<script setup>
defineProps({
size: { type: String, default: 'default' }, // default / wide / narrow
padb : { type: String, default: '' },
padt : { type: String, default: '' }
})
</script>
<style lang="scss">
.page-section--inner {
// ne dépasse jamais lécran
width: 100%;
// centre le bloc horizontalement, crée des marges externes fluides, fonctionne dans toutes les largeurs décran
margin-inline: auto;
// respiration sur les côtés avec marges minimale ( surtout utile pour mobiles)
// limite de largeur quand on veut une largeur plus petit (pour les articles par exemple)
&--narrow {
max-width: var(--container-narrow);
}
// limite de largeur (par défaut)
&--default {
/* mobile / small screens */
@media (max-width: 700px) {
padding-inline: var(--page-padding-mobile);
}
@media (min-width: 0px) {
max-width: 100%;
}
@media (min-width: 600px) {
max-width: 580px;
}
@media (min-width: 700px) {
max-width: 660px;
}
@media (min-width: 800px) {
max-width: 780px;
}
@media (min-width: 900px) {
max-width: 860px;
}
@media (min-width: 1000px) {
max-width: 950px;
}
@media (min-width: 1100px) {
max-width: 1020px;
}
@media (min-width: 1200px) {
max-width: 1100px;
}
@media (min-width: 1300px) {
max-width: 1200px;
}
@media (min-width: 1400px) {
max-width: 1300px;
}
@media (min-width: 1500px) {
max-width: 1400px;
}
}
// limite de largeur un peu plus grande que par défaut
&--wide {
max-width: var(--container-wide);
}
// Padding
&--padt--xs {
padding-top: 30px;
}
&--padt--sm {
padding-top: 45px;
}
&--padb--xs {
padding-bottom: 17px;
}
&--padb--sm {
padding-bottom: 30px;
}
}
</style>

View File

@@ -0,0 +1,60 @@
<template>
<div
:class="[
`section-content`,
`section-content--tone-${tone}`,
`section-content--pad-${pad}`
]"
>
<slot />
</div>
</template>
<script setup>
defineProps({
as: { type: String, default: 'h2' },
tone: { type: String, default: 'default' },
pad: { type: String, default: '' }, // xs, sm, md, lg
})
</script>
<style lang="scss">
.section-content {
&--tone-default { background: transparent; }
&--tone-brand { background: var(--c-brand_rouge); }
&--tone-brand_rouge45 { background: var(--c-brand_rouge45); }
&--tone-muted { background: var(--c-brand_rouge-weak); }
&--tone-dark { background: var(--c-backgroud-black); }
&--tone-brandreverse { background: var(--c-backgroud-brandreverse); }
&--pad-xs {
padding-top: var(--sp-32);
padding-bottom: var(--sp-16);
padding-left: var(--sp-45);
}
&--pad-sm {
padding-top: var(--sp-32);
padding-bottom: var(--sp-16);
padding-left: var(--sp-45);
}
&--pad-md {
padding-top: var(--sp-80);
padding-bottom: var(--sp-180);
padding-left: var(--sp-45);
}
&--pad-lg {
padding-top: var(--sp-80);
padding-bottom: var(--sp-180);
padding-left: var(--sp-45);
}
}
@media (max-width: 300px) {
.section-title {
padding-left: calc(var(--section-title-pl, var(--sp-45)) - 20px);
}
}
</style>

View File

@@ -0,0 +1,56 @@
<template>
<DsHeading
as="h1"
:tone="tone"
:class="[
`section-title`,
`section-title--pad-${pad}`
]"
>
<slot />
</DsHeading>
</template>
<script setup>
import DsHeading from '@root/design-system/primitives/DsHeading.vue'
defineProps({
as: { type: String, default: 'h2' },
tone: { type: String, default: 'default' },
pad: { type: String, default: 'sm' }, // xs, sm, md, lg
})
</script>
<style lang="scss">
.section-title {
&--pad-xs {
padding-top: var(--sp-32);
padding-bottom: var(--sp-16);
padding-left: var(--sp-45);
}
&--pad-sm {
padding-top: var(--sp-48);
padding-bottom: var(--sp-48);
padding-left: var(--sp-45);
}
&--pad-md {
padding-top: var(--sp-80);
padding-bottom: var(--sp-180);
padding-left: var(--sp-45);
}
&--pad-lg {
padding-top: var(--sp-80);
padding-bottom: var(--sp-180);
padding-left: var(--sp-45);
}
}
@media (max-width: 300px) {
.section-title {
padding-left: calc(var(--section-title-pl, var(--sp-45)) - 20px);
}
}
</style>

20
app/layouts/default.vue Normal file
View File

@@ -0,0 +1,20 @@
<template>
<HeaderWrapper theme="light">
<HeaderDefault />
</HeaderWrapper>
<main id="main-content">
<!-- Cest le slot du layout qui reçoit le contenu de la page (pages/*.vue). -->
<slot />
</main>
<footer>
<Footer />
</footer>
</template>
<script setup>
</script>

View File

@@ -0,0 +1,15 @@
<template>
<HeaderWrapper theme="dark">
<HeaderFull />
</HeaderWrapper>
<main id="main-content">
<slot />
</main>
<footer>
<Footer />
</footer>
</template>

View File

@@ -1,68 +1,15 @@
<template>
<div>
<h1>Page Agenda</h1>
<div>
<p>Lien interne</p>
<div>
<button_link to="/">Voir l'accueil</button_link>
</div>
<div>
<button_link to="/" variant="primary">Voir l'accueil</button_link>
</div>
<div>
<button_link to="/" variant="secondary">Voir l'accueil</button_link>
</div>
<div>
<button_link to="/" variant="outline">Voir l'accueil</button_link>
</div>
</div>
<div v-if="errorApi1">Erreur : {{ errorApi1.message }}</div>
<div v-else-if="!api1">Chargement en cours...</div>
<div v-else>
<h2 v-if="api1">{{ api1.message }}</h2>
<h2 v-if="api1">api1 = {{ api1 }}</h2>
</div>
<testcomponentpage />
<div v-if="errorTotos">Erreur : {{ errorTotos.message }}</div>
<div v-else-if="!totos">Chargement en cours...</div>
<div v-else>
<pre v-if="totos">
{{ totos }}
</pre>
<div v-if="totos">
<article v-for="toto in totos" :key="toto.id">
<h2>{{ toto.title }}</h2>
<p>{{ toto.body.slice(0, 1000) }}</p>
<p>
<NuxtLink :to="`/concerts/concert-${toto.id}`">Lire la suite</NuxtLink>
</p>
</article>
</div>
</div>
</div>
<ConcertCard
v-for="c in concerts"
:key="c.id"
:title="c.title"
:date-label="c.dateLabel"
:venue="c.venue"
:city="c.city"
:image="{ src: c.imageUrl, alt: c.imageAlt }"
:tags="c.tags"
:price-from="c.priceFrom"
:is-sold-out="c.soldOut"
:href="`/concerts/${c.slug}`"
/>
</template>
<script setup>
import button_link from '~/components/button_link.vue'
const {data: totos, error: errorTotos} = await useFetch(() => 'https://jsonplaceholder.typicode.com/posts?_limit=20')
const {data: api1, error: errorApi1} = await useFetch('/api/hello')
const config = useAppConfig()
useSeoMeta({
title: config.title
})
const appConfig = useAppConfig()
console.log("test 4 : ",appConfig.title) // "Mon site Nuxt"
</script>
<style>
</style>

66
app/pages/agendatest.vue Normal file
View File

@@ -0,0 +1,66 @@
<template>
<div>
<h1>Page Agenda</h1>
<div>
<p>Lien interne</p>
<div>
<NuxtLink to="/" class="btn btn--primary">Voir l'accueil</NuxtLink>
</div>
<div>
<NuxtLink to="/" class="btn btn--primary">Voir l'accueil</NuxtLink>
</div>
<div>
<NuxtLink to="/" class="btn btn--secondary">Voir l'accueil</NuxtLink>
</div>
<div>
<NuxtLink to="/" class="btn btn--outline">Voir l'accueil</NuxtLink>
</div>
</div>
<div v-if="errorApi1">Erreur : {{ errorApi1.message }}</div>
<div v-else-if="!api1">Chargement en cours...</div>
<div v-else>
<h2 v-if="api1">{{ api1.message }}</h2>
<h2 v-if="api1">api1 = {{ api1 }}</h2>
</div>
<testcomponentpage />
<div v-if="errorTotos">Erreur : {{ errorTotos.message }}</div>
<div v-else-if="!totos">Chargement en cours...</div>
<div v-else>
<pre v-if="totos">
{{ totos }}
</pre>
<div v-if="totos">
<article v-for="toto in totos" :key="toto.id">
<h2>{{ toto.title }}</h2>
<p>{{ toto.body.slice(0, 1000) }}</p>
<p>
<NuxtLink :to="`/concerts/concert-${toto.id}`">Lire la suite</NuxtLink>
</p>
</article>
</div>
</div>
</div>
</template>
<script setup>
const {data: totos, error: errorTotos} = await useFetch(() => 'https://jsonplaceholder.typicode.com/posts?_limit=20')
const {data: api1, error: errorApi1} = await useFetch('/api/hello')
const config = useAppConfig()
useSeoMeta({
title: config.title
})
const appConfig = useAppConfig()
console.log("test 4 : ",appConfig.title) // "Mon site Nuxt"
</script>
<style lang="scss">
</style>

View File

@@ -19,6 +19,6 @@
})
</script>
<style>
<style lang="scss">
</style>

138
app/pages/design-system.vue Normal file
View File

@@ -0,0 +1,138 @@
<template>
<div class="ds-preview">
<DsHeading class="titre" as="h1" size="">Design du site internet de l'Orchestre National d'Île-de-France</DsHeading>
<DsHeading class="centrer" as="h1" tone="brand_rouge" size="">TYPOGRAPHIE</DsHeading>
<div class="category">
<DsHeading class="centrer rempli" as="h3" size="">Les titres avec la police Roboto Flex (police par défaut des titres)</DsHeading>
<DsHeading as="h1" size="">Titres niveau 1 (h1) Roboto extrabold Taille 2xl/40px</DsHeading>
<DsHeading as="h2" size="">Titres niveau 2 (h2) Roboto bold Taille xl/32px</DsHeading>
<DsHeading as="h3" size="">Titres niveau 3 (h3) Roboto semibold Taille lg/24px</DsHeading>
<br>
<hr>
<br>
<DsHeading as="h4" size="">Titre de carte niveau 4 (h4) Roboto black Taille lg2/30px</DsHeading>
<DsHeading as="h5" size="">Titres de carte niveau 5 (h5) Roboto medium Taille md2/23px</DsHeading>
<DsHeading as="h6" size="">Titres de carte niveau 6 (h6) Roboto extralight Taille xs2/17px</DsHeading>
</div>
<div class="category">
<DsHeading class="centrer rempli" as="h3" size="">Les titres avec la police Brandon</DsHeading>
<DsHeading as="h1" font="brandon" size="">Titres niveau 1 (h1) Brandon extrabold Taille 2xl/40px</DsHeading>
<DsHeading as="h2" font="brandon" size="">Titres niveau 2 (h2) Brandon bold Taille xl/32px</DsHeading>
<DsHeading as="h3" font="brandon" size="">Titres niveau 3 (h3) Brandon semibold Taille lg/24px</DsHeading>
<br>
<hr>
<br>
<DsHeading as="h4" font="brandon" size="">Titres de carte niveau 4 (h4) Brandon black Taille lg2/30px</DsHeading>
<DsHeading as="h5" font="brandon" size="">Titres de carte niveau 5 (h5) Brandon medium Taille md2/23px</DsHeading>
<DsHeading as="h6" font="brandon" size="">Titres de carte niveau 6 (h6) Brandon extralight Taille xs2/17px</DsHeading>
</div>
<div class="category">
<DsHeading class="centrer rempli" as="h3" font="barlow" size="">Les titres avec la police Barlow</DsHeading>
<DsHeading as="h1" font="barlow" size="">Titres niveau 1 (h1) Barlow extrabold Taille 2xl/40px</DsHeading>
<DsHeading as="h2" font="barlow" size="">Titres niveau 2 (h2) Barlow bold Taille xl/32px</DsHeading>
<DsHeading as="h3" font="barlow" size="">Titres niveau 3 (h3) Barlow semibold Taille lg/24px</DsHeading>
<br>
<hr>
<br>
<DsHeading as="h4" font="barlow" size="">Titres de carte niveau 4 (h4) Barlow black Taille lg2/30px</DsHeading>
<DsHeading as="h5" font="barlow" size="">Titres de carte niveau 5 (h5) Barlow medium Taille md2/23px</DsHeading>
<DsHeading as="h6" font="barlow" size="">Titres de carte niveau 6 (h6) Barlow extralight Taille xs2/17px</DsHeading>
</div>
<div class="category">
<DsHeading class="centrer rempli" as="h3">Les textes</DsHeading>
<DsText as="p" tone="brand_rouge">
Texte standard police Roboto Flex / Taille 16px / couleur rouge ONDIF: info éditoriale, description, contenu darticle.
</DsText>
<br>
<hr>
<br>
<DsText as="p" font="brandon">
Texte police Brandon / Taille 16px : info éditoriale, description, contenu darticle.
</DsText>
<br>
<hr>
<br>
<DsText as="p" font="barlow">
Texte police Barlow / Taille 16px : info éditoriale, description, contenu darticle.
</DsText>
<br>
<hr>
<br>
<DsText as="p" :clamp="2">
Texte police Roboto Flex / Taille 16px / clampé sur 2 lignes pour les cartes (résumé, programme, etc.).
Si ça dépasse, ça coupe proprement. Pour du texte de description qui doit tenir dans un cadre, mais qui a été écrit trop long, pour ne pas casser le design du site, on va limiter l'affichage à 2 lignes. c'est pour des espace réduit. Pour ne pas casser le design de la page. J'ai presque écrit 2 lignes, je vais bientôt être censurée.
</DsText>
</div>
<div class="category">
<DsHeading class="centrer rempli" as="h3">Carte concert</DsHeading>
<DsText as="p" tone="brand_rouge">
Pour les endroits où il y a une liste de concert page d'accueil, page agenda, page saison...
</DsText>
<br>
<hr>
<br>
<ConcertCard
id="1"
title="TITRE DU CONCERT EN MAJUSCULE"
venue="Nom du lieu, éventuellement de la salle"
dateISO="2026-01-15T20:30:00+01:00"
dateLabel="Jeudi 15 janvier 2026 — 20h30"
description="Description du concert assez courte qui reprend l'essentiel, les artistes... On pourra écrire un nombre de lettres limitées."
imageUrl="https://picsum.photos/id/56/500/700"
imageAlt="Orchestre sur scène"
ctaHref="/concert[id]"
detailsHref="/concerts/concert_template"
/>
</div>
</div>
</template>
<script setup>
import DsHeading from '@root/design-system/primitives/DsHeading.vue'
import DsText from '@root/design-system/primitives/DsText.vue'
</script>
<style lang="scss">
.ds-preview {
display: grid;
//gap: var(--sp-4);
padding: var(--sp-48);
justify-content: center;
}
.titre {
justify-self: center;
margin-bottom: 50px;
}
.category {
max-width: 1000px;
justify-self: flex-start;
margin-bottom: 30px;
padding: 40px;
border-radius: 14px;
}
.centrer {
justify-self: center;
margin-bottom: 30px;
}
.rempli {
width: 100%;
background-color: #ebebeb;
padding-top: 5px;
padding-bottom: 5px;
padding-left: 10px;
padding-right: 5px;
border-radius: 5px;
}
</style>

90
app/pages/index copie.vue Normal file
View File

@@ -0,0 +1,90 @@
<template>
<!-- Cas avec cadre couleur full page mais contenu dans marge -->
<PageSection tone="dark" :padded="true" content-size="default">
<DsHeading as="h1" size="">CONCERTS À VENIR...</DsHeading>
<ConcertCard
id="1"
title="TITRE DU CONCERT EN MAJUSCULE"
venue="Nom du lieu, éventuellement de la salle"
dateISO="2026-01-15T20:30:00+01:00"
dateLabel="Jeudi 15 janvier 2026 — 20h30"
description="Description du concert assez courte qui reprend l'essentiel, les artistes... On pourra écrire un nombre de lettres limitées."
imageUrl="https://picsum.photos/id/56/500/700"
imageAlt="Orchestre sur scène"
ctaHref="/concert[id]"
detailsHref="/concerts/concert_template"
/>
</PageSection>
<!-- Cas normal : toute la section est contenu dans les marges -->
<PageSection :padded="true" content-size="default">
<DsHeading as="h1" size="">PAR TOUS ET POUR TOUS</DsHeading>
</PageSection>
<div>
<div>IMAGE TEST</div>
<NuxtImg v-if="imageUrl" :src="imageUrl" width="1300" height="600" sizes="100vw sm:50vw md:400px" densities="x1 x2" :modifiers="{ roundCorner: '0:100' }" />
<!-- <img :src="imageUrl" alt="" style="max-width: 100%; height: auto;"> -->
</div>
</template>
<script setup>
import { onMounted, computed } from 'vue'
import { clientLog } from '~/utils/clientLog'
import DsHeading from '@root/design-system/primitives/DsHeading.vue'
const runtimeConfig = useRuntimeConfig()
const STRAPI_URL = runtimeConfig.public.strapiUrl
console.log("STRAPI_URL : ",STRAPI_URL)
// Config app (pour ton SEO)
const config = useAppConfig()
useSeoMeta({
title: config.title
})
// On récupère le fichier le plus récent de la Media Library Strapi
const { data, error } = await useFetch(
() => `${STRAPI_URL}/api/upload/files?pagination[pageSize]=1&sort=createdAt:desc`
)
const imageUrl = computed(() => {
const file = data.value?.[0]
console.log("file : ",file)
if (!file) return null
// Si Strapi renvoie une URL absolue (S3/OVH)
if (file.url?.startsWith('http')) {
return file.url
}
// Si jamais c'était une URL relative
return `${STRAPI_URL}${file.url}`
})
if (error.value) {
console.error('Erreur en récupérant les fichiers Strapi :', error.value)
clientLog('error', 'Erreur en récupérant les fichiers Strapi', {
endpoint: `${STRAPI_URL}/api/upload/files?pagination[pageSize]=1&sort=createdAt:desc`,
error: error.value?.message || error.value
})
}
const appConfig = useAppConfig()
console.log("test 3 : ",appConfig.title) // "Mon site Nuxt"
onMounted(() => {
clientLog('info', 'test de log depuis vuejs', { })
clientLog('info', `STRAPI_URL : ${STRAPI_URL}`, { strapiUrl: STRAPI_URL })
})
</script>
<style>
</style>

View File

@@ -1,36 +1,122 @@
<template>
<div>
<Header_full></Header_full>
<main>
<div>
<div>IMAGE TEST</div>
<NuxtImg :src="imageUrl" width="1300" height="600" sizes="100vw sm:50vw md:400px" densities="x1 x2" :modifiers="{ roundCorner: '0:100' }" />
<!-- <img :src="imageUrl" alt="" style="max-width: 100%; height: auto;"> -->
</div>
</main>
</div>
<!-- Fond noir -->
<PageSection tone="dark" :padded="false" content-size="default">
<SectionTitle tone="invert" pad="md">
CONCERTS À VENIR
</SectionTitle>
</PageSection>
<!-- Listes des prochains conncerts -->
<PageSection content-size="default" class="remonter_concert_list">
<ConcertCardList>
<ConcertCard
id="1"
title="TITRE DU CONCERT EN MAJUSCULE"
venue="Nom du lieu, éventuellement de la salle"
dateISO="2026-01-15T20:30:00+01:00"
dateLabel="Jeudi 15 janvier 2026 — 20h30"
description="Description du concert assez courte qui reprend l'essentiel, les artistes... On pourra écrire un nombre de lettres limitées."
imageUrl="https://picsum.photos/id/56/500/700"
imageAlt="Orchestre sur scène"
ctaHref="/concert[id]"
detailsHref="/concerts/concert_template"
/>
<ConcertCard
id="1"
title="TITRE DU CONCERT EN MAJUSCULE"
venue="Nom du lieu, éventuellement de la salle"
dateISO="2026-01-15T20:30:00+01:00"
dateLabel="Jeudi 15 janvier 2026 — 20h30"
description="Description du concert assez courte qui reprend l'essentiel, les artistes... On pourra écrire un nombre de lettres limitées."
imageUrl="https://picsum.photos/id/56/500/700"
imageAlt="Orchestre sur scène"
ctaHref="/concert[id]"
detailsHref="/concerts/concert_template"
/>
<ConcertCard
id="1"
title="TITRE DU CONCERT EN MAJUSCULE"
venue="Nom du lieu, éventuellement de la salle"
dateISO="2026-01-15T20:30:00+01:00"
dateLabel="Jeudi 15 janvier 2026 — 20h30"
description="Description du concert assez courte qui reprend l'essentiel, les artistes... On pourra écrire un nombre de lettres limitées."
imageUrl="https://picsum.photos/id/56/500/700"
imageAlt="Orchestre sur scène"
ctaHref="/concert[id]"
detailsHref="/concerts/concert_template"
/>
</ConcertCardList>
</PageSection>
<!-- Carte Île-De-France Par tous et pour tous -->
<PageSection class="theme_ptpt_wp">
<SectionContent class="theme_ptpt">
<DsMedia :src="ptpt_img" alt="Carte Île-De-France" class="theme_ptpt--img"/>
<SectionContent tone="brand_rouge45" pad="xs" class="theme_ptpt--content">
<SectionTitle tone="invert" pad="xs">
PAR TOUS ET POUR TOUS
</SectionTitle>
<SectionContent pad="xs" class="theme_ptpt--description">
<DsText tone="invert" size="lg" class="theme_ptpt--txt" >
Ici le texte qui décrit le concept de Tous à lOrchestre - Dans les régions - Ici le texte qui décrit le concept de Tous à lOrchestre - Dans les régions - Ici le texte qui décrit le concept de Tous à lOrchestre - Dans les régions -
</DsText>
<DsButtonArrow to="/" variant="invert">
Carte des événements
</DsButtonArrow>
</SectionContent>
</SectionContent>
</SectionContent>
</PageSection>
<!-- Tous à l'Orchestre -->
<PageSection tone="brandreverse" :padded="true" content-size="default" padb="xs" class="theme_tao">
<SectionContent>
<SectionTitle tone="invert" pad="xs">
TOUS À LORCHESTRE
</SectionTitle>
<SectionContent pad="xs" class="theme_ptpt--description">
<DsText tone="invert" size="lg" class="theme_ptpt--txt" >
Phrase daccroche / explicative de cette rubrique par tous et pour tous
</DsText>
</SectionContent>
</SectionContent>
</PageSection>
</template>
<script setup>
const runtimeConfig = useRuntimeConfig()
const STRAPI_URL = "http://localhost:1337"
//const STRAPI_URL = runtimeConfig.public.strapiUrl
console.log("STRAPI_URL : ",STRAPI_URL) // "Mon site Nuxt"
import { onMounted, computed } from 'vue'
import { clientLog } from '~/utils/clientLog'
import SectionContent from '../components/section/SectionContent.vue'
import DsText from '@root/design-system/primitives/DsText.vue'
import DsMedia from '@root/design-system/primitives/DsMedia.vue'
import DsButtonArrow from '@root/design-system/primitives/DsButtonArrow.vue'
import ptpt_img from '@/assets/img/illustrations/map_idf.jpg'
// Config app (pour ton SEO)
// Layout utilisé
definePageMeta({ layout: 'default' })
const runtimeConfig = useRuntimeConfig()
const STRAPI_URL = runtimeConfig.public.strapiUrl
console.log("STRAPI_URL : ",STRAPI_URL)
// Config app (pour SEO)
const config = useAppConfig()
useSeoMeta({
title: config.title
})
// On récupère le fichier le plus récent de la Media Library Strapi
const { data: files, error } = await useFetch(
const { data, error } = await useFetch(
() => `${STRAPI_URL}/api/upload/files?pagination[pageSize]=1&sort=createdAt:desc`
)
const imageUrl = computed(() => {
const file = files.value?.[0]
const file = data.value?.[0]
console.log("file : ",file)
if (!file) return null
@@ -42,18 +128,57 @@
// Si jamais c'était une URL relative
return `${STRAPI_URL}${file.url}`
})
console.log("imageUrl : ",imageUrl)
if (error.value) {
console.error('Erreur en récupérant les fichiers Strapi :', error.value)
clientLog('error', 'Erreur en récupérant les fichiers Strapi', {
endpoint: `${STRAPI_URL}/api/upload/files?pagination[pageSize]=1&sort=createdAt:desc`,
error: error.value?.message || error.value
})
}
const appConfig = useAppConfig()
console.log("test 3 : ",appConfig.title) // "Mon site Nuxt"
onMounted(() => {
clientLog('info', 'test de log depuis vuejs', { })
clientLog('info', `STRAPI_URL : ${STRAPI_URL}`, { strapiUrl: STRAPI_URL })
})
</script>
<style>
<style lang="scss">
.remonter_concert_list {
transform: translateY(-170px);
}
.theme_ptpt_wp {
margin-bottom: 50px;
}
.theme_ptpt {
display: grid;
// 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: -170px;
&--img {
grid-row: 1;
grid-column: 1;
}
&--content {
grid-row: 1;
grid-column: 1;
}
&--description {
max-width: 520px;
margin-top: 35px;
}
&--txt {
margin-bottom: 35px;
}
}
.theme_tao {
margin-bottom: 50px;
}
</style>
</style>

64
app/pages/orchestre.vue Normal file
View File

@@ -0,0 +1,64 @@
<template>
<div>
<div>IMAGE TEST</div>
<!-- <NuxtImg v-if="imageUrl" :src="imageUrl" width="1300" height="600" sizes="100vw sm:50vw md:400px" densities="x1 x2" :modifiers="{ roundCorner: '0:100' }" /> -->
</div>
</template>
<script setup>
import { onMounted, computed } from 'vue'
import { clientLog } from '~/utils/clientLog'
// Layout utilisé
definePageMeta({ layout: 'pageheaderfull' })
const runtimeConfig = useRuntimeConfig()
//const STRAPI_URL = "http://localhost:1337"
const STRAPI_URL = runtimeConfig.public.strapiUrl
console.log("STRAPI_URL : ",STRAPI_URL)
// Config app (pour SEO)
const config = useAppConfig()
useSeoMeta({
title: config.title
})
// On récupère le fichier le plus récent de la Media Library Strapi
const { data, error } = await useFetch(
() => `${STRAPI_URL}/api/upload/files?pagination[pageSize]=1&sort=createdAt:desc`
)
const imageUrl = computed(() => {
const file = data.value?.[0]
console.log("file : ",file)
if (!file) return null
// Si Strapi renvoie une URL absolue (S3/OVH)
if (file.url?.startsWith('http')) {
return file.url
}
// Si jamais c'était une URL relative
return `${STRAPI_URL}${file.url}`
})
if (error.value) {
console.error('Erreur en récupérant les fichiers Strapi :', error.value)
clientLog('error', 'Erreur en récupérant les fichiers Strapi', {
endpoint: `${STRAPI_URL}/api/upload/files?pagination[pageSize]=1&sort=createdAt:desc`,
error: error.value?.message || error.value
})
}
const appConfig = useAppConfig()
console.log("test 3 : ",appConfig.title) // "Mon site Nuxt"
onMounted(() => {
clientLog('info', 'test de log depuis vuejs', { })
clientLog('info', `STRAPI_URL : ${STRAPI_URL}`, { strapiUrl: STRAPI_URL })
})
</script>
<style lang="scss">
</style>

View File

@@ -34,7 +34,7 @@
console.log("test 3 : ",appConfig.title) // "Mon site Nuxt"
</script>
<style>
<style lang="scss">
</style>

17
app/utils/clientLog.js Normal file
View File

@@ -0,0 +1,17 @@
const ALLOWED_LEVELS = ['info', 'warn', 'error'];
export async function clientLog(level, message, meta = {}) {
if (!ALLOWED_LEVELS.includes(level)) {
console.warn('clientLog: invalid level, fallback to info', level);
level = 'info';
}
try {
await $fetch('/api/log', {
method: 'POST',
body: { level, message, meta }
});
} catch (e) {
console.error('Failed to send client log', e);
}
}