Pārlūkot izejas kodu

Merge branch 'release/0.4' into develop

Olivier Massot 1 gadu atpakaļ
vecāks
revīzija
69c17322fa
100 mainītis faili ar 3493 papildinājumiem un 3657 dzēšanām
  1. 51 0
      .eslintrc.cjs
  2. 0 24
      .eslintrc.yaml
  3. 9 0
      .gitignore
  4. 9 15
      .gitlab-ci.yml
  5. 1 0
      .nuxtignore
  6. 4 5
      .prettierrc
  7. 1 0
      .yarnrc.yml
  8. 18 17
      README.md
  9. 6 10
      app.vue
  10. 9 2
      assets/style/main.scss
  11. 6 1
      assets/style/theme.scss
  12. 153 105
      components/About/Chronologie.vue
  13. 66 62
      components/About/Equipe.vue
  14. 25 25
      components/About/FAQ.vue
  15. 83 70
      components/About/Logiciels.vue
  16. 65 52
      components/About/Presentation.vue
  17. 48 40
      components/About/Valeurs.vue
  18. 54 44
      components/Common/ActionMenu.vue
  19. 61 76
      components/Common/Agenda.vue
  20. 9 7
      components/Common/AgendaLink.vue
  21. 9 17
      components/Common/Avantages.vue
  22. 33 16
      components/Common/Banner.vue
  23. 8 11
      components/Common/Card/Benefit.vue
  24. 10 6
      components/Common/Card/Stat.vue
  25. 26 32
      components/Common/Carousel/Clients.vue
  26. 57 48
      components/Common/Carousel/Fonctionnalite.vue
  27. 54 44
      components/Common/Contact.vue
  28. 13 12
      components/Common/ContainerVideo.vue
  29. 20 22
      components/Common/MenuScroll.vue
  30. 31 29
      components/Common/Meta.vue
  31. 92 104
      components/Common/Presentation.vue
  32. 89 97
      components/Common/ReviewSection.vue
  33. 47 47
      components/Common/Share.vue
  34. 37 47
      components/Common/Table/Comparatif.vue
  35. 36 46
      components/Contact/AddressSection.vue
  36. 0 24
      components/Contact/Banner.vue
  37. 129 102
      components/Contact/Form.vue
  38. 35 41
      components/Contact/Map.vue
  39. 76 95
      components/Formation/Catalogue.vue
  40. 19 7
      components/Formation/Certification.vue
  41. 13 9
      components/Formation/OPCA.vue
  42. 19 25
      components/Formation/Participation.vue
  43. 13 10
      components/Formation/Presentation.vue
  44. 16 16
      components/Formation/Reviews.vue
  45. 7 15
      components/Home/Besoin.vue
  46. 139 129
      components/Home/Caroussel.vue
  47. 33 22
      components/Home/EventAgenda.vue
  48. 20 29
      components/Home/Help.vue
  49. 102 89
      components/Home/Promotion.vue
  50. 69 71
      components/Home/Reviews.vue
  51. 75 80
      components/Home/Solution.vue
  52. 60 60
      components/JoinUs/Form.vue
  53. 33 42
      components/JoinUs/MissionDetail.vue
  54. 38 53
      components/JoinUs/Missions.vue
  55. 33 37
      components/Layout/AnchoredSection.vue
  56. 39 36
      components/Layout/Captcha.vue
  57. 21 25
      components/Layout/FAQ.vue
  58. 99 111
      components/Layout/Footer/Footer.vue
  59. 13 7
      components/Layout/Footer/Prefooter.vue
  60. 0 199
      components/Layout/Footer/Solutions.vue
  61. 20 23
      components/Layout/Navigation.vue
  62. 15 20
      components/Layout/Navigation/Lg.vue
  63. 48 48
      components/Layout/Navigation/Md.vue
  64. 15 18
      components/Layout/Navigation/Topbar.vue
  65. 11 12
      components/Layout/Pagination.vue
  66. 4 7
      components/Layout/UI/SectionTitle.vue
  67. 7 12
      components/Layout/UI/SubTitle.vue
  68. 11 14
      components/Layout/UI/Title.vue
  69. 8 8
      components/Layout/UI/TitlePage.vue
  70. 55 26
      components/Logiciels/Artist/Abonnement.vue
  71. 13 24
      components/Logiciels/Artist/Abonnement/ToSubscribe.vue
  72. 18 17
      components/Logiciels/Artist/Avantages.vue
  73. 30 35
      components/Logiciels/Artist/Comparatif.vue
  74. 56 66
      components/Logiciels/Artist/Fonctionnalites.vue
  75. 8 12
      components/Logiciels/Artist/Formations.vue
  76. 18 16
      components/Logiciels/Artist/Presentation.vue
  77. 8 8
      components/Logiciels/Artist/Reviews.vue
  78. 41 30
      components/Logiciels/Artist/SomeNumbers.vue
  79. 36 35
      components/Logiciels/Manager/Avantages.vue
  80. 67 59
      components/Logiciels/Manager/Fonctionnalites.vue
  81. 35 31
      components/Logiciels/Manager/Formation.vue
  82. 5 6
      components/Logiciels/Manager/Network.vue
  83. 17 18
      components/Logiciels/Manager/Presentation.vue
  84. 22 31
      components/Logiciels/Manager/Reviews.vue
  85. 7 23
      components/Logiciels/Manager/SomeNumbers.vue
  86. 16 10
      components/Logiciels/School/Avantages.vue
  87. 45 51
      components/Logiciels/School/Comparatif.vue
  88. 77 83
      components/Logiciels/School/Fonctionnalites.vue
  89. 51 37
      components/Logiciels/School/Formations.vue
  90. 14 15
      components/Logiciels/School/Presentation.vue
  91. 14 14
      components/Logiciels/School/Reviews.vue
  92. 57 63
      components/Logiciels/School/SomeNumbers.vue
  93. 2 4
      components/Logiciels/Title.vue
  94. 38 44
      components/News/Details.vue
  95. 41 33
      components/News/List.vue
  96. 124 148
      components/Webinaire/Catalogue.vue
  97. 46 50
      components/Webinaire/FAQ.vue
  98. 42 26
      composables/data/useEntityFetch.ts
  99. 3 3
      composables/data/useEntityManager.ts
  100. 7 10
      composables/data/useEnumFetch.ts

+ 51 - 0
.eslintrc.cjs

@@ -0,0 +1,51 @@
+module.exports = {
+  root: true,
+  env: {
+    browser: true,
+    node: true,
+  },
+  parser: 'vue-eslint-parser',
+  parserOptions: {
+    ecmaVersion: 2020,
+    parser: '@typescript-eslint/parser',
+    sourceType: 'module',
+    tsconfigRootDir: __dirname,
+  },
+  extends: [
+    '@nuxtjs/eslint-config-typescript',
+    'plugin:nuxt/recommended',
+    'eslint:recommended',
+    'plugin:@typescript-eslint/recommended',
+    'plugin:vue/vue3-recommended',
+    'plugin:prettier/recommended',
+  ],
+  ignorePatterns: ['.nuxt', 'coverage/*', 'vendor/*', 'dist/*'],
+  plugins: ['vue', '@typescript-eslint'],
+  // add your custom rules here
+  rules: {
+    'no-console': 0, // on autorise les appels à la console (puisque ceux-ci seront de toute façon nettoyés à la compilation)
+    'vue/valid-v-slot': [
+      'error',
+      {
+        allowModifiers: true,
+      },
+    ],
+    'vue/multi-word-component-names': 0,
+    'vue/no-v-html': 0,
+    '@typescript-eslint/ban-ts-comment': 0,
+  },
+  globals: {
+    useRuntimeConfig: 'readonly',
+    navigateTo: 'readonly',
+    computed: 'readonly',
+    ref: 'readonly',
+    definePageMeta: 'readonly',
+    useRouter: 'readonly',
+    useRoute: 'readonly',
+    useI18n: 'readonly',
+    onMounted: 'readonly',
+    useLayoutStore: 'readonly',
+    useClientDevice: 'readonly',
+    useSeoMeta: 'readonly',
+  },
+}

+ 0 - 24
.eslintrc.yaml

@@ -1,24 +0,0 @@
-env:
-  browser: true
-  node: true
-parser: vue-eslint-parser
-parserOptions:
-  parser: '@typescript-eslint/parser'
-  ecmaVersion: 2020
-  sourceType: 'module'
-plugins:
-  - vue
-  - '@typescript-eslint'
-extends:
-  - '@nuxtjs/eslint-config-typescript',
-  - eslint:recommended
-  - plugin:vue/recommended
-  - plugin:nuxt/recommended
-  - plugin:@typescript-eslint/recommended
-  - plugin:vue/vue3-recommended
-  - plugin:prettier/recommended
-rules:
-  vue/multi-word-component-names: off
-  vue/no-multiple-template-root: off
-  eqeqeq: warn
-  strict: off

+ 9 - 0
.gitignore

@@ -8,3 +8,12 @@
 dist
 .DS_Store
 .idea
+
+# https://yarnpkg.com/getting-started/qa#which-files-should-be-gitignored
+.pnp.*
+.yarn/*
+!.yarn/patches
+!.yarn/plugins
+!.yarn/releases
+!.yarn/sdks
+!.yarn/versions

+ 9 - 15
.gitlab-ci.yml

@@ -1,24 +1,18 @@
 stages:
   - qa
-  - deploy_test
+
+cache:
+  paths:
+    - ./node_modules
+    - .yarn
 
 before_script:
-  - apt-get install
-  - curl -fsSL https://deb.nodesource.com/setup_14.x | bash -
-  - apt-get install -y nodejs
-  - npm install yarn --force
-  - yarn generate
+  - corepack enable
+  - yarn set version berry
+  - yarn install --network-timeout 10000
+  - HOST=ci yarn prepare
 
 qa:
   stage: qa
   script:
     - yarn lint
-
-#deploy_test:
-#  stage: deploy_test
-#  script:
-#    # - apt-get update -qq && apt-get install -y -qq sshpass
-#    # - ssh exploitation@test5 "cd /var/opentalent/git/portail_v2 && nvm exec yarn deploy && echo 'Deploy successful' "
-#    - ssh exploitation@test3 'ls /tmp'
-#  only:
-#    - home

+ 1 - 0
.nuxtignore

@@ -1,2 +1,3 @@
 .git/*
 coverage
+.idea

+ 4 - 5
.prettierrc

@@ -1,7 +1,6 @@
 {
-  "prettier": {
-    "tabWidth": 2,
-    "singleQuote": true,
-    "semi": false
-  }
+  "trailingComma": "es5",
+  "tabWidth": 2,
+  "semi": false,
+  "singleQuote": true
 }

+ 1 - 0
.yarnrc.yml

@@ -0,0 +1 @@
+nodeLinker: node-modules

+ 18 - 17
README.md

@@ -1,29 +1,30 @@
-# Nuxt 3 Minimal Starter
 
-Look at the [Nuxt 3 documentation](https://nuxt.com/docs/getting-started/introduction) to learn more.
+[![pipeline status](http://gitlab.2iopenservice.com/opentalent/portail_v2/badges/master/pipeline.svg)](http://gitlab.2iopenservice.com/opentalent/portail_v2/-/commits/master) 
 
-## Setup
+[![Latest Release](http://gitlab.2iopenservice.com/opentalent/portail_v2/-/badges/release.svg)](http://gitlab.2iopenservice.com/opentalent/portail_v2/-/releases) 
 
-Make sure to install the dependencies:
+# Site Logiciels
 
-    yarn install
+Le website "vitrine" qui présente les logiciels, formations et autres services de l'entreprise.
+Développé en nuxt3.
+
+> @see [vuejs.org](https://vuejs.org/guide/introduction.html) : Vue est le framework de base de l'application  
+> @see [nuxtjs.org](https://nuxt.com/docs/getting-started/introduction) : Nuxt est une surcouche à Vue qui automatise et simplifie beaucoup de choses  
+> @see [pinia.vuejs.org](https://pinia.vuejs.org/introduction.html) : Store library that allow you to share a state accross your components / pages  
+> @see [pinia-orm.codedredd.de](https://pinia-orm.codedredd.de/guide/getting-started/quick-start) : Ajoute une gestion par modèles / repos au store Pinia  
+> @see [vuetifyjs.com](https://cdn.vuetifyjs.com/docs/images/logos/vuetify-logo-v3-slim-text-light.svg) : Composants graphiques préconstruits  
+> @see [typescriptlang.org](https://www.typescriptlang.org/) : Typescript
 
-Créer le symlink vers le bon fichier env (remplacer <environnement> par l'env courant):
 
-    ln -s .env.<environnement> .env
+### Installer
 
-## Development Server
+    yarn install
 
-Start the development server on http://localhost:3000
+### Exécuter sur un environnement local
 
-```bash
-yarn dev
-````
+    yarn dev
 
-## SSG
+### Déployer
 
-```bash
-yarn generate
-```
+    yarn generate
 
-Check out the [deployment documentation](https://nuxt.com/docs/getting-started/deployment) for more information.

+ 6 - 10
app.vue

@@ -1,21 +1,17 @@
 <template>
-  <div id="top" />
+  <div>
+    <div id="top" />
 
-  <LayoutNavigation />
+    <LayoutNavigation />
 
-  <nuxt-page />
+    <nuxt-page />
 
-  <LayoutFooter />
+    <LayoutFooter />
+  </div>
 </template>
 
 <script setup lang="ts">
-
-import { useDisplay } from "vuetify";
-
-const { mdAndDown } = useDisplay()
-
 const layoutStore = useLayoutStore()
 
 layoutStore.resetAnchoredSections()
-
 </script>

+ 9 - 2
assets/style/main.scss

@@ -3,10 +3,14 @@
 body {
   font-family: "Barlow", serif;
   font-style: normal;
-
+  text-align: justify;
   --banner-center-image: 20%;
 }
 
+.v-container {
+  overflow: hidden;
+}
+
 .table-row {
   background-color: white;
   text-align: center;
@@ -19,6 +23,7 @@ body {
 
 .center-90 {
   width: 90%;
+  max-width: 1600px;
   margin-right: auto;
   margin-left: auto;
 
@@ -30,4 +35,6 @@ body {
   margin: -12px auto;
 }
 
-
+h1, h2, h3, h4, h5, li, .v-btn {
+  text-align: start;
+}

+ 6 - 1
assets/style/theme.scss

@@ -9,8 +9,10 @@ body {
   --on-primary-color: #ffffff;
   --on-primary-color-alt: #caf5f4;
   --secondary-color: #9edbdd;
+  --secondary-color-light: #c6eaeb;
   --on-secondary-color: #262626;
   --neutral-color-alt: #dbdbdb;
+  --neutral-color-alt-light: #f2f2f2;
   --neutral-color-alt-strong: #999999;
   --on-neutral-color-alt: #000000;
 
@@ -29,8 +31,11 @@ body {
   --action-menu-secondary-color: #9edbdd;
   --action-menu-on-secondary-color: #262626;
 
+  --scroll-menu-primary-color: #0e2d32;
+  --scroll-menu-on-primary-color: #ffffff;
+
   --artist-color-light: #fef3ce;
-  --school-color-light: #9edbdd;
+  --school-color-light: #a5d4e5;
   --manager-color-light: #f7cdce;
 }
 

+ 153 - 105
components/About/Chronologie.vue

@@ -1,84 +1,66 @@
 <template>
   <AnchoredSection id="history">
     <LayoutContainer class="alt-theme">
-      <v-container >
-        <v-row class="mb-6 mt-6">
-          <v-col cols="6">
+      <v-container>
+        <v-row class="mb-6 mt-6 center-90">
+          <v-col cols="12" md="6">
             <LayoutUISubTitle>
               Découvrez toute notre histoire
             </LayoutUISubTitle>
           </v-col>
 
-          <v-col cols="6">
+          <v-col cols="12" md="6">
             <div class="carousel-controls">
-              <v-btn
-                icon="fas fa-chevron-left"
-                @click="goPrevious"
-              />
-              <v-btn
-                icon="fas fa-chevron-right"
-                @click="goNext"
-              />
+              <v-btn icon="fas fa-chevron-left" @click="goPrevious" />
+              <v-btn icon="fas fa-chevron-right" @click="goNext" />
             </div>
           </v-col>
         </v-row>
       </v-container>
 
-      <v-row class="mb-12">
+      <v-row class="mb-12 center-90">
         <v-col cols="12">
           <Carousel
-            v-model="activeSlide"
             ref="carousel"
-            :items-to-show="2"
+            v-model="activeSlide"
+            :items-to-show="lgAndUp ? 2 : 1"
             :items-to-scroll="1"
-            :wrap-around="true"
           >
             <Slide
               v-for="(slide, index) in slides"
               :key="slide.title"
-              :class="{'active': index === activeSlide}"
+              :class="{ active: index === activeSlide }"
             >
-              <v-row justify="center">
-                <v-col cols="4">
-                  <div class="image-container">
-                    <v-img :src="slide.imageUrl" cover />
-                  </div>
-                </v-col>
+              <div class="card">
+                <div class="image-container">
+                  <v-img :src="slide.imageUrl" cover />
+                </div>
 
-                <v-col cols="4">
-                  <div class="description-container">
-                    <span class="year">
-                      {{ slide.year }}
-                    </span>
+                <div class="description-container">
+                  <span class="year">
+                    {{ slide.year }}
+                  </span>
 
-                    <h4>
-                      {{ slide.title }}
-                    </h4>
+                  <h4 v-html="slide.title" />
 
-                    <p class="mb-6">
-                      {{ slide.description }}
-                    </p>
-                  </div>
-                </v-col>
+                  <p class="mb-6" v-html="slide.description" />
+                </div>
+              </div>
 
-                <div class="timeline-container">
+              <div class="timeline-container">
+                <div v-if="slide.year" class="timeline">
                   <div
-                    v-if="slide.year"
-                    class="timeline"
+                    class="timeline-point"
+                    :style="{
+                      left: computePositionOnTimeline(slide.year) + '%',
+                    }"
                   >
-                    <div
-                      class="timeline-point"
-                      :style="{
-                        left: computePositionOnTimeline(slide.year) + '%',
-                      }"
-                    >
-                      <p class="timeline-year">
-                        {{ slide.year }}
-                      </p>
-                    </div>
+                    <p class="timeline-year">
+                      {{ slide.year }}
+                    </p>
                   </div>
                 </div>
-              </v-row>
+              </div>
             </Slide>
           </Carousel>
         </v-col>
@@ -88,104 +70,115 @@
 </template>
 
 <script setup lang="ts">
-import { useDisplay } from "vuetify";
-import { Carousel, Slide } from "vue3-carousel";
-import "vue3-carousel/dist/carousel.css";
-import AnchoredSection from "~/components/Layout/AnchoredSection.vue";
-import type { ChronologyItem } from "~/types/interface";
+import { useDisplay } from 'vuetify'
+import { Carousel, Slide } from 'vue3-carousel'
+import 'vue3-carousel/dist/carousel.css'
+import type { Ref } from 'vue'
+import AnchoredSection from '~/components/Layout/AnchoredSection.vue'
+import type { ChronologyItem } from '~/types/interface'
 
-const activeSlide: Ref<number> = ref(0);
+const activeSlide: Ref<number> = ref(0)
 
-const { mdAndDown } = useDisplay();
+const { lgAndUp } = useDisplay()
 
-const carousel: Ref<typeof Carousel | null> = ref(null);
+const carousel: Ref<typeof Carousel | null> = ref(null)
 
-const goPrevious = () => carousel.value!.prev();
-const goNext = () => carousel.value!.next();
+const goPrevious = () => carousel.value!.prev()
+const goNext = () => carousel.value!.next()
 
 const computePositionOnTimeline = (year: string) => {
   const intYear = parseInt(year)
 
   if (!intYear || isNaN(intYear)) {
-    return 0;
+    return 0
   }
-  const startYear = 2005;
-  const endYear = 2024;
-  return ((intYear - startYear) / (endYear - startYear)) * 100;
-};
+  const startYear = 2005
+  const endYear = 2024
+  return ((intYear - startYear) / (endYear - startYear)) * 100
+}
 
 const slides: Array<ChronologyItem> = [
   {
-    year: "2005",
+    year: '2005',
     title: "L'origine d'Opentalent",
     description:
       "Sous une pleine lune inspirante, Guillaume alors imagine un outil collaboratif en ligne révolutionnaire pour le secteur culturel. Cette idée germe alors qu'il est président d'orchestre et membre du CA d'une école de musique, marquant le début du concept Opentalent.",
-    imageUrl: "/images/about/Origine-Opentalent-outil-collaboratif-pour-la-culture.jpg",
+    imageUrl:
+      '/images/pages/qui-sommes-nous/chronologie/1-Origine_Opentalent-outil_collaboratif_pour_la_culture.jpg',
   },
   {
-    year: "2006",
-    title: "Développement et partenariat stratégique",
+    year: '2006',
+    title: 'Développement et partenariat stratégique',
     description:
       "Michel, passionné par l'innovation technologique, rejoint Guillaume. Ensemble, ils développent Opentalent avec le soutien de la Fédération de Haute-Savoie. Leur travail acharné bénévole durant 2 ans donne naissance à un logiciel SAS avant-gardiste, une première dans l'univers des structures culturelles.",
-    imageUrl: "/images/about/Developpement-et-partenariat-stratégique-Opentalent.jpg",
+    imageUrl:
+      '/images/pages/qui-sommes-nous/chronologie/2-Developpement_et_partenariat_strategique_Opentalent.jpg',
   },
   {
-    year: "2008",
+    year: '2008',
     title: "Naissance de l'entreprise 2iOpenservice",
     description:
       "La Fédération de Haute-Savoie, séduite par le projet, invite à collaborer avec la CMF, élargissant l'impact d'Opentalent. 2IOpenservice est alors officiellement créée, marquant une nouvelle ère dans la gestion culturelle digitale.  ",
-    imageUrl: "/images/about/idee.png",
+    imageUrl:
+      '/images/pages/qui-sommes-nous/chronologie/3-Naissance_de_l_entreprise_2IOpenservice-Opentalent.jpg',
   },
   {
-    year: "2009",
-    title: "MusAssos - la réponse aux besoins pour les petites structures",
+    year: '2009',
+    title: 'MusAssos - la réponse aux besoins pour les petites structures',
     description:
-      "Pour répondre aux besoins spécifiques des écoles affiliées à la CMF, 2iopenservice lance MusAssos, une solution adapté aux petites et moyennes structures, facilitant la gestion et la promotion culturelle.",
-    imageUrl: "/images/about/idee.png",
+      'Pour répondre aux besoins spécifiques des écoles affiliées à la CMF, 2iopenservice lance MusAssos, une solution adapté aux petites et moyennes structures, facilitant la gestion et la promotion culturelle.',
+    imageUrl:
+      '/images/pages/qui-sommes-nous/chronologie/4-Logiciel_MusAssos-pour_les_petites_et_moyennes_structures.png',
   },
   {
-    year: "2010",
+    year: '2010',
     title: "CMF Réseau <br> l'innovation communautaire",
     description:
       "La CMF adopte AdminFédé pour connecter ses adhérents, et AdminAsso devient accessible à tous, démocratisant l'accès aux outils de gestion artistique.",
-    imageUrl: "/images/about/idee.png",
+    imageUrl:
+      '/images/pages/qui-sommes-nous/chronologie/5-Confédération_Musicale_de_France-CMF_Réseau-AdminFédé_AdminAsso.png',
   },
   {
-    year: "2014",
-    title: "Vers une Culture Multidisciplinaire avec FFEC",
+    year: '2014',
+    title: 'Vers une Culture Multidisciplinaire avec FFEC',
     description:
       "Le logiciel d'Opentalent s'étend au-delà de l'enseignement artistique, embrassant l'art, la musique, le théâtre, la danse et le cirque. En partenariat avec la FFEC, Reso Cirque voit le jour, intégrant notre solution au cœur de la pratique circassienne.",
-    imageUrl: "/images/about/idee.png",
+    imageUrl:
+      '/images/pages/qui-sommes-nous/chronologie/6-FFEC_Reso_Cirque-Ouverture_vers_une_culture_multidisciplinaire.png',
   },
   {
-    year: "2015",
-    title: "Refonte Technologique",
+    year: '2015',
+    title: 'Refonte Technologique',
     description:
-      "Nous modernisons notre gamme de logiciels pour la rendre plus sécurisée et compatible avec divers supports, marquant une étape clé dans notre évolution technologique.",
-    imageUrl: "/images/about/Refonte-du-site-internet-Opentalent-agenda-et-logiciels-culturels.jpg",
+      'Nous modernisons notre gamme de logiciels pour la rendre plus sécurisée et compatible avec divers supports, marquant une étape clé dans notre évolution technologique.',
+    imageUrl:
+      '/images/pages/qui-sommes-nous/chronologie/7-Refonte_technologique_des_logiciels_Opentalent_securitee_modernitee_intuitivitee.jpg',
   },
   {
-    year: "2019",
-    title: "Nouvelle Génération Opentalent",
+    year: '2019',
+    title: 'Nouvelle Génération Opentalent',
     description:
       "Avec des fonctionnalités améliorées et une interface utilisateur intuitive, la nouvelle génération d'Opentalent se démarque, prouvant notre engagement envers l'excellence et l'accessibilité.",
-    imageUrl: "/images/about/Nouvelle-génération-Opentalent-moderne-securisee-experience-optimisee.jpg",
+    imageUrl:
+      '/images/pages/qui-sommes-nous/chronologie/8-Nouvelle_generation_Opentalent_moderne_securisee_experience_optimisee.jpg',
   },
   {
-    year: "2024",
-    title: "Relooking du site Opentalent",
+    year: '2024',
+    title: 'Relooking du site Opentalent',
     description:
-      "Le site Opentalent se réinvente, reflétant notre évolution et notre capacité à nous adapter aux tendances actuelles, tout en conservant notre essence originelle.",
-    imageUrl: "/images/about/idee.png",
+      'Le site Opentalent se réinvente, reflétant notre évolution et notre capacité à nous adapter aux tendances actuelles, tout en conservant notre essence originelle.',
+    imageUrl:
+      '/images/pages/qui-sommes-nous/chronologie/9-Relooking_du_site_internet_Opentalent_agenda_et_logiciels_culturels.jpg',
   },
   {
-    year: "",
-    title: "LE FUTUR AVEC VOUS... ",
+    year: '',
+    title: 'LE FUTUR AVEC VOUS... ',
     description:
-      "Opentalent, plus qu'une gamme de logiciels ou un agenda culturel, c'est une aventure collective. Ensemble, poursuivons cette quête d'innovation et de partage culturel. <br> Rejoignez-nous dans cette aventure passionnante et façonnons l'avenir de la culture. <br> <strong> Opentalent, c'est vous ! </strong>",
-    imageUrl: "/images/about/idee.png",
+      "Opentalent, plus qu'une gamme de logiciels ou un agenda culturel, c'est une aventure collective. Ensemble, poursuivons cette quête d'innovation et de partage culturel. <br> Rejoignez-nous dans cette aventure passionnante et façonnons l'avenir de la culture. <br><br> <strong> OPENTALENT, C'EST VOUS ! </strong>",
+    imageUrl:
+      '/images/pages/qui-sommes-nous/chronologie/10-Opentalent_ensemble_construisons_notre_futur.jpg',
   },
-];
+]
 </script>
 
 <style scoped lang="scss">
@@ -215,18 +208,34 @@ const slides: Array<ChronologyItem> = [
 }
 
 .carousel {
+  padding-bottom: 72px;
+
+  :deep(.carousel__viewport) {
+    overflow: visible;
+  }
+
   .carousel__slide {
     opacity: 0.5;
     transition: opacity 0.3s ease-in-out;
+    display: flex;
+    flex-direction: column;
   }
   .carousel__slide.active {
     opacity: 1;
     transform: scale(1.1);
-    transition: transform 0.3s ease-in-out, opacity 0.3s ease-in-out;
+    transition:
+      transform 0.3s ease-in-out,
+      opacity 0.3s ease-in-out;
   }
 
-  .v-row {
-    height: 32rem;
+  .card {
+    display: flex;
+    flex-direction: row;
+    margin-bottom: 18px;
+
+    @media (max-width: 600px) {
+      flex-direction: column;
+    }
   }
 
   .v-col {
@@ -240,6 +249,16 @@ const slides: Array<ChronologyItem> = [
   .description-container {
     height: 300px;
     width: 300px;
+
+    @media (max-width: 1480px) {
+      height: 320px;
+      width: 260px;
+    }
+
+    @media (max-width: 600px) {
+      width: 80%;
+      height: auto;
+    }
   }
 
   .image-container {
@@ -249,13 +268,22 @@ const slides: Array<ChronologyItem> = [
       border-top-left-radius: 20%;
       border-bottom-left-radius: 20%;
     }
+
+    @media (max-width: 600px) {
+      margin: auto;
+
+      .v-img {
+        border-top-left-radius: 20%;
+        border-top-right-radius: 20%;
+        border-bottom-left-radius: 0;
+      }
+    }
   }
 
   .description-container {
     padding: 1rem;
     text-align: center;
-    margin-left: 1rem;
-    background-color: var(--primary-color);
+    background-color: rgba(0, 0, 0, 0.3);
     color: var(--on-primary-color);
     border-top-right-radius: 20%;
     border-bottom-right-radius: 20%;
@@ -266,9 +294,8 @@ const slides: Array<ChronologyItem> = [
     }
 
     h4 {
-      justify-content: flex-end;
-      align-items: center;
       font-size: 1rem;
+      text-align: center;
     }
 
     p {
@@ -277,11 +304,32 @@ const slides: Array<ChronologyItem> = [
       font-size: 0.8rem;
       color: var(--secondary-color);
     }
+
+    @media (max-width: 700px) {
+      padding: 1rem 0;
+
+      h4 {
+        font-size: 1.6rem;
+        text-align: left;
+        padding: 1rem;
+      }
+
+      p {
+        text-align: justify;
+      }
+    }
+
+    @media (max-width: 600px) {
+      margin: auto;
+      border-top-right-radius: 0;
+      border-bottom-left-radius: 20%;
+      border-bottom-right-radius: 20%;
+    }
   }
 }
 
 .timeline-container {
-  width: 90%;
+  width: 70%;
   padding: 10px 0;
 
   .timeline {

+ 66 - 62
components/About/Equipe.vue

@@ -2,33 +2,29 @@
   <AnchoredSection id="team">
     <LayoutContainer class="mb-12">
       <v-row class="mt-12 center-90">
-        <LayoutUISubTitle>
-          Notre équipe
-        </LayoutUISubTitle>
+        <LayoutUISubTitle> Notre équipe </LayoutUISubTitle>
       </v-row>
 
       <v-row class="center-90">
-        <LayoutUITitle>
-          Une équipe spécialisée et passionnée
-        </LayoutUITitle>
+        <LayoutUITitle> Une équipe spécialisée et passionnée </LayoutUITitle>
 
         <span class="details ml-4 mt-6 mb-12">
-          Chez Opentalent, on recherche des compétences mais surtout des hommes et
-          des femmes qui souhaitent s'engager dans un projet porteur de sens.
+          Chez Opentalent, on recherche des compétences mais surtout des hommes
+          et des femmes qui souhaitent s'engager dans un projet porteur de sens.
         </span>
       </v-row>
 
       <v-row class="center-90">
         <v-col
-          cols="12" sm="6" md="4" lg="3"
           v-for="associate in associates"
           :key="associate.name"
+          cols="12"
+          sm="6"
+          md="4"
+          lg="3"
         >
           <v-card>
-            <v-img
-              :src="associate.photo"
-              :height="370"
-            />
+            <v-img :src="associate.photo" :height="370" />
 
             <v-card-title class="name">
               {{ associate.name }}
@@ -43,15 +39,15 @@
 
       <v-row class="center-90">
         <v-col
-          cols="12" sm="6" md="4" lg="3"
           v-for="employee in employees"
           :key="employee.name"
+          cols="12"
+          sm="6"
+          md="4"
+          lg="3"
         >
           <v-card>
-            <v-img
-              :src="employee.photo"
-              :height="370"
-            />
+            <v-img :src="employee.photo" :height="370" />
 
             <v-card-title class="name">
               {{ employee.name }}
@@ -68,74 +64,82 @@
 </template>
 
 <script setup lang="ts">
-import AnchoredSection from "~/components/Layout/AnchoredSection.vue";
-import type { SocietyMember } from "~/types/interface";
+import AnchoredSection from '~/components/Layout/AnchoredSection.vue'
+import type { SocietyMember } from '~/types/interface'
 
 const associates: Array<SocietyMember> = [
   {
-    name: "Guillaume",
-    position: "Fondateur / DIRECTEUR COMMERCIAL",
-    photo: "/images/about/equipe/Guillaume_CORCOBA-co-fondateur_et_Gerant.png",
-    alt: "Avatar d’un homme avec les cheveux poivre et sel court portant un polo bordeaux et un jean"
+    name: 'Guillaume',
+    position: 'Co-fondateur / Gérant',
+    photo:
+      '/images/pages/qui-sommes-nous/equipe/Guillaume_CORCOBA-co-fondateur_et_Gerant.png',
+    alt: 'Avatar d’un homme avec les cheveux poivre et sel court portant un polo bordeaux et un jean',
   },
   {
-    name: "Michel",
-    position: "FONDATEUR / Directeur développement",
-    photo: "/images/about/equipe/Michel_PERNET-SOLLIET-Co-fondateur_et_Product_Owner.png",
-    alt: "Avatar d’un homme avec les cheveux bruns mi-long portant un pull jaune et un pantalon noir"
+    name: 'Michel',
+    position: 'Co-fondateur / Product Owner',
+    photo:
+      '/images/pages/qui-sommes-nous/equipe/Michel_PERNET-SOLLIET-Co-fondateur_et_Product_Owner.png',
+    alt: 'Avatar d’un homme avec les cheveux bruns mi-long portant un pull jaune et un pantalon noir',
   },
-];
+]
 
 const employees: Array<SocietyMember> = [
   {
-    name: "Johan",
-    position: " FORMATEUR",
-    photo: "/images/about/equipe/Johan_HAUDIQUET-Formateur_et_Assistance.png",
-    alt: "Avatar d’un homme avec les cheveux bruns court portant un sweat noir et un pantalon beige"
+    name: 'Johan',
+    position: 'Formation et Assistance',
+    photo:
+      '/images/pages/qui-sommes-nous/equipe/Johan_HAUDIQUET-Formateur_et_Assistance.png',
+    alt: 'Avatar d’un homme avec les cheveux bruns court portant un sweat noir et un pantalon beige',
   },
   {
-    name: "Nathalie",
-    position: "Ch. DEVELOPPEMENT COMMERCIAL",
-    photo: "/images/about/equipe/Nathalie_CHEVALON-Chargee_de_developpement_commercial.png",
-    alt: "Avatar d’une femme avec les cheveux bruns mi-long et ondulée portant une chemise noire/blanche et un jean bleu foncé"
+    name: 'Nathalie',
+    position: 'Développement Commercial',
+    photo:
+      '/images/pages/qui-sommes-nous/equipe/Nathalie_CHEVALON-Chargee_de_developpement_commercial.png',
+    alt: 'Avatar d’une femme avec les cheveux bruns mi-long et ondulée portant une chemise noire/blanche et un jean bleu foncé',
   },
   {
-    name: "Laetitia",
-    position: "CH. COMMUNICATION & MARKETING",
-    photo: "/images/about/equipe/Laetitia_SIFFOINTE-Chargee_de_Marketing_et_Communication.png",
-    alt: "Avatar d’une femme avec les cheveux blonds long et ondulée portant un pull gris et un jean noir"
+    name: 'Laetitia',
+    position: 'Marketing & Communication',
+    photo:
+      '/images/pages/qui-sommes-nous/equipe/Laetitia_SIFFOINTE-Chargee_de_Marketing_et_Communication.png',
+    alt: 'Avatar d’une femme avec les cheveux blonds long et ondulée portant un pull gris et un jean noir',
   },
   {
-    name: "Florence",
-    position: "ASSISTANTE ADMINISTRATIVE",
-    photo: "/images/about/equipe/Florence_JOANNIDIS-ADV.png",
-    alt: "Avatar d’une femme avec des lunettes, les cheveux bruns long et attaché portant un pull bleu et un jean bleu foncé"
+    name: 'Florence',
+    position: 'Assistante administrative et commerciale',
+    photo: '/images/pages/qui-sommes-nous/equipe/Florence_JOANNIDIS-ADV.png',
+    alt: 'Avatar d’une femme avec des lunettes, les cheveux bruns long et attaché portant un pull bleu et un jean bleu foncé',
   },
   {
-    name: "Vincent",
-    position: "LEAD DEVELOPPEUR",
-    photo: "/images/about/equipe/Vincent_GUFFON-Lead_dev.png",
-    alt: "Avatar d’un homme avec les cheveux bruns court avec une barbe rousse portant un tee-shirt noir et un jean bleu"
+    name: 'Vincent',
+    position: 'Lead developer',
+    photo: '/images/pages/qui-sommes-nous/equipe/Vincent_GUFFON-Lead_dev.png',
+    alt: 'Avatar d’un homme avec les cheveux bruns court avec une barbe rousse portant un tee-shirt noir et un jean bleu',
   },
   {
-    name: "Olivier",
-    position: "DEVELOPPEUR",
-    photo: "/images/about/equipe/Olivier_MASSOT-Developpeur.png",
-    alt: "Avatar d’un homme avec les cheveux blonds mi-long et un bouc blond portant un gilet gris et un jean noir"
+    name: 'Olivier',
+    position: 'Développeur',
+    photo:
+      '/images/pages/qui-sommes-nous/equipe/Olivier_MASSOT-Developpeur.png',
+    alt: 'Avatar d’un homme avec les cheveux blonds mi-long et un bouc blond portant un gilet gris et un jean noir',
   },
   {
-    name: "Sébastien",
-    position: "DEVELOPPEUR",
-    photo: "/images/about/equipe/Sebastien_FAVRE-BONTE_Developpeur.png",
-    alt: "Avatar d’un homme avec des lunettes, les cheveux bruns court portant un pull bleu et un jean bleu foncé"
+    name: 'Sébastien',
+    position: 'Développeur',
+    photo:
+      '/images/pages/qui-sommes-nous/equipe/Sebastien_FAVRE-BONTE_Developpeur.png',
+    alt: 'Avatar d’un homme avec des lunettes, les cheveux bruns court portant un pull bleu et un jean bleu foncé',
   },
   {
-    name: "Maha",
-    position: "DEVELOPPEUSE",
-    photo: "/images/about/equipe/Maha_BOUCHIBA-Developpeuse.png",
-    alt: "Avatar d’une femme portant un turban sur les cheveux, haut beige et blanc et un jean bleu foncé"
+    name: 'Maha',
+    position: 'Développeuse',
+    photo:
+      '/images/pages/qui-sommes-nous/equipe/Maha_BOUCHIBA-Developpeuse.png',
+    alt: 'Avatar d’une femme portant un turban sur les cheveux, haut beige et blanc et un jean bleu foncé',
   },
-];
+]
 </script>
 
 <style scoped lang="scss">

+ 25 - 25
components/About/FAQ.vue

@@ -3,24 +3,21 @@
     <LayoutContainer>
       <v-row no-gutters class="alt-theme">
         <v-col cols="12" md="6">
-           <v-img
-             src="/images/help/Help.png"
-             alt="Un homme et une femme tous les deux le sourire aux lèvres se serre la main"
-             cover
-           />
+          <v-img
+            src="/images/pages/qui-sommes-nous/contact/Opentalent_a_votre_service.png"
+            alt="Un homme et une femme tous les deux le sourire aux lèvres se serre la main"
+            cover
+          />
         </v-col>
 
         <v-col cols="12" md="6">
-          <div>
+          <div class="d-flex flex-column">
             <h4>
-              Chez Opentalent, nous avons à coeur de répondre à vos interrogations
-              et de vous apporter la solution faite pour vous.
+              Chez Opentalent, nous avons à coeur de répondre à vos
+              interrogations et de vous apporter la solution faite pour vous.
             </h4>
 
-            <v-btn
-              to="/nous-contacter"
-              class="mt-12"
-            >
+            <v-btn to="/nous-contacter" class="inv-theme mt-12">
               Nous contacter
             </v-btn>
           </div>
@@ -31,50 +28,53 @@
 </template>
 
 <script setup lang="ts">
-import AnchoredSection from "~/components/Layout/AnchoredSection.vue";
+import AnchoredSection from '~/components/Layout/AnchoredSection.vue'
 </script>
 
 <style scoped lang="scss">
 .v-col {
-  height: 20rem;
+  height: 25rem;
 }
 
-.help-img {
-  background-repeat: no-repeat;
-  background-position: center;
-  width: 100%;
-  height: 20rem;
+.v-img {
+  height: 25rem;
 }
 
 h4 {
   font-weight: 400;
   font-size: 2rem;
   line-height: 34px;
-  width: 40rem;
-  margin: 3rem auto 2rem 62px;
+  width: 60%;
+  margin: 3rem auto 2rem auto;
   color: var(--on-primary-color);
+  text-align: justify;
 
   @media (max-width: 600px) {
     width: 80%;
     margin-left: 10%;
-    text-align: justify;
   }
 }
 
 .v-btn {
   width: 195px;
   height: 53px;
-  background: var(--secondary-color);
+  background: var(--secondary-color) !important;
   border-radius: 6px;
   color: var(--on-secondary-color);
   padding: 19px 28px;
   gap: 9px;
-  margin-left: 84px;
+  margin-right: auto;
+  margin-left: auto;
+
+  @media (max-width: 1240px) {
+    width: 40%;
+    margin-left: 30%;
+    margin-bottom: 48px;
+  }
 
   @media (max-width: 600px) {
     width: 80%;
     margin-left: 10%;
-    margin-bottom: 48px;
   }
 }
 </style>

+ 83 - 70
components/About/Logiciels.vue

@@ -2,9 +2,7 @@
   <AnchoredSection id="softwares">
     <LayoutContainer>
       <v-row class="mb-6 center-90">
-        <LayoutUISubTitle>
-          Nos logiciels
-        </LayoutUISubTitle>
+        <LayoutUISubTitle> Nos logiciels </LayoutUISubTitle>
 
         <LayoutUITitle>
           Nos logiciels dédiés à chaque acteur culturel
@@ -13,53 +11,41 @@
 
       <v-row class="mb-12 center-90">
         <v-col md="3">
-          <p class="text-justify mr-4 ml-6 mb-6">
+          <p class="text-justify mr-4 ml-2 mb-6">
             Découvrez notre gamme de logiciels de gestion & de communication
             adapté au secteur culturel. <br />
             Des fonctionnalités complètes:
           </p>
 
-          <ul class="ml-6">
-            <li
-              v-for="(feature, index) in features"
-              :key="index"
-            >
+          <ul class="ml-4">
+            <li v-for="(feature, index) in features" :key="index">
               {{ feature }}
             </li>
           </ul>
 
-          <p class="text-justify mr-4 ml-6 mt-6">
-            À chaque logiciel sa spécificité !
+          <p class="text-justify mr-4 mt-6">
+            <b>À chaque logiciel sa spécificité !</b>
           </p>
         </v-col>
 
         <v-col
-          cols="12"
-          md="3"
           v-for="(item, index) in items"
           :key="index"
+          cols="12"
+          md="3"
           :class="item.class"
         >
-          <v-img
-            :src="item.imageUrl"
-            cover
-            class="container-image"
-          >
-            <footer>
-              <v-img
-                :src="item.logoUrl"
-                :alt="item.logoAlt"
-                class="logo"
-              />
-
-              <v-btn
-                :to="item.link"
-                class="plus-button"
-              >
-                <v-icon>fas fa-plus</v-icon>
-              </v-btn>
-            </footer>
-          </v-img>
+          <nuxt-link :to="item.link" class="software-link">
+            <v-img :src="item.imageUrl" cover class="container-image">
+              <footer>
+                <v-img :src="item.logoUrl" :alt="item.logoAlt" class="logo" />
+
+                <v-btn class="plus-button">
+                  <v-icon>fas fa-plus</v-icon>
+                </v-btn>
+              </footer>
+            </v-img>
+          </nuxt-link>
         </v-col>
       </v-row>
     </LayoutContainer>
@@ -67,44 +53,57 @@
 </template>
 
 <script setup lang="ts">
-import AnchoredSection from "~/components/Layout/AnchoredSection.vue";
+import AnchoredSection from '~/components/Layout/AnchoredSection.vue'
 
 const features: Array<string> = [
-  "Une gestion de vos contacts",
-  "un agenda collaboratif et interactif",
-  "Une gestion du matériel et du stock",
-  "Une communication simplifiée",
+  'Une gestion de vos contacts',
+  'Un agenda collaboratif et interactif',
+  'Une gestion du matériel et du stock',
+  'Une communication simplifiée',
   "Un rapport d'activité complet",
-  "Un site internet intégré",
-  "Et bien plus encore...",
-];
-
-const items: Array<{imageUrl: string, alt: string, logoUrl: string, logoAlt: string, class: string, link: string}> = [
+  'Un site internet intégré',
+  'Et bien plus encore...',
+]
+
+const items: Array<{
+  imageUrl: string
+  alt: string
+  logoUrl: string
+  logoAlt: string
+  class: string
+  link: string
+}> = [
   {
-    imageUrl: "/images/solutions/artist.jpg",
-    alt: "Partition tenue par une femme dans une chorale",
-    logoUrl: "/images/logo/logiciels/Artist-Blanc.png",
-    logoAlt: "Logo Opentalent Artist - logiciel de gestion et de communication pour les orchestres, les chorales, les compagnies artistiques et troupes",
-    class: "artist",
-    link: "/opentalent_artist",
+    imageUrl:
+      '/images/pages/qui-sommes-nous/logiciels/Opentalent_Artist_pour_les_structures_culturelles.jpg',
+    alt: 'Partition tenue par une femme dans une chorale',
+    logoUrl: '/images/logos/opentalent/Logo_Opentalent_Artist-blanc.png',
+    logoAlt:
+      'Logo Opentalent Artist - logiciel de gestion et de communication pour les orchestres, les chorales, les compagnies artistiques et troupes',
+    class: 'artist',
+    link: '/opentalent_artist',
   },
   {
-    imageUrl: "/images/solutions/school.jpg",
-    alt: "Deux jeunes filles jouant du violon",
-    logoUrl: "/images/logo/logiciels/School-Blanc.png",
-    logoAlt: "Logo Opentalent School - logiciel de gestion et de communication pour les établissements d’enseignement artistique",
-    class: "school",
-    link: "/opentalent_school",
+    imageUrl:
+      '/images/pages/qui-sommes-nous/logiciels/Opentalent_School_pour_les_etablissements_d_enseignement_artistique.JPG',
+    alt: 'Deux jeunes filles jouant du violon',
+    logoUrl: '/images/logos/opentalent/Logo_Opentalent_School-blanc.png',
+    logoAlt:
+      'Logo Opentalent School - logiciel de gestion et de communication pour les établissements d’enseignement artistique',
+    class: 'school',
+    link: '/opentalent_school',
   },
   {
-    imageUrl: "/images/solutions/manager.png",
-    alt: "Carte de réseau des structures de la confédération musicale de France",
-    logoUrl: "/images/logo/logiciels/Manager-Blanc.png",
-    logoAlt: "Logo Opentalent Manager - logiciel de gestion et de communication pour les fédérations, les confédérations et les collectivités",
-    class: "manager",
-    link: "/opentalent_manager",
+    imageUrl:
+      '/images/pages/qui-sommes-nous/logiciels/Opentalent_Manager_pour_les_reseaux_culturels.png',
+    alt: 'Carte de réseau des structures de la confédération musicale de France',
+    logoUrl: '/images/logos/opentalent/Logo_Opentalent_Manager-blanc.png',
+    logoAlt:
+      'Logo Opentalent Manager - logiciel de gestion et de communication pour les fédérations, les confédérations et les collectivités',
+    class: 'manager',
+    link: '/opentalent_manager',
   },
-];
+]
 </script>
 
 <style scoped lang="scss">
@@ -122,11 +121,11 @@ ul {
 li {
   margin-left: 0.8rem;
   position: relative;
-  margin-bottom: 10px;
+  margin-bottom: 6px;
 }
 
 li:before {
-  content: "";
+  content: '';
   position: absolute;
   left: -10px;
   top: 50%;
@@ -137,6 +136,12 @@ li:before {
   border-radius: 50%;
 }
 
+.software-link {
+  > .container-image:hover {
+    transform: scale(1.05);
+  }
+}
+
 .container-image {
   position: relative;
   background-repeat: no-repeat;
@@ -145,6 +150,7 @@ li:before {
   width: 100%;
   height: 370px;
   z-index: 0;
+  border-radius: 12px 12px 0 12px;
 
   footer {
     position: absolute;
@@ -165,24 +171,31 @@ li:before {
   }
 
   .plus-button {
-    width: 80px;
-    height: 80px;
+    width: 100px;
+    height: 100px;
     border-radius: 50% 0 0 0;
     background: var(--primary-color);
     color: var(--on-primary-color);
     box-shadow: none !important;
     border-top-left-radius: 10% !important;
+    margin-right: -10px;
+    margin-bottom: -10px;
 
     .v-icon {
       color: var(--on-primary-color);
       font-size: 2rem;
     }
   }
+}
 
-  :hover .plus-button {
-    transform: scale(1.2);
-    transition: all 0.3s ease-in-out;
-  }
+.container-image::after {
+  content: "";
+  position: absolute;
+  top: 0;
+  bottom: 0;
+  left: 0;
+  right: 0;
+  background: rgba(0, 0, 0, 0.4);
 }
 
 .artist .plus-button {

+ 65 - 52
components/About/Presentation.vue

@@ -1,68 +1,65 @@
 <template>
   <AnchoredSection id="about">
     <LayoutContainer>
-      <v-row class="mt-12 center-90">
-        <v-col md="4">
-          <LayoutUISubTitle>
-            Qui sommes-nous ?
-          </LayoutUISubTitle>
+      <v-row class="my-4 center-90">
+        <v-col cols="12">
+          <LayoutUISubTitle> Qui sommes-nous ? </LayoutUISubTitle>
         </v-col>
+      </v-row>
 
-        <v-col md="8">
-          <div class="italic-title mr-8">
-            “Imaginé par des musiciens pour des musiciens, Opentalent se veut être
-            la référence pour la gestion et la promotion du spectacle vivant sur
-            les territoires.”
+      <v-row class="my-6 center-90">
+        <v-col cols="12">
+          <div class="italic-title">
+            “Imaginé par des musiciens pour des musiciens, Opentalent se veut
+            être la référence pour la gestion et la promotion du spectacle
+            vivant sur les territoires.”
           </div>
         </v-col>
       </v-row>
 
       <v-row class="history mb-12">
-        <v-col md="6">
+        <v-col cols="12" md="6">
           <v-img
-            src="/images/about/passion.jpg"
+            src="/images/pages/qui-sommes-nous/presentation/Concu_par_des_passiones_pour_des_passionnes.JPG"
             alt="Entretien dans un bureau entre un homme et une femme de dos"
             cover
           />
         </v-col>
 
-        <v-col md="6">
-          <h3>
-            Une histoire de passionnés
-          </h3>
+        <v-col cols="12" md="6">
+          <h3>Une histoire de passionnés</h3>
 
           <p class="mb-8">
-            En 2005, Guillaume CORCOBA, musicien depuis toujours et à ce moment
-            président d'un orchestre d'harmonie, mais également membre du conseil
-            d'administration de sa fédération, réfléchit à un outil pour
-            centraliser les informations de sa structure, mais également au niveau
-            fédéral. Il souhaite simplifier la gestion des structures culturelles
-            et en faire la promotion, car pour lui, le milieu culturel est
-            indispensable. Il est rapidement rejoint par Michel   PERNET-SOLLIET,
-            lui aussi musicien, et ils montent ensemble Openassos, qui deviendra
-            quelques années plus tard, Opentalent. Opentalent c'est un ensemble de
-            3 logiciels spécialement dédiés à la culture et un agenda culturel
-            pour en faire la promotion.
+            En 2005, Guillaume CORCOBA, musicien depuis toujours et à ce moment
+            président d'un orchestre d'harmonie, mais également membre du
+            conseil d'administration de sa fédération, réfléchit à un outil pour
+            centraliser les informations de sa structure, mais également au
+            niveau fédéral. Il souhaite simplifier la gestion des structures
+            culturelles et en faire la promotion, car pour lui, le milieu
+            culturel est indispensable. Il est rapidement rejoint par Michel
+            PERNET-SOLLIET, lui aussi musicien, et ils montent ensemble
+            Openassos, qui deviendra quelques années plus tard, Opentalent.
+            Opentalent c'est un ensemble de 3 logiciels spécialement dédiés à la
+            culture et un agenda culturel pour en faire la promotion.
           </p>
 
-          <h3>
-            La Culture au service du développement territorial
-          </h3>
+          <h3>La Culture au service du développement territorial</h3>
 
           <p>
-            Qui n'a jamais entendu que la culture coûtait trop cher ? On l'entend
-            , ha ça oui on l'a même trop entendu ! Mais la culture c'est avant
-            tout un facteur de lien social incroyable. On se retrouve, on échange,
-            on partage... on vit ensemble. On crée des vrais moments et on
-            développe des groupes de passionnés. On participe à rendre nos
-            collectivités attractives et surtout on les fait vivre, toute l'année,
-            à toutes les saisons. Depuis plusieurs décennies, un grand nombre de
-            territoires s'appuie sur le développement de la culture comme un outil
-            de développement territorial pour faire face à la
-            désindustrialisation, à une croissance démographique ralentie ou
-            encore une image défavorable. Ce modèle de développement par la
-            culture pour pallier un déficit d’attractivité touristique inspire de
-            plus en plus de politiques de développement territorial.
+            Qui n'a jamais entendu que la culture coûtait trop cher ? On
+            l'entend , ha ça oui on l'a même trop entendu ! Mais la culture
+            c'est avant tout un facteur de lien social incroyable. On se
+            retrouve, on échange, on partage... on vit ensemble. On crée des
+            vrais moments et on développe des groupes de passionnés. On
+            participe à rendre nos collectivités attractives et surtout on les
+            fait vivre, toute l'année, à toutes les saisons. Depuis plusieurs
+            décennies, un grand nombre de territoires s'appuie sur le
+            développement de la culture comme un outil de développement
+            territorial pour faire face à la désindustrialisation, à une
+            croissance démographique ralentie ou encore une image défavorable.
+            Ce modèle de développement par la culture pour pallier un déficit
+            d’attractivité touristique inspire de plus en plus de politiques de
+            développement territorial.
           </p>
         </v-col>
       </v-row>
@@ -71,20 +68,24 @@
 </template>
 
 <script setup lang="ts">
-import AnchoredSection from "~/components/Layout/AnchoredSection.vue";
+import AnchoredSection from '~/components/Layout/AnchoredSection.vue'
 </script>
 
 <style scoped lang="scss">
 .italic-title {
-  text-align: justify;
   font-style: italic;
   font-weight: 300;
   font-size: 34px;
   line-height: 40px;
   color: var(--primary-color);
   width: 80%;
-  margin-left: auto;
-  margin-bottom: auto;
+  margin: auto;
+
+  @media (max-width: 1240px) {
+    width: 90%;
+    margin-left: auto;
+    margin-right: auto;
+  }
 }
 
 .v-row.history {
@@ -92,12 +93,17 @@ import AnchoredSection from "~/components/Layout/AnchoredSection.vue";
   margin-left: auto;
   margin-right: auto;
 
+  .v-col-12 {
+    padding: 16px 5%;
+  }
+
   .v-img {
     background-repeat: no-repeat;
     background-position: center;
-    width: 400px;
+    width: 100%;
     height: 100%;
     border-radius: 20px;
+    margin: 0 auto;
 
     @media (max-width: 600px) {
       width: 90%;
@@ -127,18 +133,25 @@ import AnchoredSection from "~/components/Layout/AnchoredSection.vue";
   }
 
   p {
-    text-align: justify;
     font-weight: 300;
     font-size: 16px;
     line-height: 20px;
-    width: 30rem;
     margin-bottom: 2rem;
 
     @media (max-width: 600px) {
       width: 100%;
     }
   }
-}
-
 
+  @media (max-width: 1240px) {
+    h3,
+    h4,
+    p,
+    .v-img {
+      width: 100%;
+      margin-left: auto;
+      margin-right: auto;
+    }
+  }
+}
 </style>

+ 48 - 40
components/About/Valeurs.vue

@@ -2,42 +2,35 @@
   <AnchoredSection id="values">
     <LayoutContainer class="mt-12">
       <v-row class="center-90">
-        <LayoutUISubTitle>
-          Les valeurs qui nous portent
-        </LayoutUISubTitle>
+        <LayoutUISubTitle> Les valeurs qui nous portent </LayoutUISubTitle>
       </v-row>
 
       <v-row class="mt-6 center-90 align-center mb-12">
-        <v-col md="6">
+        <v-col cols="12" lg="6">
           <v-img
-            src="/images/about/valeurs/valeur.png"
+            src="/images/pages/qui-sommes-nous/valeurs/Opentalent_les_valeurs_qui_nous_portent.png"
             alt="Quatre photos: une prise de haut où l’on voit les pieds d’une personne avec un smiley dessiné sur du goudron, l'une de mains tenant de la terre avec une plante dans un décor de forêt, l'une d’une enseigne lumineuse écrit « Open » en blanc entouré d’un cercle orange et l'une de mains de femmes posées les unes en dessus des autres."
             cover
             class="valeur-img"
           />
         </v-col>
 
-        <v-col md="6">
+        <v-col cols="12" lg="6">
           <div class="values">
-            <v-row
-              v-for="(row, rowIndex) in values"
-              :key="rowIndex"
-            >
+            <v-row v-for="(row, rowIndex) in values" :key="rowIndex">
               <v-col
-                cols="12"
-                md="6"
                 v-for="(value, valueIndex) in row"
                 :key="valueIndex"
+                cols="12"
+                md="6"
               >
-                <v-img
-                  :src="value.img"
-                  :alt="value.alt"
-                  cover
-                />
+                <div class="d-flex flex-row align-center">
+                  <v-img :src="value.img" :alt="value.alt" cover class="mr-3" />
 
-                <h6>
-                  {{ value.title }}
-                </h6>
+                  <h6>
+                    {{ value.title }}
+                  </h6>
+                </div>
 
                 <p>
                   {{ value.description }}
@@ -52,43 +45,43 @@
 </template>
 
 <script setup lang="ts">
-import AnchoredSection from "~/components/Layout/AnchoredSection.vue";
-import type { SocietyValue } from "~/types/interface";
+import AnchoredSection from '~/components/Layout/AnchoredSection.vue'
+import type { SocietyValue } from '~/types/interface'
 
 const values: Array<Array<SocietyValue>> = [
   [
     {
-      img: "/images/about/valeurs/Management.svg",
-      alt: "Icône de deux mains tenant une roue crantée",
-      title: "Management social",
+      img: '/images/pages/qui-sommes-nous/valeurs/Management.svg',
+      alt: 'Icône management social',
+      title: 'Management social',
       description:
         "Guillaume et Michel sont sur la même longueur d’onde et donnent le « La » à un management social et solidaire où plus que de mettre en avant l'entreprise, ils privilégient la mise en avant des hommes et femmes qui la composent. Toux ceux qui participent jour après jour à l’écriture de la partition sont valorisés. Le partage, l’échange et le dialogue en lieu et place des liens de subordination.",
     },
     {
-      img: "/images/about/valeurs/Satisfaction-client.svg",
-      alt: "Icône d’utilisateurs avec des étoiles en dessous",
-      title: "Satisfaction client",
+      img: '/images/pages/qui-sommes-nous/valeurs/Satisfaction-client.svg',
+      alt: 'Icône Satisfaction client',
+      title: 'Satisfaction client',
       description:
-        "Opentalent met un point d’honneur à satisfaire ses clients en leur proposant des solutions de qualité, un projet global dans lequel ils se retrouvent. L’intention de base est bel et bien de proposer un équilibre entre les solutions informatiques et la volonté personnelle en lien avec la production et les publics concernés.",
+        'Opentalent met un point d’honneur à satisfaire ses clients en leur proposant des solutions de qualité, un projet global dans lequel ils se retrouvent. L’intention de base est bel et bien de proposer un équilibre entre les solutions informatiques et la volonté personnelle en lien avec la production et les publics concernés.',
     },
   ],
   [
     {
-      img: "/images/about/valeurs/Ecologie.svg",
-      alt: "Icône de la planète Terre entourée d’une branche avec des feuilles",
-      title: "Écologie",
+      img: '/images/pages/qui-sommes-nous/valeurs/Ecologie.svg',
+      alt: 'Icône Écologie',
+      title: 'Écologie',
       description:
-        "Proche des entreprises de l’Économie Sociale et Solidaire, Opentalent accorde une grande importance aux démarches liées à l’écologie et au développement durable. Le code des outils est par exemple optimisé pour limiter les ressources nécessaires des serveurs, réduisant ainsi leur empreinte carbone et améliorant le confort des utilisateurs au quotidien.",
+        'Proche des entreprises de l’Économie Sociale et Solidaire, Opentalent accorde une grande importance aux démarches liées à l’écologie et au développement durable. Le code des outils est par exemple optimisé pour limiter les ressources nécessaires des serveurs, réduisant ainsi leur empreinte carbone et améliorant le confort des utilisateurs au quotidien.',
     },
     {
-      img: "/images/about/valeurs/Open-source.svg",
-      alt: "Icône d’une roue crantée ouverte avec des flèches entrant et sortant",
-      title: "Open source",
+      img: '/images/pages/qui-sommes-nous/valeurs/Open-source.svg',
+      alt: 'Icône Open source',
+      title: 'Open source',
       description:
-        "Opentalent est une entreprise qui croit profondément aux vertus des logiciels Open Source et qui par son action contribue à leur développement.",
+        'Opentalent est une entreprise qui croit profondément aux vertus des logiciels Open Source et qui par son action contribue à leur développement.',
     },
   ],
-];
+]
 </script>
 
 <style scoped lang="scss">
@@ -97,20 +90,29 @@ const values: Array<Array<SocietyValue>> = [
   background-position: center;
   height: 400px;
   width: 450px;
+  margin-left: auto;
+  margin-right: auto;
+
+  @media (max-width: 1240px) {
+    width: 90%;
+  }
 }
 
 .values {
   .v-row {
-    border-top: 1px solid var(--on-neutral-color-extra-light);
+    @media (min-width: 1240px) {
+      border-top: 1px solid var(--on-neutral-color-extra-light);
+    }
   }
 
   .v-img {
     width: 50px;
+    max-width: 50px;
     height: 50px;
     margin-bottom: 1rem;
 
     @media (max-width: 600px) {
-      margin-left: auto;
+      margin-left: 0;
       margin-right: auto;
     }
   }
@@ -122,5 +124,11 @@ const values: Array<Array<SocietyValue>> = [
     color: var(--primary-color);
     margin-bottom: 1rem;
   }
+
+  @media (max-width: 1240px) {
+    width: 90%;
+    margin-left: auto;
+    margin-right: auto;
+  }
 }
 </style>

+ 54 - 44
components/Common/ActionMenu.vue

@@ -4,7 +4,7 @@ de l'écran (ou au bas de l'écran sur les petits écrans)
 -->
 <template>
   <!-- Écrans larges : menu lateral, accroché au bord droit de l'écran -->
-  <div class="sticky-menu lateral" v-if="lgAndUp && isVisible">
+  <div v-if="lgAndUp && isVisible" class="sticky-menu lateral">
     <v-row
       v-for="(action, index) in actionsOrDefault"
       :key="index"
@@ -13,9 +13,7 @@ de l'écran (ou au bas de l'écran sur les petits écrans)
     >
       <NuxtLink :to="action.url" class="link">
         <div>
-          <v-icon
-            :class="action.icon"
-          />
+          <v-icon :class="action.icon" />
 
           <p class="text-square mt-2">
             {{ action.text }}
@@ -26,7 +24,15 @@ de l'écran (ou au bas de l'écran sur les petits écrans)
   </div>
 
   <!-- Petits écrans : menu sous forme de bandeau en pied de page (sauf si le footer du site est visible) -->
-  <div class="sticky-menu band" v-else-if="isVisible">
+  <div v-else-if="isVisible" class="sticky-menu band">
+    <v-btn
+      :to="{ path: '', hash: '#top' }"
+      class="primary"
+      :width="24"
+    >
+      <v-icon>fas fa-arrow-up</v-icon>
+    </v-btn>
+
     <v-btn
       v-for="(action, index) in actionsOrDefault"
       :key="index"
@@ -39,39 +45,43 @@ de l'écran (ou au bas de l'écran sur les petits écrans)
 </template>
 
 <script setup lang="ts">
-import { useRouter } from "vue-router";
-import { useDisplay } from "vuetify";
-import { useLayoutStore } from "~/stores/layoutStore";
-import { ActionMenuItemType } from "~/types/enum/layout";
-import type { ActionMenuItem } from "~/types/interface";
-
-const { lgAndUp } = useDisplay();
-const router = useRouter();
+import { useRouter } from 'vue-router'
+import { useDisplay } from 'vuetify'
+import type { ComputedRef } from 'vue'
+import { useLayoutStore } from '~/stores/layoutStore'
+import { ActionMenuItemType } from '~/types/enum/layout'
+import type { ActionMenuItem } from '~/types/interface'
+
+const { lgAndUp } = useDisplay()
+const router = useRouter()
 const layoutStore = useLayoutStore()
 const { isMobileDevice } = useClientDevice()
 
-const telephoneNumber = "09 72 12 60 17";
+const telephoneNumber = '09 72 12 60 17'
 
-const isVisible: ComputedRef<boolean> = computed(() =>
-  !layoutStore.isHeaderVisible && !layoutStore.isFooterVisible
+const isVisible: ComputedRef<boolean> = computed(
+  () =>
+    !layoutStore.isHeaderVisible &&
+    !layoutStore.isBannerVisible &&
+    !layoutStore.isFooterVisible
 )
 
 // Actions par défaut du menu, peut-être surchargé via la propriété `actions`
 const defaultActions: Array<ActionMenuItem> = [
   {
     type: ActionMenuItemType.FOLLOW_LINK,
-    color: "secondary",
-    icon: "far fa-comments",
-    text: "Nous contacter",
-    url: "/nous-contacter",
+    color: 'secondary',
+    icon: 'far fa-comments',
+    text: 'Nous contacter',
+    url: { path: 'nous-contacter', hash: '#form' },
   },
   {
     type: ActionMenuItemType.CALL_US,
-    color: "secondary",
-    icon: "fas fa-phone",
-    text: "Nous Appeler",
+    color: 'primary',
+    icon: 'fas fa-phone',
+    text: 'Nous Appeler',
   },
-];
+]
 
 const props = defineProps({
   /**
@@ -80,8 +90,8 @@ const props = defineProps({
   actions: {
     type: Array<ActionMenuItem>,
     required: false,
-    default: []
-  }
+    default: [],
+  },
 })
 
 const actionsOrDefault: ComputedRef<Array<ActionMenuItem>> = computed(() => {
@@ -90,9 +100,9 @@ const actionsOrDefault: ComputedRef<Array<ActionMenuItem>> = computed(() => {
 
 const callUs = () => {
   if (isMobileDevice()) {
-    window.location.href = `tel:${telephoneNumber}`;
+    window.location.href = `tel:${telephoneNumber}`
   } else {
-    alert(`Notre numéro de téléphone : ${telephoneNumber}`);
+    navigateTo({ path: 'nous-contacter', hash: '#details' })
   }
 }
 
@@ -103,35 +113,34 @@ const callUs = () => {
 const onActionClick = (action: ActionMenuItem) => {
   switch (action.type) {
     case ActionMenuItemType.ASK_FOR_A_DEMO:
-      router.push({ path: action.url, query: { request: "demo" } });
-      break;
+      router.push({ path: action.url as string, query: { request: 'demo' } })
+      break
 
     case ActionMenuItemType.CALL_US:
       callUs()
-      break;
+      break
 
     case ActionMenuItemType.FOLLOW_LINK:
       if (!action.url) {
-        throw Error('Missing prop : url')
+        throw new Error('Missing prop : url')
       }
-      router.push({ path: action.url });
+      navigateTo(action.url)
       break
 
     default:
-      throw Error('Unrecognized action')
+      throw new Error('Unrecognized action')
   }
-};
+}
 </script>
 
 <style scoped lang="scss">
-
 .sticky-menu {
   z-index: 100;
 }
 
 // Menu format lateral (pour affichage écrans larges)
 .sticky-menu.lateral {
-  position: sticky;
+  position: fixed;
   right: 0;
   top: 60%;
   transform: translateY(-50%);
@@ -143,7 +152,7 @@ const onActionClick = (action: ActionMenuItem) => {
   font-weight: 500;
   font-size: 0.7rem;
   line-height: 15px;
-  text-align: center;
+  text-align: center !important;
   letter-spacing: 0.2em;
   text-transform: uppercase;
 }
@@ -157,10 +166,11 @@ const onActionClick = (action: ActionMenuItem) => {
   display: flex;
   justify-content: center;
   background-color: var(--neutral-color);
+  max-width: 100vw;
+  padding: 0 6px;
 
   .v-btn {
     margin: 6px 2%;
-    width: 46%;
   }
 }
 
@@ -171,11 +181,7 @@ const onActionClick = (action: ActionMenuItem) => {
   cursor: pointer;
 
   transition: transform 0.3s ease-in-out;
-  box-shadow: -1px 2px 4px 2px var(--on-neutral-color-light);
-}
-
-.square:last-child {
-
+  box-shadow: -1px 2px 6px 1px var(--on-neutral-color-light);
 }
 
 .square:hover {
@@ -185,6 +191,10 @@ const onActionClick = (action: ActionMenuItem) => {
 .link {
   text-decoration: none;
   color: var(--on-primary-color);
+
+  * {
+    text-align: center;
+  }
 }
 
 .primary {

+ 61 - 76
components/Common/Agenda.vue

@@ -3,32 +3,22 @@ Section "Agenda des évènements"
 -->
 <template>
   <AnchoredSection id="agenda">
-    <LayoutContainer class="mb-12" >
+    <LayoutContainer class="mb-12">
       <v-row class="center-90 align-center my-6">
         <v-col cols="4" class="align-center">
-          <LayoutUITitle>
-            L'agenda Opentalent
-          </LayoutUITitle>
+          <LayoutUITitle> L'agenda Opentalent </LayoutUITitle>
         </v-col>
 
         <v-col cols="4">
           <!-- Factoriser les contrôles du carousel dans un component -->
           <div class="carousel-controls">
-            <v-btn
-              icon="fas fa-chevron-left"
-              @click="goPrevious"
-            />
-            <v-btn
-              icon="fas fa-chevron-right"
-              @click="goNext"
-            />
+            <v-btn icon="fas fa-chevron-left" @click="goPrevious" />
+            <v-btn icon="fas fa-chevron-right" @click="goNext" />
           </div>
         </v-col>
 
         <v-col cols="4" class="d-flex flex-row flex-1 justify-end align-center">
-          <v-btn class="btn-news" text>
-            Voir tous les évènements
-          </v-btn>
+          <v-btn class="btn-news" text> Voir tous les évènements </v-btn>
         </v-col>
       </v-row>
 
@@ -40,11 +30,7 @@ Section "Agenda des évènements"
 
       <v-row class="center-90">
         <v-col cols="12">
-          <Carousel
-            ref="carousel"
-            :items-to-show="3"
-            :items-to-scroll="2"
-          >
+          <Carousel ref="carousel" :items-to-show="3" :items-to-scroll="2">
             <Slide
               v-for="(event, eventIndex) in events"
               :key="eventIndex"
@@ -69,9 +55,7 @@ Section "Agenda des évènements"
                       :color="tagColor(tag)"
                       label
                     >
-                      <span
-                        :class="tagTextColor(tag)"
-                      >
+                      <span :class="tagTextColor(tag)">
                         {{ tag }}
                       </span>
                     </v-chip>
@@ -87,88 +71,89 @@ Section "Agenda des évènements"
 </template>
 
 <script setup lang="ts">
-import { Carousel, Slide } from "vue3-carousel";
-import "vue3-carousel/dist/carousel.css";
-import AnchoredSection from "~/components/Layout/AnchoredSection.vue";
-import type { Event } from "~/types/interface";
+import { Carousel, Slide } from 'vue3-carousel'
+import 'vue3-carousel/dist/carousel.css'
+import type { Ref } from 'vue'
+import AnchoredSection from '~/components/Layout/AnchoredSection.vue'
+import type { Event } from '~/types/interface'
 
 const tagColor = (tag: string) => {
   switch (tag) {
-    case "Payant":
-      return "red";
-    case "Gratuit":
-      return "green";
+    case 'Payant':
+      return 'red'
+    case 'Gratuit':
+      return 'green'
     default:
-      return "primary";
+      return 'primary'
   }
-};
+}
 
 const tagTextColor = (tag: string) => {
   switch (tag) {
-    case "Payant":
-      return "red--text";
-    case "Gratuit":
-      return "green--text";
+    case 'Payant':
+      return 'red--text'
+    case 'Gratuit':
+      return 'green--text'
     default:
-      return "black--text";
+      return 'black--text'
   }
-};
+}
 
 const events: Array<Event> = [
   {
-    rdv: "20h00",
-    title: "LA NUIT DES RÊVES  ",
-    localisation: "FESTIVALDE musique - LONGCHAMP",
-    date: "21/06/2023",
-    img: "/images/agenda/agenda2.jpg",
-    tags: ["Festival", "Musique", "Tout public", "Payant"],
+    rdv: '20h00',
+    title: 'LA NUIT DES RÊVES  ',
+    localisation: 'FESTIVALDE musique - LONGCHAMP',
+    date: '21/06/2023',
+    img: '/images/agenda/agenda2.jpg',
+    tags: ['Festival', 'Musique', 'Tout public', 'Payant'],
   },
   {
-    rdv: "20h00",
-    title: "LE LAC DES CYGNES",
-    localisation: "SPECTACLE DE DANSE - PARIS 1",
-    date: "22/06/2023",
-    img: "/images/agenda/agenda3.jpg",
-    tags: ["Festival", "Musique", "Tout public", "Gratuit"],
+    rdv: '20h00',
+    title: 'LE LAC DES CYGNES',
+    localisation: 'SPECTACLE DE DANSE - PARIS 1',
+    date: '22/06/2023',
+    img: '/images/agenda/agenda3.jpg',
+    tags: ['Festival', 'Musique', 'Tout public', 'Gratuit'],
   },
   {
-    rdv: "20h00",
-    title: "SOLIDAYS 2023  : 23 > 25 juin",
-    localisation: "ORCHESTRE DE PARIS - PARIS 12",
-    date: "23/06/2023",
-    img: "/images/agenda/agenda4.jpg",
-    tags: ["Festival", "Musique", "Tout public", "Payant"],
+    rdv: '20h00',
+    title: 'SOLIDAYS 2023  : 23 > 25 juin',
+    localisation: 'ORCHESTRE DE PARIS - PARIS 12',
+    date: '23/06/2023',
+    img: '/images/agenda/agenda4.jpg',
+    tags: ['Festival', 'Musique', 'Tout public', 'Payant'],
   },
   {
-    rdv: "20h00",
-    title: "LE LAC DES CYGNES",
-    localisation: "FESTIVALDE musique - LONGCHAMP",
-    date: "24/06/2023",
-    img: "/images/agenda/agenda5.jpg",
-    tags: ["Festival", "Musique", "Tout public", "Payant"],
+    rdv: '20h00',
+    title: 'LE LAC DES CYGNES',
+    localisation: 'FESTIVALDE musique - LONGCHAMP',
+    date: '24/06/2023',
+    img: '/images/agenda/agenda5.jpg',
+    tags: ['Festival', 'Musique', 'Tout public', 'Payant'],
   },
   {
-    rdv: "20h00",
-    title: "SOLIDAYS 2023  : 23 > 25 juin ",
-    localisation: "SPECTACLE DE DANSE - PARIS 1",
-    date: "20/06/2023",
-    img: "/images/agenda/agenda1.jpg",
-    tags: ["Festival", "Musique", "Tout public", "Payant"],
+    rdv: '20h00',
+    title: 'SOLIDAYS 2023  : 23 > 25 juin ',
+    localisation: 'SPECTACLE DE DANSE - PARIS 1',
+    date: '20/06/2023',
+    img: '/images/agenda/agenda1.jpg',
+    tags: ['Festival', 'Musique', 'Tout public', 'Payant'],
   },
-];
+]
 
-const carousel: Ref<typeof Carousel | null> = ref(null);
+const carousel: Ref<typeof Carousel | null> = ref(null)
 
-const goPrevious = () => carousel.value!.prev();
-const goNext = () => carousel.value!.next();
+const goPrevious = () => carousel.value!.prev()
+const goNext = () => carousel.value!.next()
 </script>
 
 <style scoped>
-.v-container{
+.v-container {
   padding: 0 !important;
 }
 
-.container{
+.container {
   background: var(--neutral-color);
 }
 
@@ -226,7 +211,7 @@ const goNext = () => carousel.value!.next();
     }
   }
 
-  footer{
+  footer {
     display: flex;
     text-align: left !important;
 

+ 9 - 7
components/Common/AgendaLink.vue

@@ -5,21 +5,23 @@
 </template>
 
 <script setup lang="ts">
-import UrlUtils from "~/services/utils/urlUtils";
+import UrlUtils from '~/services/utils/urlUtils'
 
 const runtimeConfig = useRuntimeConfig()
 
 const props = defineProps({
   href: {
-    type: String
-  }
+    type: String,
+    required: true,
+  },
 })
 
 const target = computed(() => {
-  return UrlUtils.join(runtimeConfig.public.agendaBaseUrl as string, props.href as string)
+  return UrlUtils.join(
+    runtimeConfig.public.agendaBaseUrl as string,
+    props.href as string
+  )
 })
 </script>
 
-<style scoped lang="scss">
-
-</style>
+<style scoped lang="scss"></style>

+ 9 - 17
components/Common/Avantages.vue

@@ -10,36 +10,28 @@
       </LayoutUITitle>
     </v-row>
 
-    <v-row  class="center-90">
-      <v-col
-        cols="12"
-        md="4"
-        offset-md="1"
-        v-for="(benefit, index) in benefits"
-        :key="index"
-      >
-        <CommonCardBenefit
-          :benefit="benefit"
-        />
+    <v-row class="center-90 benefits">
+      <v-col v-for="(benefit, index) in benefits" :key="index" cols="12" md="4">
+        <CommonCardBenefit :benefit="benefit" />
       </v-col>
     </v-row>
   </LayoutContainer>
 </template>
 
 <script setup lang="ts">
-import type { Benefit } from "~/types/interface";
-import { useDisplay } from "vuetify";
+import type { PropType } from 'vue'
+import type { Benefit } from '~/types/interface'
 
-const props = defineProps({
+defineProps({
   benefits: {
     type: Array as PropType<Array<Benefit>>,
-    required: true
+    required: true,
   },
   title: {
     type: String,
     required: false,
-    default: "Des avantages concrets"
-  }
+    default: 'Des avantages concrets',
+  },
 })
 </script>
 

+ 33 - 16
components/Common/Banner.vue

@@ -1,5 +1,5 @@
 <template>
-  <LayoutContainer>
+  <LayoutContainer v-intersect="onIntersect">
     <v-row>
       <v-col cols="12">
         <div class="banner-container">
@@ -13,7 +13,7 @@
             <v-row>
               <div class="content-row">
                 <img
-                  src="/images/logiciels/icons/la-musique.svg"
+                  src="/images/components/banner/Icone_instruments_de_musique_trompette_et_tambour_avec_des_notes_de_musique.svg"
                   alt="Icône instruments de musique trompette et tambour avec des notes de musique"
                   class="custom-icon"
                 />
@@ -24,8 +24,11 @@
             </v-row>
           </div>
 
-          <div v-if="logoSrc" :class="'logo-square' + (logoAltTheme ? ' alt-theme' : '')">
-            <img :src="logoSrc" :alt="logoAlt"/>
+          <div
+            v-if="logoSrc"
+            :class="'logo-square' + (logoAltTheme ? ' alt-theme' : '')"
+          >
+            <img :src="logoSrc" :alt="logoAlt" />
           </div>
 
           <div class="image-text mt-12">
@@ -38,45 +41,55 @@
 </template>
 
 <script setup lang="ts">
+import type { PropType } from 'vue'
+import { useLayoutStore } from '~/stores/layoutStore'
 
-const props = defineProps({
+defineProps({
   imageSrc: {
     type: String,
-    required: true
+    required: true,
   },
   imageAlt: {
     type: String,
-    default: ""
+    default: '',
   },
   squareText: {
     type: String,
-    default: "École de musique, d'art, de danse, de cirque, conservatoires et MJC"
+    default:
+      "École de musique, d'art, de danse, de cirque, conservatoires et MJC",
   },
   logoSrc: {
     type: String as PropType<string | null>,
     required: false,
-    default: null
+    default: null,
   },
   logoAlt: {
     type: String,
     required: false,
-    default: ""
+    default: '',
   },
   logoAltTheme: {
     type: Boolean,
-    default: false
+    default: false,
   },
   reverseImage: {
     type: Boolean,
-    default: false
-  }
-});
+    default: false,
+  },
+})
+
+const layoutStore = useLayoutStore()
+const onIntersect = (isIntersecting: boolean) => {
+  layoutStore.setIsBannerVisible(isIntersecting)
+}
 </script>
 
 <style scoped lang="scss">
 .banner-container {
   position: relative;
   overflow: hidden;
+  min-height: 400px;
+  max-height: 400px;
 
   .image-text {
     position: absolute;
@@ -89,6 +102,10 @@ const props = defineProps({
     font-weight: 300;
     line-height: 40px;
   }
+
+  @media (max-width: 600px) {
+    min-height: 0;
+  }
 }
 
 .cover-image {
@@ -112,7 +129,7 @@ const props = defineProps({
 .custom-icon {
   width: 3rem;
   height: 3rem;
-  margin-top: .5rem;
+  margin-top: 0.5rem;
 }
 
 .details-square {
@@ -131,7 +148,7 @@ const props = defineProps({
 .logo-square {
   position: absolute;
   bottom: 0;
-  right: 10rem;
+  right: 13rem;
   width: 13rem;
   height: 10rem;
 

+ 8 - 11
components/Common/Card/Benefit.vue

@@ -14,7 +14,7 @@ Carte "Avantage" de la section Avantages d'une page Logiciel
         </span>
       </div>
 
-      <v-divider thickness="2"/>
+      <v-divider thickness="1" />
 
       <div class="description">
         <p class="mr-4">
@@ -22,24 +22,21 @@ Carte "Avantage" de la section Avantages d'une page Logiciel
         </p>
       </div>
 
-      <v-img
-        :src="benefit.image"
-        :alt="benefit.alt"
-        cover
-      />
+      <v-img :src="benefit.image" :alt="benefit.alt" cover />
     </div>
   </LayoutContainer>
 </template>
 
 <script setup lang="ts">
-import type { Benefit } from "~/types/interface";
+import type { PropType } from 'vue'
+import type { Benefit } from '~/types/interface'
 
-const props = defineProps({
+defineProps({
   benefit: {
     type: Object as PropType<Benefit>,
-    required: true
-  }
-});
+    required: true,
+  },
+})
 </script>
 
 <style scoped lang="scss">

+ 10 - 6
components/Common/Card/Stat.vue

@@ -12,12 +12,14 @@
 <script setup lang="ts">
 const props = defineProps({
   number: {
-    type: String
+    type: String,
+    required: true,
   },
   text: {
-    type: String
+    type: String,
+    required: true,
   },
-});
+})
 </script>
 
 <style scoped lang="scss">
@@ -33,18 +35,20 @@ const props = defineProps({
   align-items: center;
   text-align: center;
 
-  p:first-child{
+  p:first-child {
     font-weight: 600;
     font-size: 60px;
     line-height: 68px;
     text-align: center;
     margin-bottom: 0.5rem;
+
+    @media (max-width: 1600px) {
+      font-size: 48px;
+    }
   }
 
   @media (max-width: 1240px) {
     height: 12rem;
   }
 }
-
-
 </style>

+ 26 - 32
components/Common/Carousel/Clients.vue

@@ -6,7 +6,8 @@
     <v-row justify="center">
       <h3 class="text-center">
         <slot name="title">
-          Plus de <span class="alt-color">5000 structures</span> nous font confiance
+          Plus de <span class="alt-color">5000 structures</span> nous font
+          confiance
         </slot>
       </h3>
     </v-row>
@@ -15,7 +16,7 @@
       <v-row>
         <!-- Fléche de gauche -->
         <v-btn
-          v-if="mdAndUp"
+          v-if="lgAndUp"
           icon="fas fa-chevron-left"
           @click="goToPrevious"
         />
@@ -24,10 +25,11 @@
         <Carousel
           ref="carousel"
           class="elevation-4 mb-12"
-          :items-to-show="lgAndUp ? 4 : 1"
-          :items-to-scroll="lgAndUp ? 2 : 1"
+          :items-to-show="smAndUp ? 4 : 1"
+          :items-to-scroll="smAndUp ? 2 : 1"
+          :wrap-around="true"
         >
-          <Slide v-for="(item, index) in items" :key="index">
+          <Slide v-for="item in items" :key="item.src">
             <div>
               <v-img :src="item.src" :alt="item.alt" />
             </div>
@@ -35,50 +37,40 @@
         </Carousel>
 
         <!-- Fléche de droite -->
-        <v-btn
-          v-if="mdAndUp"
-          icon="fas fa-chevron-right"
-          @click="goToNext"
-        />
+        <v-btn v-if="lgAndUp" icon="fas fa-chevron-right" @click="goToNext" />
       </v-row>
 
       <v-row v-if="mdAndDown">
-        <v-btn
-          icon="fas fa-chevron-left"
-          @click="goToPrevious"
-        />
-        <v-btn
-          icon="fas fa-chevron-right"
-          @click="goToNext"
-        />
+        <v-btn icon="fas fa-chevron-left" @click="goToPrevious" />
+        <v-btn icon="fas fa-chevron-right" @click="goToNext" />
       </v-row>
     </v-container>
   </LayoutContainer>
 </template>
 
 <script setup lang="ts">
-import { Carousel, Slide } from "vue3-carousel";
-import type { PropType } from "@vue/runtime-core";
-import { useDisplay } from "vuetify";
+import { Carousel, Slide } from 'vue3-carousel'
+import type { PropType, Ref } from 'vue'
+import { useDisplay } from 'vuetify'
 
-const { mdAndUp, lgAndUp, mdAndDown } = useDisplay()
+const { smAndUp, lgAndUp, mdAndDown } = useDisplay()
 
-const carousel: Ref<typeof Carousel | null> = ref(null);
+const carousel: Ref<typeof Carousel | null> = ref(null)
 
-const props = defineProps({
+defineProps({
   items: {
-    type: Array as PropType<Array<{ src: string, alt: string }>>,
-    required: true
-  }
-});
+    type: Array as PropType<Array<{ src: string; alt: string }>>,
+    required: true,
+  },
+})
 
 const goToPrevious = () => {
-  carousel.value!.prev();
-};
+  carousel.value!.prev()
+}
 
 const goToNext = () => {
-  carousel.value!.next();
-};
+  carousel.value!.next()
+}
 </script>
 
 <style scoped lang="scss">
@@ -126,6 +118,8 @@ h3 {
 }
 
 .carousel {
+  width: 960px;
+  height: 240px;
   background-color: var(--neutral-color);
   margin-top: 2rem;
   border-radius: 20px;

+ 57 - 48
components/Common/Carousel/Fonctionnalite.vue

@@ -1,7 +1,7 @@
 <template>
   <LayoutContainer>
-    <v-row>
-      <v-col cols="6">
+    <v-row class="center-90">
+      <v-col cols="12" md="6">
         <LayoutUISubTitle>
           Découvrez toutes les fonctionnalités de notre solution
         </LayoutUISubTitle>
@@ -11,28 +11,24 @@
         </LayoutUITitle>
       </v-col>
 
-      <v-col cols="12" md="6" class="d-flex align-center justify-start">
+      <v-col cols="12" md="6" class="arrows">
         <v-btn icon="fas fa-chevron-left" @click="previousAction" />
         <v-btn icon="fas fa-chevron-right" @click="nextAction" />
       </v-col>
     </v-row>
 
     <v-row>
-      <v-col cols="12" md="12">
+      <v-col cols="12">
         <Carousel
           ref="carousel"
-          :items-to-show="4"
+          :items-to-show="itemsToShow"
           :items-to-scroll="1"
           :wrap-around="true"
         >
-          <Slide v-for="(card, index) in cards" :key="index" >
+          <Slide v-for="(card, index) in cards" :key="index">
             <div class="card-container">
               <v-card class="inv-theme">
-                <v-img
-                  :src="card.logo"
-                  :alt="card.title"
-                  class="mx-auto"
-                />
+                <v-img :src="card.logo" :alt="card.title" class="mx-auto" />
 
                 <v-card-title>
                   <h5>
@@ -43,24 +39,18 @@
                 <v-card-item>
                   <v-card-text>
                     <ul>
-                      <li
-                        v-for="item in card.list"
-                        :key="item"
-                      >
+                      <li v-for="item in card.list" :key="item">
                         <p>{{ item }}</p>
                       </li>
                     </ul>
                   </v-card-text>
-
                 </v-card-item>
+
                 <div class="footer">
-                    <p
-                      v-for="option in card.options"
-                      :key="option"
-                    >
-                      {{ option }}
-                    </p>
-                  </div>
+                  <p v-for="option in card.options" :key="option">
+                    {{ option }}
+                  </p>
+                </div>
               </v-card>
             </div>
           </Slide>
@@ -71,33 +61,41 @@
 </template>
 
 <script setup lang="ts">
-import { useDisplay } from "vuetify";
-import { Carousel, Slide } from "vue3-carousel";
-import "vue3-carousel/dist/carousel.css";
-import type { PropType } from "@vue/runtime-core";
-import type { Functionality } from "~/types/interface";
+import { useDisplay } from 'vuetify'
+import { Carousel, Slide } from 'vue3-carousel'
+import 'vue3-carousel/dist/carousel.css'
+import type { PropType, Ref } from 'vue'
+import type { Functionality } from '~/types/interface'
 
-const { mdAndDown } = useDisplay();
+const { lgAndUp, mdAndUp, smAndUp } = useDisplay()
 
-const props = defineProps({
+defineProps({
   cards: {
     type: Array as PropType<Array<Functionality>>,
-    required: true
-  }
+    required: true,
+  },
 })
 
-const carousel: Ref<typeof Carousel | null> = ref(null);
+const carousel: Ref<typeof Carousel | null> = ref(null)
+
+const itemsToShow = computed(() =>
+  lgAndUp.value ? 5 : mdAndUp.value ? 3 : smAndUp.value ? 2 : 1
+)
 
 const nextAction = () => {
-  carousel.value!.next();
-};
+  carousel.value!.next()
+}
 
 const previousAction = () => {
-  carousel.value!.prev();
-};
+  carousel.value!.prev()
+}
 </script>
 
 <style scoped lang="scss">
+h5 {
+  text-align: center;
+}
+
 .v-row {
   width: 95%;
   margin-left: auto;
@@ -119,26 +117,32 @@ const previousAction = () => {
 .carousel {
   margin-left: 2rem;
   margin-right: 2rem;
+  margin-bottom: 2rem;
 }
 
 .card-container {
   display: flex;
   justify-content: center;
   align-items: center;
-  margin-bottom: 3rem;
   margin-right: 2rem;
+  width: 100%;
+  height: 100%;
 }
 
 .v-card {
   border-radius: 1rem;
   transition: transform 0.3s;
   font-weight: 300;
-  min-height: 25rem !important;
+  width: 100%;
+  height: 100%;
+  padding: 0 10% 14px 10%;
 
   .v-img {
     width: 5rem;
     height: 3rem;
     margin-top: 1rem;
+    margin-bottom: 12px;
+    fill: #fac20a !important;
   }
 
   .v-card-title {
@@ -160,19 +164,24 @@ const previousAction = () => {
   .footer {
     position: absolute;
     left: 0;
-    margin-left: .5rem;
-    font-size: .9rem;
+    bottom: 1rem;
+    margin-left: 1.3rem;
+    font-size: 0.9rem;
+
+    p {
+      text-align: left;
+    }
   }
 }
 
-@media(min-width: 1800px){
-  .v-card{
-    min-height: 400px !important;
-    max-height: 400px !important;
-    min-width: 400px !important;
-    max-width: 400px !important;
+.arrows {
+  display: flex;
+  align-content: center;
+  justify-content: end;
+
+  @media (max-width: 600px) {
+    justify-content: center;
   }
 }
 
-
 </style>

+ 54 - 44
components/Logiciels/School/Contact.vue → components/Common/Contact.vue

@@ -2,32 +2,24 @@
   <AnchoredSection id="contact">
     <LayoutContainer>
       <!-- Section "Appelez nous" -->
-      <v-row>
-        <LayoutUISubTitle v-if="smAndDown">
-          Contactez-nous
-        </LayoutUISubTitle>
+      <v-row class="center-90">
+        <LayoutUISubTitle v-if="smAndDown"> Contactez-nous </LayoutUISubTitle>
 
         <v-col cols="12" md="6">
           <v-img
-            src="/images/contact/contact.jpg"
+            src="/images/components/contact/Contact_Opentalent_agenda_et_logiciels_culturels.jpg"
             alt="Téléphone fixe posé sur un fond bleu comportant des bulles d’onomatopée : HAHA! OH! HEY! WOW! "
+            :cover="mdAndDown"
             class="help-img"
           />
         </v-col>
 
-        <v-col cols="12" lg="5">
-          <LayoutUISubTitle v-if="mdAndUp">
-            Contactez-nous
-          </LayoutUISubTitle>
+        <v-col cols="12" lg="5" class="contact-section">
+          <LayoutUISubTitle v-if="mdAndUp"> Contactez-nous </LayoutUISubTitle>
 
-          <LayoutUITitle>
-            Vous avez un projet ?
-          </LayoutUITitle>
+          <LayoutUITitle> Vous avez un projet ? </LayoutUITitle>
 
-          <div class="pl-6">
-            <h6 class="subtitle">
-              N'attendez plus, appelez-nous !
-            </h6>
+          <div class="px-6">
             <p class="contact-details">
               Vous avez une identité, des besoins, des projets... On est là pour
               vous écouter et vous offrir une offre personnalisée ! Que vous
@@ -37,28 +29,28 @@
               l'intégralité des fonctionnalités.
             </p>
 
-            <v-btn to="nous-contacter" class="btn-contact"> Nous contacter </v-btn>
+            <v-btn to="nous-contacter" class="btn-contact">
+              Nous contacter
+            </v-btn>
           </div>
         </v-col>
       </v-row>
 
       <!-- Section "Adhérent CMF" -->
-      <v-row class="center-90" >
-        <v-col cols="12" lg="6" >
-          <LayoutUISubTitle>
-            Adhérents CMF
-          </LayoutUISubTitle>
+      <v-row class="center-90 cmf-section">
+        <v-col cols="12" lg="6">
+          <LayoutUISubTitle> Adhérents CMF </LayoutUISubTitle>
 
-          <LayoutUITitle>
-            Bénéficiez de conditions privilégiées
-          </LayoutUITitle>
+          <LayoutUITitle> Bénéficiez de conditions privilégiées </LayoutUITitle>
 
           <div class="pl-4">
-            <h6 class="subtitle">
-              N'attendez plus, appelez-nous
-            </h6>
+            <v-img v-if="mdAndDown"
+              src="/images/logos/cmf/Logo_Confederation_Musicale_de_France-CMF_vivre_la_musique_ensemble.jpg"
+              alt="Logo Confédération Musicale de France - CMF avec son slogan : vivre la musique ensemble"
+              class="logo-cmf my-6"
+            />
 
-            <p class="contact-details mr-12">
+            <p class="contact-details">
               Si votre établissement d’enseignement artistique est adhérent à la
               Confédération Musicale de France (CMF), vous bénéficiez
               gratuitement, dans le cadre de votre adhésion, de la version
@@ -81,23 +73,22 @@
           </div>
         </v-col>
 
-        <v-col cols="12" md="6">
-           <v-img
-             src="/images/logiciels/school/CMF-vivre_la_musique_ensemble.jpg"
-             alt="Logo Confédération Musicale de France - CMF avec son slogan : vivre la musique ensemble"
-             class="logo-cmf mt-12"
-           />
+        <v-col v-if="mdAndUp" cols="12" md="6">
+          <v-img
+            src="/images/logos/cmf/Logo_Confederation_Musicale_de_France-CMF_vivre_la_musique_ensemble.jpg"
+            alt="Logo Confédération Musicale de France - CMF avec son slogan : vivre la musique ensemble"
+            class="logo-cmf mt-12"
+          />
         </v-col>
       </v-row>
     </LayoutContainer>
   </AnchoredSection>
 </template>
 <script setup>
-import AnchoredSection from "~/components/Layout/AnchoredSection.vue";
-import { useDisplay } from "vuetify";
-
-const { smAndDown, mdAndUp } = useDisplay()
+import { useDisplay } from 'vuetify'
+import AnchoredSection from '~/components/Layout/AnchoredSection.vue'
 
+const { smAndDown, mdAndDown, mdAndUp } = useDisplay()
 </script>
 
 <style scoped>
@@ -111,11 +102,13 @@ const { smAndDown, mdAndUp } = useDisplay()
 .logo-cmf {
   background-repeat: no-repeat;
   background-size: contain;
-  width: 80%;
+  width: 50%;
+  min-width: 250px;
   height: 100%;
+  margin-left: 100px;
 
-  @media (max-width: 600px) {
-    margin: 0 auto !important;
+  @media (max-width: 1240px) {
+    margin: 12px auto 48px auto !important;
   }
 }
 
@@ -143,7 +136,22 @@ const { smAndDown, mdAndUp } = useDisplay()
   font-size: 16px;
   line-height: 20px;
   color: var(--on-neutral-color);
-  text-align: justify;
+  max-width: 80%;
+
+}
+
+@media (max-width: 1240px) {
+  .contact-section {
+    text-align: center;
+  }
+
+  .cmf-section {
+    text-align: center;
+  }
+
+  .contact-details {
+    margin: 0 auto;
+  }
 }
 
 @media (max-width: 1600px) and (min-width: 600px) {
@@ -154,7 +162,9 @@ const { smAndDown, mdAndUp } = useDisplay()
 
 @media (max-width: 600px) {
   .contact-details {
-    width: 90%;
+    max-width: 100%;
+    width: 100%;
+    text-align: justify;
   }
 }
 </style>

+ 13 - 12
components/Common/ContainerVideo.vue

@@ -1,6 +1,6 @@
 <template>
   <LayoutContainer>
-    <div v-if="mdAndUp" class="container-green">
+    <div v-if="videoUrl" class="container-green">
       <v-row class="mt-12">
         <v-row>
           <v-col cols="6">
@@ -24,27 +24,28 @@
       </v-row>
     </div>
 
-    <div v-else>
-
-    </div>
+    <div v-else></div>
   </LayoutContainer>
 </template>
 
 <script setup lang="ts">
+import { useDisplay } from 'vuetify'
 
-import { useDisplay } from "vuetify";
+const { lgAndUp } = useDisplay()
 
-const { mdAndUp, lgAndUp } = useDisplay()
-
-const props = defineProps({
+defineProps({
   title: {
     type: String,
-    required: true
+    required: true,
   },
   quote: {
     type: String,
-    required: true
-  }
+    required: true,
+  },
+  videoUrl: {
+    type: String,
+    default: '',
+  },
 })
 </script>
 
@@ -70,7 +71,7 @@ const props = defineProps({
 }
 
 .screen-img-3 {
-  background-image: url("/images/logiciels/school/screen2.png");
+  background-image: url('/images/components/presentation/Opentalent-disponible-su-Multi-support.png');
   background-size: cover;
   background-position: center;
   width: 650px;

+ 20 - 22
components/Common/MenuScroll.vue

@@ -4,9 +4,7 @@ Menu de navigation entre les sections d'une page, accrochée au haut de l'écran
 <template>
   <LayoutContainer v-scroll="handleScroll">
     <v-row>
-      <v-col
-        cols="12"
-      >
+      <v-col cols="12">
         <v-list
           class="menu-container"
           density="compact"
@@ -23,7 +21,7 @@ Menu de navigation entre les sections d'une page, accrochée au haut de l'écran
           <div v-for="menu in menus" :key="menu.anchor">
             <nuxt-link :to="{ path: '', hash: '#' + menu.anchor }">
               <v-list-item
-                :class="{ active : isSticky && menu.anchor === activeMenuItem }"
+                :class="{ active: isSticky && menu.anchor === activeMenuItem }"
               >
                 {{ menu.label }}
               </v-list-item>
@@ -36,38 +34,38 @@ Menu de navigation entre les sections d'une page, accrochée au haut de l'écran
 </template>
 
 <script setup lang="ts">
-import type { PropType } from "@vue/runtime-core";
-import type { MenuScroll } from "~/types/interface";
-import { useLayoutStore } from "~/stores/layoutStore";
+import type { ComputedRef, PropType, Ref } from 'vue'
+import type { MenuScroll } from '~/types/interface'
+import { useLayoutStore } from '~/stores/layoutStore'
 
 defineProps({
   menus: {
-    type: Array as PropType<Array < MenuScroll >>,
-    required: true
-  }
-});
+    type: Array as PropType<Array<MenuScroll>>,
+    required: true,
+  },
+})
 
 const layoutStore = useLayoutStore()
 
-const isSticky: Ref<boolean> = ref(false);
+const isSticky: Ref<boolean> = ref(false)
 
 const activeMenuItem: ComputedRef<string | null> = computed(() => {
-  return Object.entries(
-    layoutStore.isAnchoredSectionOnScreen
-  ).find(
-    ([key, value]) => value === true
-  )?.[0] ?? null
+  return (
+    Object.entries(layoutStore.isAnchoredSectionOnScreen).find(
+      ([_, value]) => value
+    )?.[0] ?? null
+  )
 })
 
 const handleScroll = () => {
-  isSticky.value = window.scrollY > 800;
+  isSticky.value = window.scrollY > 800
 }
 </script>
 
 <style scoped lang="scss">
 .sticky-menu {
   position: fixed;
-  top: 0;
+  top: 0 !important;
   left: 0;
   right: 0;
   background: var(--neutral-color);
@@ -75,6 +73,7 @@ const handleScroll = () => {
 }
 
 .menu-container {
+  top: -32px;
   z-index: 3;
   display: flex;
   justify-content: center;
@@ -99,10 +98,9 @@ const handleScroll = () => {
 }
 
 .active {
-  background-color: var(--on-primary-color);
-  color: var(--primary-color);
+  background-color: var(--scroll-menu-primary-color);
+  color: var(--scroll-menu-on-primary-color);
   border-radius: 16px;
   padding: 5px;
 }
 </style>
-

+ 31 - 29
components/Common/Meta.vue

@@ -1,36 +1,38 @@
 <!--
 Définit les balises meta de la page
 -->
-<template></template>
+<template>
+  <div />
+</template>
 
 <script setup lang="ts">
-  const props = defineProps({
-    title: {
-      type: String,
-      required: true
-    },
-    description: {
-      type: String,
-      required: true
-    },
-    image: {
-      type: String,
-      required: false,
-      default: 'images/Opentalent'
-    }
-  })
+const props = defineProps({
+  title: {
+    type: String,
+    required: true,
+  },
+  description: {
+    type: String,
+    required: true,
+  },
+  image: {
+    type: String,
+    required: false,
+    default: 'images/Opentalent',
+  },
+})
 
-  useSeoMeta({
-    title : props.title,
-    ogTitle : props.title,
-    twitterTitle : props.title,
-    description : props.description,
-    ogDescription : props.description,
-    twitterDescription : props.description,
-    ogImage : props.image,
-    twitterImage: props.image,
-    twitterCard : 'summary_large_image',
-    ogType: 'website',
-    ogLocale: 'fr_FR'
-  })
+useSeoMeta({
+  title: props.title,
+  ogTitle: props.title,
+  twitterTitle: props.title,
+  description: props.description,
+  ogDescription: props.description,
+  twitterDescription: props.description,
+  ogImage: props.image,
+  twitterImage: props.image,
+  twitterCard: 'summary_large_image',
+  ogType: 'website',
+  ogLocale: 'fr_FR',
+})
 </script>

+ 92 - 104
components/Common/Presentation.vue

@@ -2,152 +2,137 @@
 Section "Présentation" d'une page Logiciel
 -->
 <template>
-  <div id="Presentation">
-    <LayoutContainer>
-      <v-row class="center-90">
-
-        <!-- Colonne 1 (sous-titre, illustration logiciels, prix) -->
-        <v-col cols="12" lg="5">
-          <LayoutUISubTitle class="ml-8" >
-            {{ title }}
-          </LayoutUISubTitle>
-
-          <v-img
-            src="/images/logiciels/Opentalent-disponible-su-Multi-support.png"
-            alt="Ordinateur de bureau, ordinateur portable tablette et smartphone montrant le logiciel Opentalent"
-            class="w-100"
-          />
-
-          <div class="pricing-rectangle rectangle-4 ml-6">
-            <div class="logo-circle">
-              <div class="content-flex ml-6">
-                <v-img
-                  :src="logoSrc"
-                  :alt="logoAlt"
-                  class="software-logo"
-                />
-              </div>
-            </div>
-
-            <div v-if="pricingAmount" class="details">
-              <p class="small-text">
-                {{ pricingFromText }}
-              </p>
-              <p class="big-text">
-                {{ pricingAmount }}
-                <span class="smaller-text">
-                  {{ pricingPeriodText }}
-                </span>
-              </p>
-              <p class="small-text">
-                {{ pricingAnnouncementText }}
-              </p>
-            </div>
-            <div v-else class="details medium-text">
-              {{ pricingAltText }}
+  <LayoutContainer>
+    <v-row class="center-90">
+      <!-- Colonne 1 (sous-titre, illustration logiciels, prix) -->
+      <v-col cols="12" lg="5">
+        <LayoutUISubTitle class="ml-8">
+          {{ title }}
+        </LayoutUISubTitle>
+
+        <v-img
+          src="/images/components/presentation/Opentalent-disponible-su-Multi-support.png"
+          alt="Ordinateur de bureau, ordinateur portable tablette et smartphone montrant le logiciel Opentalent"
+          class="w-100"
+        />
+
+        <div class="pricing-rectangle rectangle-4 ml-6">
+          <div class="logo-circle">
+            <div class="content-flex ml-6">
+              <v-img :src="logoSrc" :alt="logoAlt" class="software-logo" />
             </div>
           </div>
-        </v-col>
-
-        <!-- Colonne 2 (présentation, pictogrammes des fonctionnalités) -->
-        <v-col cols="12" lg="6">
-          <h3>
-            {{ section1title }}
-          </h3>
-
-          <ul class="ml-12 mt-6">
-            <li
-              v-for="item in features"
-              :key="item"
-            >
-              {{ item }}
-            </li>
-          </ul>
-
-          <h3 class="mt-12 ml-6">
-            {{ section2title }}
-          </h3>
-
-          <div class="picto-container">
-            <div
-              v-for="picto in pictos"
-              :key="picto.text"
-              class="picto"
-            >
-              <v-img :src="picto.src" class="img" />
 
-              <p class="text">
-                {{ picto.text }}
-              </p>
-            </div>
+          <div v-if="pricingAmount" class="details">
+            <p class="small-text">
+              {{ pricingFromText }}
+            </p>
+            <p class="big-text">
+              {{ pricingAmount }}
+              <span class="smaller-text">
+                {{ pricingPeriodText }}
+              </span>
+            </p>
+            <p class="small-text">
+              {{ pricingAnnouncementText }}
+            </p>
+          </div>
+          <div v-else class="details medium-text">
+            {{ pricingAltText }}
+          </div>
+        </div>
+      </v-col>
+
+      <!-- Colonne 2 (présentation, pictogrammes des fonctionnalités) -->
+      <v-col cols="12" lg="6">
+        <h3>
+          {{ section1title }}
+        </h3>
+
+        <ul class="ml-12 mt-6">
+          <li v-for="item in features" :key="item">
+            {{ item }}
+          </li>
+        </ul>
+
+        <h3 class="mt-12 ml-6">
+          {{ section2title }}
+        </h3>
+
+        <div class="picto-container">
+          <div v-for="picto in pictos" :key="picto.text" class="picto">
+            <v-img :src="picto.src" class="img" />
+
+            <p class="text">
+              {{ picto.text }}
+            </p>
           </div>
-        </v-col>
-      </v-row>
-    </LayoutContainer>
-  </div>
+        </div>
+      </v-col>
+    </v-row>
+  </LayoutContainer>
 </template>
 
 <script setup lang="ts">
-import type { PropType } from "@vue/runtime-core";
-import type { FeaturePicto } from "~/types/interface";
+import type { PropType } from 'vue'
+import type { FeaturePicto } from '~/types/interface'
 
-const route = useRoute();
-
-const props = defineProps({
+defineProps({
   title: {
     type: String,
-    required: true
+    required: true,
   },
   section1title: {
     type: String,
     required: false,
-    default: "Un outil complet en ligne"
+    default: 'Un outil complet en ligne',
   },
   section2title: {
     type: String,
     required: false,
-    default: "Des caractéristiques uniques & dédiée"
+    default: 'Des caractéristiques uniques & dédiée',
   },
   features: {
     type: Object as PropType<Array<string>>,
-    required: true
+    required: true,
   },
   pictos: {
     type: Array as PropType<Array<FeaturePicto>>,
-    required: true
+    required: true,
   },
   logoSrc: {
     type: String,
-    default: "",
+    default: '',
   },
   logoAlt: {
     type: String,
-    default: "",
+    default: '',
   },
   pricingFromText: {
     type: String,
     required: false,
-    default: "à partir de"
+    default: 'à partir de',
   },
   pricingAmount: {
     type: String,
-    default: ""
+    default: '',
   },
   pricingPeriodText: {
     type: String,
     required: false,
-    default: "mois"
+    default: '/ mois',
   },
   pricingAnnouncementText: {
     type: String,
     required: false,
-    default: "payable annuellement"
+    default: 'payable annuellement',
   },
   pricingAltText: {
+    type: String,
     required: false,
-    default: ""
-  }
-});
+    default: '',
+  },
+})
 </script>
 
 <style scoped lang="scss">
@@ -163,7 +148,7 @@ const props = defineProps({
   .logo-circle {
     background-color: #0e2d32;
     border-radius: 3rem;
-    width: 7rem;
+    width: 6rem;
     height: 6rem;
   }
 
@@ -171,8 +156,8 @@ const props = defineProps({
     display: flex;
     align-items: center;
     justify-content: center;
-    top:1rem;
-    right: .5rem;
+    top: 1.3rem;
+    right: 0.7rem;
   }
 
   .details {
@@ -196,7 +181,7 @@ const props = defineProps({
     font-size: 2.5rem;
     font-weight: bold;
     line-height: 2rem;
-    margin-left: 1rem;
+    margin-left: 0.8rem;
   }
 
   .smaller-text {
@@ -220,9 +205,11 @@ const props = defineProps({
 .picto-container {
   display: flex;
   flex-direction: row;
-  flex-wrap: wrap;
+  flex-wrap: nowrap;
 
-  @media (max-width: 600px) {
+  @media (max-width: 1240px) {
+    flex-wrap: wrap;
+    justify-content: center;
   }
 }
 
@@ -238,6 +225,7 @@ const props = defineProps({
     margin-top: -3rem;
     text-align: center;
     width: 60%;
+    height: 100px;
     margin-right: auto;
     margin-left: auto;
   }

+ 89 - 97
components/Common/ReviewSection.vue

@@ -1,98 +1,86 @@
 <template>
-    <LayoutContainer>
-      <v-row class="center-90">
-        <v-col cols="12" lg="3">
-          <div class="controls-section">
-            <h3>
-              Ce sont eux qui en parlent le mieux
-            </h3>
-
-            <div v-if="lgAndUp" class="carousel-controls">
-              <v-btn
-                icon="fas fa-chevron-left"
-                @click="goPrevious"
-              />
-              <v-btn
-                icon="fas fa-chevron-right"
-                @click="goNext"
-              />
-            </div>
+  <LayoutContainer>
+    <v-row class="center-90">
+      <v-col cols="12" lg="3">
+        <div class="controls-section">
+          <h3>Ce sont eux qui en parlent le mieux</h3>
+
+          <div class="carousel-controls">
+            <v-btn icon="fas fa-chevron-left" @click="goPrevious" />
+            <v-btn icon="fas fa-chevron-right" @click="goNext" />
           </div>
-        </v-col>
-
-        <v-col cols="12" lg="9">
-          <v-carousel
-            ref="carousel"
-            :items-to-show="lgAndUp ? 3 : 1"
-            :wrapAround="true"
-            :show-arrows="false"
-            height="350"
-            class="carousel"
-          >
-            <v-carousel-item
-              v-for="(card, index) in cards"
-              :key="index"
-              class="card"
-            >
-              <v-container>
-                <v-card class="inv-theme">
-                  <v-card-item>
-                    <v-card-text>
-                      {{ card.review }}
-                    </v-card-text>
-                  </v-card-item>
-
-                  <v-card-actions>
-                    <p class="reviewer-name">
-                      {{ card.name }}
-                    </p>
-
-                    <p class="reviewer-status">
-                      {{ card.status }}
-                    </p>
-                    <p class="reviewer-structure">
-                      {{ card.structure }}
-                    </p>
-                  </v-card-actions>
-                </v-card>
-              </v-container>
-            </v-carousel-item>
-          </v-carousel>
-        </v-col>
-      </v-row>
+        </div>
+      </v-col>
+
+      <v-col cols="12" lg="9">
+        <Carousel
+          ref="carousel"
+          :items-to-show="lgAndUp ? 3 : 1"
+          :wrap-around="true"
+          :show-arrows="false"
+          snap-align="center"
+          class="carousel"
+        >
+          <Slide v-for="(card, index) in cards" :key="index" class="card">
+            <v-container>
+              <v-card class="inv-theme">
+                <v-card-item>
+                  <v-card-text>
+                    <i>"{{ card.review }}"</i>
+                  </v-card-text>
+                </v-card-item>
+
+                <v-card-actions>
+                  <p class="reviewer-name">
+                    {{ card.name }}
+                  </p>
+
+                  <p class="reviewer-status">
+                    {{ card.status }}
+                  </p>
+                  <p class="reviewer-structure">
+                    {{ card.structure }}
+                  </p>
+                </v-card-actions>
+              </v-card>
+            </v-container>
+          </Slide>
+        </Carousel>
+      </v-col>
+    </v-row>
   </LayoutContainer>
 </template>
 
 <script setup lang="ts">
-import { Carousel, Slide } from "vue3-carousel";
-import "vue3-carousel/dist/carousel.css";
-import type { PropType } from "@vue/runtime-core";
-import type { Review } from "~/types/interface";
-import { useDisplay } from "vuetify";
+import { Carousel, Slide } from 'vue3-carousel'
+import 'vue3-carousel/dist/carousel.css'
+import type { PropType, Ref } from 'vue'
+import { useDisplay } from 'vuetify'
+import type { Review } from '~/types/interface'
 
-const props = defineProps({
+defineProps({
   cards: {
     type: Array as PropType<Array<Review>>,
     required: true,
   },
-});
+})
 
 const { lgAndUp } = useDisplay()
 
-const carousel: Ref<typeof Carousel | null> = ref(null);
+const carousel: Ref<typeof Carousel | null> = ref(null)
 
 const goPrevious = () => {
-  carousel.value!.prev();
-};
+  carousel.value!.prev()
+}
 
 const goNext = () => {
-  carousel.value!.next();
-};
+  carousel.value!.next()
+}
 </script>
 
 <style scoped lang="scss">
 .v-container {
-  padding: 0 !important;
+  padding: 0 0 48px 0 !important;
 }
 
 .controls-section {
@@ -130,33 +118,51 @@ const goNext = () => {
     margin-right: 1rem;
     margin-bottom: 2rem;
     border-radius: 0;
+
+    @media (max-width: 1240px) {
+      margin-top: 2rem;
+      margin-bottom: 1rem;
+    }
   }
 }
 
 .carousel {
+  @media (max-width: 1240px) {
+    left: -36px;
+  }
+
+  .v-container {
+    height: 100%;
+  }
+
   .v-card {
     display: flex;
     flex-direction: column;
     padding: 0 0.5rem;
     border-radius: 1rem;
-    min-height: 300px;
-    max-height: 300px;
     margin-top: 2rem;
     margin-bottom: 0.6rem;
+    height: 100%;
 
     @media (max-width: 1240px) {
-      min-height: 120px;
       max-width: 70%;
-      margin: 0 auto;
+      margin: 0 auto 48px auto;
+    }
+
+    @media (max-width: 600px) {
+      height: auto;
     }
   }
 
   .v-card-item {
-    flex: 1
+    flex: 1;
+
+    @media (max-width: 600px) {
+      flex: 0;
+    }
   }
 
   .v-card-text {
-    text-align: justify;
     min-height: 120px;
     overflow: auto;
     font-size: 1rem;
@@ -206,13 +212,6 @@ const goNext = () => {
     margin-bottom: 1rem;
   }
 
-  @media (min-width:2100px) {
-    .v-card-text {
-      min-height: 150px !important;
-      max-height: 150px !important;
-    }
-  }
-
   @media (max-width: 1240px) {
   }
 }
@@ -220,21 +219,14 @@ const goNext = () => {
 .card {
   margin-left: 0.5rem;
   border-radius: 1rem;
-
-  @media (max-width:1240px) {
-    margin-left: 15%;
-    max-width: 70%;
-  }
 }
 
-@media (min-width:2100px) {
-  .v-card {
-    min-height: 360px !important;
-    max-height: 360px !important;
-  }
+.v-card-item {
+  display: block;
+  padding-top: 16px;
 }
 
-@media (max-width:600px) {
+@media (max-width: 600px) {
   :deep(.v-carousel__controls) {
     color: var(--on-neutral-color);
     background-color: var(--neutral-color);

+ 47 - 47
components/Common/Share.vue

@@ -7,60 +7,60 @@
       target="_blank"
       :style="{ color: network.colorOnHover }"
     >
-      <v-icon :icon="network.icon"/>
+      <v-icon :icon="network.icon" />
     </nuxt-link>
   </div>
 </template>
 
 <script setup lang="ts">
-  import type { SocialNetworkShareBtn } from "~/types/interface";
+import type { Ref } from 'vue'
+import type { SocialNetworkShareBtn } from '~/types/interface'
 
-  const url: Ref<string | null> = ref(null)
-  const networks: Ref<Array<SocialNetworkShareBtn>> = ref([])
+const url: Ref<string | null> = ref(null)
+const networks: Ref<Array<SocialNetworkShareBtn>> = ref([])
 
-  if (process.client) {
-    url.value = window.location.href
-
-    networks.value = [
-      {
-        name: "Facebook",
-        icon: "fa-brands fa-facebook",
-        colorOnHover: "#135fc2",
-        url: `https://www.facebook.com/sharer/sharer.php?u=${encodeURIComponent(url.value)}`
-      },
-      {
-        name: "Twitter",
-        icon: "fa-brands fa-twitter",
-        colorOnHover: "#1781c2",
-        url: `https://twitter.com/intent/tweet?url=${encodeURIComponent(url.value)}`
-      },
-      {
-        name: "Messenger",
-        icon: "fa-brands fa-facebook-messenger",
-        colorOnHover: "#0085ff",
-        url: `https://messenger.com`
-      },
-      {
-        name: "Instagram",
-        icon: "fa-brands fa-instagram",
-        colorOnHover: "#d0006a",
-        url: "https://instagram.com"
-      },
-      {
-        name: "Linkedin",
-        icon: "fa-brands fa-linkedin",
-        colorOnHover: "#006291",
-        url: `https://www.linkedin.com/shareArticle?mini=true&url=${encodeURIComponent(url.value)}`
-      },
-      {
-        name: "Email",
-        icon: "fas fa-envelope",
-        colorOnHover: "#292929",
-        url: `mailto:?body=${url.value}`
-      },
-    ]
-  }
+if (process.client) {
+  url.value = window.location.href
 
+  networks.value = [
+    {
+      name: 'Facebook',
+      icon: 'fa-brands fa-facebook',
+      colorOnHover: '#135fc2',
+      url: `https://www.facebook.com/sharer/sharer.php?u=${encodeURIComponent(url.value)}`,
+    },
+    {
+      name: 'Twitter',
+      icon: 'fa-brands fa-twitter',
+      colorOnHover: '#1781c2',
+      url: `https://twitter.com/intent/tweet?url=${encodeURIComponent(url.value)}`,
+    },
+    {
+      name: 'Messenger',
+      icon: 'fa-brands fa-facebook-messenger',
+      colorOnHover: '#0085ff',
+      url: `https://messenger.com`,
+    },
+    {
+      name: 'Instagram',
+      icon: 'fa-brands fa-instagram',
+      colorOnHover: '#d0006a',
+      url: 'https://instagram.com',
+    },
+    {
+      name: 'Linkedin',
+      icon: 'fa-brands fa-linkedin',
+      colorOnHover: '#006291',
+      url: `https://www.linkedin.com/shareArticle?mini=true&url=${encodeURIComponent(url.value)}`,
+    },
+    {
+      name: 'Email',
+      icon: 'fas fa-envelope',
+      colorOnHover: '#292929',
+      url: `mailto:?body=${url.value}`,
+    },
+  ]
+}
 </script>
 
 <style scoped lang="scss">
@@ -74,7 +74,7 @@
   i {
     font-size: 32px;
     margin: 0.5rem 0.3rem;
-    color: var(--on-neutral-color-light);
+    color: var(--primary-color);
   }
 
   a:hover i {

+ 37 - 47
components/Common/Table/Comparatif.vue

@@ -4,7 +4,7 @@
       <table v-if="mdAndUp">
         <thead>
           <tr>
-            <th/>
+            <th />
 
             <th>
               <p class="standard">Standard</p>
@@ -27,10 +27,7 @@
         </thead>
 
         <tbody>
-          <tr
-            v-for="(item, index) in items"
-            :key="item.label"
-          >
+          <tr v-for="item in items" :key="item.label">
             <td class="label-column">
               {{ item.label }}
             </td>
@@ -109,10 +106,7 @@
 
             <table>
               <tbody>
-                <tr
-                  v-for="(item, index) in items"
-                  :key="item.label"
-                >
+                <tr v-for="item in items" :key="item.label">
                   <td class="label-column">
                     {{ item.label }}
                   </td>
@@ -153,33 +147,30 @@
 
             <table>
               <tbody>
-              <tr
-                v-for="(item, index) in items"
-                :key="item.label"
-              >
-                <td class="label-column">
-                  {{ item.label }}
-                </td>
-
-                <td>
-                  <v-icon
-                    v-if="item.includedInPremium === true"
-                    icon="far fa-check-circle"
-                    size="18"
-                  />
-
-                  <v-icon
-                    v-else-if="item.includedInPremium === false"
-                    icon="far fa-times-circle"
-                    size="18"
-                    color="red"
-                  />
-
-                  <span v-else>
-                  {{ item.includedInPremium }}
-                </span>
-                </td>
-              </tr>
+                <tr v-for="item in items" :key="item.label">
+                  <td class="label-column">
+                    {{ item.label }}
+                  </td>
+
+                  <td>
+                    <v-icon
+                      v-if="item.includedInPremium === true"
+                      icon="far fa-check-circle"
+                      size="18"
+                    />
+
+                    <v-icon
+                      v-else-if="item.includedInPremium === false"
+                      icon="far fa-times-circle"
+                      size="18"
+                      color="red"
+                    />
+
+                    <span v-else>
+                      {{ item.includedInPremium }}
+                    </span>
+                  </td>
+                </tr>
               </tbody>
             </table>
           </v-carousel-item>
@@ -190,25 +181,26 @@
 </template>
 
 <script setup lang="ts">
-import type { ComparisonItem } from "~/types/interface";
-import { useDisplay } from "vuetify";
+import { useDisplay } from 'vuetify'
+import type { PropType } from 'vue'
+import type { ComparisonItem } from '~/types/interface'
 
 const { mdAndUp } = useDisplay()
 
 const props = defineProps({
   standardPrice: {
     type: String,
-    required: true
+    required: true,
   },
   premiumPrice: {
     type: String,
-    required: true
+    required: true,
   },
   items: {
     type: Array as PropType<Array<ComparisonItem>>,
-    required: true
-  }
-});
+    required: true,
+  },
+})
 
 const height = computed(() => 150 + props.items.length * 48)
 
@@ -216,11 +208,11 @@ const carouselPos = ref(0)
 
 const goToPrevious = () => {
   carouselPos.value = 0
-};
+}
 
 const goToNext = () => {
   carouselPos.value = 1
-};
+}
 </script>
 
 <style scoped lang="scss">
@@ -349,6 +341,4 @@ td:first-child {
     padding-right: 10px;
   }
 }
-
-
 </style>

+ 36 - 46
components/Contact/AddressSection.vue

@@ -5,27 +5,18 @@
         <ContactMap class="contact-map" />
       </v-col>
       <v-col cols="6" class="address-col px-8">
-
-        <h4>
-          <v-icon icon="fas fa-envelope"/> Pour nous écrire
-        </h4>
+        <h4><v-icon icon="fas fa-envelope" /> Pour nous écrire</h4>
 
         <v-card>
-          <div>
-            2iOpenService
-          </div>
-          <div>
-            217, rue Raoul Follereau
-          </div>
-          <div>
-            74300 - Cluses
-          </div>
+          <div>2iOpenService</div>
+          <div>217, rue Raoul Follereau</div>
+          <div>74300 - Cluses</div>
         </v-card>
 
         <div class="mb-6" />
 
         <h4>
-          <v-icon icon="fas fa-phone"/>
+          <v-icon icon="fas fa-phone" />
           Ou par téléphone
         </h4>
 
@@ -39,9 +30,7 @@
           <span v-else>
             <v-card>
               Contactez nous au
-              <a href="tel:+33972126017">
-                09 72 12 60 17
-              </a>
+              <a href="tel:+33972126017"> 09 72 12 60 17 </a>
             </v-card>
           </span>
         </div>
@@ -51,42 +40,43 @@
 </template>
 
 <script setup lang="ts">
-  const revealPhoneNumber = ref(false)
+const revealPhoneNumber = ref(false)
 </script>
 
 <style scoped lang="scss">
-  .container {
-    width: 70%;
-  }
+.container {
+  width: 70%;
+}
 
-  h4 {
-    display: flex;
-    flex-direction: row;
-    color: var(--primary-color);
-    font-size: 20px;
-    font-weight: 500;
-    margin: 24px 0;
-  }
+h4 {
+  display: flex;
+  flex-direction: row;
+  color: var(--primary-color);
+  font-size: 20px;
+  font-weight: 500;
+  margin: 24px 0;
+}
 
-  .v-icon {
-    margin-right: 16px;
-  }
+.v-icon {
+  margin-right: 16px;
+}
 
-  .address-col > div, .address-col > .v-card > div {
-    padding: 8px 16px;
-  }
+.address-col > div,
+.address-col > .v-card > div {
+  padding: 8px 16px;
+}
 
-  .v-card {
-    margin: 16px 64px;
-    padding: 12px;
-  }
+.v-card {
+  margin: 16px 64px;
+  padding: 12px;
+}
 
-  .v-btn {
-    margin: 16px 64px;
-  }
+.v-btn {
+  margin: 16px 64px;
+}
 
-  a {
-    color: var(--on-neutral-color);
-    text-decoration: underline;
-  }
+a {
+  color: var(--on-neutral-color);
+  text-decoration: underline;
+}
 </style>

+ 0 - 24
components/Contact/Banner.vue

@@ -1,24 +0,0 @@
-<template>
-  <LayoutContainer>
-    <v-row>
-      <v-col cols="12" class="position-relative">
-        <v-img
-          src="/images/contact/Contactez_nous-visuel_Opentalent.jpg"
-          alt="Icône téléphone, enveloppe, arobase, bulles de discussion et homme sur son smartphone et son ordinateur portable"
-          cover
-          class="banner"
-        />
-      </v-col>
-    </v-row>
-  </LayoutContainer>
-</template>
-
-<style scoped lang="scss">
-.banner {
-  width: 100%;
-  height: 15rem;
-  object-position: center 30%;
-  margin: 0 auto;
-  transform: scaleX(-1);
-}
-</style>

+ 129 - 102
components/Contact/Form.vue

@@ -2,6 +2,8 @@
   <LayoutContainer>
     <div id="anchor" />
 
+    <h4><span class="line" /> Veuillez remplir le formulaire ci-dessous</h4>
+
     <v-form
       v-if="!contactRequestSent"
       ref="form"
@@ -9,25 +11,17 @@
       @submit.prevent="submit"
     >
       <v-container>
-        <h4>
-          <span class="line" /> Veuillez remplir le formulaire ci-dessous
-        </h4>
-
-        <i>Les champs dont le nom est suivi d'un astérisque (*) sont obligatoires</i>
+        <i
+          >Les champs dont le nom est suivi d'un astérisque (*) sont
+          obligatoires</i
+        >
 
-        <h6>
-          Vos coordonnées
-        </h6>
+        <h6>Vos coordonnées</h6>
 
         <!-- Gender selection -->
         <v-row>
           <v-col cols="12">
-            <v-radio-group
-              v-model="contactRequest.gender"
-              row
-              mandatory
-              inline
-            >
+            <v-radio-group v-model="contactRequest.gender" row mandatory inline>
               <v-radio label="Madame" value="Madame" />
               <v-radio label="Monsieur" value="Monsieur" />
             </v-radio-group>
@@ -68,7 +62,8 @@
           <v-col cols="12" md="6">
             <v-text-field
               v-model="contactRequest.city"
-              label="Ville"
+              label="Ville*"
+              :rules="[validateCity]"
             />
           </v-col>
         </v-row>
@@ -107,9 +102,7 @@
           </v-col>
         </v-row>
 
-        <h6>
-          Votre demande concerne *
-        </h6>
+        <h6>Votre demande concerne *</h6>
 
         <!-- Request type and product concerned  -->
         <v-row>
@@ -135,9 +128,7 @@
           </v-col>
         </v-row>
 
-        <h6>
-          Votre message
-        </h6>
+        <h6>Votre message</h6>
 
         <!-- Message  -->
         <v-row class="mb-8">
@@ -149,15 +140,20 @@
               required
               maxlength="400"
             />
-            <span class="remaining-cars-notice">{{ leftCars }} caractères restants</span>
+            <span class="remaining-cars-notice"
+              >{{ leftCars }} caractères restants</span
+            >
           </v-col>
         </v-row>
 
         <!-- Policy and  checkboxes -->
         <v-checkbox
           v-model="contactRequest.privacyPolicyAccepted"
-          :rules="[(v: boolean) => v || 'Vous devez accepter la politique de confidentialité']"
-          label="J'ai pris connaissance de la politique de confidentialité et j'accepte le traitement de mes données personnelles par Opentalent."
+          :rules="[
+            (v: boolean) =>
+              v || 'Vous devez accepter la politique de confidentialité',
+          ]"
+          label="J'ai pris connaissance de la politique de confidentialité et j'accepte le traitement de mes données personnelles par Opentalent. *"
         />
 
         <v-checkbox
@@ -167,7 +163,7 @@
 
         <div class="d-flex flex-row justify-center">
           <!-- @see https://github.com/hCaptcha/vue-hcaptcha -->
-          <LayoutCaptcha/>
+          <LayoutCaptcha />
         </div>
 
         <!-- Submit Button -->
@@ -182,91 +178,113 @@
             Envoyer
           </v-btn>
         </div>
+
+        <div v-if="errorMsg" class="error">
+          {{ errorMsg }}
+        </div>
       </v-container>
 
       <div class="legal">
-        Les données recueillies par Opentalent sont utilisées pour le traitement de votre demande et pour vous informer sur nos offres.
-        Elles sont destinées aux services Opentalent et à ses sous-traitants pour l’exécution des contrats. Conformément à la loi
-        "Informatique et Libertés du 6 Janvier 1978", vous disposez d’un droit d’accès, de modifications, de rectification et de suppression
-        des données vous concernant. Pour toute demande, adressez-vous à : Opentalent, 217 rue Raoul Follereau, 74300 CLUSES,
-        opentalent.fr s’engage à la confidentialité et à la protection de vos données.
+        Les données recueillies par Opentalent sont utilisées pour le traitement
+        de votre demande et pour vous informer sur nos offres. Elles sont
+        destinées aux services Opentalent et à ses sous-traitants pour
+        l’exécution des contrats. Conformément à la loi "Informatique et
+        Libertés du 6 Janvier 1978", vous disposez d’un droit d’accès, de
+        modifications, de rectification et de suppression des données vous
+        concernant. Pour toute demande, adressez-vous à : Opentalent, 217 rue
+        Raoul Follereau, 74300 CLUSES, opentalent.fr s’engage à la
+        confidentialité et à la protection de vos données.
       </div>
     </v-form>
 
     <div v-else class="confirmation-message d-flex flex-row justify-center">
       <v-card>
-        <v-icon icon="fas fa-check mr-1"/>
-        Votre demande de contact a bien été enregistrée, nous reviendrons vers vous dès que possible.
+        <v-icon icon="fas fa-check mr-1" />
+        Votre demande de contact a bien été enregistrée, nous reviendrons vers
+        vous dès que possible.
       </v-card>
     </div>
   </LayoutContainer>
 </template>
 
 <script setup lang="ts">
-import ContactRequest from "~/models/Maestro/ContactRequest";
-import { useEntityManager } from "~/composables/data/useEntityManager";
-import { useRouter } from "vue-router";
+import { useRouter } from 'vue-router'
+import type { ComputedRef, Ref } from 'vue'
+import { reactive } from 'vue'
+import ContactRequest from '~/models/Maestro/ContactRequest'
+import { useEntityManager } from '~/composables/data/useEntityManager'
 
-const route = useRoute();
+const route = useRoute()
 const router = useRouter()
 const { em } = useEntityManager()
 
-const form: Ref<any | null> = ref(null)
+const form: Ref<HTMLElement | null> = ref(null)
 
-const requestTypes: Array<{id: string, label: string}> = [
-  { id: "CONTACT_REQUEST_INFORMATION", label: "Demande d'information"},
-  { id: "CONTACT_REQUEST_ESTIMATE", label: "Demande de devis"},
-  { id: "CONTACT_REQUEST_DEMO", label: "Demande de démonstration"},
-  { id: "CONTACT_REQUEST_OPTION", label: "Demande d'option supplémentaire"},
-  { id: "CONTACT_REQUEST_OTHER", label: "Autre"}
+const requestTypes: Array<{ id: string; label: string }> = [
+  { id: 'CONTACT_REQUEST_INFORMATION', label: "Demande d'information" },
+  { id: 'CONTACT_REQUEST_ESTIMATE', label: 'Demande de devis' },
+  { id: 'CONTACT_REQUEST_DEMO', label: 'Demande de démonstration' },
+  { id: 'CONTACT_REQUEST_OPTION', label: "Demande d'option supplémentaire" },
+  { id: 'CONTACT_REQUEST_OTHER', label: 'Autre' },
 ]
 
-const products: Array<{id: string, label: string}> = [
-  { id: "PRODUCT_AGENDA", label: "Agenda culturel"},
-  { id: "PRODUCT_ARTIST", label: "Opentalent Artist"},
-  { id: "PRODUCT_SCHOOL", label: "Opentalent School"},
-  { id: "PRODUCT_MANAGER", label: "Opentalent Manager"},
-  { id: "PRODUCT_ADVERTISING", label: "Publicité"},
-  { id: "PRODUCT_OTHER", label: "Autre"}
+const products: Array<{ id: string; label: string }> = [
+  { id: 'PRODUCT_AGENDA', label: 'Agenda culturel' },
+  { id: 'PRODUCT_ARTIST', label: 'Opentalent Artist' },
+  { id: 'PRODUCT_SCHOOL', label: 'Opentalent School' },
+  { id: 'PRODUCT_MANAGER', label: 'Opentalent Manager' },
+  { id: 'PRODUCT_ADVERTISING', label: 'Publicité' },
+  { id: 'PRODUCT_OTHER', label: 'Autre' },
 ]
 
 const defaultRequestType = route.query.request ?? 'CONTACT_REQUEST_INFORMATION'
 
-//@ts-ignore
-const contactRequest: ContactRequest = reactive(em.newInstance(ContactRequest, { requestType: defaultRequestType }))
+// @ts-ignore
+const contactRequest: ContactRequest = reactive(
+  em.newInstance(ContactRequest, { requestType: defaultRequestType })
+)
 
 // --- Validation ---
 const maxMessageLength = 2000
 
-const leftCars: ComputedRef<number> = computed(() =>
-  maxMessageLength - (contactRequest.message ? contactRequest.message.length : 0)
+const leftCars: ComputedRef<number> = computed(
+  () =>
+    maxMessageLength -
+    (contactRequest.message ? contactRequest.message.length : 0)
 )
 
-const validateName = (name: string | null) => !!name || "Le nom est obligatoire";
+const validateName = (name: string | null) => !!name || 'Le nom est obligatoire'
 
-const validateSurname = (surname: string | null) => !!surname || "Le prénom est obligatoire";
+const validateSurname = (surname: string | null) =>
+  !!surname || 'Le prénom est obligatoire'
 
 const validatePostalCode = (postalCode: string | null) =>
-  (!!postalCode && /^\d{5}$/.test(postalCode)) || "Le code postal doit être valide";
+  (!!postalCode && /^\d{5}$/.test(postalCode)) ||
+  'Le code postal doit être valide'
+
+const validateCity = (city: string | null) =>
+  !!city || 'La ville est obligatoire'
 
 const validateEmail = (email: string | null) =>
-  (!!email && /.+@.+\..+/.test(email)) || "L'adresse e-mail doit être valide";
+  (!!email && /.+@.+\..+/.test(email)) || "L'adresse e-mail doit être valide"
 
-const validatePhone = (email: string | null) =>
-  (!!email && /^((\+|00)33\s?|0)[1-7]([\s.]?\d{2}){4}$/.test(email)) || "Le numéro de téléphone doit être valide";
+const validatePhone = (phone: string | null) =>
+  (!!phone && /^((\+|00)33\s?|0)[1-9]([\s.]?\d{2}){4}$/.test(phone)) ||
+  'Le numéro de téléphone doit être valide'
 
 const validateStructureName = (structureName: string | null) =>
-  !!structureName || "Le nom de la structure est requis";
+  !!structureName || 'Le nom de la structure est requis'
 
 const validateNonEmptyMessage = (message: string | null) =>
-  (!!message && message.length > 0) ||
-  "Le message ne peut pas être vide";
+  (!!message && message.length > 0) || 'Le message ne peut pas être vide'
 
 const validateMessageLength = (message: string | null) =>
   (!!message && message.length <= maxMessageLength) ||
-  "Le message ne doit pas dépasser " + maxMessageLength + " caractères";
+  'Le message ne doit pas dépasser ' + maxMessageLength + ' caractères'
+
+const contactRequestSent: Ref<boolean> = ref(false)
 
-const contactRequestSent: Ref<boolean> = ref(false);
+const errorMsg: Ref<string | null> = ref(null)
 
 /**
  * Submits the contact form.
@@ -285,48 +303,51 @@ const submit = async (): Promise<void> => {
     return
   }
 
-  await em.persist(ContactRequest, contactRequest)
+  try {
+    await em.persist(ContactRequest, contactRequest)
+  } catch (e) {
+    errorMsg.value =
+      "Une erreur s'est produite, nous sommes navrés pour le désagrément. Veuillez réessayer plus tard."
+    return
+  }
 
-  contactRequestSent.value = true;
+  contactRequestSent.value = true
+  errorMsg.value = null
 
   // Défile vers le début de page pour afficher le message de confirmation
-  setTimeout(
-    () => router.push({ path: '', hash: '#anchor' }),
-    30
-  )
-};
+  setTimeout(() => router.push({ path: '', hash: '#anchor' }), 30)
+}
 </script>
 
 <style scoped lang="scss">
+h4 {
+  display: flex;
+  flex-direction: row;
+  font-size: 40px;
+  line-height: 95px;
+  margin-bottom: 1rem;
+  align-items: center;
+  font-weight: 100;
+
+  @media (max-width: 600px) {
+    font-size: 24px;
+    line-height: 48px;
+  }
+
+  .line {
+    display: block;
+    height: 1px;
+    width: 64px;
+    min-width: 64px;
+    border-top: solid 1px var(--on-neutral-color);
+    margin-right: 18px;
+  }
+}
 
 .v-form {
   max-width: 1400px;
   margin: 0 auto;
 
-  h4 {
-    display: flex;
-    flex-direction: row;
-    font-size: 40px;
-    line-height: 95px;
-    margin-bottom: 1rem;
-    align-items: center;
-    font-weight: 100;
-
-    @media (max-width: 600px) {
-      font-size: 24px;
-      line-height: 48px;
-    }
-
-    .line {
-      display: block;
-      height: 1px;
-      width: 64px;
-      min-width: 64px;
-      border-top: solid 1px var(--on-neutral-color);
-      margin-right: 18px;
-    }
-  }
-
   h6 {
     margin-top: 32px;
     font-size: 16px;
@@ -353,14 +374,20 @@ const submit = async (): Promise<void> => {
     font-weight: 600;
   }
 
+  .error {
+    color: red;
+    width: 80%;
+    margin: 0 auto 2em;
+    text-align: center;
+  }
+
   .legal {
     opacity: 0.7;
-
-    @media (max-width: 600px) {
-      max-width: 80%;
-      margin-left: auto;
-      margin-right: auto;
-    }
+    font-size: 14px;
+    font-style: italic;
+    margin-left: auto;
+    margin-right: auto;
+    max-width: 80%;
   }
 }
 

+ 35 - 41
components/Contact/Map.vue

@@ -1,8 +1,6 @@
 <template>
-<LayoutContainer>
-    <h4>
-      <span class="line" /> Contactez-nous
-    </h4>
+  <LayoutContainer>
+    <h4><span class="line" /> Contactez-nous</h4>
 
     <v-row>
       <v-col cols="12" md="6">
@@ -11,7 +9,7 @@
             ref="map"
             :zoom="15"
             :center="location"
-            :options="{scrollWheelZoom: false}"
+            :options="{ scrollWheelZoom: false }"
           >
             <l-tile-layer
               url="https://{s}.basemaps.cartocdn.com/light_all/{z}/{x}/{y}{r}.png"
@@ -20,53 +18,48 @@
               attribution='&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors &copy; <a href="https://carto.com/attributions">CARTO</a>'
             />
 
-            <l-marker
-              :icon="icon"
-              :lat-lng="location"
-            />
-<!--              <l-popup>-->
-<!--                <v-row>-->
-<!--                  <v-col cols="4" class="d-flex align-center">-->
-<!--                    <v-img src="/images/Opentalent_Griffe.png"/>-->
-<!--                  </v-col>-->
-<!--                  <v-col cols="8">-->
-<!--                    <div>-->
-<!--                      OPENTALENT-->
-<!--                    </div>-->
-<!--                    <div>-->
-<!--                      217, rue Raoul Follereau-->
-<!--                    </div>-->
-<!--                    <div>-->
-<!--                      74300 - Cluses-->
-<!--                    </div>-->
-<!--                  </v-col>-->
-<!--                </v-row>-->
-<!--              </l-popup>-->
+            <l-marker :icon="icon" :lat-lng="location" />
+            <!--              <l-popup>-->
+            <!--                <v-row>-->
+            <!--                  <v-col cols="4" class="d-flex align-center">-->
+            <!--                    <v-img src="/images/Opentalent_Griffe.png"/>-->
+            <!--                  </v-col>-->
+            <!--                  <v-col cols="8">-->
+            <!--                    <div>-->
+            <!--                      OPENTALENT-->
+            <!--                    </div>-->
+            <!--                    <div>-->
+            <!--                      217, rue Raoul Follereau-->
+            <!--                    </div>-->
+            <!--                    <div>-->
+            <!--                      74300 - Cluses-->
+            <!--                    </div>-->
+            <!--                  </v-col>-->
+            <!--                </v-row>-->
+            <!--              </l-popup>-->
           </l-map>
         </div>
       </v-col>
 
       <v-col cols="12" md="6" class="infos">
-        <div class="name mb-8">
-          Opentalent
-        </div>
+        <div class="name mb-8">Opentalent</div>
 
         <div class="d-flex flex-row align-center mb-8">
           <v-icon icon="fa fa-map-marker-alt" />
           <span>
-            217 rue Raoul Follereau<br/>
+            217 rue Raoul Follereau<br />
             74300 CLUSES
           </span>
         </div>
 
         <div class="d-flex flex-row mb-4">
           <v-icon icon="fa fa-phone" />
-          09.72.12.60.17
+          <a href="tel:+33972126017">09.72.12.60.17</a>
         </div>
 
         <div class="d-flex flex-row mb-4">
           <v-icon icon="far fa-envelope" />
-          contact@opentalent.fr
+          <a href="mailto:contact@opentalent.fr">contact@opentalent.fr</a>
         </div>
       </v-col>
     </v-row>
@@ -75,31 +68,29 @@
 
 <script setup lang="ts">
 import 'leaflet/dist/leaflet.css'
-import { LMap, LTileLayer, LMarker, LIcon } from '@vue-leaflet/vue-leaflet'
-import L from 'leaflet';
+import { LMap, LTileLayer, LMarker } from '@vue-leaflet/vue-leaflet'
+import L from 'leaflet'
 
 const location = [46.075245, 6.570162]
 
+// eslint-disable-next-line import/no-named-as-default-member
 const icon = L.icon({
-  iconUrl: '/images/contact/Pointeur_Opentalent.png',
+  iconUrl: '/images/pages/contact/map/Pointeur_Opentalent.png',
   iconSize: [80, 80],
   iconAnchor: [22, 94],
   popupAnchor: [5, -100],
 })
-
 </script>
 
 <style scoped lang="scss">
-
 h4 {
   display: flex;
   flex-direction: row;
   font-size: 40px;
   line-height: 95px;
+  margin-bottom: 1rem;
   align-items: center;
   font-weight: 100;
-  margin: 0 auto 1rem auto;
-  max-width: 1400px;
 
   @media (max-width: 600px) {
     font-size: 24px;
@@ -116,7 +107,6 @@ h4 {
   }
 }
 
-
 .map-container {
   height: 500px;
   width: 100%;
@@ -139,5 +129,9 @@ h4 {
     margin-right: 16px;
     opacity: 0.6;
   }
+
+  @media (max-width: 600px) {
+    order: -1
+  }
 }
 </style>

+ 76 - 95
components/Formation/Catalogue.vue

@@ -6,17 +6,11 @@
           Découvrez notre catalogue de formation
         </LayoutUISubTitle>
 
-        <LayoutUITitle class="ml-8">
-          Catalogue
-        </LayoutUITitle>
+        <LayoutUITitle class="ml-8"> Catalogue </LayoutUITitle>
       </v-row>
 
       <v-row class="center-90 catalog">
-        <v-col
-          v-for="(course, index) in courses"
-          :key="index"
-          cols="4"
-        >
+        <v-col v-for="(course, index) in courses" :key="index" cols="12" lg="4">
           <v-card class="mb-4">
             <v-card-text>
               <div class="title-card-container">
@@ -34,9 +28,7 @@
               </p>
 
               <div class="objectives">
-                <h6 class="title-obj">
-                  Objectifs pédagogiques
-                </h6>
+                <h6 class="title-obj">Objectifs pédagogiques</h6>
 
                 <ul>
                   <li
@@ -48,10 +40,10 @@
                 </ul>
               </div>
 
+              <div class="badge-time">Durée : {{ course.duration }}</div>
+
               <div class="program">
-                <h6 class="title-obj">
-                  Programme
-                </h6>
+                <h6 class="title-obj">Programme</h6>
 
                 <v-row>
                   <v-col
@@ -71,17 +63,9 @@
                 </v-row>
               </div>
 
-              <v-chip class="badge-time">
-                <span>
-                  Durée : {{ course.duration }}
-                </span>
-              </v-chip>
-
-              <v-chip class="badge-time">
-                <span>
-                  {{ course.price }}
-                </span>
-              </v-chip>
+              <div class="badge-time">
+                {{ course.price }}
+              </div>
 
               <v-chip
                 class="chip-register"
@@ -98,117 +82,114 @@
 </template>
 
 <script setup lang="ts">
-import { useDisplay } from "vuetify";
-import AnchoredSection from "~/components/Layout/AnchoredSection.vue";
-import type { Training } from "~/types/interface";
-
-const { mdAndDown } = useDisplay();
+import AnchoredSection from '~/components/Layout/AnchoredSection.vue'
+import type { Training } from '~/types/interface'
 
 const downloadPdf = (pdfUrl: string) => {
-  window.open(pdfUrl, "_blank");
-};
+  window.open(pdfUrl, '_blank')
+}
 
 const courses: Array<Training> = [
   {
-    number: "01",
-    title: "Formation initiale ",
+    number: '01',
+    title: 'Formation initiale',
     description:
       "Cette formation est destinée aux nouveaux utilisateurs. Elle est obligatoire lors de l'acquisition du logiciel. Elle est également utile lors d'un changement de personnel dans la structure. ",
     objectives: [
-      "Ajuster la configuration du logiciel",
-      "Gérer les élèves et leurs familles",
-      "Générer des factures et faire le suivi des règlements",
-      "Gérer le planning des cours",
-      "Évaluer les élèves et générer des bulletins",
-      "Communiquer avec les personnes du répertoire",
+      'Ajuster la configuration du logiciel',
+      'Gérer les élèves et leurs familles',
+      'Générer des factures et faire le suivi des règlements',
+      'Gérer le planning des cours',
+      'Évaluer les élèves et générer des bulletins',
+      'Communiquer avec les personnes du répertoire',
     ],
-    duration: "14h",
+    duration: '14h',
     program: [
       {
         id: 1,
         objectives: [
-          "Accès et interface",
-          "Configuration",
-          "Répertoire",
-          "Agenda",
+          'Accès et interface',
+          'Configuration',
+          'Répertoire',
+          'Agenda',
         ],
       },
       {
         id: 2,
         objectives: [
-          "Parc matériel",
-          "Suivi pédagogique",
-          "Facturation",
-          "Communication",
+          'Parc matériel',
+          'Suivi pédagogique',
+          'Facturation',
+          'Communication',
         ],
       },
     ],
-    price: "1 580 € TTC",
+    price: '2 008,80€ TTC',
     downloadLink:
-      "https://www.opentalent.fr/fileadmin/stockage/stockage/support/programme/PF-School-2023-02_2-jours.pdf",
+      'public/files/PF-School-2024-02_2-jours.pdf',
   },
   {
-    number: "02",
-    title: "Formation complémentaire",
+    number: '02',
+    title: 'Formation complémentaire',
     // imageUrl: "/images/opentalent_school_black.jpg",
     description:
-      "Cette formation suppose d’avoir les connaissances de base sur le logiciel. Elle permet d’avoir une remise à niveau sur sur des fonctionnalités qui ont été incorrectement comprises / configurées, ou qui ont été récemment développées.",
+      'Cette formation suppose d’avoir les connaissances de base sur le logiciel. Elle permet d’avoir une remise à niveau sur sur des fonctionnalités qui ont été incorrectement comprises / configurées, ou qui ont été récemment développées.',
     objectives: [
-      "Ajuster la configuration du logiciel",
-      "Gérer les élèves et leurs familles",
+      'Ajuster la configuration du logiciel',
+      'Gérer les élèves et leurs familles',
     ],
-    duration: "7h",
+    duration: '7h',
     program: [
       {
         id: 1,
-        objectives: ["Accès et interface", "Configuration"],
+        objectives: ['Accès et interface', 'Configuration'],
       },
       {
         id: 2,
-        objectives: ["Répertoire"],
+        objectives: ['Répertoire'],
       },
     ],
-    price: "790€ TTC",
+    price: '1004,40€ TTC',
     downloadLink:
-      "https://www.opentalent.fr/fileadmin/stockage/stockage/support/programme/PF-School-2023-02_1-jour.pdf",
+      'public/files/PF-School-2024-02_1-jour.pdf',
   },
   {
-    number: "03",
-    title: "Formation Typo 3",
+    number: '03',
+    title: 'Formation Typo 3',
     // imageUrl: "/images/opentalent_school_black.jpg",
     description:
       "Cette formation est destinée aux nouveaux utilisateurs Typo3. Elle est optionnelle et permet d'aller plus loin dans la gestion du site internet intégré.",
     objectives: [
-      "Gérer les pages et leur accès",
-      "Gérer le contenu des pages et leur accès",
-      "Configurer les options du site internet côté logiciel",
+      'Gérer les pages et leur accès',
+      'Gérer le contenu des pages et leur accès',
+      'Configurer les options du site internet côté logiciel',
     ],
-    duration: "7h",
+    duration: '7h',
     program: [
       {
         id: 1,
-        objectives: ["Gestion des pages", "Gestion des blocs"],
+        objectives: ['Gestion des pages', 'Gestion des blocs'],
       },
       {
         id: 2,
-        objectives: ["Configuration côté logiciel"],
+        objectives: ['Configuration côté logiciel'],
       },
     ],
-    price: "790€ TTC",
+    price: '1004,40€ TTC',
     downloadLink:
-      " https://www.opentalent.fr/fileadmin/stockage/stockage/support/programme/PF-Typo3-2023-02_1-jour.pdf",
+      'public/files/PF-Typo3-2024-02_1-jour.pdf',
   },
-];
+]
 </script>
 
-<style scoped>
-
-* {
-  text-align: justify;
-}
-
+<style scoped lang="scss">
 .catalog {
   padding: 2rem;
+  background: var(--neutral-color-alt-light);
+
+  @media (max-width: 600px) {
+    padding: 0.5rem;
+  }
 
   .v-card {
     border: none !important;
@@ -241,14 +222,15 @@ const courses: Array<Training> = [
     line-height: 1rem;
     color: var(--primary-color);
     margin-top: 1rem;
-    margin-bottom: .5rem;
+    margin-bottom: 0.5rem;
     height: 5rem;
   }
 
-  .objectives, .program {
+  .objectives,
+  .program {
     justify-content: space-between;
     align-items: center;
-    background: var(--secondary-color);
+    background: var(--secondary-color-light);
     margin-top: 1rem;
     margin-bottom: 1rem;
     border-radius: 1rem;
@@ -268,24 +250,23 @@ const courses: Array<Training> = [
       font-size: 14px;
       line-height: 18px;
     }
+
+    @media (max-width: 600px) {
+      height: auto;
+    }
   }
 
   .badge-time {
-    color: var(--on-primary-color);
-    border: 1px solid var(--primary-color);
-    border-radius: 3rem;
+    color: var(--primary-color);
+    background: var(--neutral-color);
+    width: 100%;
+    height: 36px;
+    text-align: center;
+    font-size: 18px;
     font-weight: 500;
-    font-size: 14px;
-    line-height: 18px;
-    margin-top: 1rem;
-    margin-bottom: 1rem;
-    display: flex;
-    justify-content: center;
-    align-items: center;
-
-    span {
-      color: var(--primary-color);
-    }
+    border-radius: 12px;
+    vertical-align: center;
+    padding-top: 6px;
   }
 
   .chip-register {

+ 19 - 7
components/Formation/Certification.vue

@@ -3,15 +3,13 @@
     <LayoutContainer>
       <v-row class="center-90">
         <v-col cols="12" md="5">
-          <LayoutUISubTitle>
-            DES FORMATIONS CERTIFIÉES
-          </LayoutUISubTitle>
+          <LayoutUISubTitle> DES FORMATIONS CERTIFIÉES </LayoutUISubTitle>
 
           <LayoutUITitle>
             Certification Qualiopi : Marque de certification
           </LayoutUITitle>
 
-          <div class="bloc-certif ml-12 mt-6 mr-12">
+          <div class="bloc-certif">
             <p>
               Nos formations sont certifiées Qualiopi - Actions de formation.
             </p>
@@ -34,9 +32,9 @@
           </div>
         </v-col>
 
-        <v-col cols="12" md="7">
+        <v-col cols="12" md="7" class="image-container">
           <v-img
-            src="/images/formation/qualiopi.jpg"
+            src="/images/logos/qualiopi/Logo-Qualiopi_Processus_Certifié-Republique_Française.png"
             alt="Deux personnes en train d’échanger sur un projet devant deux ordinateurs dans un open space"
           />
         </v-col>
@@ -46,12 +44,13 @@
 </template>
 
 <script setup lang="ts">
-import AnchoredSection from "~/components/Layout/AnchoredSection.vue";
+import AnchoredSection from '~/components/Layout/AnchoredSection.vue'
 </script>
 
 <style scoped lang="scss">
 .bloc-certif {
   text-align: justify;
+  margin: 18px;
 }
 
 ul {
@@ -60,6 +59,7 @@ ul {
   line-height: 20px;
   color: var(--primary-color);
   margin-top: 1rem;
+  margin-left: 22px;
 }
 
 .details-certifications {
@@ -69,4 +69,16 @@ ul {
   color: var(--primary-color);
   margin-top: 1rem;
 }
+
+.image-container {
+  display: flex;
+  flex-direction: column;
+  justify-content: center;
+
+  .v-img {
+    width: 80%;
+    max-width: 500px;
+    margin: auto;
+  }
+}
 </style>

+ 13 - 9
components/Formation/OPCA.vue

@@ -2,17 +2,15 @@
   <AnchoredSection id="financing">
     <LayoutContainer class="alt-theme py-6 my-6">
       <v-row class="center-90">
-        <LayoutUISubTitle>
-          Financement des formations
-        </LayoutUISubTitle>
+        <LayoutUISubTitle> Financement des formations </LayoutUISubTitle>
       </v-row>
 
       <v-container>
         <v-row class="align-center center-90">
           <v-col cols="12" md="6">
             <v-img
-              src="/images/formation/programme.jpg"
-              alt="Logo Qualiopi processus certifié"
+              src="/images/pages/formations/opca/Formations_eligibles_aux_OPCA.jpg"
+              alt="Hommes discutant devant des ordinateurs"
               class="opca-img"
               cover
             />
@@ -53,14 +51,14 @@
 </template>
 
 <script setup lang="ts">
-import AnchoredSection from "~/components/Layout/AnchoredSection.vue";
+import AnchoredSection from '~/components/Layout/AnchoredSection.vue'
 </script>
 
 <style scoped lang="scss">
 .opca-img {
-  height: 400px;
-  width: 450px;
+  width: 80%;
   border-radius: 10%;
+  margin: 16px 20% 16px 0;
 }
 
 h3 {
@@ -77,6 +75,12 @@ h3 {
   color: var(--on-primary-color);
   width: 100%;
   margin: auto;
-  text-align: justify;
+}
+
+@media (max-width: 1240px) {
+  .v-img {
+    margin-left: auto;
+    margin-right: auto;
+  }
 }
 </style>

+ 19 - 25
components/Formation/Participation.vue

@@ -3,28 +3,25 @@
     <LayoutContainer class="alt-theme">
       <v-row class="center-90">
         <v-col cols="12">
-          <LayoutUISubTitle>
-            Accessibilité
-          </LayoutUISubTitle>
+          <LayoutUISubTitle> Accessibilité </LayoutUISubTitle>
         </v-col>
       </v-row>
 
-      <h3 class="title-participation text-center mb-8">
-        Vous souhaitez participer à une formation ?
-      </h3>
-
       <v-row class="mb-12 center-90">
-        <v-col cols="12">
+        <v-col cols="12" lg="6">
           <v-img
-            src="/images/formation/participation.jpg"
+            src="/images/pages/formations/accessibilite/Formations_accessibles_a_tous.jpg"
             alt="Ordinateur avec un écran en visioconférence avec plusieurs personnes posé sur une table avec un pichet posé à côté"
             class="participation-img"
+            cover
           />
         </v-col>
-      </v-row>
 
-      <v-row class="mb-12 center-90">
-        <v-col cols="12">
+        <v-col cols="12" lg="4">
+          <h3 class="title-participation text-center mb-8">
+            Vous souhaitez participer à une formation ?
+          </h3>
+
           <div class="details-participations">
             <p class="mb-6">
               Nous vous répondons sous 48h (hors week-ends). Délais d'accès:
@@ -57,7 +54,7 @@
 </template>
 
 <script setup lang="ts">
-import AnchoredSection from "~/components/Layout/AnchoredSection.vue";
+import AnchoredSection from '~/components/Layout/AnchoredSection.vue'
 </script>
 
 <style scoped lang="scss">
@@ -72,12 +69,6 @@ import AnchoredSection from "~/components/Layout/AnchoredSection.vue";
   margin-right: auto;
 }
 
-@media (min-width: 1200px) {
-  .v-row {
-    min-width: 100%;
-  }
-}
-
 .icon-title {
   font-size: 1rem;
   margin-right: 1rem;
@@ -100,7 +91,6 @@ h3 {
 .details-participations {
   display: flex;
   flex-direction: column;
-  text-align: justify;
   font-weight: 300;
   font-size: 16px;
   line-height: 20px;
@@ -112,16 +102,20 @@ h3 {
 
 .participation-img {
   position: relative;
-  background-image: url("/images/formation/participation.jpg");
-  width: 700px;
-  height: 550px;
   background-position: center;
   background-size: cover;
   border-radius: 10%;
   display: flex;
   justify-content: center;
   align-items: center;
-  margin-left: auto;
-  margin-right: auto;
+  width: 80%;
+  margin: 16px 20% 16px 0;
+}
+
+@media (max-width: 1240px) {
+  .v-img {
+    margin-left: auto;
+    margin-right: auto;
+  }
 }
 </style>

+ 13 - 10
components/Formation/Presentation.vue

@@ -2,17 +2,16 @@
   <AnchoredSection id="presentation">
     <LayoutContainer>
       <v-row class="mt-6 center-90">
-        <LayoutUISubTitle>
-          Présentation de nos formations
-        </LayoutUISubTitle>
+        <LayoutUISubTitle> Présentation de nos formations </LayoutUISubTitle>
       </v-row>
 
       <v-row class="mb-12 center-90">
         <v-col md="6">
           <v-img
-            src="/images/formation/programme2.jpg"
+            src="/images/pages/formations/presentation/Un_programme_de_formation_complet_sur_nos_logiciels_Opentalent.jpg"
             alt="Mains tapant sur un clavier d’ordinateur portable"
-            class="programme-img1"/>
+            class="programme-img1"
+          />
         </v-col>
 
         <v-col md="6">
@@ -55,7 +54,7 @@
 
         <v-col md="6">
           <v-img
-            src="/images/formation/programme.jpg"
+            src="/images/pages/formations/presentation/Des_formations_sur-mesure.jpg"
             alt="Deux personnes en train d’échanger sur un projet devant deux ordinateurs dans un open space"
             class="programme-img2"
           />
@@ -66,12 +65,12 @@
 </template>
 
 <script setup lang="ts">
-import AnchoredSection from "~/components/Layout/AnchoredSection.vue";
+import AnchoredSection from '~/components/Layout/AnchoredSection.vue'
 </script>
 
 <style scoped lang="scss">
 .v-img {
-  width: 80%;
+  width: 560px;
   height: 100%;
   border-radius: 10%;
 
@@ -81,9 +80,14 @@ import AnchoredSection from "~/components/Layout/AnchoredSection.vue";
   }
 }
 
-h3, p {
+h3,
+p {
   width: 35rem;
   max-width: 100%;
+
+  @media (max-width: 1240px) {
+    width: 100%;
+  }
 }
 
 h3 {
@@ -96,7 +100,6 @@ p {
   font-weight: 300;
   font-size: 1.2rem;
   line-height: 20px;
-  text-align: justify;
 }
 
 .school {

+ 16 - 16
components/Formation/Reviews.vue

@@ -7,37 +7,37 @@
 </template>
 
 <script setup lang="ts">
-import AnchoredSection from "~/components/Layout/AnchoredSection.vue";
-import type { Review } from "~/types/interface";
+import AnchoredSection from '~/components/Layout/AnchoredSection.vue'
+import type { Review } from '~/types/interface'
 
 const cards: Array<Review> = [
   {
     review:
-      "Formation très personnalisée et très productive. Tout à fait adaptée à nos besoins actuels.",
-    name: "Jocelyne DELAPORTE ",
-    status: "Responsable administrative",
-    structure: "École de Musique Municipale De Pecquencourt (59)",
+      'Formation très personnalisée et très productive. Tout à fait adaptée à nos besoins actuels.',
+    name: 'Jocelyne DELAPORTE ',
+    status: 'Responsable administrative',
+    structure: 'École de Musique Municipale De Pecquencourt (59)',
   },
   {
     review:
       "Merci à Johan d'avoir pris le temps de nous former, de rentrer dans les détails des questions abordées. Et merci à l'équipe pour votre réactivité lorsque l'on demande à être aidés",
-    name: "Claire CAGNON ",
-    status: "Secrétaire administrative",
-    structure: "École de Musique, Théâtre et Cirque Alsace Rhin Brisach (68)",
+    name: 'Claire CAGNON ',
+    status: 'Secrétaire administrative',
+    structure: 'École de Musique, Théâtre et Cirque Alsace Rhin Brisach (68)',
   },
   {
     review:
-      " Une journée de formation précieuse pour un point complet de la prise en main du logiciel et des réponses utiles aux questions et problématiques rencontrées.",
-    name: "Sayuri OKA NICOLEAU",
-    status: "Directrice administrative & pédagogique",
-    structure: "École Municipale de Musique de Croissy-sur-Seine (78)",
+      ' Une journée de formation précieuse pour un point complet de la prise en main du logiciel et des réponses utiles aux questions et problématiques rencontrées.',
+    name: 'Sayuri OKA NICOLEAU',
+    status: 'Directrice administrative & pédagogique',
+    structure: 'École Municipale de Musique de Croissy-sur-Seine (78)',
   },
   {
     review:
       "Un formateur à l'écoute des besoins de notre structure et des besoins de nous deux débutants sur le logiciel. Besoin compris pour une journée de formation complémentaire pour lancer la campagne d'inscription courant le deuxième trimestre 2022. Merci pour la patience de Johan, pédagogue et fin connaisseur de son logiciel.",
-    name: "Alain BATS",
-    status: "Président adjoint",
+    name: 'Alain BATS',
+    status: 'Président adjoint',
     structure: "L'École Intercommunale de Musique LEIM (74)",
   },
-];
+]
 </script>

+ 7 - 15
components/Home/Besoin.vue

@@ -1,19 +1,16 @@
 <template>
   <LayoutContainer>
-    <v-row
-      class="mt-6"
-      justify="center"
-    >
+    <v-row class="mt-6" justify="center">
       <v-col cols="12" lg="6">
         <div class="screen-img ml-4" />
       </v-col>
 
-      <v-col cols="12" lg="6" class="detail-col" >
+      <v-col cols="12" lg="6" class="detail-col">
         <h3 class="mt-12">
           Une solution évolutive pour vous donner entière satisfaction
         </h3>
 
-        <p class="details ">
+        <p class="details">
           La satisfaction de nos clients est notre première motivation et nous
           nous tenons à votre écoute pour faire évoluer notre logiciel. <br />
           <b>Un besoin ?</b> <br />
@@ -26,15 +23,11 @@
   </LayoutContainer>
 </template>
 
-<script setup lang="ts">
-  import { useDisplay } from "vuetify";
-  const { mdAndDown } = useDisplay();
-</script>
+<script setup lang="ts"></script>
 
 <style scoped lang="scss">
-.v-row
-{
-  margin-left:auto !important;
+.v-row {
+  margin-left: auto !important;
   margin-right: auto !important;
   max-width: 1400px !important;
 }
@@ -56,11 +49,10 @@ p {
   margin-left: 2rem;
   color: var(--primary-color);
   width: 20rem;
-  text-align: justify;
 }
 
 .screen-img {
-  background-image: url("/images/home/Repondre-aux-besoins-des-clients-Opentalent.png");
+  background-image: url('/images/pages/home/besoin/Repondre-aux-besoins-des-clients-Opentalent.png');
   background-position: center;
   background-size: cover;
   width: 700px;

+ 139 - 129
components/Home/Caroussel.vue

@@ -2,170 +2,177 @@
 Carrousel de la page d'accueil
 -->
 <template>
-  <v-carousel
-    ref="carousel"
-    v-model="activeIndex"
-    :show-arrows="false"
-    :hide-delimiter-background="true"
-    :show-delimiters="false"
-    :touch="true"
-    :height="lgAndUp ? 500 : 800"
-    :interval="5000"
-  >
-    <v-carousel-item
-      v-for="(item, index) in carouselItems"
-      :key="index"
+  <div v-intersect="onIntersect">
+    <v-carousel
+      ref="carousel"
+      v-model="activeIndex"
+      :show-arrows="false"
+      :hide-delimiter-background="true"
+      :show-delimiters="false"
+      :touch="true"
+      :height="lgAndUp ? 500 : 800"
+      :interval="10000"
+      :cycle="true"
     >
-      <v-row>
-        <!-- Partie description (logo, description, bouton 'en savoir plus') -->
-        <v-col cols="12" lg="6" class="col presentation">
-          <v-img
-            :src="item.logo"
-            :alt="item.alt"
-            class="logo"
-          />
-
-          <p class="description" v-html="mdAndUp ? item.description : item.descriptionSm" />
-
-          <v-row class="align-start pl-4">
+      <v-carousel-item v-for="(item, index) in carouselItems" :key="index">
+        <v-row>
+          <!-- Partie description (logo, description, bouton 'en savoir plus') -->
+          <v-col cols="12" lg="6" class="col presentation">
+            <nuxt-link :to="item.link">
+              <v-img :src="item.logo" :alt="item.logoAlt" class="logo" />
+            </nuxt-link>
+
+            <p
+              class="description"
+              v-html="mdAndUp ? item.description : item.descriptionSm"
+            />
+
             <v-btn
               :to="item.link"
               append-icon="fas fa-arrow-right"
-              :class="['learn-more-btn', item.buttonClass]"
+              :class="['mt-3 learn-more-btn', item.buttonClass]"
             >
               En savoir plus
             </v-btn>
-          </v-row>
-        </v-col>
-
-        <!-- Partie Illustration -->
-        <v-col cols="12" lg="6" class="col illustration">
-          <v-row>
-            <div
-              class="background-rectangle"
-              :style="{ backgroundColor: item.color }"
-            />
-
-            <v-card class="card" elevation="5">
-              <v-img
-                class="profile-image"
-                :src="item.avatar"
-                alt="Profile Image"
-                contain
-                rounded
+          </v-col>
+
+          <!-- Partie Illustration -->
+          <v-col cols="12" lg="6" class="col illustration">
+            <v-row>
+              <div
+                class="background-rectangle"
+                :style="{ backgroundColor: item.color }"
               />
-              <v-card-text>
-                <v-card-title class="name">
-                  {{ item.name }}
 
-                  <p class="school">
-                    {{ item.school }}
+              <v-card class="card" elevation="5">
+                <v-img
+                  class="profile-image"
+                  :src="item.avatar"
+                  :alt="item.avatarAlt"
+                  contain
+                  rounded
+                />
+                <v-card-text>
+                  <v-card-title class="name">
+                    {{ item.name }}
+
+                    <p class="school">
+                      {{ item.school }}
+                    </p>
+                  </v-card-title>
+
+                  <p class="status">
+                    {{ item.status }}
                   </p>
-                </v-card-title>
-
-                <p class="status">
-                  {{ item.status }}
-                </p>
-              </v-card-text>
-            </v-card>
-
-            <v-img
-              :src="item.image"
-              class="image"
-            />
-          </v-row>
-        </v-col>
-      </v-row>
-    </v-carousel-item>
-
-    <div class="custom-controls">
-      <!--suppress JSUnusedLocalSymbols -->
-      <div
-        v-for="(_, index) in carouselItems"
-        :key="index"
-        :class="{ 'active-control': index === activeIndex }"
-        @click="setActiveIndex(index)"
-      />
-    </div>
-  </v-carousel>
+                </v-card-text>
+              </v-card>
+
+              <v-img :src="item.image" :alt="item.imageAlt" class="image" />
+            </v-row>
+          </v-col>
+        </v-row>
+      </v-carousel-item>
+
+      <div class="custom-controls">
+        <!--suppress JSUnusedLocalSymbols -->
+        <div
+          v-for="(_, index) in carouselItems"
+          :key="index"
+          :class="{ 'active-control': index === activeIndex }"
+          @click="setActiveIndex(index)"
+        />
+      </div>
+    </v-carousel>
+  </div>
 </template>
 
 <script setup lang="ts">
+import { useDisplay } from 'vuetify'
+import type { Ref } from 'vue'
+import type { CarouselItem } from '~/types/interface'
+import { useLayoutStore } from '~/stores/layoutStore'
 
-import { useDisplay } from "vuetify";
-import type { CarouselItem } from "~/types/interface";
-const { smAndDown, mdAndDown, mdAndUp, lgAndUp } = useDisplay();
+const { mdAndUp, lgAndUp } = useDisplay()
 
 // Index de la slide active
-let activeIndex: Ref<number> = ref(0);
+const activeIndex: Ref<number> = ref(0)
 
 const setActiveIndex = (index: number) => {
-  activeIndex.value = index;
-};
+  activeIndex.value = index
+}
 
 const carouselItems: Ref<Array<CarouselItem>> = ref([
   {
-    logo: "/images/logo/logiciels/School-noir.png",
-    logoAlt: "Logo Opentalent School - logiciel de gestion et de communication pour les établissements d’enseignement artistique",
+    logo: '/images/logos/opentalent/Logo_Opentalent_School-gris.png',
+    logoAlt:
+      'Logo Opentalent School - logiciel de gestion et de communication pour les établissements d’enseignement artistique',
     description:
       "Pour les petits comme pour les GRANDS établissements d’enseignement artistique tels que les écoles de musique, de danse, de théâtre, d'art, de cirque et conservatoire.<br> Il permet la gestion au quotidien et en temps réel de votre établissement, de gérer vos élèves et vos professeurs, vos emplois du temps, le suivi pédagogique, vos salles, la facturation et les encaissements…",
     descriptionSm:
       "Pour les petits comme pour les GRANDS établissements d’enseignement artistique tels que les écoles de musique, de danse, de théâtre, d'art, de cirque et conservatoire.",
-    buttonClass: "btn-school",
+    buttonClass: 'btn-school',
     image:
-      "/images/Home_logiciel/Logiciel_Opentalent_School-eleve-Conservatoire_de_Musique.png",
-    imageAlt: "Jeune élève de batterie",
-    color: "rgba(32, 147, 190, 0.4)",
-    link: "/opentalent_school",
-    name: "Cindy Blanchard",
-    school: "Conservatoire de Musique",
-    status: "élève",
-    avatar: "/images/carousel/school/avatar.png",
-    avatarAlt: "Photo de profil d’une jeune fille",
+      '/images/pages/home/carousel/Logiciel_Opentalent_School-eleve-Conservatoire_de_Musique.png',
+    imageAlt: 'Jeune élève de batterie',
+    color: 'rgba(32, 147, 190, 0.4)',
+    link: '/opentalent_school',
+    name: 'Cindy Blanchard',
+    school: 'Conservatoire de Musique',
+    status: 'élève',
+    avatar: '/images/pages/home/carousel/Photo_de_profil_d_une_jeune_fille.png',
+    avatarAlt: 'Photo de profil d’une jeune fille',
   },
   {
-    logo: "/images/logo/logiciels/Artist-noir.png",
-    logoAlt: "Logo Opentalent Artist - logiciel de gestion et de communication pour les orchestres, les chorales, les compagnies artistiques et troupes",
+    logo: '/images/logos/opentalent/Logo_Opentalent_Artist-gris.png',
+    logoAlt:
+      'Logo Opentalent Artist - logiciel de gestion et de communication pour les orchestres, les chorales, les compagnies artistiques et troupes',
     description:
-      "Pour les structures culturelles pratiquantes telles que les orchestres, les chorales, les compagnies de danse, théâtre et cirque. <br> Gérez votre activité avec un logiciel de gestion et de communication au service de votre passion.",
+      'Pour les structures culturelles pratiquantes telles que les orchestres, les chorales, les compagnies de danse, théâtre et cirque. <br> Gérez votre activité avec un logiciel de gestion et de communication au service de votre passion.',
     descriptionSm:
-      "Pour les structures culturelles pratiquantes telles que les orchestres, les chorales, les compagnies de danse, théâtre et cirque.",
-    buttonClass: "btn-artist",
+      'Pour les structures culturelles pratiquantes telles que les orchestres, les chorales, les compagnies de danse, théâtre et cirque.',
+    buttonClass: 'btn-artist',
     image:
-      "/images/Home_logiciel/Logiciel_Opentalent_Artist-administrateur-Orchestre_d_harmonie.png",
-    imageAlt: "Homme jouant du banjo",
-    color: "rgba(250, 194, 10, 0.4)",
-    link: "opentalent_artist",
-    name: "Thierry Dupont ",
-    school: "Orchestre d’harmonie",
-    status: "Admin",
-    avatar: "/images/carousel/artist/avatar.png",
-    avatarAlt: "Photo de profil d’un homme jouant du banjo",
+      '/images/pages/home/carousel/Logiciel_Opentalent_Artist-administrateur-Orchestre_d_harmonie.png',
+    imageAlt: 'Homme jouant du banjo',
+    color: 'rgba(250, 194, 10, 0.4)',
+    link: 'opentalent_artist',
+    name: 'Thierry Dupont ',
+    school: 'Orchestre d’harmonie',
+    status: 'Admin',
+    avatar:
+      '/images/pages/home/carousel/Photo_de_profil_d_un_homme_jouant_du_banjo.png',
+    avatarAlt: 'Photo de profil d’un homme jouant du banjo',
   },
   {
-    logo: "/images/logo/logiciels/Manager-noir.png",
-    logoAlt: "Logo Opentalent Manager - logiciel de gestion et de communication pour les fédérations, les confédérations et les collectivités",
+    logo: '/images/logos/opentalent/Logo_Opentalent_Manager-gris.png',
+    logoAlt:
+      'Logo Opentalent Manager - logiciel de gestion et de communication pour les fédérations, les confédérations et les collectivités',
     description:
-      "La solution de mise en réseau des organisations culturelles.<br> Fédérations, confédérations et collectivités, utilisez une solution collaborative innovante et unique spécialement développée pour les réseaux culturels.",
+      'La solution de mise en réseau des organisations culturelles.<br> Fédérations, confédérations et collectivités, utilisez une solution collaborative innovante et unique spécialement développée pour les réseaux culturels.',
     descriptionSm:
-      "La solution de mise en réseau des organisations culturelles, telles que les fédérations, confédérations et collectivités.",
-    buttonClass: "btn-manager",
+      'La solution de mise en réseau des organisations culturelles, telles que les fédérations, confédérations et collectivités.',
+    buttonClass: 'btn-manager',
     image:
-      "/images/Home_logiciel/Logiciel_Opentalent_Managerl-Administrateur_Federation.png",
-    imageAlt: "Un homme en costard et une femme tailleur souriant",
-    color: "rgba(216, 5, 11, 0.4)",
-    link: "opentalent_manager",
-    name: "Marie Voisin",
+      '/images/pages/home/carousel/Logiciel_Opentalent_Manager-Administrateur_Federation.png',
+    imageAlt: 'Un homme en costard et une femme tailleur souriant',
+    color: 'rgba(216, 5, 11, 0.4)',
+    link: 'opentalent_manager',
+    name: 'Marie Voisin',
     school: "Réseau d'organisations culturelles ",
-    status: "ADMIN",
-    avatar: "/images/carousel/manager/avatar.png",
-    avatarAlt: "Photo de profil d’une femme en tailleur",
+    status: 'ADMIN',
+    avatar:
+      '/images/pages/home/carousel/Photo_de_profil_d_une_femme_en_tailleur.png',
+    avatarAlt: 'Photo de profil d’une femme en tailleur',
   },
-]);
+])
+
+const layoutStore = useLayoutStore()
+const onIntersect = (isIntersecting: boolean) => {
+  layoutStore.setIsBannerVisible(isIntersecting)
+}
 </script>
 
 <style scoped lang="scss">
-
 /* ============= CAROUSEL ===============  */
 :deep(.v-carousel__controls) {
   display: none;
@@ -197,10 +204,15 @@ const carouselItems: Ref<Array<CarouselItem>> = ref([
 
 /* ============= Colonne gauche - Description ===============  */
 .col.presentation {
+  padding-left: 7rem;
+
+  @media (max-width: 600px) {
+    padding-left: 0;
+  }
+
   .logo {
     width: 20rem;
     margin-top: 10px;
-    margin-left: 6rem;
 
     @media (max-width: 600px) {
       width: 15rem;
@@ -209,9 +221,7 @@ const carouselItems: Ref<Array<CarouselItem>> = ref([
   }
 
   .description {
-    text-align: justify;
     margin-top: 8px;
-    margin-left: 7rem;
     width: 25vw;
     margin-bottom: 1rem;
   }
@@ -228,7 +238,6 @@ const carouselItems: Ref<Array<CarouselItem>> = ref([
     line-height: 15px;
     width: 10rem;
     height: 2.5rem;
-    margin-left: 7rem;
 
     @media (max-width: 600px) {
       width: 80%;
@@ -269,7 +278,7 @@ const carouselItems: Ref<Array<CarouselItem>> = ref([
 .col.illustration {
   .card {
     position: relative;
-    left: 10%;
+    left: 5%;
     height: 100%;
     width: 27%;
     border-radius: 1rem;
@@ -288,7 +297,8 @@ const carouselItems: Ref<Array<CarouselItem>> = ref([
     padding: 0 !important;
   }
 
-  .school, .status {
+  .school,
+  .status {
     text-align: center;
     white-space: normal;
   }

+ 33 - 22
components/Home/EventAgenda.vue

@@ -4,20 +4,23 @@ Section "Agenda" de la page d'accueil
 <template>
   <LayoutContainer>
     <div class="container">
+      <div class="d-flex flex-row justify-center">
+        <h2 class="alt-theme bg-transparent">
+          L’agenda Opentalent
+        </h2>
+      </div>
+
       <div class="d-flex align-center justify-center">
         <h3>
-          Retrouvez tous vos évènements dans l'agenda et référencez vous dans
-          l'annuaire
+          Retrouvez tous les événements et toutes les structures culturelles
+          autour de chez vous
         </h3>
       </div>
 
       <v-row justify="center" class="btn-container">
         <v-col cols="12" lg="6">
           <AgendaLink href="/">
-            <v-btn
-              append-icon="fas fa-arrow-right"
-              class="btn-event"
-            >
+            <v-btn append-icon="fas fa-arrow-right" class="btn-event">
               Découvrir l'agenda
             </v-btn>
           </AgendaLink>
@@ -40,24 +43,29 @@ Section "Agenda" de la page d'accueil
 </template>
 
 <script setup>
-import { useDisplay } from "vuetify";
-import AgendaLink from "~/components/Common/AgendaLink.vue";
-const { lgAndUp } = useDisplay();
+import { useDisplay } from 'vuetify'
+import AgendaLink from '~/components/Common/AgendaLink.vue'
+const { lgAndUp } = useDisplay()
 </script>
 
 <style scoped>
-
 .container {
-  height: 35rem;
-  background: linear-gradient(0deg, rgba(0, 0, 0, 0.2), rgba(0, 0, 0, 0.2)),
-  linear-gradient(
-    180deg,
-    rgba(14, 45, 50, 0.04) 0%,
-    rgba(14, 45, 50, 0.2) 100%
-  ),
-  linear-gradient(0deg, rgba(0, 0, 0, 0.2), rgba(0, 0, 0, 0.2)),
-  url("/images/eventAgenda/eventAgenda.jpg") no-repeat center 60%;
+  height: 30rem;
+  background:
+    linear-gradient(0deg, rgba(0, 0, 0, 0.2), rgba(0, 0, 0, 0.2)),
+    linear-gradient(
+      180deg,
+      rgba(14, 45, 50, 0.04) 0%,
+      rgba(14, 45, 50, 0.2) 100%
+    ),
+    linear-gradient(0deg, rgba(0, 0, 0, 0.2), rgba(0, 0, 0, 0.2)),
+    url('/images/components/agenda/Opentalent_Agenda_événement_culturel.jpg')
+      no-repeat center 60%;
   background-size: cover;
+
+  @media (max-width: 600px) {
+    height: auto;
+  }
 }
 
 h3 {
@@ -80,11 +88,14 @@ h3 {
 }
 
 .btn-container {
-  display: flex;
-  align-items: center;
-  justify-content: center;
   padding: 0 20rem;
 
+  .v-col-12 {
+    display: flex;
+    align-items: center;
+    justify-content: center;
+  }
+
   @media (max-width: 1240px) {
     padding: 0 5rem;
     margin-top: 48px;

+ 20 - 29
components/Home/Help.vue

@@ -4,37 +4,28 @@ Section "Besoin d'aide" de la page d'accueil
 
 <template>
   <LayoutContainer>
-    <v-row >
+    <v-row class="center-90 mt-6">
       <v-col cols="12" lg="6" class="col">
         <v-img
-          src="/images/Home_logiciel/Opentalent_a_votre_service.png"
+          src="/images/pages/home/help/Opentalent_a_votre_service.png"
           alt="Un homme et une femme tous les deux le sourire aux lèvres se serre la main"
         />
       </v-col>
 
       <v-col cols="12" lg="6" class="col">
-        <h3>
-          Notre équipe est à vos côtés
-          pour vous guider
-        </h3>
+        <h3>Notre équipe est à vos côtés pour vous guider</h3>
 
         <p>
           Besoin d’aide ? <br />
-          Vous souhaitez en savoir plus sur nos solutions ou vous avez
-          besoin d'assistance sur l'utilisation de l'un de nos logiciels ?
+          Vous souhaitez en savoir plus sur nos solutions ou vous avez besoin
+          d'assistance sur l'utilisation de l'un de nos logiciels ?
         </p>
 
         <v-row>
           <ul>
-            <li>
-              Ouvert du lundi au vendredi de 8h15 à 17h45
-            </li>
-            <li>
-              Support joignable par mail
-            </li>
-            <li>
-              De nombreux articles tutoriels accessibles 24h/24
-            </li>
+            <li>Ouvert du lundi au vendredi de 8h30 à 17h30</li>
+            <li>Support joignable par mail</li>
+            <li>De nombreux articles tutoriels accessibles 24h/24</li>
           </ul>
         </v-row>
 
@@ -52,14 +43,9 @@ Section "Besoin d'aide" de la page d'accueil
   </LayoutContainer>
 </template>
 
-<script setup lang="ts">
-  import { useDisplay } from "vuetify";
-
-  const { mdAndDown} = useDisplay();
-</script>
+<script setup lang="ts"></script>
 
 <style scoped lang="scss">
-
 .v-container {
   margin: 64px auto 24px auto;
   padding: 16px;
@@ -137,6 +123,17 @@ ul {
   gap: 9px;
   margin-left: auto;
   margin-right: auto;
+
+  @media (max-width: 1240px) {
+    margin-top: 24px;
+    width: 40%;
+    margin-left: 30%;
+  }
+
+  @media (max-width: 600px) {
+    width: 90%;
+    margin-left: 5%;
+  }
 }
 
 @media (max-width: 1240px) {
@@ -175,11 +172,5 @@ ul {
     margin-right: auto;
     width: 30rem;
   }
-
-  .button-faq {
-    margin-left: 3rem;
-    margin-top: 2rem;
-    width: 80%;
-  }
 }
 </style>

+ 102 - 89
components/Home/Promotion.vue

@@ -12,7 +12,7 @@
 
             <span class="inline-pic-container">
               <v-img
-                src="/images/Home_logiciel/ecole_de_musique-piano.jpg"
+                src="/images/pages/home/promotion/Visuel_d_un_Pianiste.png"
                 alt="Vignette d’une personne jouant sur un piano"
               />
             </span>
@@ -21,7 +21,7 @@
 
             <span class="inline-pic-container">
               <v-img
-                src="/images/Home_logiciel/ecole_de_danse-danseuse.jpg"
+                src="/images/pages/home/promotion/Visuel_de_Danseuse.png"
                 alt="Vignette d’une danseuse"
               />
             </span>
@@ -30,7 +30,7 @@
 
             <span class="inline-pic-container">
               <v-img
-                src="/images/Home_logiciel/ecole_de_cirque.jpg"
+                src="/images/pages/home/promotion/Visuel_d_un_Comedien.PNG"
                 alt="Vignette d’un homme faisant un spectacle de mime dans une salle de spectacle"
               />
             </span>
@@ -42,96 +42,97 @@
     <v-row class="demo">
       <v-col>
         <v-img
-          src="/images/home/écran.JPG"
+          src="/images/pages/home/promotion/Ordinateur_portable_avec_ecran_logiciel_Opentalent.jpg"
           alt="Vidéo corporate de l’entreprise Opentalent"
           class="screen"
         >
-          <v-icon icon="fas fa-play" class="play-icon" />
+          <v-icon v-show="false" icon="fas fa-play" class="play-icon" />
         </v-img>
-
       </v-col>
     </v-row>
 
-    <v-row class="outil">
-      <v-row>
-        <v-col>
-          <h3>
-            Un outil complet et intuitif <br />
-            pour chaque structure
-          </h3>
-        </v-col>
-      </v-row>
-
-      <v-row class="pictos">
-        <v-col cols="12" lg="6">
-          <v-row>
-            <v-col cols="3">
-              <img src="/images/pictoHome/network.svg" alt="Icône nuage cloud" />
-            </v-col>
-            <v-col cols="9">
-              <p>
-                Logiciel de gestion et communication en ligne
-              </p>
-            </v-col>
-          </v-row>
-
-          <v-row>
-            <v-col cols="3">
-              <img src="/images/pictoHome/website.svg" alt="Icône site internet" />
-            </v-col>
-            <v-col cols="9">
-              <p>
-                Site web intégré et simple d’usage
-              </p>
-            </v-col>
-          </v-row>
-        </v-col>
-
-        <v-col cols="12" lg="6">
-          <v-row>
-            <v-col cols="3">
-              <img src="/images/pictoHome/visibility.svg" alt="Icône avion en papier" />
-            </v-col>
-            <v-col cols="9">
-              <p>
-                Augmentez votre visibilité avec l'agenda culturel
-              </p>
-            </v-col>
-          </v-row>
-
-          <v-row>
-            <v-col cols="3">
-              <img src="/images/pictoHome/communication.svg" alt="Icône de deux enveloppes" />
-            </v-col>
-            <v-col cols="9">
-              <p>
-                Communiquez en réseau
-              </p>
-            </v-col>
-          </v-row>
-        </v-col>
-      </v-row>
+    <v-row class="outil center-90">
+      <v-col>
+        <v-row>
+          <v-col>
+            <h3>Un outil complet et intuitif pour chaque structure</h3>
+          </v-col>
+        </v-row>
+
+        <v-row class="pictos">
+          <v-col cols="12" lg="6">
+            <v-row>
+              <v-col cols="3">
+                <img
+                  src="/images/pages/home/promotion/Logiciel_en_ligne_SaaS.svg"
+                  alt="Icône nuage cloud"
+                />
+              </v-col>
+              <v-col cols="9">
+                <p>Logiciel de gestion et communication en ligne</p>
+              </v-col>
+            </v-row>
+
+            <v-row>
+              <v-col cols="3">
+                <img
+                  src="/images/pages/home/promotion/Site_internet_intégré.svg"
+                  alt="Icône site internet"
+                />
+              </v-col>
+              <v-col cols="9">
+                <p>Site web intégré et simple d’usage</p>
+              </v-col>
+            </v-row>
+          </v-col>
+
+          <v-col cols="12" lg="6">
+            <v-row>
+              <v-col cols="3">
+                <img
+                  src="/images/pages/home/promotion/Visibilite_augmente_avec_l_agenda_culturel_Opentalent.svg"
+                  alt="Icône avion en papier"
+                />
+              </v-col>
+              <v-col cols="9">
+                <p>Augmentez votre visibilité avec l'agenda culturel</p>
+              </v-col>
+            </v-row>
+
+            <v-row>
+              <v-col cols="3">
+                <img
+                  src="/images/pages/home/promotion/Icone_communication_en_reseau.svg"
+                  alt="Icône de deux enveloppes"
+                />
+              </v-col>
+              <v-col cols="9">
+                <p>Communiquez en réseau</p>
+              </v-col>
+            </v-row>
+          </v-col>
+        </v-row>
+      </v-col>
     </v-row>
   </LayoutContainer>
 </template>
 
-<script setup lang="ts">
-
-import { useDisplay } from "vuetify";
-
-const { mdAndUp } = useDisplay()
-</script>
+<script setup lang="ts"></script>
 
 <style scoped lang="scss">
-
 .highlight {
   color: var(--secondary-color);
 }
 
 .v-row.gestion {
-  >.v-col {
+  > .v-col {
     margin-bottom: 4rem;
     background: var(--primary-color);
+
+    @media (max-width: 600px) {
+      min-height: 430px;
+      padding: 0 5%;
+    }
   }
 
   .text-block {
@@ -142,6 +143,10 @@ const { mdAndUp } = useDisplay()
     height: 20rem;
     width: 45rem;
     margin: 2rem auto 28rem;
+
+    @media (max-width: 600px) {
+      padding: 0 5%;
+    }
   }
 
   .inline-pic-container {
@@ -151,14 +156,14 @@ const { mdAndUp } = useDisplay()
   }
 
   .v-img {
-    height: auto;
-    width: 7rem;
+    height: 75px;
+    width: 115px;
     max-width: 100%;
     border-radius: 5rem;
   }
 
   @media (max-width: 960px) {
-    >.v-col {
+    > .v-col {
       margin-bottom: 0;
     }
 
@@ -168,7 +173,7 @@ const { mdAndUp } = useDisplay()
       line-height: 3.5rem;
       height: 10rem;
       width: 40rem;
-      margin: 3rem 2rem 5rem;
+      margin: 3rem auto 5rem;
     }
 
     .v-img {
@@ -179,6 +184,12 @@ const { mdAndUp } = useDisplay()
 }
 
 .v-row.demo {
+  max-height: 350px;
+
+  @media (max-width: 1280px) {
+    max-height: 1000px;
+  }
+
   .screen {
     width: 900px;
     object-fit: cover;
@@ -236,40 +247,42 @@ const { mdAndUp } = useDisplay()
   .pictos {
     .v-row {
       border-bottom: solid 2px var(--on-neutral-color-extra-light);
-      margin: 0;
+      border-top: solid 2px var(--on-neutral-color-extra-light);
+      margin: -2px 0 0;
       height: 100px;
       display: flex;
       align-items: center;
       justify-content: center;
-
-      @media (max-width: 600px) {
-        width: 90%;
-      }
     }
 
-    .v-col:first-child .v-row:first-child, .v-col-12:first-child .v-row:first-child {
-      border-top: solid 2px var(--on-neutral-color-extra-light);
+    > .v-col-12 {
+      padding-top: 0;
+      padding-bottom: 0;
     }
 
-    >.v-col-12 {
-      padding-top : 0;
-      padding-bottom : 0;
+    .v-col-3 {
+      display: flex;
+      flex-direction: row;
+      justify-content: flex-end;
     }
 
     img {
       width: 50px;
       height: 50px;
       margin-right: 2rem;
+
+      @media (max-width: 600px) {
+        margin-right: 0;
+      }
     }
 
     p {
       font-weight: 400;
-      font-size: 22px;
+      font-size: 20px;
       line-height: 26px;
       width: 25rem;
       max-width: 100%;
       color: var(--primary-color);
-      margin-bottom: 1rem;
 
       @media (max-width: 600px) {
         width: 90%;

+ 69 - 71
components/Home/Reviews.vue

@@ -1,26 +1,19 @@
 <template>
   <LayoutContainer>
     <div class="container-1">
-      <LayoutUISectionTitle>
-        Avis Clients
-      </LayoutUISectionTitle>
+      <LayoutUISectionTitle> Avis Clients </LayoutUISectionTitle>
 
-      <h4>
-        C'est vous qui le dites
-      </h4>
+      <h4>C'est vous qui le dites</h4>
     </div>
 
     <!-- Ecrans larges -->
     <div v-if="lgAndUp" class="container-2">
-
       <!-- Partie 1 : Avis clients -->
       <v-row justify="center">
         <div class="col-review">
           <v-col cols="6">
             <v-card class="left mx-auto">
-              <v-card-title>
-                Patrice CATHELIN
-              </v-card-title>
+              <v-card-title> Patrice CATHELIN </v-card-title>
 
               <v-card-text>
                 <p>
@@ -44,9 +37,7 @@
 
           <v-col cols="6">
             <v-card class="right mx-auto">
-              <v-card-title>
-                Karine GIRAUD
-              </v-card-title>
+              <v-card-title> Karine GIRAUD </v-card-title>
 
               <v-card-text>
                 <p>
@@ -60,9 +51,7 @@
               </v-card-text>
 
               <div class="card-footer">
-                <small class="status">
-                  Secrétaire administrative
-                </small>
+                <small class="status"> Secrétaire administrative </small>
 
                 <small class="structure">
                   Association Musicale Sainte Cécile de Lagord (17)
@@ -77,9 +66,7 @@
         <div class="col-review">
           <v-col cols="6">
             <v-card class="left mx-auto">
-              <v-card-title>
-                Laurent BEL
-              </v-card-title>
+              <v-card-title> Laurent BEL </v-card-title>
 
               <v-card-text>
                 <p>
@@ -106,9 +93,7 @@
 
           <v-col cols="6">
             <v-card class="right mx-auto">
-              <v-card-title>
-                Philippe BORY
-              </v-card-title>
+              <v-card-title> Philippe BORY </v-card-title>
 
               <v-card-text>
                 <p>
@@ -121,9 +106,7 @@
               </v-card-text>
 
               <div class="card-footer">
-                <small class="status">
-                  Personnel administratif
-                </small>
+                <small class="status"> Personnel administratif </small>
 
                 <small class="structure">
                   École d'Arts de Saint-Michel-sur-Orge (91)
@@ -144,7 +127,7 @@
     <div v-else class="container-sm">
       <v-row>
         <v-col cols="12">
-          <Carousel :itemsToShow="1" :wrapAround="true" ref="reviewCarousel">
+          <Carousel ref="reviewCarousel" :items-to-show="1" :wrap-around="true">
             <Slide v-for="(card, index) in cards" :key="index">
               <v-card>
                 <v-card-title>
@@ -168,12 +151,9 @@
         </v-col>
       </v-row>
 
-      <v-row class="justify-center align-center">
+      <v-row class="justify-center align-center mb-8">
         <v-col class="d-flex justify-space-around align-center">
-          <v-btn
-            icon="fas fa-arrow-left-long"
-            @click="goToPrevious"
-          />
+          <v-btn icon="fas fa-arrow-left-long" @click="goToPrevious" />
 
           <div class="carousel-controls">
             <div
@@ -184,90 +164,105 @@
             />
           </div>
 
-          <v-btn
-            icon="fas fa-arrow-right-long"
-            @click="goToNext"
-          />
+          <v-btn icon="fas fa-arrow-right-long" @click="goToNext" />
         </v-col>
       </v-row>
 
-      <CommonCarouselClients :items="items" class="alt-theme"/>
+      <CommonCarouselClients :items="items" class="alt-theme pt-12" />
     </div>
   </LayoutContainer>
 </template>
 
 <script setup lang="ts">
-import { Carousel, Slide } from "vue3-carousel";
-import "vue3-carousel/dist/carousel.css";
-import { useDisplay } from "vuetify";
-import type { Review } from "~/types/interface";
+import { Carousel, Slide } from 'vue3-carousel'
+import 'vue3-carousel/dist/carousel.css'
+import { useDisplay } from 'vuetify'
+import type { Ref } from 'vue'
+import type { Review } from '~/types/interface'
 
-const { lgAndUp } = useDisplay();
+const { lgAndUp } = useDisplay()
 
-const reviewCarousel: Ref<typeof Carousel | null> = ref(null);
+const reviewCarousel: Ref<typeof Carousel | null> = ref(null)
 
 const state = ref({
   activeIndex: 0,
-});
+})
 
 const goToNext = () => {
-  reviewCarousel.value!.next();
-  state.value.activeIndex = (state.value.activeIndex + 1) % cards.length;
+  reviewCarousel.value!.next()
+  state.value.activeIndex = (state.value.activeIndex + 1) % cards.length
 }
 
 const goToPrevious = () => {
-  reviewCarousel.value!.prev();
+  reviewCarousel.value!.prev()
   state.value.activeIndex =
     state.value.activeIndex - 1 < 0
       ? cards.length - 1
-      : state.value.activeIndex - 1;
+      : state.value.activeIndex - 1
 }
 
 const cards: Array<Review> = [
   {
-    name: "Patrice CATHELIN",
+    name: 'Patrice CATHELIN',
     review:
       "C'est un logiciel très bien conçu et efficace avec une équipe ouverte, dynamique et à l'écoute. L’assistance est très réactive, j'ai toujours eu une réponse rapide à mes besoins, ce qui est fort appréciable.",
-    status: "Directeur administratif & pédagogique",
-    structure: "Conservatoire de Musique & de Danse de Sens (78)",
+    status: 'Directeur administratif & pédagogique',
+    structure: 'Conservatoire de Musique & de Danse de Sens (78)',
   },
   {
-    name: "Karine GIRAUD",
+    name: 'Karine GIRAUD',
     review:
       "Étant présente depuis presque le début, je suis fière d'avoir vu grandir ce logiciel et d'avoir évoluée avec lui. De plus, je me suis sentie écoutée lors de mes propositions d'amélioration, car beaucoup ont vu le jour. Enfin, l'accompagnement et la réactivité n'ont jamais faibli depuis toutes ces années",
-    status: "Secrétaire administrative",
-    structure: "Association Musicale Sainte Cécile de Lagord (17)",
+    status: 'Secrétaire administrative',
+    structure: 'Association Musicale Sainte Cécile de Lagord (17)',
   },
   {
-    name: "Laurent BEL",
+    name: 'Laurent BEL',
     review:
       "Logiciel très complet qui permet de faire beaucoup de choses. J’apprécie particulièrement la réactivité, la bienveillance et le fait que l’équipe soit à l'écoute pour faire évoluer l'outil en fonction de nos besoins. Si besoin, la FAQ est vraiment utile. Elle permet de trouver rapidement une solution face à un problème rencontré.",
-    status: "Directeur administratif & pédagogique",
-    structure: "École de Musique EPIC Musique en 4 Rivières (74)",
+    status: 'Directeur administratif & pédagogique',
+    structure: 'École de Musique EPIC Musique en 4 Rivières (74)',
   },
   {
-    name: "Philippe BORY",
+    name: 'Philippe BORY',
     review:
       "Opentalent est une entreprise avec de vraies valeurs humaines, à l'écoute de chaque structure et qui ne cesse de s'améliorer pour toujours coller aux besoins de ses clients. Plus qu'une relation commerciale, c'est pour nous un véritable partenaire au quotidien.",
-    status: "Personnel administratif",
+    status: 'Personnel administratif',
     structure: "École d'Arts de Saint-Michel-sur-Orge (91)",
   },
-];
-
-const items: Ref<Array<{ src: string, alt: string }>> = ref([
-  { src: "/images/reviews/school/review1.svg", alt: "Logo du Conservatoire « Les ateliers des arts" },
-  { src: "/images/reviews/school/review2.png", alt: "Logo du Conservatoire de Senlis" },
-  { src: "/images/reviews/school/review3.png", alt: "Logo de l’École de musique Sausheim" },
-  { src: "/images/reviews/school/review4.jpeg", alt: "Logo du Conservatoire Marly le Roi Roger Bourdin" },
-  { src: "/images/reviews/school/review5.jpeg", alt: "Logo du Conservatoire de Musique et de Danse du Thouarsais" },
-  { src: "/images/reviews/school/review6.jpeg", alt: "Logo du Conservatoire d’Annemasse" },
-]);
+]
+
+const items: Ref<Array<{ src: string; alt: string }>> = ref([
+  {
+    src: '/images/pages/home/reviews/Logo_Conservatoire_Les_Ateliers_des_Arts_Agglomeration_du_Puy-en-Velay.svg',
+    alt: 'Logo du Conservatoire « Les ateliers des arts',
+  },
+  {
+    src: '/images/pages/home/reviews/Logo_Conservatoire-Senlis.png',
+    alt: 'Logo du Conservatoire de Senlis',
+  },
+  {
+    src: '/images/pages/home/reviews/Logo_Ecole_de_Musique-Sausheim.png',
+    alt: 'Logo de l’École de musique Sausheim',
+  },
+  {
+    src: '/images/pages/home/reviews/Logo_Conservatoire_Marly_le_Roi-Roger_Bourdin.jpeg',
+    alt: 'Logo du Conservatoire Marly le Roi Roger Bourdin',
+  },
+  {
+    src: '/images/pages/home/reviews/Logo_Conservatoire_de_Musiques_et_de_Danses_du_Thouarsais.jpeg',
+    alt: 'Logo du Conservatoire de Musique et de Danse du Thouarsais',
+  },
+  {
+    src: '/images/pages/home/reviews/Logo_Conservatoire_de_Musique_d_Annemasse.jpg',
+    alt: 'Logo du Conservatoire d’Annemasse',
+  },
+])
 </script>
 
 <style scoped>
-
 .container-1 {
-  background-color: var(--neutral-color);
+  background-color: var(--neutral-color-alt-light);
 
   @media (min-width: 1240px) {
     height: 22rem;
@@ -287,7 +282,6 @@ const items: Ref<Array<{ src: string, alt: string }>> = ref([
 
 .container-2 {
   background-color: var(--primary-color);
-  height: 60rem;
 
   .col-review {
     display: flex;
@@ -340,11 +334,15 @@ const items: Ref<Array<{ src: string, alt: string }>> = ref([
           letter-spacing: 0.18em;
           text-transform: uppercase;
           margin-bottom: 2rem;
+          width: 300px;
+          right: 18px;
         }
 
         .structure {
           font-size: 0.8rem;
           margin-bottom: 1rem;
+          width: 300px;
+          right: 18px;
         }
       }
     }

+ 75 - 80
components/Home/Solution.vue

@@ -4,13 +4,9 @@ Section "Solutions" de la page d'accueil
 
 <template>
   <LayoutContainer>
-    <LayoutUISectionTitle class="alt-theme">
-      3 solutions
-    </LayoutUISectionTitle>
+    <LayoutUISectionTitle class="alt-theme"> 3 solutions </LayoutUISectionTitle>
 
-    <h4 class="text-center" >
-      Trouvez la solution faites pour vous
-    </h4>
+    <h4 class="text-center mb-4">Trouvez la solution faite pour vous</h4>
 
     <v-row class="solutions center-90">
       <v-col
@@ -21,15 +17,13 @@ Section "Solutions" de la page d'accueil
       >
         <v-container>
           <div class="d-flex justify-center align-left flex-column">
-            <small>
-              Opentalent
-            </small>
+            <small> Opentalent </small>
 
             <h2>
               {{ solution.name }}
             </h2>
 
-            <v-divider thickness="2"/>
+            <v-divider thickness="2" />
 
             <p>
               {{ solution.description }}
@@ -37,7 +31,7 @@ Section "Solutions" de la page d'accueil
 
             <nuxt-link :to="solution.link">
               <v-row>
-                <div :class="['image-container', solution.class]" >
+                <div :class="['image-container', solution.class]">
                   <v-img :src="solution.image" />
                   <v-btn v-if="xlAndUp">Découvrir</v-btn>
                 </div>
@@ -45,7 +39,7 @@ Section "Solutions" de la page d'accueil
             </nuxt-link>
 
             <v-row class="details">
-              <v-col cols="12" md="6">
+              <v-col cols="12" sm="6">
                 <ul>
                   <li
                     v-for="(sol, i) in solution.solutions.slice(0, 4)"
@@ -56,12 +50,9 @@ Section "Solutions" de la page d'accueil
                 </ul>
               </v-col>
 
-              <v-col cols="12" md="6">
+              <v-col cols="12" sm="6">
                 <ul>
-                  <li
-                    v-for="(sol, i) in solution.solutions.slice(4)"
-                    :key="i"
-                  >
+                  <li v-for="(sol, i) in solution.solutions.slice(4)" :key="i">
                     {{ sol }}
                   </li>
                 </ul>
@@ -77,7 +68,7 @@ Section "Solutions" de la page d'accueil
     </v-row>
 
     <v-container class="footer">
-      <v-row >
+      <v-row>
         <v-col cols="12">
           <p>* en option</p>
         </v-col>
@@ -87,75 +78,72 @@ Section "Solutions" de la page d'accueil
 </template>
 
 <script setup lang="ts">
-
-import type { SolutionItem } from "~/types/interface";
-import { useDisplay } from "vuetify";
+import { useDisplay } from 'vuetify'
+import type { SolutionItem } from '~/types/interface'
 
 const { xlAndUp, lgAndDown } = useDisplay()
 
 const solutions: Array<SolutionItem> = [
   {
-    name: "Artist",
-    description: "Orchestres, chorales, compagnies de danse, théâtre et cirque",
-    image: "/images/logo/logiciels/Artist-Blanc.png",
-    alt: "Partition tenue par une femme dans une chorale",
-    link: "/opentalent_artist",
-    class: "artist-image",
+    name: 'Artist',
+    description: 'Orchestres, chorales, compagnies et troupes artistiques',
+    image: '/images/logos/Logo_Opentalent_Artist-blanc.png',
+    alt: 'Partition tenue par une femme dans une chorale',
+    link: '/opentalent_artist',
+    class: 'artist-image',
     solutions: [
-      "Gestion des membres",
-      "Agenda de la structure",
-      "Matériel & médiathèque",
-      "Export de données",
-      "Communication",
-      "Statistiques",
-      "Site internet intégré",
-      "Partage de données en réseau",
+      'Gestion des membres',
+      'Agenda de la structure',
+      'Matériel & médiathèque',
+      'Export de données',
+      'Communication',
+      'Statistiques',
+      'Site internet intégré',
+      'Partage de données en réseau',
     ],
   },
   {
-    name: "School",
+    name: 'School',
     description: "Petits et grands établissements d'enseignement artistique",
-    image: "/images/logo/logiciels/School-Blanc.png",
-    alt: "Deux jeunes filles jouant du violon",
-    link: "/opentalent_school",
-    class: "school-image",
+    image: '/images/logos/Logo_Opentalent_School-blanc',
+    alt: 'Deux jeunes filles jouant du violon',
+    link: '/opentalent_school',
+    class: 'school-image',
     solutions: [
-      "Gestion des membres",
-      "Préinscription en ligne*",
-      "Agenda de la structure",
-      "Suivi pédagogique",
-      "Gestion administrative et financière",
-      "Communication",
-      "Site internet intégré",
-      "Statistiques",
-    ]
+      'Gestion des membres',
+      'Préinscription en ligne *',
+      'Agenda de la structure',
+      'Suivi pédagogique',
+      'Gestion administrative et financière',
+      'Communication',
+      'Site internet intégré',
+      'Statistiques',
+    ],
   },
   {
-    name: "Manager",
-    description: "Fédérations, confédérations et collectivités",
-    image: "/images/logo/logiciels/Manager-Blanc.png",
-    alt: "Carte de réseau des structures de la confédération musicale de France",
-    link: "/opentalent_manager",
-    class: "manager-image",
+    name: 'Manager',
+    description: 'Fédérations, confédérations et collectivités',
+    image: '/images/logos/Logo_Opentalent_Manager-blanc.png',
+    alt: 'Carte de réseau des structures de la confédération musicale de France',
+    link: '/opentalent_manager',
+    class: 'manager-image',
     solutions: [
-      "Gestion des membres",
-      "Agenda du réseau",
-      "Matériel & médiathèque",
-      "Gestion administrative",
-      "Statistiques du réseau",
-      "Cotisations",
-      "Site internet intégré",
-      "Communication",
+      'Gestion des membres',
+      'Agenda du réseau',
+      'Matériel & médiathèque',
+      'Gestion administrative',
+      'Statistiques du réseau',
+      'Cotisations',
+      'Site internet intégré',
+      'Communication',
     ],
   },
-];
+]
 </script>
 
 <style scoped lang="scss">
 .container {
   background: var(--primary-color);
-  margin-bottom: 15rem;
-  height: 36rem;
   position: relative;
 
   @media (max-width: 1240px) {
@@ -185,7 +173,7 @@ h4 {
 
 @media (min-width: 600px) {
   h3 {
-    margin-bottom: 3rem
+    margin-bottom: 3rem;
   }
 }
 
@@ -209,7 +197,7 @@ h4 {
 
   .v-divider {
     color: var(--on-primary-color-alt);
-    width: 20rem;
+    width: 350px;
     opacity: 0.7;
   }
 
@@ -248,7 +236,7 @@ h4 {
   }
 
   .image-container::before {
-    content: "";
+    content: '';
     position: absolute;
     top: 0;
     left: 0;
@@ -261,10 +249,11 @@ h4 {
   }
 
   .v-btn {
+    left: 50%;
     font-size: 0.8rem;
     border-radius: 6px;
     background: var(--secondary-color);
-    color: var(--on-primary-color);
+    color: var(--on-secondary-color);
 
     @media (min-width: 1240px) {
       position: absolute;
@@ -275,6 +264,7 @@ h4 {
     }
 
     @media (max-width: 1240px) {
+      left: auto;
       width: 90%;
       margin: 24px auto;
     }
@@ -285,7 +275,7 @@ h4 {
   }
 
   .artist-image {
-    background-image: url(/images/solutions/artist.jpg);
+    background-image: url(/images/pages/home/solution/Opentalent_Artist_pour_les_structures_culturelles.jpg);
   }
 
   .artist-image:hover::before {
@@ -294,7 +284,7 @@ h4 {
   }
 
   .school-image {
-    background-image: url(/images/solutions/school.jpg);
+    background-image: url(/images/pages/home/solution/Opentalent_School_pour_les_etablissements_d_enseignement_artistique.jpg);
   }
 
   .school-image:hover::before {
@@ -303,7 +293,7 @@ h4 {
   }
 
   .manager-image {
-    background-image: url(/images/solutions/manager.png);
+    background-image: url(/images/pages/home/solution/Opentalent_Manager_pour_les_reseaux_culturels.png);
   }
 
   .manager-image:hover::before {
@@ -315,25 +305,30 @@ h4 {
     display: flex;
     justify-content: center;
     align-items: center;
+    max-width: 80%;
 
     ul {
       margin-top: 0.9rem;
-      font-size: 16px;
+      max-width: 100%;
+      white-space: pre-wrap;
+      margin-left: 1rem;
     }
 
     li {
+      text-align: start;
       font-size: 16px;
-      width: 10rem;
-      margin-left: 1rem;
       line-height: 18px;
-      color: var(--primary-color);
+      color: var(--on-primary-color);
+      margin: 6px 0;
 
       @media (max-width: 1240px) {
         font-size: 1.1rem;
-        color: var(--on-primary-color);
       }
     }
 
+    @media (max-width: 1240px) {
+      margin: 0 auto;
+    }
 
     @media (max-width: 600px) {
       padding: 18px;
@@ -347,14 +342,14 @@ h4 {
         padding-bottom: 0;
       }
     }
-
   }
 }
 
 .footer {
   p {
     text-align: right;
-    font-size: 12px;
+    font-size: 14px;
+    color: var(--on-primary-color);
 
     @media (max-width: 1240px) {
       font-size: 1.1rem;

+ 60 - 60
components/JoinUs/Form.vue

@@ -1,20 +1,12 @@
 <template>
   <div>
-    <v-card
-      v-if="!jobApplicationSent"
-    >
-      <v-card-title
-        class="text-center"
-      >
+    <v-card v-if="!jobApplicationSent">
+      <v-card-title class="text-center">
         Formulaire de Candidature
       </v-card-title>
 
       <v-card-text>
-        <v-form
-          ref="form"
-          validate-on="submit lazy"
-          @submit.prevent="submit"
-        >
+        <v-form ref="form" validate-on="submit lazy" @submit.prevent="submit">
           <v-text-field
             id="jobApplicationName"
             v-model="jobApplication.name"
@@ -45,7 +37,6 @@
             :rules="[validateEmail]"
             label="Email*"
             required
-
           />
 
           <v-file-input
@@ -74,46 +65,43 @@
             label="Message*"
             required
           />
-          <span class="remaining-cars-notice">{{ leftCars }} caractères restants</span>
+          <span class="remaining-cars-notice"
+            >{{ leftCars }} caractères restants</span
+          >
 
           <div class="d-flex flex-column align-center mt-4">
             <!-- @see https://github.com/hCaptcha/vue-hcaptcha -->
-            <LayoutCaptcha/>
+            <LayoutCaptcha />
           </div>
         </v-form>
       </v-card-text>
 
-      <p class="text-right mr-6">
-        * Champs obligatoires
-      </p>
+      <p class="text-right mr-6">* Champs obligatoires</p>
 
       <v-card-actions class="justify-center">
-        <v-btn
-          class="btn-more mb-4 submit"
-          @click="submit"
-        >
-          Envoyer
-        </v-btn>
+        <v-btn class="btn-more mb-4 submit" @click="submit"> Envoyer </v-btn>
       </v-card-actions>
     </v-card>
   </div>
 </template>
 
 <script setup lang="ts">
-import ContactRequest from "~/models/Maestro/ContactRequest";
-import { useEntityManager } from "~/composables/data/useEntityManager";
-import JobApplication from "~/models/Maestro/JobApplication";
-import FileUtils from "~/services/utils/FileUtils";
+import type { ComputedRef, Ref } from 'vue'
+import { reactive } from 'vue'
+import ContactRequest from '~/models/Maestro/ContactRequest'
+import { useEntityManager } from '~/composables/data/useEntityManager'
+import JobApplication from '~/models/Maestro/JobApplication'
+import FileUtils from '~/services/utils/FileUtils'
 
 const { em } = useEntityManager()
 
-const form: Ref<any | null> = ref(null)
+const form: Ref<HTMLElement | null> = ref(null)
 
 const jobApplicationSent: Ref<boolean> = ref(false)
 
 const emit = defineEmits(['submit'])
 
-//@ts-ignore
+// @ts-ignore
 const jobApplication: ContactRequest = reactive(em.newInstance(JobApplication))
 
 const resumeUpload = ref(null)
@@ -123,40 +111,44 @@ const motivationLetterUpload = ref(null)
 // --- Validation ---
 const maxMessageLength = 2000
 
-const leftCars: ComputedRef<number> = computed(() =>
-  maxMessageLength - (jobApplication.message ? jobApplication.message.length : 0)
+const leftCars: ComputedRef<number> = computed(
+  () =>
+    maxMessageLength -
+    (jobApplication.message ? jobApplication.message.length : 0)
 )
 
 // Taille maximum en Mo
 const maxFileSize = 5
 
-const validateName = (name: string | null) => !!name || "Le nom est obligatoire";
+const validateName = (name: string | null) => !!name || 'Le nom est obligatoire'
 
-const validateSurname = (surname: string | null) => !!surname || "Le prénom est obligatoire";
+const validateSurname = (surname: string | null) =>
+  !!surname || 'Le prénom est obligatoire'
 
 const validateEmail = (email: string | null) =>
-  (!!email && /.+@.+\..+/.test(email)) || "L'adresse e-mail doit être valide";
+  (!!email && /.+@.+\..+/.test(email)) || "L'adresse e-mail doit être valide"
 
 const validatePhone = (email: string | null) =>
-  (!!email && /^((\+|00)33\s?|0)[1-7]([\s.]?\d{2}){4}$/.test(email)) || "Le numéro de téléphone doit être valide";
+  (!!email && /^((\+|00)33\s?|0)[1-7]([\s.]?\d{2}){4}$/.test(email)) ||
+  'Le numéro de téléphone doit être valide'
 
 const validateResume = () =>
-  resumeUpload.value !== null && resumeUpload.value[0] !== null || "Vous devez joindre un CV à l'un des formats indiqués";
+  (resumeUpload.value !== null && resumeUpload.value[0] !== null) ||
+  "Vous devez joindre un CV à l'un des formats indiqués"
 
 const validateFileSize = () =>
-  resumeUpload.value !== null
-  && resumeUpload.value[0] !== null
-  //@ts-ignore
-  && resumeUpload.value[0].size < (maxFileSize * 1024 * 1024)
-  || "La taille du fichier ne doit pas dépasser " + maxFileSize + " Mo";
+  (resumeUpload.value !== null &&
+    resumeUpload.value[0] !== null &&
+    // @ts-ignore
+    resumeUpload.value[0].size < maxFileSize * 1024 * 1024) ||
+  'La taille du fichier ne doit pas dépasser ' + maxFileSize + ' Mo'
 
 const validateNonEmptyMessage = (message: string | null) =>
-  (!!message && message.length > 0) ||
-  "Le message ne peut pas être vide";
+  (!!message && message.length > 0) || 'Le message ne peut pas être vide'
 
-const validateMessageLength = async (message: string | null) =>
+const validateMessageLength = (message: string | null) =>
   (!!message && message.length <= maxMessageLength) ||
-  "Le message ne doit pas dépasser " + maxMessageLength + " caractères";
+  'Le message ne doit pas dépasser ' + maxMessageLength + ' caractères'
 
 /**
  * Soumet le formulaire de candidature (boite de dialogue)
@@ -169,26 +161,33 @@ const submit = async () => {
     return
   }
 
-  jobApplication.resume = (resumeUpload.value !== null && resumeUpload.value[0] !== null) ?
-    {
-      //@ts-ignore
-      'name': resumeUpload.value[0].name,
-      'content': await FileUtils.blobToBase64(resumeUpload.value[0])
-    } : null
-
-  jobApplication.motivationLetter = (motivationLetterUpload.value !== null && motivationLetterUpload.value[0] !== null) ?
-    {
-      //@ts-ignore
-      'name': motivationLetterUpload.value[0].name,
-      'content': await FileUtils.blobToBase64(motivationLetterUpload.value[0])
-    } : null
+  jobApplication.resume =
+    resumeUpload.value !== null && resumeUpload.value[0] !== null
+      ? {
+          // @ts-ignore
+          name: resumeUpload.value[0].name,
+          content: await FileUtils.blobToBase64(resumeUpload.value[0]),
+        }
+      : null
+
+  jobApplication.motivationLetter =
+    motivationLetterUpload.value !== null &&
+    motivationLetterUpload.value[0] !== null
+      ? {
+          // @ts-ignore
+          name: motivationLetterUpload.value[0].name,
+          content: await FileUtils.blobToBase64(
+            motivationLetterUpload.value[0]
+          ),
+        }
+      : null
 
   await em.persist(JobApplication, jobApplication)
 
-  jobApplicationSent.value = true;
+  jobApplicationSent.value = true
 
   emit('submit')
-};
+}
 </script>
 
 <style scoped lang="scss">
@@ -196,6 +195,7 @@ const submit = async () => {
   width: 100%;
   margin-bottom: 0 !important;
   height: 55px;
+  background: var(--secondary-color);
 }
 
 .submit:hover {

+ 33 - 42
components/JoinUs/MissionDetail.vue

@@ -1,7 +1,7 @@
 <template>
   <LayoutContainer>
     <div class="job-section">
-      <v-row class="mb-6">
+      <v-row class="mb-6 center-90">
         <v-col class="d-flex align-items-center">
           <v-btn
             to="/nous-rejoindre"
@@ -17,22 +17,16 @@
       <div>
         <div v-if="pending">
           <v-row class="justify-center progress">
-            <v-progress-circular
-              indeterminate
-              color="grey"
-            />
+            <v-progress-circular indeterminate color="grey" />
           </v-row>
         </div>
 
         <div v-else-if="job !== null">
-          <CommonMeta
-            :title="job.title"
-            description="Offre d'emploi"
-          />
+          <CommonMeta :title="job.title" description="Offre d'emploi" />
 
-          <LayoutUITitlePage>
+          <h3>
             {{ job.title }}
-          </LayoutUITitlePage>
+          </h3>
 
           <v-row class="details blue-content my-6">
             <v-col cols="12" md="6">
@@ -45,7 +39,7 @@
 
               <v-row>
                 <div>
-                  Location :
+                  Localisation :
                   <b>{{ job.postalCode }} {{ job.city }}</b>
                 </div>
               </v-row>
@@ -67,26 +61,16 @@
             </v-col>
           </v-row>
 
-          <v-row>
-            <p
-              v-html="job.content"
-              class="center-90 description mb-12"
-            />
+          <v-row class="center-90">
+            <p class="center-90 description mb-12" v-html="job.content" />
           </v-row>
 
           <v-row class="d-flex justify-center align-center">
-            <v-btn
-              prepend-icon="fas fa-info"
-              class="btn-apply mb-12"
-            >
-              Je postule
-            </v-btn>
+            <v-btn class="btn-apply mb-12"> Je postule </v-btn>
           </v-row>
 
           <v-row class="d-flex justify-space-between center-90">
-            <p>
-              MOTS CLÉS
-            </p>
+            <p>MOTS CLÉS</p>
             <div v-if="mdAndUp">
               <p>PARTAGER</p>
             </div>
@@ -94,7 +78,7 @@
 
           <v-row class="d-flex justify-space-between mb-8 center-90">
             <p class="key-word mt-3">
-              <span v-for="tag in job.tags" class="mr-2">
+              <span v-for="tag in job.tags" :key="tag.id" class="mr-2">
                 {{ tag.name }}
               </span>
             </p>
@@ -108,20 +92,19 @@
         </div>
       </div>
     </div>
-
   </LayoutContainer>
 </template>
 
 <script setup lang="ts">
-import "vue3-carousel/dist/carousel.css";
-import { useEntityFetch } from "~/composables/data/useEntityFetch";
-import JobPosting from "~/models/Maestro/JobPosting";
-import DateUtils from "~/services/utils/dateUtils";
-import { useDisplay } from "vuetify";
+import 'vue3-carousel/dist/carousel.css'
+import { useDisplay } from 'vuetify'
+import { useEntityFetch } from '~/composables/data/useEntityFetch'
+import JobPosting from '~/models/Maestro/JobPosting'
+import DateUtils from '~/services/utils/dateUtils'
 
 const { mdAndUp, smAndDown } = useDisplay()
 
-const route = useRoute();
+const route = useRoute()
 const { fetch } = useEntityFetch()
 
 const jobId: number = parseInt(route.params.id as string)
@@ -134,10 +117,10 @@ const { data: job, pending } = fetch(JobPosting, jobId)
 const formatDate = (date: string) => {
   console.log(date)
   if (!date) {
-    return "-"
+    return '-'
   }
-  return DateUtils.format(new Date(date), "dd/MM/yyyy")
-};
+  return DateUtils.format(new Date(date), 'dd/MM/yyyy')
+}
 </script>
 
 <style scoped lang="scss">
@@ -146,9 +129,17 @@ const formatDate = (date: string) => {
 }
 
 .job-section {
-  margin: 32px 12%;
+  margin: 32px 0;
+
+  h3 {
+    font-size: 32px;
+    width: 100%;
+    text-align: center;
+    text-transform: uppercase;
+  }
 
   .details {
+    padding: 0 20%;
     background-color: var(--secondary-color);
     color: var(--on-secondary-color);
     height: 10rem;
@@ -176,11 +167,11 @@ const formatDate = (date: string) => {
   }
 
   .description {
-    color: var(--primary-color);
-    text-align: justify;
-    font-size: 1.875rem;
+    color: var(--on-neutral-color);
+    font-size: 21px;
     font-weight: 500;
     line-height: 2.125rem;
+    padding: 12px 36px;
   }
 }
 
@@ -192,7 +183,7 @@ const formatDate = (date: string) => {
 
 .btn-apply {
   background: var(--secondary-color);
-  color: var(--neutral-color);
+  color: var(--on-secondary-color);
   display: flex;
   left: 0;
   padding: 25px 28px;

+ 38 - 53
components/JoinUs/Missions.vue

@@ -2,46 +2,34 @@
   <LayoutContainer>
     <div v-if="pending">
       <v-row class="justify-center progress">
-        <v-progress-circular
-          indeterminate
-          color="grey"
-        />
+        <v-progress-circular indeterminate color="grey" />
       </v-row>
     </div>
 
     <div
-      v-else
       v-for="(job, index) in jobs"
+      v-else
       :key="index"
       class="mission-container"
     >
       <div class="title-container">
-        <NuxtLink
-          :to="`/nous-rejoindre/${job.id}`"
-          class="title"
-        >
+        <NuxtLink :to="`/nous-rejoindre/${job.id}`" class="title">
           {{ job.title }} - {{ job.contractType }}
 
-          <v-icon
-            v-if="job.featured"
-            class="star fas fa-star"
-          />
+          <v-icon v-if="job.featured" class="star fas fa-star" />
         </NuxtLink>
 
-        <v-btn
-          :to="`/nous-rejoindre/${job.id}`"
-          class="btn-more"
-        >
+        <v-btn :to="`/nous-rejoindre/${job.id}`" class="btn-more">
           En savoir plus
         </v-btn>
       </div>
 
-      <v-row class="location-container">
+      <div class="location-container">
         <v-icon icon="fas fa-map-marker" />
         <div class="location">
           {{ job.city }}
         </div>
-      </v-row>
+      </div>
     </div>
 
     <v-row>
@@ -50,8 +38,8 @@
           v-if="jobCollection && jobCollection.pagination"
           :model-value="page"
           :pagination="jobCollection.pagination"
-          @update:model-value="onPageUpdated"
           class="mt-4"
+          @update:model-value="onPageUpdated"
         />
       </v-col>
     </v-row>
@@ -59,18 +47,15 @@
     <v-row class="mb-6">
       <v-col cols="12">
         <p class="apply-now">
-          Nous sommes toujours à la recherche de nouveaux talents. N'hésitez pas
-          à déposer votre candidature ci-dessous :
+          Nous sommes toujours à la recherche de nouveaux talents.<br />
+          N'hésitez pas à déposer votre candidature ci-dessous :
         </p>
       </v-col>
     </v-row>
 
     <v-row>
       <v-col cols="12">
-        <v-btn
-          class="btn-send"
-          @click="dialog = true"
-        >
+        <v-btn class="btn-send" @click="dialog = true">
           Envoyer ma candidature
         </v-btn>
       </v-col>
@@ -85,51 +70,47 @@
       :retain-focus="false"
     >
       <div v-if="!jobApplicationSent">
-        <JoinUsForm @submit="onFormSubmit"/>
+        <JoinUsForm @submit="onFormSubmit" />
 
-        <v-btn @click="dialog = false">
-          Annuler
-        </v-btn>
+        <v-btn @click="dialog = false"> Annuler </v-btn>
       </div>
       <div v-else>
         <v-card class="pa-6 text-center">
-          Votre candidature a bien été envoyée, merci de votre intérêt.<br/>
+          Votre candidature a bien été envoyée, merci de votre intérêt.<br />
           Nous vous recontacterons dès que possible.
         </v-card>
 
-        <v-btn @click="dialog = false">
-          Fermer
-        </v-btn>
+        <v-btn @click="dialog = false"> Fermer </v-btn>
       </div>
     </v-dialog>
   </LayoutContainer>
 </template>
 
 <script setup lang="ts">
-import { useEntityFetch } from "~/composables/data/useEntityFetch";
-import JobPosting from "~/models/Maestro/JobPosting";
-import type { AnyJson } from "~/types/data";
+import type { ComputedRef, Ref } from 'vue'
+import { useEntityFetch } from '~/composables/data/useEntityFetch'
+import JobPosting from '~/models/Maestro/JobPosting'
+import type { AnyJson } from '~/types/data'
 
 const { fetchCollection } = useEntityFetch()
 
-const page: Ref<number> = ref(1);
+const page: Ref<number> = ref(1)
 
 const query: ComputedRef<AnyJson> = computed(() => {
-    return { type: "ENTREPRISE", page: page.value }
-  }
-)
+  return { type: 'ENTREPRISE', page: page.value }
+})
 
-const { data: jobCollection, pending, refresh } = fetchCollection(
-  JobPosting,
-  null,
-  query
-)
+const {
+  data: jobCollection,
+  pending,
+  refresh,
+} = fetchCollection(JobPosting, null, query)
 
 // TODO: voir pourquoi on se retrouve obligé de passer par ce computed pour avoir le type TS correct?
 const jobs: ComputedRef<JobPosting[]> = computed(() => {
-  return jobCollection.value !== null ?
-         jobCollection.value.items as JobPosting[] :
-         []
+  return jobCollection.value !== null
+    ? (jobCollection.value.items as JobPosting[])
+    : []
 })
 
 const onPageUpdated = async (newVal: number): Promise<void> => {
@@ -148,7 +129,7 @@ const onPageUpdated = async (newVal: number): Promise<void> => {
 /**
  * Faut-il afficher la boite de dialogue de candidature
  */
-const dialog = ref(false);
+const dialog = ref(false)
 const jobApplicationSent: Ref<boolean> = ref(false)
 
 const onFormSubmit = () => {
@@ -164,12 +145,15 @@ const onFormSubmit = () => {
 .v-btn {
   font-weight: 600;
   height: 50px;
-  background: var(--secondary-color);
   border-radius: 6px;
-  color: var(--on-secondary-color);
+  color: var(--on-neutral-color);
   gap: 9px;
 }
 
+.v-btn:hover {
+  background-color: var(--on-neutral-color-extra-light);
+}
+
 .mission-container {
   margin: 64px 12%;
 
@@ -258,6 +242,7 @@ const onFormSubmit = () => {
   margin-left: auto;
   margin-right: auto;
   font-weight: 700;
+  background-color: var(--secondary-color);
 
   @media (max-width: 600px) {
     width: 80%;
@@ -269,7 +254,7 @@ const onFormSubmit = () => {
   text-align: center;
   font-style: italic;
   font-weight: 300;
-  font-size: 34px;
+  font-size: 1.5rem;
   line-height: 40px;
   color: var(--primary-color);
   margin-bottom: 2rem;

+ 33 - 37
components/Layout/AnchoredSection.vue

@@ -1,55 +1,51 @@
 <template>
-  <div
-    :id="id"
-    ref="section"
-    v-scroll="onScroll"
-  >
-    <slot/>
+  <div :id="id" ref="section" v-scroll="onScroll">
+    <slot />
   </div>
 </template>
 
 <script setup lang="ts">
-  import { useLayoutStore } from "~/stores/layoutStore";
+import type { Ref } from 'vue'
+import { useLayoutStore } from '~/stores/layoutStore'
 
-  const layoutStore = useLayoutStore()
+const layoutStore = useLayoutStore()
 
-  const props = defineProps({
-    id: {
-      type: String,
-      required: true
-    }
-  })
+const props = defineProps({
+  id: {
+    type: String,
+    required: true,
+  },
+})
 
-  if (!props.id) {
-    throw new Error("Anchor's id is missing")
-  }
+if (!props.id) {
+  throw new Error("Anchor's id is missing")
+}
 
-  const section: Ref<HTMLElement | null> = ref(null)
+const section: Ref<HTMLElement | null> = ref(null)
 
-  layoutStore.setIsAnchoredSectionOnScreen(props.id, false)
+layoutStore.setIsAnchoredSectionOnScreen(props.id, false)
 
-  const top: Ref<number | null> = ref(null)
-  const bottom: Ref<number | null> = ref(null)
+const top: Ref<number | null> = ref(null)
+const bottom: Ref<number | null> = ref(null)
 
-  const onScroll = (scroll: any) => {
-    top.value = section.value!.offsetTop
-    bottom.value = section.value!.offsetTop + section.value!.offsetHeight
+// @ts-ignore
+const onScroll = (scroll) => {
+  top.value = section.value!.offsetTop
+  bottom.value = section.value!.offsetTop + section.value!.offsetHeight
 
-    if (top.value === null || bottom.value === null) {
-      return
-    }
+  if (top.value === null || bottom.value === null) {
+    return
+  }
 
-    const screenVerticalCenter = scroll.target.documentElement.scrollTop + window.innerHeight / 2
+  const screenVerticalCenter =
+    scroll.target.documentElement.scrollTop + window.innerHeight / 2
 
-    const active = screenVerticalCenter > top.value && screenVerticalCenter < bottom.value
-    if (active !== layoutStore.isAnchoredSectionOnScreen[props.id]) {
-        layoutStore.setIsAnchoredSectionOnScreen(
-          props.id,
-          active
-        )
-    }
+  const active =
+    screenVerticalCenter > top.value && screenVerticalCenter < bottom.value
+  if (active !== layoutStore.isAnchoredSectionOnScreen[props.id]) {
+    layoutStore.setIsAnchoredSectionOnScreen(props.id, active)
   }
+}
 </script>
 
-<style scoped>
-</style>
+<style scoped></style>

+ 39 - 36
components/Layout/Captcha.vue

@@ -1,29 +1,32 @@
 <template>
-  <vue-hcaptcha
-    :sitekey="siteKey"
-    @verify="onVerify"
-    @expired="onExpire"
-    @challenge-expired="onChallengeExpire"
-    @error="onError"
-  />
-  <v-checkbox
-    v-model="honeyPotChecked"
-    :rules="[validateCaptchaState]"
-    class="hidden-ctrl"
-  />
+  <div class="d-flex flex-column">
+    <vue-hcaptcha
+      :sitekey="siteKey"
+      @verify="onVerify"
+      @expired="onExpire"
+      @challenge-expired="onChallengeExpire"
+      @error="onError"
+    />
+    <v-checkbox
+      v-model="honeyPotChecked"
+      :rules="[validateCaptchaState]"
+      class="hidden-ctrl"
+    />
+  </div>
 </template>
 
 <script setup lang="ts">
-import VueHcaptcha from "@hcaptcha/vue3-hcaptcha";
+import VueHcaptcha from '@hcaptcha/vue3-hcaptcha'
+import type { Ref } from 'vue'
 
 const runtimeConfig = useRuntimeConfig()
 const siteKey = runtimeConfig.public.hCaptchaSiteKey
 
-const verified: Ref<boolean> = ref(false);
-const expired: Ref<boolean> = ref(false);
-const token: Ref<string> = ref("");
-const eKey: Ref<string> = ref("");
-const error: Ref<string> = ref("");
+const verified: Ref<boolean> = ref(false)
+const expired: Ref<boolean> = ref(false)
+const token: Ref<string> = ref('')
+const eKey: Ref<string> = ref('')
+const error: Ref<string> = ref('')
 
 // La case étant masquée, si elle est cochée, alors on peut en déduire
 // qu'on a affaire un robot (voir mécanisme du honey pot)
@@ -32,39 +35,39 @@ const honeyPotChecked: Ref<boolean> = ref(false)
 const emit = defineEmits(['update'])
 
 const validateCaptchaState = () =>
-  verified.value && !honeyPotChecked.value ||
-  "Veuillez procédez à la vérification";
+  (verified.value && !honeyPotChecked.value) ||
+  'Veuillez procéder à la vérification'
 
 function onVerify(tokenStr: string, ekey: string) {
-  verified.value = true;
-  token.value = tokenStr;
-  eKey.value = ekey;
+  verified.value = true
+  token.value = tokenStr
+  eKey.value = ekey
   emit('update', true)
 }
 
 function onExpire() {
-  verified.value = false;
-  token.value = '';
-  eKey.value = '';
-  expired.value = true;
+  verified.value = false
+  token.value = ''
+  eKey.value = ''
+  expired.value = true
 }
 
 function onChallengeExpire() {
-  verified.value = false;
-  token.value = '';
-  eKey.value = '';
-  expired.value = true;
+  verified.value = false
+  token.value = ''
+  eKey.value = ''
+  expired.value = true
 }
 
 function onError(err: string) {
-  token.value = '';
-  eKey.value = '';
-  error.value = err;
-  console.log(`Error: ${err}`);
+  token.value = ''
+  eKey.value = ''
+  error.value = err
+  console.log(`Error: ${err}`)
 
   if (process.dev) {
     console.log('Dev mode: force captcha validation')
-    verified.value = true;
+    verified.value = true
   }
 }
 </script>

+ 21 - 25
components/Layout/FAQ.vue

@@ -7,8 +7,8 @@
         </LayoutUISubTitle>
 
         <h3 class="mt-6">
-          Quelle que soit votre demande, notre équipe est à vos côtés pour
-          vous guider
+          Quelle que soit votre demande, notre équipe est à vos côtés pour vous
+          guider
         </h3>
 
         <v-btn
@@ -22,34 +22,28 @@
 
       <v-col cols="12" lg="6" class="links">
         <v-btn
-          href="https://ressources.opentalent.fr/pages/viewpage.action?pageId=75170564"
+          href="https://ressources.opentalent.fr/space/FAQ/2496592/Tutoriels+vid%C3%A9os"
           target="_blank"
         >
           <div>
             <v-img
-              src="/images/icons/tuto.svg"
+              src="/images/components/faq/Icone_tutoriels-videos.svg"
               alt="Icône livre avec logo Youtube"
             />
 
-            <p>
-              De nombreux articles tutoriels accessibles 24h/24
-            </p>
+            <p>De nombreux articles tutoriels accessibles 24h/24</p>
           </div>
         </v-btn>
 
-        <v-btn
-          href="https://ressources.opentalent.fr/?contact"
-          target="_blank"
-        >
+        <v-btn href="https://ressources.opentalent.fr/" target="_blank">
           <div>
             <v-img
-              src="/images/icons/faq.svg"
+              src="/images/components/faq/Icone_FAQ.svg"
               alt="Icône deux bulles de conversation avec indiquée FAQ à l’intérieur d’une"
             />
 
             <p class="text-btn">
-              Support accessible du lundi au vendredi via l’outil en
-              ligne
+              Support accessible du lundi au vendredi via l’outil en ligne
             </p>
           </div>
         </v-btn>
@@ -58,6 +52,7 @@
   </div>
 </template>
 
+<script setup lang="ts"></script>
 <style scoped lang="scss">
 .v-row {
   position: relative;
@@ -67,7 +62,7 @@
 
 .main {
   min-height: 600px;
-  background-image: url("/images/logiciels/school/faq.jpg");
+  background-image: url('/images/components/faq/Orchestre_de_rue_avec_danseuse.jpg');
   background-size: cover;
   background-position: center 15%;
   background-repeat: no-repeat;
@@ -80,7 +75,7 @@
 }
 
 .main::after {
-  content: "";
+  content: '';
   position: absolute;
   top: 0;
   left: 0;
@@ -91,7 +86,7 @@
 }
 
 h3 {
-  margin-left: 3rem;
+  margin-left: 20px;
   margin-right: 15rem;
   width: 28rem;
   margin-bottom: 3rem;
@@ -108,14 +103,19 @@ h3 {
 .btn-faq {
   width: 14rem;
   height: 3.5rem;
-  margin-left: 3rem;
+  margin-left: 20px;
   border-radius: 6px;
   font-weight: 500;
   font-size: 0.8rem;
   z-index: 2;
   text-transform: none !important;
   line-height: 1rem;
+  margin-right: auto;
 
+  @media (max-width: 1240px) {
+    width: 40%;
+    margin-left: 30%;
+  }
 
   @media (max-width: 600px) {
     width: 90%;
@@ -143,15 +143,15 @@ h3 {
     height: 5.5rem;
     margin-left: 3rem;
     border-radius: 6px;
-    background: transparent;
     font-weight: 500;
     font-size: 0.8rem;
     line-height: 1rem;
     border: 1px var(--on-alt-theme) solid;
     margin-bottom: 2rem;
     text-transform: none !important;
+    background: rgba(0, 0, 0, 0.6);
 
-    .v-btn__content>div {
+    .v-btn__content > div {
       display: flex;
       flex-direction: row;
       align-items: center;
@@ -179,7 +179,7 @@ h3 {
       margin: 12px 5%;
       height: 8rem;
 
-      .v-btn__content>div {
+      .v-btn__content > div {
         display: flex;
         flex-direction: column;
         align-items: center;
@@ -198,9 +198,5 @@ h3 {
       max-width: 90%;
     }
   }
-
-
 }
 </style>
-<script setup lang="ts">
-</script>

+ 99 - 111
components/Layout/Footer/Footer.vue

@@ -6,43 +6,36 @@
         <v-row>
           <!-- Première section : Logo Opentalent -->
           <v-col cols="12" lg="3" class="logo">
-            <nuxt-link to="/">
-              <v-img src="/images/logo/footer-logo.png" alt="Logo Opentalent - Agenda et Logiciels culturels" />
+            <nuxt-link :to="{ path: '/', hash: '#top' }">
+              <v-img
+                src="/images/logos/opentalent/Logo_Opentalent-blanc.png"
+                alt="Logo Opentalent - Agenda et Logiciels culturels"
+              />
             </nuxt-link>
           </v-col>
 
           <!-- Deuxième section : liens agenda culturel (écrans larges seulement) -->
-          <v-col v-if="mdAndUp" cols="7" >
+          <v-col v-if="lgAndUp" cols="7">
             <v-row>
               <v-col cols="3">
                 <v-row>
-                  <h5>
-                    Agenda culturel
-                  </h5>
+                  <h5>Agenda</h5>
                 </v-row>
                 <v-row>
-                  <AgendaLink href="/annuaire">
-                    Annuaire
-                  </AgendaLink>
+                  <AgendaLink href="/annuaire"> Annuaire </AgendaLink>
                 </v-row>
                 <v-row>
-                  <AgendaLink href="/actualites">
-                    Actualités
-                  </AgendaLink>
+                  <AgendaLink href="/actualites"> Actualités </AgendaLink>
                 </v-row>
                 <v-row>
-                  <AgendaLink href="/annonces">
-                    Annonces
-                  </AgendaLink>
+                  <AgendaLink href="/annonces"> Annonces </AgendaLink>
                 </v-row>
               </v-col>
 
               <!-- Troisième section : liens logiciels culturels (écrans larges seulement) -->
               <v-col cols="3">
                 <v-row>
-                  <h5>
-                    Logiciels culturels
-                  </h5>
+                  <h5>Logiciels</h5>
                 </v-row>
                 <v-row>
                   <nuxt-link to="/opentalent_artist">
@@ -52,8 +45,7 @@
                 <v-row>
                   <nuxt-link to="/opentalent_school">
                     Opentalent School
-                  </nuxt-link
-                  >
+                  </nuxt-link>
                 </v-row>
                 <v-row>
                   <nuxt-link to="/opentalent_manager">
@@ -65,60 +57,48 @@
               <!-- Quatrième section : A propos (écrans larges seulement) -->
               <v-col cols="3">
                 <v-row>
-                  <h5>
-                    A PROPOS
-                  </h5>
+                  <h5>A PROPOS</h5>
                 </v-row>
                 <v-row>
-                  <nuxt-link to="/qui-sommes-nous">
-                    Qui sommes-nous
-                  </nuxt-link>
+                  <nuxt-link to="/qui-sommes-nous"> Qui sommes-nous </nuxt-link>
                 </v-row>
                 <v-row>
-                  <nuxt-link to="/nous-rejoindre">
-                    Nous rejoindre
-                  </nuxt-link
-                  >
+                  <nuxt-link to="/nous-rejoindre"> Nous rejoindre </nuxt-link>
                 </v-row>
                 <v-row>
-                  <nuxt-link to="/nous-contacter">
-                    Nous contacter
-                  </nuxt-link>
+                  <nuxt-link to="/nous-contacter"> Nous contacter </nuxt-link>
                 </v-row>
               </v-col>
 
               <!-- Cinquième section : liens espace client (écrans larges seulement) -->
               <v-col cols="3">
                 <v-row>
-                  <h5>
-                    Espace client
-                  </h5>
+                  <h5>Espace client</h5>
                 </v-row>
                 <v-row>
-                  <nuxt-link href="https://ressources.opentalent.fr/display/FAQ/Accueil" target="_blank">
+                  <nuxt-link
+                    href="https://ressources.opentalent.fr/display/FAQ/Accueil"
+                    target="_blank"
+                  >
                     Foire Aux Questions
                   </nuxt-link>
                 </v-row>
                 <v-row>
-                  <nuxt-link href="https://ressources.opentalent.fr/" target="_blank">
+                  <nuxt-link
+                    href="https://ressources.opentalent.fr/"
+                    target="_blank"
+                  >
                     Support en ligne
                   </nuxt-link>
                 </v-row>
-                <v-row>
-                  <nuxt-link to="/nous-contacter" target="_blank" >
-                    Nous contacter
-                  </nuxt-link>
-                </v-row>
               </v-col>
             </v-row>
           </v-col>
 
           <!-- Sixième section : liens réseaux sociaux (écrans larges seulement) -->
-          <v-col v-if="mdAndUp" cols="2">
+          <v-col v-if="lgAndUp" cols="2">
             <v-row class="justify-center">
-              <h5>
-                Suivez-nous
-              </h5>
+              <h5>Suivez-nous</h5>
             </v-row>
 
             <v-row class="justify-center social-networks">
@@ -156,10 +136,7 @@
         </v-row>
 
         <!-- Deuxième section alt : version petits écrans -->
-        <v-row
-          v-if="mdAndDown"
-          class="justify-center social-networks"
-        >
+        <v-row v-if="mdAndDown" class="justify-center social-networks">
           <!-- TODO: voir si faisable de fusionner avec la section précédente -->
           <v-col cols="12" class="text-center">
             <nuxt-link
@@ -188,7 +165,7 @@
 
       <!-- Troisième section alt : version petits écrans -->
       <v-row v-if="mdAndDown">
-        <v-col cols="12" >
+        <v-col cols="12">
           <div v-for="(item, index) in footerLinks" :key="index">
             <v-container>
               <div class="section" @click="toggleSection(index)">
@@ -196,23 +173,26 @@
                   {{ item.label }}
 
                   <v-icon
-                    :icon="isActive(index) ? 'fas fa-chevron-up' : 'fas fa-chevron-down'"
+                    :icon="
+                      isActive(index)
+                        ? 'fas fa-chevron-up'
+                        : 'fas fa-chevron-down'
+                    "
                   />
                 </div>
 
                 <div
-                  v-show="isActive(index)"
                   v-for="(sublink, sublinkIndex) in item.sublink"
+                  v-show="isActive(index)"
                   :key="sublinkIndex"
                   class="mt-3"
                 >
-                  <nuxt-link :href="sublink.link">
+                  <CommonAgendaLink :href="sublink.link">
                     {{ sublink.label }}
-                  </nuxt-link>
+                  </CommonAgendaLink>
                 </div>
               </div>
             </v-container>
-
           </div>
         </v-col>
       </v-row>
@@ -220,23 +200,21 @@
       <div class="footnotes">
         <v-row justify="center">
           <p class="mt-6">
-            <nuxt-link to="/mentions-legales">
-              Mentions légales
-            </nuxt-link>
+            <nuxt-link to="/mentions-legales"> Mentions légales </nuxt-link>
             -
-            <nuxt-link to="/politique-de-confidentialite-et-protection-des-donnees-personnelles">
-              Politiques de cookies
+            <nuxt-link
+              to="/politique-de-confidentialite-et-protection-des-donnees-personnelles"
+            >
+              Politiques de confidentialité
             </nuxt-link>
             -
-            <nuxt-link to="/CGV">
-              Conditions Générales de Ventes
-            </nuxt-link>
+            <nuxt-link to="/CGV"> Conditions Générales de Ventes </nuxt-link>
           </p>
         </v-row>
 
-        <v-row class="mb-6" justify="center">
+        <v-row class="mb-3" justify="center">
           <p>
-            2024 &copy; Tous droits réservés par Opentalent
+            2024 © Opentalent est une marque déposée par 2iOPENservice
           </p>
         </v-row>
       </div>
@@ -245,111 +223,114 @@
 </template>
 
 <script setup>
-import { useDisplay } from "vuetify";
-import { useLayoutStore } from "~/stores/layoutStore";
-import AgendaLink from "~/components/Common/AgendaLink.vue";
-
+import { useDisplay } from 'vuetify'
+import { useLayoutStore } from '~/stores/layoutStore'
+import AgendaLink from '~/components/Common/AgendaLink.vue'
 
-const { mdAndDown, mdAndUp } = useDisplay();
+const { mdAndDown, lgAndUp } = useDisplay()
 
 const footerLinks = ref([
   {
-    label: "AGENDA CULTUREL",
+    label: 'AGENDA CULTUREL',
     sublink: [
       {
-        label: "Annuaire",
-        link: "/annuaire",
+        label: 'Annuaire',
+        link: '/annuaire',
       },
       {
-        label: "Actualités",
-        link: "/actualites",
+        label: 'Actualités',
+        link: '/actualites',
       },
       {
-        label: "Annonces",
-        link: "/annonces",
+        label: 'Annonces',
+        link: '/annonces',
       },
     ],
   },
   {
-    label: "LOGICIELS CULTURELS ",
+    label: 'LOGICIELS CULTURELS ',
     sublink: [
       {
-        label: "Opentalent Artist",
-        link: "/opentalent_artist",
+        label: 'Opentalent Artist',
+        link: '/opentalent_artist',
       },
       {
-        label: "Opentalent School",
-        link: "/opentalent_school",
+        label: 'Opentalent School',
+        link: '/opentalent_school',
       },
       {
-        label: "Opentalent Manager",
-        link: "/opentalent_manager",
+        label: 'Opentalent Manager',
+        link: '/opentalent_manager',
       },
     ],
   },
   {
-    label: "À PROPOS ",
+    label: 'À PROPOS ',
     sublink: [
       {
-        label: "Qui sommes-nous",
-        link: "/qui-sommes-nous",
+        label: 'Qui sommes-nous',
+        link: '/qui-sommes-nous',
       },
       {
-        label: "Nous rejoindre",
-        link: "/nous-rejoindre",
+        label: 'Nous rejoindre',
+        link: '/nous-rejoindre',
       },
       {
-        label: "Nous contacter",
-        link: "/nous-contacter",
+        label: 'Nous contacter',
+        link: '/nous-contacter',
       },
     ],
   },
   {
-    label: "ESPACE CLIENT ",
+    label: 'ESPACE CLIENT ',
     sublink: [
       {
-        label: "Foire Aux Questions ",
-        link: "/ https://ressources.opentalent.fr",
+        label: 'Foire Aux Questions ',
+        link: '/ https://ressources.opentalent.fr',
       },
       {
-        label: "Support en ligne ",
-        link: "/https://ressources.opentalent.fr/?contact",
+        label: 'Support en ligne ',
+        link: '/https://ressources.opentalent.fr/?contact',
       },
       {
-        label: "Nous contacter ",
-        link: "/nous-contacter",
+        label: 'Nous contacter ',
+        link: '/nous-contacter',
       },
     ],
   },
-]);
+])
 
-const activeIndex = ref(-1);
+const activeIndex = ref(-1)
 function toggleSection(index) {
-  activeIndex.value = activeIndex.value === index ? -1 : index;
+  activeIndex.value = activeIndex.value === index ? -1 : index
 }
 
 function isActive(index) {
-  return activeIndex.value === index;
+  return activeIndex.value === index
 }
 
 const layoutStore = useLayoutStore()
 const onIntersect = (isIntersecting) => {
   layoutStore.setIsFooterVisible(isIntersecting)
 }
-
 </script>
 
 <style scoped lang="scss">
-
 .container {
   background: var(--primary-color);
   color: var(--on-primary-color);
 }
 
+.logo {
+  display: flex;
+  flex-direction: row;
+  justify-content: center;
+  margin-bottom: 20px;
+}
+
 .logo .v-img {
-  margin-bottom: 3rem;
+  height: 120px;
   width: 300px;
-  height: 100px;
 }
 
 .v-col {
@@ -385,13 +366,21 @@ a {
     font-size: 1.9rem;
     text-decoration: none !important;
   }
+
+  @media (max-width: 1240px) {
+    a {
+      margin: 0 3%;
+      font-size: 2.4rem;
+    }
+  }
 }
 
 .footnotes {
   border-top: 0.4px solid var(--neutral-color-alt-strong);
   box-shadow: 0 3px 24px rgba(0, 0, 0, 0.07);
 
-  a, p {
+  a,
+  p {
     text-decoration: none;
     color: var(--on-primary-color);
     font-size: 0.8rem;
@@ -399,7 +388,6 @@ a {
     @media (max-width: 600px) {
       max-width: 90%;
       text-align: center;
-
     }
   }
 }
@@ -432,7 +420,7 @@ a {
     font-size: 1.5rem;
     cursor: pointer;
 
-    >div:first-child {
+    > div:first-child {
       border-bottom: 1px solid var(--on-primary-color);
       padding-bottom: 6px;
       text-transform: uppercase;

+ 13 - 7
components/Layout/Footer/Prefooter.vue

@@ -10,7 +10,7 @@ Première section du footer (galerie des logiciels)
         <v-col cols="4" class="text-center">
           <nuxt-link to="/opentalent_artist">
             <v-img
-              src="/images/logo/logiciels/Artist-noir.png"
+              src="/images/logos/opentalent/Logo_Opentalent_Artist-gris.png"
               alt="Logo Opentalent Artist - logiciel de gestion et de communication pour les orchestres, les chorales, les compagnies artistiques et troupes"
             />
           </nuxt-link>
@@ -25,7 +25,7 @@ Première section du footer (galerie des logiciels)
         <v-col cols="4" class="text-center">
           <nuxt-link to="/opentalent_school">
             <v-img
-              src="/images/logo/logiciels/School-noir.png"
+              src="/images/logos/opentalent/Logo_Opentalent_School-gris.png"
               alt="Logo Opentalent School - logiciel de gestion et de communication pour les établissements d’enseignement artistique "
             />
           </nuxt-link>
@@ -40,7 +40,7 @@ Première section du footer (galerie des logiciels)
         <v-col cols="3" class="text-center">
           <nuxt-link to="/opentalent_manager">
             <v-img
-              src="/images/logo/logiciels/Manager-noir.png"
+              src="/images/logos/opentalent/Logo_Opentalent_Manager-gris.png"
               alt="Logo Opentalent Manager - logiciel de gestion et de communication pour les fédérations, les confédérations et les collectivités"
             />
           </nuxt-link>
@@ -57,7 +57,9 @@ Première section du footer (galerie des logiciels)
       <v-row class="justify-center">
         <v-col cols="3" class="border-right">
           <nuxt-link to="/opentalent_artist">
-            <v-img src="/images/logo/logiciels/&_Jaune.png"/>
+            <v-img
+              src="/images/logos/opentalent/Logo_Opentalent_Artist_Griffe.png"
+            />
           </nuxt-link>
         </v-col>
 
@@ -67,7 +69,9 @@ Première section du footer (galerie des logiciels)
 
         <v-col cols="3">
           <nuxt-link to="/opentalent_school">
-            <v-img src="/images/logo/logiciels/&_Bleu.png"/>
+            <v-img
+              src="/images/logos/opentalent/Logo_Opentalent_School_Griffe.png"
+            />
           </nuxt-link>
         </v-col>
 
@@ -77,7 +81,9 @@ Première section du footer (galerie des logiciels)
 
         <v-col cols="3">
           <nuxt-link to="/opentalent_manager">
-            <v-img src="/images/logo/logiciels/&_Rouge.png"/>
+            <v-img
+              src="/images/logos/opentalent/Logo_Opentalent_Manager_Griffe.png"
+            />
           </nuxt-link>
         </v-col>
       </v-row>
@@ -86,7 +92,7 @@ Première section du footer (galerie des logiciels)
 </template>
 
 <script setup lang="ts">
-import { useDisplay } from "vuetify";
+import { useDisplay } from 'vuetify'
 
 const { lgAndUp } = useDisplay()
 </script>

+ 0 - 199
components/Layout/Footer/Solutions.vue

@@ -1,199 +0,0 @@
-<template>
-  <div id="solutions">
-    <LayoutContainer>
-      <v-row class="center-90">
-        <v-col cols="12">
-          <LayoutUISubTitle>
-            NOS LOGICIELS OPENTALENT
-          </LayoutUISubTitle>
-
-          <LayoutUITitle>
-            Ces solutions peuvent aussi vous intéresser
-          </LayoutUITitle>
-        </v-col>
-      </v-row>
-
-      <v-row
-        v-if="showArtist"
-        class="row-artist"
-      >
-        <v-col cols="6" md="2">
-          <NuxtLink to="/opentalent_artist">
-            <v-img src="/images/logo/logiciels/Artist-noir.png" class="logo" />
-          </NuxtLink>
-        </v-col>
-
-        <v-col cols="6" md="10">
-          <!-- list v-chip-->
-          <v-chip-group column disabled>
-            <v-chip class="ma-2 chip-custom" label>
-              <span class="chip-detail">Orchestres</span>
-            </v-chip>
-            <v-chip class="ma-2 chip-custom" label>
-              <span class="chip-detail">Chorales</span>
-            </v-chip>
-            <v-chip class="ma-2 chip-custom" label>
-              <span class="chip-detail">Compagnies de danse</span>
-            </v-chip>
-            <v-chip class="ma-2 chip-custom" label>
-              <span class="chip-detail">Compagnies de théatre</span>
-            </v-chip>
-            <v-chip class="ma-2 chip-custom" label>
-              <span class="chip-detail">Compagnies de Cirque</span>
-            </v-chip>
-          </v-chip-group>
-        </v-col>
-      </v-row>
-
-      <v-row
-        v-if="showManager"
-        class="row-manager"
-      >
-        <v-col cols="6" md="2">
-          <NuxtLink to="/opentalent_manager">
-          <v-img src="/images/logo/logiciels/Manager-noir.png" class="logo" />
-        </NuxtLink>
-        </v-col>
-
-        <v-col cols="6" md="10">
-          <!-- list v-chip-->
-          <v-chip-group column disabled>
-            <v-chip class="ma-2 chip-custom" color="primary" label>
-              <span class="chip-detail">Fédérations</span>
-            </v-chip>
-            <v-chip class="ma-2 chip-custom" color="primary" label>
-              <span class="chip-detail">Confédérations</span>
-            </v-chip>
-            <v-chip class="ma-2 chip-custom" color="primary" label>
-              <span class="chip-detail">Collectivités</span>
-            </v-chip>
-            <v-chip class="ma-2 chip-custom" color="primary" label>
-              <span class="chip-detail">Réseaux</span>
-            </v-chip>
-          </v-chip-group>
-        </v-col>
-      </v-row>
-
-      <v-row
-        v-if="showSchool"
-        class="row-school"
-      >
-        <v-col cols="6" md="2">
-          <NuxtLink to="/opentalent_school">
-            <v-img src="/images/logo/logiciels/School-noir.png" class="logo" />
-          </NuxtLink>
-        </v-col>
-
-        <v-col cols="6" md="10">
-          <!-- list v-chip-->
-          <v-chip-group column disabled>
-            <v-chip class="ma-2 chip-custom" label>
-              <span class="chip-detail">Conservatoire</span>
-            </v-chip>
-            <v-chip class="ma-2 chip-custom" label>
-              <span class="chip-detail">Écoles d'art</span>
-            </v-chip>
-            <v-chip class="ma-2 chip-custom" label>
-              <span class="chip-detail">École de musique</span>
-            </v-chip>
-            <v-chip class="ma-2 chip-custom" label>
-              <span class="chip-detail">École de danse</span>
-            </v-chip>
-            <v-chip class="ma-2 chip-custom" label>
-              <span class="chip-detail">École de théâtre</span>
-            </v-chip>
-            <v-chip class="ma-2 chip-custom" label>
-              <span class="chip-detail">École de cirque</span>
-            </v-chip>
-            <v-chip class="ma-2 chip-custom" label>
-              <span class="chip-detail">MJC</span>
-            </v-chip>
-          </v-chip-group>
-        </v-col>
-      </v-row>
-    </LayoutContainer>
-  </div>
-</template>
-
-<script setup lang="ts">
-const props = defineProps({
-  showArtist: {
-    type: Boolean,
-    required: false,
-    default: true
-  },
-  showSchool: {
-    type: Boolean,
-    required: false,
-    default: true
-  },
-  showManager: {
-    type: Boolean,
-    required: false,
-    default: true
-  },
-})
-</script>
-
-<style scoped lang="scss">
-.chip-detail {
-  color: var(--on-neutral-color);
-
-  @media (max-width: 600px) {
-    width: 100%;
-    text-align: center;
-  }
-}
-
-.chip-custom {
-  opacity: 1;
-  color: var(--on-primary-color);
-  border: 1px solid var(--primary-color);
-  border-radius: 3rem;
-  text-transform: uppercase;
-  font-weight: 500;
-  line-height: 16px;
-  display: flex;
-  align-items: center;
-  text-align: center;
-  letter-spacing: 0.2em;
-
-  @media (max-width: 600px) {
-    font-size: 10px !important;
-    width: 90%;
-    margin-left: auto;
-    margin-right: auto;
-    text-align: center;
-
-    :deep(.v-chip__content) {
-      width: 100%;
-    }
-  }
-}
-
-.row-artist,
-.row-school,
-.row-manager {
-  display: flex;
-  flex-direction: row;
-  align-items: center;
-  border-top: 1px solid var(--on-primary-color-alt);
-}
-
-.solution-title {
-  font-weight: 500;
-  font-size: 1.5rem;
-  line-height: 1.5rem;
-  color: var(--on-neutral-color);
-  margin-top: 2rem;
-  margin-bottom: 2rem;
-  text-align: center;
-}
-
-.logo {
-  width: 15rem;
-  height: 10rem;
-  margin-left: .5rem;
-  margin-right: 2rem;
-}
-</style>

+ 20 - 23
components/Layout/Navigation.vue

@@ -16,46 +16,43 @@ Menu Navigation
 </template>
 
 <script setup lang="ts">
-import { useDisplay } from "vuetify";
-import type { MainMenuItem } from "~/types/interface";
-import { useLayoutStore } from "~/stores/layoutStore";
+import { useDisplay } from 'vuetify'
+import type { MainMenuItem } from '~/types/interface'
+import { useLayoutStore } from '~/stores/layoutStore'
 
-const { lgAndUp } = useDisplay();
+const { lgAndUp } = useDisplay()
 
 const menu: Array<MainMenuItem> = [
   {
-    label: "Nos logiciels",
+    label: 'Nos logiciels',
     children: [
-      { label: "Opentalent Artist", to: "/opentalent_artist" },
-      { label: "Opentalent School", to: "/opentalent_school" },
-      { label: "Opentalent Manager", to: "/opentalent_manager" },
-    ]
+      { label: 'Opentalent Artist', to: '/opentalent_artist' },
+      { label: 'Opentalent School', to: '/opentalent_school' },
+      { label: 'Opentalent Manager', to: '/opentalent_manager' },
+    ],
   },
   {
-    label: "Nos services",
+    label: 'Nos services',
     children: [
-      { label: "Formations", to: "/formations" },
-      { label: "Webinaires", to: "/webinaires" },
-    ]
+      { label: 'Formations', to: '/formations' },
+      { label: 'Webinaires', to: '/webinaires' },
+    ],
   },
   {
-    label: "À propos",
+    label: 'À propos',
     children: [
-      { label: "Qui sommes-nous", to: "/qui-sommes-nous" },
-      { label: "Nous rejoindre", to: "/nous-rejoindre" },
-    ]
+      { label: 'Qui sommes-nous', to: '/qui-sommes-nous' },
+      { label: 'Nous rejoindre', to: '/nous-rejoindre' },
+    ],
   },
-  { label: "Actualités", to: "/actualites" },
-  { label: "Contact", to: "/nous-contacter" },
+  { label: 'Actualités', to: '/actualites' },
+  { label: 'Contact', to: '/nous-contacter' },
 ]
 
 const layoutStore = useLayoutStore()
 const onIntersect = (isIntersecting: boolean) => {
   layoutStore.setIsHeaderVisible(isIntersecting)
 }
-
 </script>
 
-<style scoped>
-
-</style>
+<style scoped></style>

+ 15 - 20
components/Layout/Navigation/Lg.vue

@@ -3,26 +3,22 @@
   <div>
     <LayoutNavigationTopbar />
 
-    <v-row class="navigation-lg" style="margin-top: 0 !important;">
+    <v-row class="navigation-lg" style="margin-top: 0 !important">
       <!-- Logo Opentalent -->
       <v-col cols="2">
         <nuxt-link to="/">
           <v-img
-            src="/images/logo/navigation-logo.png"
+            src="/images/logos/opentalent/Logo_Opentalent-gris.png"
             alt="Logo Opentalent - Agenda et logiciels culturels"
-            class="logo"
+            class="logo ml-4"
           />
         </nuxt-link>
       </v-col>
 
       <!-- Menu principal -->
       <v-col cols="10" class="pl-6">
-        <v-menu
-          v-for="item in menu"
-          :key="item.label"
-          :open-on-hover="true"
-        >
-          <template v-slot:activator="{ props }">
+        <v-menu v-for="item in menu" :key="item.label" :open-on-hover="true">
+          <template #activator="{ props }">
             <nuxt-link
               v-bind="props"
               class="menuItem first-level"
@@ -32,10 +28,7 @@
             </nuxt-link>
           </template>
 
-          <v-list
-            v-if="item.children?.length! > 0"
-            class="menu-list"
-          >
+          <v-list v-if="item.children?.length! > 0" class="menu-list">
             <v-list-item
               v-for="child in item.children"
               :key="child.label"
@@ -52,13 +45,14 @@
 </template>
 
 <script setup lang="ts">
-import type { PropType } from "@vue/runtime-core";
-import type { MainMenuItem } from "~/types/interface";
+import type { PropType } from 'vue'
+import type { MainMenuItem } from '~/types/interface'
 
-const props = defineProps({
+defineProps({
   menu: {
-    type: Array as PropType<Array<MainMenuItem>>
-  }
+    type: Array as PropType<Array<MainMenuItem>>,
+    required: true,
+  },
 })
 </script>
 
@@ -72,7 +66,8 @@ const props = defineProps({
   color: var(--on-neutral-color);
 }
 
-.menuItem, .menuItem .v-list-item-title {
+.menuItem,
+.menuItem .v-list-item-title {
   font-weight: 500;
   font-size: 0.9rem;
   letter-spacing: 0.1em;
@@ -87,7 +82,7 @@ const props = defineProps({
   align-items: center;
   background-color: var(--neutral-color);
 
-  .menuItem  {
+  .menuItem {
     padding: 18px;
   }
 

+ 48 - 48
components/Layout/Navigation/Md.vue

@@ -2,48 +2,37 @@
   <div class="app-container">
     <v-app class="navigation-sm">
       <!-- Top bar -->
-      <v-app-bar app>
-        <v-app-bar-nav-icon
-          @click="toggleMenu"
-        />
-
-        <nuxt-link to="/">
-          <v-img
-            class="logo-md"
-            :src="smAndUp ? '/images/logo/navigation-logo.png' : '/images/Opentalent_Griffe.png'"
-          />
-        </nuxt-link>
-
-        <v-spacer />
+      <v-app-bar>
+        <template #prepend>
+          <v-app-bar-nav-icon @click="toggleMenu" />
+        </template>
+
+        <v-app-bar-title>
+          <nuxt-link to="/">
+            <v-img
+              class="logo-md"
+              src="/images/logos/opentalent/Logo_Opentalent-gris.png"
+            />
+          </nuxt-link>
+        </v-app-bar-title>
 
-        <div class="mx-4">
+        <template #append>
           <v-btn
             href="https://admin.opentalent.fr/#/login/"
             icon="fas fa-user"
             class="icon"
           />
 
-          <v-btn
-            to="/nous-contacter"
-            icon="fas fa-phone"
-            class="icon"
-          />
+          <v-btn to="/nous-contacter" icon="fas fa-phone" class="icon" />
 
           <AgendaLink href="/agenda-culturel">
-            <v-btn
-              icon="fas fa-calendar"
-              class="icon"
-            />
+            <v-btn icon="fas fa-calendar" class="icon" />
           </AgendaLink>
-        </div>
+        </template>
       </v-app-bar>
 
       <!-- Tiroir de navigation principal -->
-      <v-navigation-drawer
-        v-model="isMenuOpen"
-        app
-        temporary
-      >
+      <v-navigation-drawer v-model="isMenuOpen" app temporary>
         <v-list nav dense>
           <v-list-item
             v-if="isSubMenu"
@@ -51,7 +40,7 @@
             @click="onBackItemClick"
           >
             <v-list-item-title>
-              <v-icon icon="fas fa-caret-left" class="mr-1"/> Retour
+              <v-icon icon="fas fa-caret-left" class="mr-1" /> Retour
             </v-list-item-title>
           </v-list-item>
 
@@ -78,28 +67,31 @@
 </template>
 
 <script setup lang="ts">
-import AgendaLink from "~/components/Common/AgendaLink.vue";
-import type { PropType } from "@vue/runtime-core";
-import type { MainMenuItem } from "~/types/interface";
-import { useDisplay } from "vuetify";
+import type { PropType, Ref } from 'vue'
+import { useDisplay } from 'vuetify'
+import AgendaLink from '~/components/Common/AgendaLink.vue'
+import type { MainMenuItem } from '~/types/interface'
 
-const { smAndUp } = useDisplay()
+const { mdAndDown } = useDisplay()
 
 const props = defineProps({
   menu: {
-    type: Array as PropType<Array<MainMenuItem>>
-  }
+    type: Array as PropType<Array<MainMenuItem>>,
+    required: true,
+  },
 })
 
-const isMenuOpen: Ref<boolean> = ref(false);
+const isMenuOpen: Ref<boolean> = ref(false)
 const toggleMenu = () => {
-  isMenuOpen.value = !isMenuOpen.value;
-};
+  isMenuOpen.value = !isMenuOpen.value
+}
 
 const activeMenuIndex: Ref<number | null> = ref(null)
 
 const activeMenu = computed(() =>
-  activeMenuIndex.value !== null ? props.menu![activeMenuIndex.value].children : props.menu
+  activeMenuIndex.value !== null
+    ? props.menu![activeMenuIndex.value].children
+    : props.menu
 )
 
 /**
@@ -121,14 +113,14 @@ const onMenuItemClick = (index: number, item: MainMenuItem): void => {
   if (!item.children) {
     return
   }
-  withAnimation(() => activeMenuIndex.value = index)
+  withAnimation(() => (activeMenuIndex.value = index))
 }
 
 /**
  * Function to handle back button click event.
  */
 const onBackItemClick = (): void => {
-  withAnimation(() => activeMenuIndex.value = null)
+  withAnimation(() => (activeMenuIndex.value = null))
 }
 
 /**
@@ -138,7 +130,15 @@ const onBackItemClick = (): void => {
 const withAnimation = (callback: () => void) => {
   isMenuOpen.value = false
   callback()
-  setTimeout(() => {isMenuOpen.value = true}, 85)
+  setTimeout(() => {
+    isMenuOpen.value = true
+  }, 85)
+}
+
+const showBackToTheTop = ref(false)
+
+const handleScroll = () => {
+  showBackToTheTop.value = window.scrollY > 50
 }
 </script>
 
@@ -147,6 +147,10 @@ const withAnimation = (callback: () => void) => {
   height: 54px;
 }
 
+.v-app-bar {
+  max-width: 100vw;
+}
+
 .navigation-sm {
   background-color: var(--neutral-color);
   position: fixed;
@@ -157,10 +161,6 @@ const withAnimation = (callback: () => void) => {
 .logo-md {
   width: 150px;
   height: 50px;
-
-  @media (max-width: 600px) {
-    width: 50px;
-  }
 }
 
 .back-item {

+ 15 - 18
components/Layout/Navigation/Topbar.vue

@@ -1,26 +1,23 @@
 <template>
-  <div class="top-bar" >
-      <v-btn
-        href="https://admin.opentalent.fr/#/login/"
-        prepend-icon="fas fa-user"
-        class="btn-login"
-      >
-        Se connecter
-      </v-btn>
+  <div class="top-bar">
+    <v-btn
+      href="https://admin.opentalent.fr/#/login/"
+      prepend-icon="fas fa-user"
+      class="btn-login"
+    >
+      Se connecter
+    </v-btn>
 
-      <AgendaLink href="/">
-        <v-btn
-          prepend-icon="fas fa-calendar"
-          class="btn-agenda"
-        >
-            Agenda Culturel
-        </v-btn>
-      </AgendaLink>
+    <AgendaLink href="/">
+      <v-btn prepend-icon="fas fa-calendar" class="btn-agenda">
+        Agenda Culturel
+      </v-btn>
+    </AgendaLink>
   </div>
 </template>
 
 <script setup lang="ts">
-import AgendaLink from "~/components/Common/AgendaLink.vue";
+import AgendaLink from '~/components/Common/AgendaLink.vue'
 </script>
 
 <style scoped lang="scss">
@@ -37,7 +34,7 @@ import AgendaLink from "~/components/Common/AgendaLink.vue";
   .v-btn {
     margin: 4px 8px;
     border-radius: 6px;
-    height: 44px;
+    height: 36px;
   }
 }
 

+ 11 - 12
components/Layout/Pagination.vue

@@ -9,26 +9,25 @@
 </template>
 
 <script setup lang="ts">
-import type { PropType } from "@vue/runtime-core";
-import type { Pagination } from "~/types/data";
+import type { PropType } from 'vue'
+import type { Pagination } from '~/types/data'
 
-const props = defineProps({
+defineProps({
   modelValue: {
     type: Number,
-    required: true
+    required: true,
   },
   pagination: {
     type: Object as PropType<Pagination>,
-    required: true
-  }
-});
+    required: true,
+  },
+})
 
-const emit = defineEmits(['update:modelValue']);
+const emit = defineEmits(['update:modelValue'])
 
 const onPageUpdated = (newPage: number) => {
-  emit('update:modelValue', newPage);
-};
+  emit('update:modelValue', newPage)
+}
 </script>
 
-<style scoped lang="scss">
-</style>
+<style scoped lang="scss"></style>

+ 4 - 7
components/Layout/UI/SectionTitle.vue

@@ -1,18 +1,14 @@
 <!-- Titre H2 -->
 <template>
   <div class="d-flex justify-center align-center flex-column">
-    <v-icon
-      size="6"
-      icon="fas fa-circle"
-    />
+    <v-icon size="6" icon="fas fa-circle" />
     <h3>
       <slot />
     </h3>
   </div>
 </template>
 
-<script setup lang="ts">
-</script>
+<script setup lang="ts"></script>
 
 <style scoped lang="scss">
 h3 {
@@ -30,9 +26,10 @@ h3 {
 }
 
 .fa-circle {
+  font-size: 16px;
   margin-top: 1rem;
   margin-right: 1rem;
-  color: var(--on-neutral-color-light) !important;
+  color: var(--secondary-color) !important;
 }
 
 .alt-theme .fa-circle {

+ 7 - 12
components/Layout/UI/SubTitle.vue

@@ -4,10 +4,7 @@ Titre H4 précédé d'une puce
 <template>
   <LayoutContainer>
     <div class="container">
-      <v-icon
-        :icon="icon"
-        :size="iconSize"
-      />
+      <v-icon :icon="icon" :size="iconSize" />
       <h2>
         <slot />
       </h2>
@@ -16,18 +13,16 @@ Titre H4 précédé d'une puce
 </template>
 
 <script setup lang="ts">
-const router = useRouter();
-
-const props = defineProps({
+defineProps({
   icon: {
     type: String,
-    default: "fas fa-circle",
+    default: 'fas fa-circle',
   },
   iconSize: {
     type: [String, Number],
     default: 5,
   },
-});
+})
 </script>
 
 <style scoped lang="scss">
@@ -35,7 +30,7 @@ const props = defineProps({
   display: flex;
   align-items: center;
   gap: 0.5rem;
-  margin-left: 1rem;
+  margin-left: 4px;
   color: var(--primary-color);
   font-size: 10px;
   font-weight: 600;
@@ -45,7 +40,8 @@ const props = defineProps({
 }
 
 .v-icon {
-  color: var(--on-primary-color-alt);
+  color: var(--on-primary-color-alt) !important;
+  margin-top: 1px;
 }
 
 h2 {
@@ -56,5 +52,4 @@ h2 {
   letter-spacing: 1px;
   text-transform: uppercase;
 }
-
 </style>

+ 11 - 14
components/Layout/UI/Title.vue

@@ -7,22 +7,19 @@
   </LayoutContainer>
 </template>
 
-<script setup lang="ts">
-</script>
+<script setup lang="ts"></script>
 
 <style scoped lang="scss">
-  h3 {
-    color: var(--on-neutral-color);
-    font-weight: 600;
-    font-size: 3rem;
-    line-height: 3rem;
-    margin-left: 1rem;
+h3 {
+  color: var(--on-neutral-color);
+  font-weight: 600;
+  font-size: 3rem;
+  margin-left: 1rem;
 
-    @media (max-width: 600px) {
-      font-size: 2rem;
-      line-height: 2rem;
-      margin-left: 12px;
-      width: 100%;
-    }
+  @media (max-width: 600px) {
+    font-size: 2rem;
+    margin-left: 1.5%;
+    width: 97%;
   }
+}
 </style>

+ 8 - 8
components/Layout/UI/TitlePage.vue

@@ -3,20 +3,21 @@
     <h1>
       <slot />
     </h1>
-    <h2>
+    <h2 v-if="mdAndUp">
       <slot name="subtitle" />
     </h2>
   </div>
 </template>
 
 <script setup lang="ts">
-import { useDisplay } from "vuetify";
+import { useDisplay } from 'vuetify'
 
-const { mdAndDown } = useDisplay()
+const { mdAndDown, mdAndUp } = useDisplay()
 </script>
 
 <style scoped lang="scss">
-h1, h2 {
+h1,
+h2 {
   text-align: center;
   text-transform: uppercase;
 }
@@ -50,10 +51,10 @@ h2 {
 }
 
 @media (max-width: 600px) {
-
-  h1, h2 {
+  h1,
+  h2 {
     width: 80%;
-    margin: auto
+    margin: auto;
   }
 
   h1 {
@@ -67,5 +68,4 @@ h2 {
     font-size: 1.2rem;
   }
 }
-
 </style>

+ 55 - 26
components/Logiciels/Artist/Abonnement.vue

@@ -1,18 +1,17 @@
 <template>
   <AnchoredSection id="subscription">
     <LayoutContainer>
-      <LayoutUISubTitle>
-        S'abonner dès maintenant
-      </LayoutUISubTitle>
-
       <v-row class="mt-12 center-90">
-        <v-col v-if="lgAndUp" cols="4" class="col-1">
+        <LayoutUISubTitle> S'abonner dès maintenant </LayoutUISubTitle>
+
+        <v-col v-if="mdAndUp" cols="4" class="col-1">
           <LogicielsArtistAbonnementToSubscribe />
         </v-col>
 
         <v-col cols="12" lg="8" class="col-2">
           <h3>
-            Opentalent Artist, <br> la solution que vous attendiez...
+            Opentalent Artist, <br />
+            la solution que vous attendiez...
           </h3>
 
           <p class="solution">
@@ -26,25 +25,21 @@
           <LogicielsArtistAbonnementToSubscribe v-if="mdAndDown" />
 
           <p class="cmf">
-            Adhérents CMF ? <br> Et si on vous disait que vous l’aviez déjà&nbsp;...
+            Adhérents CMF ? <br />
+            Et si on vous disait que vous l’aviez déjà&nbsp;...
           </p>
 
-          <div class="border-row">
-            <nuxt-link href="https://www.cmf-musique.org/" target="_blank">
-              <v-img
-                v-if="lgAndUp"
-                src="/images/logo/logo-cmf-petit.png"
-                alt="Logo Confédération Musicale de France - CMF"
-                class="logo-cmf"
-              />
+          <div class="adherent-warning">
+            <nuxt-link
+              href="https://www.cmf-musique.org/"
+              target="_blank"
+              class="logo-cmf-link"
+            >
               <v-img
-                v-else
-                src="/images/logo/logo-cmf.png"
+                src="/images/logos/cmf/Logo_Confederation_Musicale_de_France-CMF_vivre_la_musique_ensemble.jpg"
                 alt="Logo Confédération Musicale de France - CMF"
                 class="logo-cmf"
               />
-
-
             </nuxt-link>
 
             <div class="cmf-container">
@@ -56,6 +51,16 @@
                 Contactez nous ou contactez votre fédération pour obtenir vos
                 codes d'accès.
               </p>
+
+              <div class="d-flex flex-row justify-center my-4">
+                <v-btn
+                  href="https://www.cmf-musique.org/contact/"
+                  target="_blank"
+                  class="btn-contact"
+                >
+                  Obtenir mon code d'accès
+                </v-btn>
+              </div>
             </div>
           </div>
         </v-col>
@@ -65,26 +70,24 @@
 </template>
 
 <script setup>
-import AnchoredSection from "~/components/Layout/AnchoredSection.vue";
-import { useDisplay } from "vuetify";
+import { useDisplay } from 'vuetify'
+import AnchoredSection from '~/components/Layout/AnchoredSection.vue'
 
-const { mdAndDown, lgAndUp } = useDisplay()
+const { mdAndDown, mdAndUp, lgAndUp } = useDisplay()
 </script>
 
 <style scoped lang="scss">
-
 @media (max-width: 1240px) {
   .col-1 {
-    order: 2
+    order: 2;
   }
   .col-2 {
-    order: 1
+    order: 1;
   }
 }
 
 .solution {
   width: 45rem;
-  text-align: justify;
 
   @media (max-width: 600px) {
     width: 100%;
@@ -155,4 +158,30 @@ h3 {
     width: 100%;
   }
 }
+
+.adherent-warning {
+  display: flex;
+  flex-direction: row;
+
+  .logo-cmf-link {
+    margin-top: auto;
+    margin-bottom: auto;
+    padding: 0 16px;
+    border-right: solid 2px var(--on-neutral-color-extra-light);
+  }
+
+  @media (max-width: 600px) {
+    flex-direction: column;
+  }
+}
+
+.btn-contact {
+  height: 53px;
+  background: var(--secondary-color);
+  border-radius: 6px;
+  color: var(--on-secondary-color);
+  padding: 19px 28px;
+  gap: 9px;
+  max-width: 90%;
+}
 </style>

+ 13 - 24
components/Logiciels/Artist/Abonnement/ToSubscribe.vue

@@ -1,18 +1,18 @@
 <template>
   <div class="profile-circle">
     <v-img
-      src="/images/logo/logiciels/OT_Artist-BLANC.png"
+      src="/images/logos/opentalent/Logo_Opentalent_Artist-blanc-col.png"
       alt="Logo Opentalent Artist - logiciel de gestion et de communication pour les orchestres, les chorales, les compagnies artistiques et troupes"
     />
   </div>
 
   <div class="subscription-info">
     <p class="mt-3 mb-6">
-      Pour vous abonner au logiciel, téléchargez et remplissez le
-      formulaire avant de nous le transmettre
+      Pour vous abonner au logiciel, téléchargez et remplissez le formulaire
+      avant de nous le transmettre
     </p>
     <a
-      href="https://www.opentalent.fr/fileadmin/stockage/commercial/contrats/BDC_Artist_Public-23.pdf"
+      href="/files/Bon_De_Commande_Artist_Public-2024.pdf"
       target="_blank"
       class="download-button"
     >
@@ -22,36 +22,23 @@
 
   <div class="subscription-steps">
     <ol>
-      <li class="mt-6">
-        Téléchargez le formulaire
-      </li>
-      <li>
-        Complétez le formulaire
-      </li>
+      <li class="mt-6">Téléchargez et complétez le formulaire</li>
       <li>
-        Joignez le règlement par chèque avec le formulaire à <br />
-        <p class="pa-3">
-          2iOPENService <br />
-          217 rue Raoul Follereau <br />
-          74300 CLUSES
-        </p>
+        Réglez votre abonnement par virement ou par chèque
       </li>
       <li>
-        Après réception de votre formulaire d'adhésion et de votre
-        règlement, nous vous ouvrons le service choisi. Vous recevrez
-        alors un mail avec votre identifiant de connexion, votre mot de
-        passe, ainsi que l'URL de votre site internet.
+        Après réception de votre formulaire d'adhésion et de votre règlement,
+        nous vous ouvrons le service choisi. Vous recevrez alors un mail avec
+        votre identifiant de connexion, votre mot de passe, ainsi que l'URL de
+        votre site internet.
       </li>
     </ol>
   </div>
 </template>
 
-<script setup lang="ts">
-
-</script>
+<script setup lang="ts"></script>
 
 <style scoped lang="scss">
-
 .profile-circle {
   top: 3rem;
   width: 100px;
@@ -60,6 +47,7 @@
   background-color: var(--on-neutral-color);
   border-radius: 50%;
   margin-left: 11rem;
+  padding-top: 12px;
 
   @media (max-width: 1240px) {
     margin-left: auto;
@@ -103,6 +91,7 @@
   border-radius: 5px;
   text-decoration: none;
   display: inline-block;
+  text-align: center;
 }
 
 .subscription-steps ol {

+ 18 - 17
components/Logiciels/Artist/Avantages.vue

@@ -8,36 +8,37 @@ Section "Avantages" de la page du logiciel Artist
 </template>
 
 <script setup lang="ts">
-import AnchoredSection from "~/components/Layout/AnchoredSection.vue";
-import type { Benefit } from "~/types/interface";
+import type { Ref } from 'vue'
+import AnchoredSection from '~/components/Layout/AnchoredSection.vue'
+import type { Benefit } from '~/types/interface'
 
 const benefits: Ref<Array<Benefit>> = ref([
   {
-    title: "Un gain de temps",
-    number: "01",
+    title: 'Un gain de temps',
+    number: '01',
     description:
-      "Centralisez toutes vos informations sur un seul et même outil et ne perdez plus de temps avec des fichiers sur diverses applications.",
-    image: "/images/avantages/school/temps.jpg",
-    alt: "Main tenant un mini réveil",
+      'Centralisez toutes vos informations sur un seul et même outil et ne perdez plus de temps avec des fichiers sur diverses applications.',
+    image: '/images/components/avantages/un_gain_de_temps.jpg',
+    alt: 'Main tenant un mini réveil',
     isMemberCMF: true,
   },
   {
-    title: "Une activité structurée",
-    number: "02",
+    title: 'Une activité structurée',
+    number: '02',
     description:
-      "Des espaces dédiés et des outils spécifiques à vos besoins pour une gestion optimisée et une lecture simplifiée.",
-    image: "/images/avantages/school/struture.png",
-    alt: "Empilement de cube transparent structuré au-dessus d’un plan de maison",
+      'Des espaces dédiés et des outils spécifiques à vos besoins pour une gestion optimisée et une lecture simplifiée.',
+    image: '/images/components/avantages/une_activite_structuree.png',
+    alt: 'Empilement de cube transparent structuré au-dessus d’un plan de maison',
     isMemberCMF: false,
   },
   {
-    title: "Une gestion collaborative",
-    number: "03",
+    title: 'Une gestion collaborative',
+    number: '03',
     description:
       "Grâce à des comptes dédiés, personnalisés et autonomes, permettez à vos membres de mettre à jour leurs informations et d'interagir dans leur agenda.",
-    image: "/images/avantages/school/collaborative.jpg",
-    alt: "Mains de plusieurs couleurs posées les unes à côté des autres",
+    image: '/images/components/avantages/une_gestion_collaborative.jpg',
+    alt: 'Mains de plusieurs couleurs posées les unes à côté des autres',
     isMemberCMF: true,
   },
-]);
+])
 </script>

+ 30 - 35
components/Logiciels/Artist/Comparatif.vue

@@ -1,17 +1,13 @@
 <template>
   <AnchoredSection id="comparative">
     <LayoutContainer>
-      <LayoutUISubTitle>
-        Comparatif de nos solutions
-      </LayoutUISubTitle>
+      <LayoutUISubTitle> Comparatif de nos solutions </LayoutUISubTitle>
 
-      <LayoutUITitle>
-        Choisissez la version qui vous convient !
-      </LayoutUITitle>
+      <LayoutUITitle> Choisissez la version qui vous convient ! </LayoutUITitle>
 
       <CommonTableComparatif
-        standardPrice="14€"
-        premiumPrice="18€"
+        standard-price="11€"
+        premium-price="18€"
         :items="comparisonItems"
       />
     </LayoutContainer>
@@ -19,80 +15,79 @@
 </template>
 
 <script setup lang="ts">
-import AnchoredSection from "~/components/Layout/AnchoredSection.vue";
-import type { ComparisonItem } from "~/types/interface";
+import AnchoredSection from '~/components/Layout/AnchoredSection.vue'
+import type { ComparisonItem } from '~/types/interface'
 
 const comparisonItems: Array<ComparisonItem> = [
   {
-    label: "GESTION DU RÉPERTOIRE",
+    label: 'GESTION DU RÉPERTOIRE',
     includedInStandard: true,
     includedInPremium: true,
   },
   {
-    label: "AGENDA",
+    label: 'AGENDA',
     includedInStandard: true,
     includedInPremium: true,
   },
   {
-    label: "GESTION DU PARC MATÉRIEL",
+    label: 'GESTION DU PARC MATÉRIEL',
     includedInStandard: true,
     includedInPremium: true,
   },
   {
-    label: "COMMUNICATION",
+    label: 'COMMUNICATION',
     includedInStandard: false,
     includedInPremium: true,
   },
   {
-    label: "SMS",
-    includedInStandard: "Option",
-    includedInPremium: "Option",
+    label: 'SMS',
+    includedInStandard: 'Option',
+    includedInPremium: 'Option',
   },
   {
-    label: "NOM DE DOMAINE",
-    includedInStandard: "Option",
-    includedInPremium: "Option",
+    label: 'NOM DE DOMAINE',
+    includedInStandard: 'Option',
+    includedInPremium: 'Option',
   },
   {
-    label: "SITE INTERNET",
+    label: 'SITE INTERNET',
     includedInStandard: true,
     includedInPremium: true,
   },
   {
-    label: "STATISTIQUES",
+    label: 'STATISTIQUES',
     includedInStandard: true,
     includedInPremium: true,
   },
   {
-    label: "FONCTIONNALITÉ DU RÉSEAU CMF",
+    label: 'FONCTIONNALITÉ DU RÉSEAU CMF',
     includedInStandard: true,
     includedInPremium: true,
   },
   {
-    label: "SAUVEGARDE",
+    label: 'SAUVEGARDE',
     includedInStandard: true,
     includedInPremium: true,
   },
   {
-    label: "EXTRANET UTILISATEURS",
-    includedInStandard: "75 comptes",
-    includedInPremium: "150 comptes",
+    label: 'EXTRANET UTILISATEURS',
+    includedInStandard: '75 comptes',
+    includedInPremium: '150 comptes',
   },
   {
-    label: "ESPACE DE STOCKAGE",
-    includedInStandard: "100 Mo",
-    includedInPremium: "1 Go",
+    label: 'ESPACE DE STOCKAGE',
+    includedInStandard: '100 Mo',
+    includedInPremium: '1 Go',
   },
   {
-    label: "PAGE DU SITE INTERNET",
-    includedInStandard: "Restreint",
-    includedInPremium: "Illimités",
+    label: 'PAGES DU SITE INTERNET',
+    includedInStandard: 'Restreint',
+    includedInPremium: 'Illimité',
   },
-];
+]
 </script>
 
 <style scoped>
-
 .v-container {
   width: 95%;
   margin-right: auto;

+ 56 - 66
components/Logiciels/Artist/Fonctionnalites.vue

@@ -2,116 +2,106 @@
   <AnchoredSection id="functionalities">
     <div>
       <LayoutContainer>
-        <v-row>
-          <v-col cols="12">
-            <CommonCarouselFonctionnalite
-              :cards="cards"
-            />
-          </v-col>
-        </v-row>
+        <CommonCarouselFonctionnalite :cards="cards" />
       </LayoutContainer>
     </div>
   </AnchoredSection>
 </template>
 
 <script setup lang="ts">
-import "vue3-carousel/dist/carousel.css";
-import AnchoredSection from "~/components/Layout/AnchoredSection.vue";
-import type { Functionality } from "~/types/interface";
+import 'vue3-carousel/dist/carousel.css'
+import AnchoredSection from '~/components/Layout/AnchoredSection.vue'
+import type { Functionality } from '~/types/interface'
 
 const cards: Array<Functionality> = [
   {
-    logo: "/images/logiciels/artist/fonctionnalites/Espaces_dedies.svg",
-    logoAlt: "Icône smartphone avec cadenas verrouillé",
-    title: "ESPACES DÉDIÉS *",
-    list: [
-      "Administration",
-      "Professeurs",
-      "Élèves / Familles",
-    ],
-    options: ["*Disponible sur tous supports"],
+    logo: '/images/components/fonctionnalites/Icone_espaces_dedies.svg',
+    logoAlt: 'Icône smartphone avec cadenas verrouillé',
+    title: 'ESPACES DÉDIÉS *',
+    list: ['Administrations', 'Membres/Adhérents'],
+    options: ['*Disponible sur tous supports'],
   },
   {
-    logo: "/images/logiciels/artist/fonctionnalites/Repertoire.svg",
-    logoAlt: "Icône carnet annuaire",
-    title: "RÉPERTOIRE",
+    logo: '/images/components/fonctionnalites/Icone_repertoire.svg',
+    logoAlt: 'Icône carnet annuaire',
+    title: 'RÉPERTOIRE',
     list: [
-      "Membres",
-      "Personnel administratif ",
-      "Contacts extérieurs, partenaires & donateurs",
+      'Membres',
+      'Personnel administratif ',
+      'Contacts extérieurs, partenaires & donateurs',
     ],
   },
   {
-    logo: "/images/logiciels/artist/fonctionnalites/Agenda.svg",
-    logoAlt: "Icône calendrier",
-    title: "AGENDA",
+    logo: '/images/components/fonctionnalites/Icone_agenda.svg',
+    logoAlt: 'Icône calendrier',
+    title: 'AGENDA',
     list: [
-      "Création et gestion des événements internes et externes",
-      "Invitation aux événements",
-      "Gestion des présences ",
+      'Création et gestion des événements internes et externes',
+      'Invitation aux événements',
+      'Gestion des présences ',
     ],
   },
   {
-    logo: "/images/logiciels/artist/fonctionnalites/Parc_materiel.svg",
-    logoAlt: "Icône carton avec stylos et cahier à l’intérieur",
-    title: "PARC MATÉRIEL ",
+    logo: '/images/components/fonctionnalites/Icone_parc_materiel.svg',
+    logoAlt: 'Icône carton avec stylos et cahier à l’intérieur',
+    title: 'PARC MATÉRIEL ',
     list: [
-      "Gestion de votre parc matériel (instruments, costumes, accessoires..)",
-      "Locations et prêts de matériel",
-      "Partage de partitions",
+      'Gestion de votre parc matériel (instruments, costumes, accessoires..)',
+      'Locations et prêts de matériel',
+      'Partage de partitions',
     ],
   },
   {
-    logo: "/images/logiciels/artist/fonctionnalites/Communication.svg",
-    logoAlt: "Icône enveloppe, téléphone et bulle SMS",
-    title: "COMMUNICATION *",
+    logo: '/images/components/fonctionnalites/Icone_communication.svg',
+    logoAlt: 'Icône enveloppe, téléphone et bulle SMS',
+    title: 'COMMUNICATION *',
     list: [
-      "Édition et envoi de courriers, de mails ou de SMS**",
-      "Création de modèles de courriers, mails ou SMS **",
-      "Outil de publipostage intégré pour un envoi personnalisé",
+      'Édition et envoi de courriers, de mails ou de SMS**',
+      'Création de modèles de courriers, mails ou SMS **',
+      'Outil de publipostage intégré pour un envoi personnalisé',
     ],
-    options: ["* version Artist Premium ", "** en option"],
+    options: ['* version Artist Premium ', '** en option'],
   },
   {
-    logo: "/images/logiciels/artist/fonctionnalites/Site_internet.svg",
-    logoAlt: "Icône site internet",
-    title: "SITE INTERNET ",
+    logo: '/images/components/fonctionnalites/Icone_site_internet.svg',
+    logoAlt: 'Icône site internet',
+    title: 'SITE INTERNET ',
     list: [
-      "Gestion intégrée au logiciel",
-      "Mise à jour automatique des membres et événements sur votre site",
-      "Possibilité de personnalisé votre template",
+      'Gestion intégrée au logiciel',
+      'Mise à jour automatique des membres et événements sur votre site',
+      'Possibilité de personnalisé votre template',
     ],
   },
   {
-    logo: "/images/logiciels/artist/fonctionnalites/Statistique.svg",
-    logoAlt: "Icône graphique à barre avec ligne ascendante",
-    title: "STATISTIQUES",
+    logo: '/images/components/fonctionnalites/Icone_statistiques.svg',
+    logoAlt: 'Icône graphique à barre avec ligne ascendante',
+    title: 'STATISTIQUES',
     list: [
       "Rapport d'activité complet en fonction de vos activités",
       "Personnalisation du rapport d'activité grâce aux différents formats proposés lors du téléchargement",
-      "Export des données du logiciel pour une analyse complète",
+      'Export des données du logiciel pour une analyse complète',
     ],
   },
   {
-    logo: "/images/logiciels/artist/fonctionnalites/CMF-réseau-J.png",
-    logoAlt: "Icône du logo de la CMF (confédération musicale de France)",
-    title: "RÉSEAU CMF ",
+    logo: '/images/logos/cmf/Icone_CMF_reseau_BLACK.png',
+    logoAlt: 'Icône du logo de la CMF (confédération musicale de France)',
+    title: 'RÉSEAU CMF *',
     list: [
-      "Uniquement dédié aux adhérents CMF",
-      "Accès au répertoire du réseau",
-      "Renouvellement de votre adhésion fédérale",
+      'Accès au répertoire du réseau',
+      'Renouvellement de votre adhésion fédérale',
       "Gestion de l'assurance CMF",
     ],
+    options: ['* uniquement dédié aux adhérents CMF'],
   },
   {
-    logo: "/images/logiciels/artist/fonctionnalites/Promotion.svg",
-    logoAlt: "Icône mégaphone",
-    title: "PROMOTION DE VOTRE STRUCTURE & VOS ÉVÉNEMENTS ",
+    logo: '/images/components/fonctionnalites/Icone_promotion.svg',
+    logoAlt: 'Icône mégaphone',
+    title: 'PROMOTION DE VOTRE STRUCTURE & VOS ÉVÉNEMENTS ',
     list: [
-      "Sur votre site internet intégré",
+      'Sur votre site internet intégré',
       "Sur l'agenda de la CMF",
-      "Sur l'Agenda culturel Opentalent ",
+      "Sur l'agenda culturel Opentalent ",
     ],
   },
-];
+]
 </script>

+ 8 - 12
components/Logiciels/Artist/Formations.vue

@@ -4,17 +4,16 @@
       <div class="alt-theme">
         <v-container>
           <v-row class="center-90">
-            <LayoutUISubTitle class="mt-12" >
+            <LayoutUISubTitle class="mt-12">
               Pour aller plus loin
             </LayoutUISubTitle>
           </v-row>
 
-          <v-row class="formation py-12 align-center mb-12" no-gutters>
+          <v-row class="formation center-90 py-12 align-center mb-12">
             <v-col cols="12" lg="4">
               <v-img
-                src="/images/logiciels/artist/webinaire.jpg"
+                src="/images/pages/opentalent_artist/formations/Webinaire_Opentalent_Artist.jpg"
                 alt="Ordinateur avec un écran en visioconférence avec plusieurs personnes posé sur une table de salon devant une fenêtre avec des plantes et une tasse posées à côté"
-                class="meeting-img"
               />
             </v-col>
 
@@ -23,7 +22,7 @@
                 Webinaire - Partez à la découverte du logiciel Opentalent Artist
               </h3>
 
-              <p class="details" >
+              <p class="details">
                 Rejoignez notre webinaire, spécialement conçu pour les
                 professionnels du secteur culturel, orchestres, chorales,
                 compagnies de danse, ainsi que les troupes de théâtre et de
@@ -36,9 +35,7 @@
               </p>
 
               <nuxt-link to="/webinaires">
-                <v-btn>
-                  S'inscrire à nos webinaires
-                </v-btn>
+                <v-btn> S'inscrire à nos webinaires </v-btn>
               </nuxt-link>
             </v-col>
           </v-row>
@@ -49,7 +46,7 @@
 </template>
 
 <script setup lang="ts">
-import AnchoredSection from "~/components/Layout/AnchoredSection.vue";
+import AnchoredSection from '~/components/Layout/AnchoredSection.vue'
 </script>
 
 <style scoped lang="scss">
@@ -63,8 +60,8 @@ import AnchoredSection from "~/components/Layout/AnchoredSection.vue";
 
 .formation {
   .v-img {
-    width: 600px;
-    height: 500px;
+    width: 500px;
+    height: 440px;
     background-position: center;
     background-size: cover;
     border-radius: 10%;
@@ -91,7 +88,6 @@ import AnchoredSection from "~/components/Layout/AnchoredSection.vue";
     font-size: 1rem;
     line-height: 1.5rem;
     color: var(--on-primary-color);
-    text-align: justify;
 
     @media (max-width: 1240px) {
       margin-right: 24px !important;

+ 18 - 16
components/Logiciels/Artist/Presentation.vue

@@ -4,43 +4,45 @@
       title="Présentation d'Opentalent Artist"
       :features="features"
       :pictos="pictos"
-      logo-src="/images/logo/logiciels/OT_Artist-BLANC.png"
+      logo-src="/images/logos/opentalent/Logo_Opentalent_Artist-blanc-col.png"
       logo-alt="Logo Opentalent Artist - logiciel de gestion et de communication pour les orchestres, les chorales, les compagnies artistiques et troupes"
-      pricingAmount="14€"
+      pricing-amount="11€"
     />
 
     <CommonContainerVideo
       title="Logiciel OpenTalent Artist"
       quote="Le logiciel de gestion et communication au service de votre passion"
-      image-url="/images/logiciels/school/screen2.png"
     />
   </AnchoredSection>
 </template>
 
 <script setup lang="ts">
-import AnchoredSection from "~/components/Layout/AnchoredSection.vue";
-import type { FeaturePicto } from "~/types/interface";
+import AnchoredSection from '~/components/Layout/AnchoredSection.vue'
+import type { FeaturePicto } from '~/types/interface'
 
 const features = [
-  "Logiciel de gestion et communication en ligne",
-  "Destiné aux structures culturelles (tout statut juridique)",
-  "Gestion complète (membres, événements, planning, matériel,...)",
-  "Une solution simple d'utilisation, intuitive et collaborative"
+  'Logiciel de gestion et communication en ligne',
+  'Destiné aux structures culturelles (tout statut juridique)',
+  'Gestion complète (membres, événements, planning, matériel,...)',
+  "Une solution simple d'utilisation, intuitive et collaborative",
 ]
 
 const pictos: Array<FeaturePicto> = [
   {
-    src: "/images/logiciels/artist/picto1.png",
-    text: "Logiciel de gestion et communication full web",
+    src: '/images/pages/opentalent_artist/presentation/Logiciel_multi-support.png',
+    text: 'Logiciel de gestion et communication full web',
   },
   {
-    src: "/images/logiciels/artist/picto2.png",
+    src: '/images/pages/opentalent_artist/presentation/Site_internet_integre.png',
     text: "Site web intégré & simple d'usage",
   },
   {
-    src: "/images/logiciels/artist/picto3.png",
-    text: "Boostez votre visibilité & communication",
+    src: '/images/pages/opentalent_artist/presentation/Boostez_votre_visibilite_et_communication.png',
+    text: 'Boostez votre visibilité & communication',
   },
-  { src: "/images/logiciels/artist/picto4.png", text: "Communiquez en réseau" },
-];
+  {
+    src: '/images/pages/opentalent_artist/presentation/Communication_en_reseau.png',
+    text: 'Communiquez en réseau',
+  },
+]
 </script>

+ 8 - 8
components/Logiciels/Artist/Reviews.vue

@@ -11,25 +11,25 @@
 </template>
 
 <script setup lang="ts">
-import AnchoredSection from "~/components/Layout/AnchoredSection.vue";
-import type { Review } from "~/types/interface";
+import AnchoredSection from '~/components/Layout/AnchoredSection.vue'
+import type { Review } from '~/types/interface'
 
 const cards: Array<Review> = [
   {
     review:
       "L'outil répond à toutes les demandes d'une structure de notre taille et la connexion avec le site internet est très pratique.",
-    name: "Patrice MONTESSUIT",
-    status: "Directeur musical ",
+    name: 'Patrice MONTESSUIT',
+    status: 'Directeur musical ',
     structure: "Orchestre d'Harmonie de Cluses (74)",
   },
   {
     review:
       "C'est un outil de travail très intéressant, complet et intuitif quand on comprend certaines subtilités. Il a très bien évolué aussi bien pour les chorales que les harmonie. Mes remarques ont toujours été prises en compte.",
-    name: "Gérard LEFÈBVRE ",
-    status: "Président",
-    structure: "Le choeur du Brevon (74)",
+    name: 'Gérard LEFÈBVRE ',
+    status: 'Président',
+    structure: 'Le choeur du Brevon (74)',
   },
-];
+]
 </script>
 
 <style scoped lang="scss">

+ 41 - 30
components/Logiciels/Artist/SomeNumbers.vue

@@ -1,56 +1,67 @@
 <template>
   <LayoutContainer>
     <v-row class="custom-row">
-      <LayoutUISubTitle class="mb-12">
-        Quelques chiffres
-      </LayoutUISubTitle>
+      <LayoutUISubTitle class="mb-12"> Quelques chiffres </LayoutUISubTitle>
     </v-row>
 
     <v-container>
       <v-row class="card-container mb-12">
-        <v-col
-          lg="3"
-          class="d-flex justify-center align-center small-padding"
-        >
-          <CommonCardStat
-            number="184 634"
-            text="Utilisateurs"
-          />
+        <v-col lg="3" class="d-flex justify-center align-center small-padding">
+          <CommonCardStat number="184 634" text="Utilisateurs" />
         </v-col>
 
         <v-col lg="3" class="d-flex justify-center align-center">
-          <CommonCardStat
-            number="3 424"
-            text="Structures"
-          />
+          <CommonCardStat number="3 423" text="Structures" />
         </v-col>
 
         <v-col lg="3" class="d-flex justify-center align-center">
-          <CommonCardStat
-            number="13"
-            text="Années d'expérience"
-          />
+          <CommonCardStat number="15" text="Années d'expérience" />
         </v-col>
       </v-row>
     </v-container>
 
-    <CommonCarouselClients :items="items" >
-      <template v-slot:title>
-        Plus de <span class="alt-color">3400 structures</span> nous ont déjà adoptées
+    <CommonCarouselClients :items="items">
+      <template #title>
+        Plus de <span class="alt-color">3400 structures</span> nous ont déjà
+        adoptées
       </template>
     </CommonCarouselClients>
   </LayoutContainer>
 </template>
 
 <script setup lang="ts">
-const items: Ref<Array<{ src: string, alt: string }>> = ref([
-  { src: "/images/reviews/artist/review1.jpeg", alt: "Logo de l’Union Musicale Sarriannaise" },
-  { src: "/images/reviews/artist/review2.jpg", alt: "Logo de la Société Musicale de Sully sur Loire" },
-  { src: "/images/reviews/artist/review3.jpeg", alt: "Logo de l’Orchestre d’Harmonie de Cluses" },
-  { src: "/images/reviews/artist/review4.jpg", alt: "Logo Musique Municipale de Geispolsheim" },
-  { src: "/images/reviews/artist/review5.png", alt: "Logo de l’Harmonie Municipale de Montherme" },
-  { src: "/images/reviews/artist/review6.jpeg", alt: "Logo de l’Echo Musical de Faye d’Anjou" },
-]);
+import type { Ref } from 'vue'
+
+const items: Ref<Array<{ src: string; alt: string }>> = ref([
+  {
+    src: '/images/pages/opentalent_artist/reviews/Logo_Union_Musicale_Sarriannaise.jpeg',
+    alt: 'Logo de l’Union Musicale Sarriannaise',
+  },
+  {
+    src: '/images/pages/opentalent_artist/reviews/Logo_Societe_Musicale_Sully_sur_Loire.jpg',
+    alt: 'Logo de la Société Musicale de Sully sur Loire',
+  },
+  {
+    src: '/images/pages/opentalent_artist/reviews/Logo_Orchestre_d_Harmonie_de_Cluses.jpeg',
+    alt: 'Logo de l’Orchestre d’Harmonie de Cluses',
+  },
+  {
+    src: '/images/pages/opentalent_artist/reviews/Logo_Musique_Municipale_Geispolsheim.jpeg',
+    alt: 'Logo Musique Municipale de Geispolsheim',
+  },
+  {
+    src: '/images/pages/opentalent_artist/reviews/Logo_Harmonie_Municipale_de_Montherme.png',
+    alt: 'Logo de l’Harmonie Municipale de Montherme',
+  },
+  {
+    src: '/images/pages/opentalent_artist/reviews/Logo_Echo_Musical_de_Faye_d_Anjou.jpeg',
+    alt: 'Logo de l’Echo Musical de Faye d’Anjou',
+  },
+  {
+    src: '/images/pages/opentalent_artist/reviews/Logo_Union_Musicale_Wattrelosienne.jpg',
+    alt: 'Logo de l’Union Musicale Wattrelosienne',
+  },
+])
 </script>
 
 <style scoped lang="scss">

+ 36 - 35
components/Logiciels/Manager/Avantages.vue

@@ -1,5 +1,3 @@
-
-
 <template>
   <AnchoredSection id="benefits">
     <CommonAvantages
@@ -10,59 +8,62 @@
 </template>
 
 <script setup lang="ts">
-import AnchoredSection from "~/components/Layout/AnchoredSection.vue";
-import type { Benefit } from "~/types/interface";
+import AnchoredSection from '~/components/Layout/AnchoredSection.vue'
+import type { Benefit } from '~/types/interface'
 
 const benefits: Array<Benefit> = [
   {
-    title: "Sur-mesure",
-    number: "01",
+    title: 'Sur-mesure',
+    number: '01',
     description:
-      "S'adapte à tous les réseaux de type pyramidal, quelque soit le nombre de niveaux :",
-    list: ["Fédérations", "Institutions publiques"],
-    image: "/images/avantages/manager/Sur-mesure.jpg",
-    alt: "Mètre ruban de couture"
+      "S'adapte à tous les réseaux de type pyramidal, quelque soit le nombre de niveaux : fédérations, institutions publiques...",
+    image:
+      '/images/pages/opentalent_manager/avantages/Un_logiciel_sur-mesure.jpg',
+    alt: 'Mètre ruban de couture',
   },
   {
-    title: "Adapté",
-    number: "02",
+    title: 'Adapté',
+    number: '02',
     description:
-      "Chaque structure du réseau dispose de sa propre solution indépendante et connectée au réseau :",
-    list: ["Opentalent manager", "Opentalent school", "Opentalent artist"],
-    image: "/images/avantages/manager/Adapte.jpg",
-    alt: "Réseaux structurés différemment ayant un lien part un atome commun"
+      'Chaque structure du réseau dispose de sa propre solution indépendante et connectée au réseau : Opentalent manager, Opentalent school, Opentalent artist',
+    image:
+      '/images/pages/opentalent_manager/avantages/Un_logiciel_adapte_a_chaque_reseau.jpg',
+    alt: 'Réseaux structurés différemment ayant un lien part un atome commun',
   },
   {
-    title: "Économique",
-    number: "03",
+    title: 'Économique',
+    number: '03',
     description:
-      "Une solution éprouvée au niveau national, sans avoir à supporter de coûts de développement importants pour ce type de logiciel.",
-    image: "/images/avantages/manager/Economique.jpg",
-    alt: "Main mettant une pièce dans un cochon tirelire"
+      'Une solution éprouvée au niveau national, sans avoir à supporter de coûts de développement importants pour ce type de logiciel.',
+    image: '/images/pages/opentalent_manager/avantages/Un_outil_economique.jpg',
+    alt: 'Main mettant une pièce dans un cochon tirelire',
   },
   {
-    title: "De pilotage",
-    number: "04",
+    title: 'De pilotage',
+    number: '04',
     description:
       "Pilotez votre réseau de manière quotidienne et en temps réel. Gagnez du temps avec notre solution qui génère automatiquement un rapport d'activité complet.",
-    image: "/images/avantages/manager/Pilotage.jpg",
-    alt: "Commandant de bord posant en uniforme"
+    image:
+      '/images/pages/opentalent_manager/avantages/Un_pilotage_des_structures_simple.jpg',
+    alt: 'Commandant de bord posant en uniforme',
   },
   {
-    title: "En réseau",
-    number: "05",
+    title: 'En réseau',
+    number: '05',
     description:
-      "Mise à jour automatique des coordonnées publiques entre les membres du réseau.",
-    image: "/images/avantages/manager/En-reseau.jpg",
-    alt: "Multi-réseau"
+      'Mise à jour automatique des coordonnées publiques entre les membres du réseau.',
+    image:
+      '/images/pages/opentalent_manager/avantages/Un_logiciel_adapte_a_chaque_reseau.jpg',
+    alt: 'Multi-réseau',
   },
   {
-    title: "Confidentiel",
-    number: "06",
+    title: 'Confidentiel',
+    number: '06',
     description:
       "Chaque structure garde son indépendance et reste entièrement maître des informations et des données qu'elle saisit.",
-    image: "/images/avantages/manager/Confidentiel-les-donnees-appartiennent-aux-structures.jpg",
-    alt: "Jeune femme ayant le doigt devant la bouche pour instaurer le silence"
+    image:
+      '/images/pages/opentalent_manager/avantages/Confidentialite_des_donnees_et_independance.jpg',
+    alt: 'Jeune femme ayant le doigt devant la bouche pour instaurer le silence',
   },
-];
+]
 </script>

+ 67 - 59
components/Logiciels/Manager/Fonctionnalites.vue

@@ -4,9 +4,7 @@
       <LayoutContainer>
         <v-row>
           <v-col cols="12">
-            <CommonCarouselFonctionnalite
-              :cards="cards"
-            />
+            <CommonCarouselFonctionnalite :cards="cards" />
           </v-col>
         </v-row>
       </LayoutContainer>
@@ -15,99 +13,109 @@
 </template>
 
 <script setup lang="ts">
-import "vue3-carousel/dist/carousel.css";
-import AnchoredSection from "~/components/Layout/AnchoredSection.vue";
-import type { Functionality } from "~/types/interface";
+import 'vue3-carousel/dist/carousel.css'
+import AnchoredSection from '~/components/Layout/AnchoredSection.vue'
+import type { Functionality } from '~/types/interface'
 
 const cards: Array<Functionality> = [
   {
-    logo:"images/logiciels/manager/fonctionnalites/Espaces_dedies.svg",
-    logoAlt: "Icône smartphone avec cadenas verrouillé",
-    title: "ESPACES DÉDIÉS *",
-    list: ["Administration","Membres / Adhérents"],
-    options: ["*Disponible sur tous supports "],
+    logo: '/images/components/fonctionnalites/Icone_espaces_dedies.svg',
+    logoAlt: 'Icône smartphone avec cadenas verrouillé',
+    title: 'ESPACES DÉDIÉS *',
+    list: ['Administration', 'Membres / Adhérents'],
+    options: ['*Disponible sur tous supports '],
   },
   {
-    logo: "images/logiciels/manager/fonctionnalites/Repertoire.svg",
-    logoAlt: "Icône carnet annuaire",
-    title: "RÉPERTOIRE",
+    logo: '/images/components/fonctionnalites/Icone_repertoire.svg',
+    logoAlt: 'Icône carnet annuaire',
+    title: 'RÉPERTOIRE',
     list: [
-      "Membres",
-      "Personnel administratif ",
-      "Contacts extérieurs, partenaires & donateurs",
+      'Membres',
+      'Personnel administratif ',
+      'Contacts extérieurs, partenaires & donateurs',
     ],
   },
   {
-    logo: "images/logiciels/manager/fonctionnalites/Agenda.svg",
-    logoAlt: "Icône calendrier",
-    title: "AGENDA",
+    logo: '/images/components/fonctionnalites/Icone_agenda.svg',
+    logoAlt: 'Icône calendrier',
+    title: 'AGENDA',
     list: [
-      "Création et gestion des événements internes et externes",
-      "Invitation aux événements",
-      "Gestion des présences ",
+      'Création et gestion des événements internes et externes',
+      'Invitation aux événements',
+      'Gestion des présences ',
     ],
   },
   {
-    logo: "images/logiciels/manager/fonctionnalites/Parc_materiel.svg",
-    logoAlt: "Icône carton avec stylos et cahier à l’intérieur",
-    title: "PARC MATÉRIEL ",
+    logo: '/images/components/fonctionnalites/Icone_parc_materiel.svg',
+    logoAlt: 'Icône carton avec stylos et cahier à l’intérieur',
+    title: 'PARC MATÉRIEL ',
     list: [
-      "Gestion de votre parc matériel (instruments, costumes, accessoires..)",
-      "Locations et prêts de matériel",
-      "Partage de partitions",
+      'Gestion de votre parc matériel (instruments, costumes, accessoires..)',
+      'Locations et prêts de matériel',
+      'Partage de partitions',
     ],
   },
   {
-    logo: "images/logiciels/manager/fonctionnalites/communication.svg",
-    logoAlt: "Icône enveloppe, téléphone et bulle SMS",
-    title: "COMMUNICATION RÉSEAU",
+    logo: '/images/components/fonctionnalites/Icone_communication_en_reseau.svg',
+    logoAlt: 'Icône enveloppe, téléphone et bulle SMS',
+    title: 'COMMUNICATION RÉSEAU',
     list: [
-      "Édition et envoi de courriers, de mails ou de SMS*",
-      "Édition et envoi de newsletter au adhérent du réseau",
-      "Création de modèles de courriers, mails ou SMS",
-      "Outil de publipostage intégré pour un envoi personnalisé",
+      'Édition et envoi de courriers, de mails ou de SMS*',
+      'Édition et envoi de newsletter au adhérent du réseau',
+      'Création de modèles de courriers, mails ou SMS',
+      'Outil de publipostage intégré pour un envoi personnalisé',
     ],
-    options: ["* en option"]
+    options: ['* en option'],
   },
   {
-    logo: "images/logiciels/manager/fonctionnalites/Site_internet.svg",
-    logoAlt: "Icône site internet",
-    title: "SITE INTERNET ",
+    logo: '/images/components/fonctionnalites/Icone_site_internet.svg',
+    logoAlt: 'Icône site internet',
+    title: 'SITE INTERNET ',
     list: [
-      "Gestion intégrée au logiciel",
-      "Mise à jour automatique des membres et événements sur votre site",
-      "Possibilité de personnalisé votre template",
+      'Gestion intégrée au logiciel',
+      'Mise à jour automatique des membres et événements sur votre site',
+      'Possibilité de personnalisé votre template',
     ],
   },
   {
-    logo: "images/logiciels/manager/fonctionnalites/Statistiques.svg",
-    logoAlt: "Icône graphique à barre avec ligne ascendante",
-    title: "STATISTIQUES",
+    logo: '/images/components/fonctionnalites/Icone_statistiques.svg',
+    logoAlt: 'Icône graphique à barre avec ligne ascendante',
+    title: 'STATISTIQUES',
     list: [
       "Rapport d'activité complet en fonction de vos activités",
       "Personnalisation du rapport d'activité grâce aux différents formats proposés lors du téléchargement",
-      "Export des données du logiciel pour une analyse complète",
+      'Export des données du logiciel pour une analyse complète',
     ],
   },
   {
-    logo: "images/logiciels/manager/fonctionnalites/Cotisation.svg",
-    logoAlt: "Icône d’une main donnant de l’argent à une autre main",
-    title: "COTISATION CMF ",
+    logo: '/images/components/fonctionnalites/Icone_cotisation.svg',
+    logoAlt: 'Icône d’une main donnant de l’argent à une autre main',
+    title: 'COTISATION CMF ',
     list: [
-      "Paramétrage des cotisations",
-      "Lancement de la campagne",
-      "Gestion des règlement & envoi de justificatif (adhésion/assurance...)",
+      'Paramétrage des cotisations',
+      'Lancement de la campagne',
+      'Gestion des règlement & envoi de justificatif (adhésion/assurance...)',
     ],
   },
   {
-    logo: "images/logiciels/manager/fonctionnalites/Fonctionnement_pyramidal.svg",
-    logoAlt: "Icône graphique pyramidale",
-    title: "FONCTIONNEMENT PYRAMIDAL ",
+    logo: '/images/components/fonctionnalites/Icone_fonctionnement_pyramidal.svg',
+    logoAlt: 'Icône graphique pyramidale',
+    title: 'FONCTIONNEMENT PYRAMIDAL ',
     list: [
-      "Mise en relation des logiciels (Artist, School et Manager)",
+      'Mise en relation des logiciels (Artist, School et Manager)',
       "Mise en place d'un système d'adhésion",
-      "Communication en réseau",
+      'Communication en réseau',
     ],
   },
-];
+  {
+    logo: '/images/components/fonctionnalites/Icone_agenda.svg',
+    logoAlt: 'Icône graphique pyramidale',
+    title: "PROMOTION DU RÉSEAU SUR L'AGENDA CULTUREL",
+    list: [
+      'Publication des événements des structures de votre réseau',
+      "Référencement des structures de votre réseau sur l'annuaire",
+      'Diffusion des annonces du réseau et des structures de votre réseau',
+    ],
+  },
+]
 </script>

+ 35 - 31
components/Logiciels/Manager/Formation.vue

@@ -3,17 +3,13 @@
     <LayoutContainer>
       <div class="alt-theme pt-6 mt-12">
         <v-row>
-          <LayoutUISubTitle class="mb-6 mt-6">
+          <LayoutUISubTitle class="center-90">
             Nos accompagnements pour aller plus loin
           </LayoutUISubTitle>
         </v-row>
 
-        <v-row class="formation pb-6 align-center">
-          <v-col
-            md="6"
-            v-for="(formation, index) in formations"
-            :key="index"
-          >
+        <v-row class="formation pb-6 align-center center-90">
+          <v-col v-for="(formation, index) in formations" :key="index" md="6">
             <div class="mb-6">
               <v-img
                 :src="formation.image"
@@ -47,33 +43,34 @@
 </template>
 
 <script setup lang="ts">
-import AnchoredSection from "~/components/Layout/AnchoredSection.vue";
-import type { Formation } from "~/types/interface.js";
+import AnchoredSection from '~/components/Layout/AnchoredSection.vue'
+import type { Formation } from '~/types/interface.js'
 
 const formations: Array<Formation> = [
   {
-    image: "/images/logiciels/school/formation.png",
-    alt: "Formateur dans une salle avec 5 personnes levant la main",
-    overlayClass: "image-overlay1",
-    sessions: "Formation sur-mesure",
-    title: " Des formations adaptées à votre projet - en ligne",
+    image:
+      '/images/components/formations/Formations_en_ligne_et_presentiel.jpg',
+    alt: 'Formateur dans une salle avec 5 personnes levant la main',
+    overlayClass: 'image-overlay1',
+    sessions: 'Formation sur-mesure',
+    title: ' Des formations adaptées à votre projet - en ligne',
     description:
       "Chaque projet de solution de mise en réseau d'organisation nécessite un accompagnement sur-mesure par notre équipe de formation en fonction de vos besoins.",
-    buttonText: "Formation sur-mesure",
-    link: "/nous-contacter",
+    buttonText: 'Formation sur-mesure',
+    link: '/nous-contacter',
   },
   {
-    image: "/images/logiciels/school/webinaire.png",
-    alt: "Femme sur son bureau avec devant deux écrans d’ordinateur de bureau en visioconférence devant 12 personnes",
-    overlayClass: "image-overlay2",
-    sessions: "Webinaire CMF Réseau",
+    image: '/images/components/formations/Webinaires_visioconferences.jpg',
+    alt: 'Femme sur son bureau avec devant deux écrans d’ordinateur de bureau en visioconférence devant 12 personnes',
+    overlayClass: 'image-overlay2',
+    sessions: 'Webinaire CMF Réseau',
     title: "Trouvez le webinaire qu'il vous faut ",
     description:
       "Des explications précises sur certains modules du logiciel Opentalent Manager, c'est possible pour aller encore plus loin... ",
-    buttonText: "Découvrir nos webinaires ",
-    link: "/webinaires",
+    buttonText: 'Découvrir nos webinaires ',
+    link: '/webinaires',
   },
-];
+]
 </script>
 
 <style scoped>
@@ -82,8 +79,10 @@ const formations: Array<Formation> = [
   margin: 0 auto;
 }
 
-:deep(h2) {
-  width: 60rem;
+@media (min-width: 600px) {
+  :deep(h2) {
+    width: 60rem;
+  }
 }
 
 .background-img {
@@ -91,14 +90,18 @@ const formations: Array<Formation> = [
   height: 400px;
   background-size: cover;
   background-position: center;
+
+  @media (max-width: 600px) {
+    height: auto;
+  }
 }
 
 .formation {
   .v-btn {
-    width: 30rem;
-    height: 4rem;
+    width: 26rem;
+    height: 44px;
     font-weight: 500;
-    font-size: 1.5rem;
+    font-size: 18px;
     line-height: 18px;
     background: transparent;
     color: var(--on-primary-color);
@@ -110,10 +113,10 @@ const formations: Array<Formation> = [
 
   h3 {
     font-weight: 500;
-    font-size: 1.8rem;
+    font-size: 1.4rem;
     line-height: 26px;
-    color: var(--on-primary-color);
-    margin-bottom: 3rem;
+    color: #caf5f4 !important;
+    margin-bottom: 1.5rem;
   }
 
   h4 {
@@ -127,6 +130,7 @@ const formations: Array<Formation> = [
   .details {
     font-weight: 300;
     font-size: 1.2rem;
+    max-width: 650px;
     line-height: 1.5rem;
     color: var(--on-primary-color);
   }

+ 5 - 6
components/Logiciels/Manager/Network.vue

@@ -2,9 +2,7 @@
   <AnchoredSection id="network">
     <LayoutContainer>
       <v-row class="mt-12 center-90">
-        <LayoutUISubTitle>
-          Un réseau pyramidal
-        </LayoutUISubTitle>
+        <LayoutUISubTitle> Un réseau pyramidal </LayoutUISubTitle>
       </v-row>
 
       <v-row class="center-90">
@@ -14,13 +12,14 @@
           </LayoutUITitle>
 
           <p class="pyramide-details ml-3 mt-6">
-            Notre système s'adapte à toutes les structures de réseau pyramidal, quel que soit le nombre de niveau.
+            Notre système s'adapte à toutes les structures de réseau pyramidal,
+            quel que soit le nombre de niveau.
           </p>
         </v-col>
 
         <v-col cols="12" lg="6" md="6">
           <v-img
-            src="/images/logiciels/manager/reseau.png"
+            src="/images/pages/opentalent_manager/network/Reseau_pyramidale_Opentalent_Manager.png"
             alt="Graphique réseau pyramidal de la CMF avec les fédérations, les écoles artistique et les structures pratiquantes"
             class="schema-manager"
           />
@@ -31,7 +30,7 @@
 </template>
 
 <script setup lang="ts">
-import AnchoredSection from "~/components/Layout/AnchoredSection.vue";
+import AnchoredSection from '~/components/Layout/AnchoredSection.vue'
 </script>
 
 <style scoped lang="scss">

+ 17 - 18
components/Logiciels/Manager/Presentation.vue

@@ -7,7 +7,7 @@
           section1title="La solution de mise en réseau des organisations culturelles"
           :features="features"
           :pictos="pictos"
-          logo-src="/images/logo/logiciels/OT_Manager-BLANC.png"
+          logo-src="/images/logos/opentalent/Logo_Opentalent_Manager-blanc-col.png"
           pricing-alt-text="Sur devis"
           pricing-announcement-text=""
           pricing-from-text=""
@@ -18,47 +18,46 @@
       <CommonContainerVideo
         title="Logiciel OpenTalent Manager"
         quote="Une solution unique, collaborative et innovante pour une gestion optimale de votre réseau culturel"
-        image-url="/images/logiciels/school/screen2.png"
       />
     </LayoutContainer>
   </AnchoredSection>
 </template>
 
 <script setup lang="ts">
-import type { FeaturePicto } from "~/types/interface";
-import AnchoredSection from "~/components/Layout/AnchoredSection.vue";
+import type { FeaturePicto } from '~/types/interface'
+import AnchoredSection from '~/components/Layout/AnchoredSection.vue'
 
 const features: Array<string> = [
-  "Logiciel de gestion et communication en ligne ",
-  "Répond aux besoins globaux des réseaux culturels ",
-  "Gestion collaborative ",
-  "Mise en valeur des activités des membres du réseau ",
+  'Logiciel de gestion et communication en ligne ',
+  'Répond aux besoins globaux des réseaux culturels ',
+  'Gestion collaborative ',
+  'Mise en valeur des activités des membres du réseau ',
 ]
 
 const pictos: Array<FeaturePicto> = [
   {
-    src: "/images/logiciels/manager/picto1.png",
-    text: "Logiciel de gestion et communication full web",
+    src: '/images/pages/opentalent_manager/presentation/picto1.png',
+    text: 'Logiciel de gestion et communication full web',
   },
   {
-    src: "/images/logiciels/manager/picto2.png",
+    src: '/images/pages/opentalent_manager/presentation/picto2.png',
     text: "Site web intégré & simple d'usage",
   },
   {
-    src: "/images/logiciels/manager/picto3.png",
-    text: "Boostez votre visibilité & communication",
+    src: '/images/pages/opentalent_manager/presentation/picto3.png',
+    text: 'Boostez votre visibilité & communication',
   },
   {
-    src: "/images/logiciels/manager/picto4.png",
-    text: "Communiquez en réseau",
+    src: '/images/pages/opentalent_manager/presentation/picto4.png',
+    text: 'Communiquez en réseau',
   },
   // {
   //   src: "/images/logiciels/manager/picto5.png",
   //   text: "Sur-mesure",
   // },
   {
-    src: "/images/logiciels/manager/picto6.png",
-    text: "Pout tout type de réseau pyramidal",
+    src: '/images/pages/opentalent_manager/presentation/picto6.png',
+    text: 'Pout tout type de réseau pyramidal',
   },
-];
+]
 </script>

+ 22 - 31
components/Logiciels/Manager/Reviews.vue

@@ -11,50 +11,41 @@
 </template>
 
 <script setup lang="ts">
-
-import AnchoredSection from "~/components/Layout/AnchoredSection.vue";
-import type { Review } from "~/types/interface";
+import AnchoredSection from '~/components/Layout/AnchoredSection.vue'
+import type { Review } from '~/types/interface'
 
 const cards: Array<Review> = [
   {
     review:
       "L'outil répond à toutes les demandes d'une structure de notre taille et la connexion avec le site internet est très pratique.",
-    name: "Christophe MORIZOT",
-    status: "Président ",
-    structure: "Confédération Musicale de France (92)",
-  },
-  {
-    review:
-      "Lorem ipsum dolor sit amet consectetur adipisicing elit.Provident porro fuga incidunt quae, doloremque tenetur aliquam  exercitationem deleniti aspernatur illo rem deserunt sapiente empore dolorem ipsa aliquid vel nihil eius.",
-    name: "Eric TAUVRON ",
-    status: "Vice-président",
-    structure: "CMF Rhône - Grand Lyon (69)",
+    name: 'Christophe MORIZOT',
+    status: 'Président ',
+    structure: 'Confédération Musicale de France (92)',
   },
+  // {
+  //   review:
+  //     'Lorem ipsum dolor sit amet consectetur adipisicing elit.Provident porro fuga incidunt quae, doloremque tenetur aliquam  exercitationem deleniti aspernatur illo rem deserunt sapiente empore dolorem ipsa aliquid vel nihil eius.',
+  //   name: 'Eric TAUVRON ',
+  //   status: 'Vice-président',
+  //   structure: 'CMF Rhône - Grand Lyon (69)',
+  // },
   {
     review:
       "C'est un outil de travail très intéressant, complet et intuitif quand on comprend certaines subtilités. Il a très bien évolué aussi bien pour les chorales que les harmonie. Mes remarques ont toujours été prises en compte.",
-    name: "Noëlle ROBERT",
-    status: "Président",
+    name: 'Noëlle ROBERT',
+    status: 'Président',
     structure: "CMF Côte d'or (21)",
   },
-  {
-    review:
-      "Lorem ipsum dolor sit amet consectetur adipisicing elit.Provident porro fuga incidunt quae, doloremque tenetur aliquam  exercitationem deleniti aspernatur illo rem deserunt sapiente empore dolorem ipsa aliquid vel nihil eius.",
-    name: "Laurent Lebon",
-    status: "Chef d'orchestre",
-    structure: "Conservatoire de Lyon",
-  },
-  {
-    review:
-      "Lorem ipsum dolor sit amet consectetur adipisicing elit.Provident porro fuga incidunt quae, doloremque tenetur aliquam  exercitationem deleniti aspernatur illo rem deserunt sapiente empore dolorem ipsa aliquid vel nihil eius.",
-    name: "Laurent Lebon",
-    status: "Chef d'orchestre",
-    structure: "Conservatoire de Lyon",
-  },
-];
+  // {
+  //   review:
+  //     'Lorem ipsum dolor sit amet consectetur adipisicing elit.Provident porro fuga incidunt quae, doloremque tenetur aliquam  exercitationem deleniti aspernatur illo rem deserunt sapiente empore dolorem ipsa aliquid vel nihil eius.',
+  //   name: 'Laurent Lebon',
+  //   status: "Chef d'orchestre",
+  //   structure: 'Conservatoire de Lyon',
+  // },
+]
 </script>
 
-
 <style scoped>
 .v-container {
   padding: 0 !important;

+ 7 - 23
components/Logiciels/Manager/SomeNumbers.vue

@@ -1,33 +1,19 @@
 <template>
   <LayoutContainer>
     <v-row class="align-center">
-      <LayoutUISubTitle>
-        Quelques chiffres
-      </LayoutUISubTitle>
+      <LayoutUISubTitle> Quelques chiffres </LayoutUISubTitle>
     </v-row>
 
     <v-container>
       <v-row class="card-container justify-center mb-12">
-        <v-col
-          md="3"
-          class="d-flex justify-center align-center small-padding"
-        >
-          <CommonCardStat
-            number="140"
-            text="Structures en réseau"
-          />
+        <v-col md="3" class="d-flex justify-center align-center small-padding">
+          <CommonCardStat number="140" text="Structures en réseau" />
         </v-col>
         <v-col md="3" class="d-flex justify-center align-center">
-          <CommonCardStat
-            number="300 000"
-            text="Utilisateurs"
-          />
+          <CommonCardStat number="216 498" text="Utilisateurs" />
         </v-col>
         <v-col md="3" class="d-flex justify-center align-center">
-          <CommonCardStat
-            number="12"
-            text="Années de collaboration"
-          />
+          <CommonCardStat number="17" text="Années de collaboration" />
         </v-col>
       </v-row>
     </v-container>
@@ -40,7 +26,7 @@
 
         <nuxt-link href="https://www.cmf-musique.org/" target="_blank">
           <v-img
-            src="/images/logiciels/manager/cmf.jpg"
+            src="/images/logos/cmf/Logo_Confederation_Musicale_de_France-CMF_vivre_la_musique_ensemble.jpg"
             class="cmf-img mb-6"
           />
         </nuxt-link>
@@ -49,9 +35,7 @@
   </LayoutContainer>
 </template>
 
-<script setup lang="ts">
-
-</script>
+<script setup lang="ts"></script>
 
 <style scoped lang="scss">
 .custom-row {

+ 16 - 10
components/Logiciels/School/Avantages.vue

@@ -8,32 +8,38 @@ Section "Avantages" de la page du logiciel School
 </template>
 
 <script setup lang="ts">
-import AnchoredSection from "~/components/Layout/AnchoredSection.vue";
-import type { Benefit } from "~/types/interface";
+import type { Ref } from 'vue'
+import AnchoredSection from '~/components/Layout/AnchoredSection.vue'
+import type { Benefit } from '~/types/interface'
 
 // Exemple de données pour les cartes
 const benefits: Ref<Array<Benefit>> = ref([
   {
     title: 'Un gain de temps',
     number: '01',
-    description: 'Centralisez toutes vos informations sur un seul et même outil et ne perdez plus de temps avec des fichiers sur diverses applications.',
-    image: '/images/avantages/school/temps.jpg',
+    description:
+      'Centralisez toutes vos informations sur un seul et même outil et ne perdez plus de temps avec des fichiers sur diverses applications.',
+    image: '/images/components/avantages/un_gain_de_temps.jpg',
+    alt: '',
     isMemberCMF: true,
   },
   {
     title: 'Une activité structurée',
     number: '02',
-    description: 'Des espaces dédiés et des outils spécifiques à vos besoins pour une gestion optimisée et une lecture simplifiée.',
-    image: '/images/avantages/school/struture.png',
+    description:
+      'Des espaces dédiés et des outils spécifiques à vos besoins pour une gestion optimisée et une lecture simplifiée.',
+    image: '/images/components/avantages/une_activite_structuree.png',
+    alt: '',
     isMemberCMF: false,
   },
   {
     title: 'Une gestion collaborative',
     number: '03',
-    description: 'Grâce à des comptes dédiés, personnalisés et autonomes, permettez à vos membres de mettre à jour leurs informations et d\'interagir dans leur agenda.',
-    image: '/images/avantages/school/collaborative.jpg',
+    description:
+      "Grâce à des comptes dédiés, personnalisés et autonomes, permettez à vos membres de mettre à jour leurs informations et d'interagir dans leur agenda.",
+    image: '/images/components/avantages/une_gestion_collaborative.jpg',
+    alt: '',
     isMemberCMF: true,
   },
-]);
-
+])
 </script>

+ 45 - 51
components/Logiciels/School/Comparatif.vue

@@ -1,119 +1,113 @@
 <template>
   <AnchoredSection id="comparative">
     <LayoutContainer>
-      <LayoutUISubTitle>
-        Comparatif de nos solutions
-      </LayoutUISubTitle>
+      <v-row class="center-90">
+        <LayoutUISubTitle> Comparatif de nos solutions </LayoutUISubTitle>
 
-      <LayoutUITitle>
-        Choisissez la version qui vous convient !
-      </LayoutUITitle>
+        <LayoutUITitle>
+          Choisissez la version qui vous convient !
+        </LayoutUITitle>
 
-      <CommonTableComparatif
-        standardPrice="32,90€"
-        premiumPrice="46,20€"
-        :items="comparisonItems"
-      />
+        <CommonTableComparatif
+          standard-price="34,90€"
+          premium-price="49€"
+          :items="comparisonItems"
+        />
+      </v-row>
     </LayoutContainer>
   </AnchoredSection>
 </template>
 
 <script setup lang="ts">
-import AnchoredSection from "~/components/Layout/AnchoredSection.vue";
-import type { ComparisonItem } from "~/types/interface";
+import AnchoredSection from '~/components/Layout/AnchoredSection.vue'
+import type { ComparisonItem } from '~/types/interface'
 
 const comparisonItems: Array<ComparisonItem> = [
   {
-    label: "GESTION DU RÉPERTOIRE",
+    label: 'GESTION DU RÉPERTOIRE',
     includedInStandard: true,
     includedInPremium: true,
   },
   {
-    label: "AGENDA",
+    label: 'AGENDA',
     includedInStandard: true,
     includedInPremium: true,
   },
   {
-    label: "SUIVI PÉDAGOGIQUE",
+    label: 'SUIVI PÉDAGOGIQUE',
     includedInStandard: true,
     includedInPremium: true,
   },
   {
-    label: "GESTION DU PARC MATÉRIEL",
+    label: 'GESTION DU PARC MATÉRIEL',
     includedInStandard: true,
     includedInPremium: true,
   },
   {
-    label: "COMMUNICATION",
+    label: 'COMMUNICATION',
     includedInStandard: true,
     includedInPremium: true,
   },
   {
-    label: "SMS",
-    includedInStandard: "Option",
-    includedInPremium: "Option",
+    label: 'SMS',
+    includedInStandard: 'Option',
+    includedInPremium: 'Option',
   },
   {
-    label: "NOM DE DOMAINE",
-    includedInStandard: "Option",
-    includedInPremium: "Option",
+    label: 'NOM DE DOMAINE',
+    includedInStandard: 'Option',
+    includedInPremium: 'Option',
   },
   {
-    label: "SITE INTERNET",
+    label: 'SITE INTERNET',
     includedInStandard: true,
     includedInPremium: true,
   },
   {
-    label: "STATISTIQUES",
+    label: 'STATISTIQUES',
     includedInStandard: true,
     includedInPremium: true,
   },
   {
-    label: "FONCTIONNALITÉ DU RÉSEAU CMF",
+    label: 'FONCTIONNALITÉ DU RÉSEAU CMF',
     includedInStandard: true,
     includedInPremium: true,
   },
   {
-    label: "SAUVEGARDE",
+    label: 'SAUVEGARDE',
     includedInStandard: true,
     includedInPremium: true,
   },
   {
-    label: "EXTRANET UTILISATEURS",
+    label: 'EXTRANET UTILISATEURS',
     includedInStandard: false,
-    includedInPremium: "Option",
+    includedInPremium: 'Option',
   },
   {
-    label: "PRÉINSCRIPTION EN LIGNE",
+    label: 'PRÉINSCRIPTION EN LIGNE',
     includedInStandard: false,
-    includedInPremium: "Option",
+    includedInPremium: 'Option',
   },
   {
     label: "GRILLES D'ÉVALUATION",
-    includedInStandard: true,
-    includedInPremium: "Option",
+    includedInStandard: 'Option',
+    includedInPremium: 'Option',
   },
   {
-    label: "GESTION DES RÈGLEMENTS",
-    includedInStandard: "Option",
-    includedInPremium: "Option",
+    label: 'GESTION DES RÈGLEMENTS',
+    includedInStandard: 'Option',
+    includedInPremium: 'Option',
   },
   {
-    label: "ESPACE DE STOCKAGE",
-    includedInStandard: "500 Mo",
-    includedInPremium: "1 Go",
+    label: 'ESPACE DE STOCKAGE',
+    includedInStandard: '500 Mo',
+    includedInPremium: '1 Go',
   },
   {
-    label: "PAGE DU SITE INTERNET",
-    includedInStandard: "restreint",
-    includedInPremium: "illimités",
+    label: 'PAGE DU SITE INTERNET',
+    includedInStandard: 'Restreint',
+    includedInPremium: 'Illimité',
   },
-];
+]
 </script>
-<style scoped>
-
-.v-container{
-  width: 95%;
-  margin-right: auto;
-  margin-left: auto;
-}</style>
+<style scoped></style>

+ 77 - 83
components/Logiciels/School/Fonctionnalites.vue

@@ -1,143 +1,137 @@
 <template>
   <AnchoredSection id="functionalities">
-    <div>
-      <LayoutContainer>
-        <v-row>
-          <v-col cols="12">
-            <CommonCarouselFonctionnalite
-              :cards="cards"
-            />
-          </v-col>
-        </v-row>
-      </LayoutContainer>
-    </div>
+    <LayoutContainer>
+      <CommonCarouselFonctionnalite :cards="cards" />
+    </LayoutContainer>
   </AnchoredSection>
 </template>
 
 <script setup lang="ts">
-import "vue3-carousel/dist/carousel.css";
-import AnchoredSection from "~/components/Layout/AnchoredSection.vue";
-import type { Functionality } from "~/types/interface";
+import 'vue3-carousel/dist/carousel.css'
+import AnchoredSection from '~/components/Layout/AnchoredSection.vue'
+import type { Functionality } from '~/types/interface'
 
 const cards: Array<Functionality> = [
   {
-    logo: "/images/logiciels/school/fonctionnalites/Espaces.svg",
-    title: "ESPACES DÉDIÉS *",
-    list: [
-      "Administration",
-      "Professeurs",
-      "Élèves / Familles",
-    ],
-    options: ["*Disponible sur tous supports"],
+    logo: '/images/components/fonctionnalites/Icone_espaces_dedies.svg',
+    logoAlt: 'Icône smartphone avec cadenas verrouillé',
+    title: 'ESPACES DÉDIÉS *',
+    list: ['Administration', 'Professeurs', 'Élèves / Familles'],
+    options: ['* Disponible sur tous supports'],
   },
   {
-    logo: "/images/logiciels/school/fonctionnalites/Répertoire.png",
-
-    title: "RÉPERTOIRE",
+    logo: '/images/components/fonctionnalites/Icone_repertoire.svg',
+    logoAlt: 'Icône carnet annuaire',
+    title: 'RÉPERTOIRE',
     list: [
-      "Élèves et responsable légaux",
-      "Personnel administratif et professeurs",
-      "Contacts extérieurs, partenaires & donateurs",
+      'Élèves et responsable légaux',
+      'Personnel administratif et professeurs',
+      'Contacts extérieurs, partenaires & donateurs',
     ],
   },
   {
-    logo: "/images/logiciels/school/fonctionnalites/Pré-inscription.png",
-    title: "PRÉINSCRIPTION EN LIGNE",
+    logo: '/images/components/fonctionnalites/Icone_preinscription_en_ligne.svg',
+    logoAlt: "Icône d'un fichier devant un écran d'ordinateur",
+    title: 'PRÉINSCRIPTION EN LIGNE *',
     list: [
-      "Paramètrage personnalisé des formulaires & mails automatiques",
-      "Gestion des réinscriptions et des nouvelles inscriptions",
-      "Gestion des quotas et du suivi des préinscriptions en ligne",
+      'Paramétrage personnalisé des formulaires & mails automatiques',
+      'Gestion des réinscriptions et des nouvelles inscriptions',
+      'Gestion des quotas et du suivi des préinscriptions en ligne',
     ],
+    options: ['* en option'],
   },
   {
-    logo: "/images/logiciels/school/fonctionnalites/Agenda.png",
-    title: "AGENDA",
+    logo: '/images/components/fonctionnalites/Icone_agenda.svg',
+    logoAlt: 'Icône calendrier',
+    title: 'AGENDA',
     list: [
-      "Création et gestion des cours, examens, événements et prestations pédagogiques",
-      "Planning interactif avec un contrôle de cohérence",
-      "Gestion des présences et absences",
+      'Création et gestion des cours, examens, événements et prestations pédagogiques',
+      'Planning interactif avec un contrôle de cohérence',
+      'Gestion des présences et absences',
     ],
   },
   {
-    logo: "/images/logiciels/school/fonctionnalites/Parc-matériel.png",
-    title: "PARC MATÉRIEL ",
+    logo: '/images/components/fonctionnalites/Icone_parc_materiel.svg',
+    logoAlt: 'Icône carton avec stylos et cahier à l’intérieur',
+    title: 'PARC MATÉRIEL ',
     list: [
-      "Gestion de votre parc matériel (instruments, costumes, accessoires..)",
-      "Planning interactif avec un contrôle de cohérence",
-      "Gestion des présences et absences",
+      'Gestion de votre parc matériel (instruments, costumes, accessoires..)',
+      'Planning interactif avec un contrôle de cohérence',
+      'Gestion des présences et absences',
     ],
   },
   {
-    logo: "/images/logiciels/school/fonctionnalites/Suivi-pédagogique.png",
-
-    title: "SUIVI PÉDAGOGIQUE",
+    logo: '/images/components/fonctionnalites/Icone_suivi_pedagogique.svg',
+    logoAlt: 'Chapeau de diplômé américain',
+    title: 'SUIVI PÉDAGOGIQUE',
     list: [
-      "Gestion du cursus pédagogique (critères personnalisables)",
-      "Création des examens et envoi des convocations",
-      "Édition des bulletins de notes",
+      'Gestion du cursus pédagogique (critères personnalisables)',
+      'Création des examens et envoi des convocations',
+      'Édition des bulletins de notes',
     ],
   },
   {
-    logo: "/images/logiciels/school/fonctionnalites/Facture.png",
-
-    title: "FACTURATION",
+    logo: '/images/components/fonctionnalites/Icone_facturation_et_reglement.svg',
+    logoAlt:
+      "Fichier arborant un symbole monétaire devant un écran d'ordinateur",
+    title: 'FACTURATION',
     list: [
-      "Facturation automatisée selon différents critères",
-      "Suivi des règlements et gestion des relances",
-      "En option : de nombreux moyens de paiement",
+      'Facturation automatisée selon différents critères',
+      'Suivi des règlements et gestion des relances',
+      'En option : de nombreux moyens de paiement',
     ],
   },
   {
-    logo: "/images/logiciels/school/fonctionnalites/Communication.png",
-
-    title: "COMMUNICATION",
+    logo: '/images/components/fonctionnalites/Icone_communication.svg',
+    logoAlt: 'Icône enveloppe, téléphone et bulle SMS',
+    title: 'COMMUNICATION',
     list: [
-      "Édition et envoi de courriers, de mails ou de SMS*",
-      "Création de modèles de courriers, mails ou SMS",
-      "Outil de publipostage intégré pour un envoi personnalisé",
+      'Édition et envoi de courriers, de mails ou de SMS*',
+      'Création de modèles de courriers, mails ou SMS',
+      'Outil de publipostage intégré pour un envoi personnalisé',
     ],
-    options: ["* en option"],
+    options: ['* en option'],
   },
   {
-    logo: "/images/logiciels/school/fonctionnalites/internet.png",
-
-    title: "SITE INTERNET ",
+    logo: '/images/components/fonctionnalites/Icone_site_internet.svg',
+    logoAlt: 'Icône site internet',
+    title: 'SITE INTERNET ',
     list: [
-      "Gestion intégrée au logiciel",
-      "Mise à jour automatique des membres et événements sur votre site",
-      "Possibilité de personnalisé votre template",
+      'Gestion intégrée au logiciel',
+      'Mise à jour automatique des membres et événements sur votre site',
+      'Possibilité de personnalisé votre template',
     ],
   },
   {
-    logo: "/images/logiciels/school/fonctionnalites/Statistiques.png",
-
-    title: "STATISTIQUES",
+    logo: '/images/components/fonctionnalites/Icone_statistiques.svg',
+    logoAlt: 'Icône graphique à barre avec ligne ascendante',
+    title: 'STATISTIQUES',
     list: [
       "Rapport d'activité complet en fonction de vos activités",
       "Personnalisation du rapport d'activité grâce aux différents formats proposés lors du téléchargement",
-      "Export des données du logiciel pour une analyse complète",
+      'Export des données du logiciel pour une analyse complète',
     ],
   },
   {
-    logo: "/images/logiciels/school/fonctionnalites/Agenda.png",
-
-    title: "RÉSEAU CMF *",
+    logo: '/images/logos/cmf/Icone_CMF_reseau_BLACK.png',
+    logoAlt: 'Logo CMF',
+    title: 'RÉSEAU CMF *',
     list: [
-      "Accès au répertoire du réseau",
-      "Renouvellement de votre adhésion fédérale",
+      'Accès au répertoire du réseau',
+      'Renouvellement de votre adhésion fédérale',
       "Gestion de l'assurance CMF",
     ],
-    options: ["* Uniquement dédié au adhérents CMF"],
+    options: ['* Uniquement dédié au adhérents CMF'],
   },
   {
-    logo: "/images/logiciels/school/fonctionnalites/Promotion.png",
-
-    title: "PROMOTION DE VOTRE STRUCTURE & VOS ÉVÉNEMENTS ",
+    logo: '/images/components/fonctionnalites/Icone_promotion.svg',
+    logoAlt: 'Icône mégaphone',
+    title: 'PROMOTION DE VOTRE STRUCTURE & VOS ÉVÉNEMENTS ',
     list: [
-      "Sur votre site internet intégré",
+      'Sur votre site internet intégré',
       "Sur l'agenda de la CMF",
       "Sur l'agenda culturel Opentalent",
     ],
   },
-];
+]
 </script>

+ 51 - 37
components/Logiciels/School/Formations.vue

@@ -2,18 +2,16 @@
   <AnchoredSection id="webinars">
     <LayoutContainer>
       <div class="alt-theme pt-6 mt-12">
-        <v-row>
-          <LayoutUISubTitle>
-            Nos accompagnements sur-mesure
-          </LayoutUISubTitle>
+        <v-row class="center-90">
+          <LayoutUISubTitle> Nos accompagnements sur-mesure </LayoutUISubTitle>
         </v-row>
 
-        <v-row class="formation pb-6 align-center">
+        <v-row class="formation pb-6 align-center center-90">
           <v-col
-            cols="12"
-            md="6"
             v-for="(formation, index) in formations"
             :key="index"
+            cols="12"
+            md="6"
           >
             <div class="mb-6">
               <v-img
@@ -48,41 +46,37 @@
 </template>
 
 <script setup lang="ts">
-import AnchoredSection from "~/components/Layout/AnchoredSection.vue";
-import type { Formation } from "~/types/interface";
+import AnchoredSection from '~/components/Layout/AnchoredSection.vue'
+import type { Formation } from '~/types/interface'
 
 const formations: Array<Formation> = [
   {
-    image: "/images/logiciels/school/formation.png",
-    alt: "Formateur dans une salle avec 5 personnes levant la main",
-    overlayClass: "image-overlay1",
-    sessions: "3 formations disponibles",
-    title: "Des formations adaptées à chacun - en ligne",
+    image:
+      '/images/components/formations/Formations_en_ligne_et_presentiel.jpg',
+    alt: 'Formateur dans une salle avec 5 personnes levant la main',
+    overlayClass: 'image-overlay1',
+    sessions: '3 formations disponibles',
+    title: 'Des formations adaptées à chacun - en ligne',
     description:
-      "Parce qu’on sait qu’appréhender un nouvel outil peut-être fastidieux et que vous n’avez pas de temps à perdre,...",
-    buttonText: "Découvrir toutes nos formations",
-    link: "/formations",
+      'Parce qu’on sait qu’appréhender un nouvel outil peut-être fastidieux et que vous n’avez pas de temps à perdre,...',
+    buttonText: 'Découvrir toutes nos formations',
+    link: '/formations',
   },
   {
-    image: "/images/logiciels/school/webinaire.png",
-    alt: "Femme sur son bureau avec devant deux écrans d’ordinateur de bureau en visioconférence devant 12 personnes",
-    overlayClass: "image-overlay2",
-    sessions: "Toutes nos sessions",
+    image: '/images/components/formations/Webinaires_visioconferences.jpg',
+    alt: 'Femme sur son bureau avec devant deux écrans d’ordinateur de bureau en visioconférence devant 12 personnes',
+    overlayClass: 'image-overlay2',
+    sessions: 'Toutes nos sessions',
     title: "Trouvez le webinaire qu'il vous faut ",
     description:
       "Des explications précises sur certains modules du logiciel Opentalent School, c'est possible pour aller encore plus loin...",
-    buttonText: "Découvrir nos webinaires ",
-    link: "/webinaires",
+    buttonText: 'Découvrir nos webinaires ',
+    link: '/webinaires',
   },
-];
+]
 </script>
 
 <style scoped>
-.v-row {
-  max-width: 1600px;
-  margin: 0 auto;
-}
-
 :deep(h2) {
   width: 60rem;
 }
@@ -92,6 +86,10 @@ const formations: Array<Formation> = [
   height: 400px;
   background-size: cover;
   background-position: center;
+
+  @media (max-width: 600px) {
+    height: auto;
+  }
 }
 
 .alt-color {
@@ -100,10 +98,10 @@ const formations: Array<Formation> = [
 
 .formation {
   .v-btn {
-    width: 30rem;
-    height: 4rem;
+    width: 26rem;
+    height: 44px;
     font-weight: 500;
-    font-size: 1.5rem;
+    font-size: 18px;
     line-height: 18px;
     background: transparent;
     color: var(--on-primary-color);
@@ -115,10 +113,10 @@ const formations: Array<Formation> = [
 
   h3 {
     font-weight: 500;
-    font-size: 1.8rem;
+    font-size: 1.4rem;
     line-height: 26px;
-    color: var(--on-primary-color);
-    margin-bottom: 3rem;
+    color: var(--secondary-color) !important;
+    margin-bottom: 1.5rem;
   }
 
   h4 {
@@ -132,10 +130,27 @@ const formations: Array<Formation> = [
   .details {
     font-weight: 300;
     font-size: 1.2rem;
+    max-width: 650px;
     line-height: 1.5rem;
     color: var(--on-primary-color);
   }
 
+  @media (max-width: 1240px) {
+    .background-img,
+    h3,
+    h4,
+    .details {
+      margin-left: auto;
+      margin-right: auto;
+      text-align: center;
+    }
+
+    .v-btn {
+      width: 80%;
+      margin-left: 10%;
+    }
+  }
+
   @media (max-width: 600px) {
     .v-btn {
       height: 96px;
@@ -144,10 +159,9 @@ const formations: Array<Formation> = [
     :deep(.v-btn__content) {
       white-space: pre-wrap;
       line-height: 1.2em;
-      padding: auto;
+      padding: initial;
       text-align: center;
     }
   }
-
 }
 </style>

+ 14 - 15
components/Logiciels/School/Presentation.vue

@@ -4,45 +4,44 @@
       title="Présentation d'Opentalent School"
       :features="features"
       :pictos="pictos"
-      logo-src="/images/logo/logiciels/OT_School-blanc.png"
+      logo-src="/images/logos/opentalent/Logo_Opentalent_School-blanc-col.png"
       pricing-amount="20€"
     />
 
     <CommonContainerVideo
       title="Logiciel OpenTalent School"
       quote="Pour les petits comme pour les grands établissements d’enseignement artistique"
-      image-url="/images/logiciels/school/screen2.png"
     />
   </AnchoredSection>
 </template>
 
 <script setup lang="ts">
-import AnchoredSection from "~/components/Layout/AnchoredSection.vue";
-import type { FeaturePicto } from "~/types/interface";
+import AnchoredSection from '~/components/Layout/AnchoredSection.vue'
+import type { FeaturePicto } from '~/types/interface'
 
 const features = [
-  "Logiciel de gestion et communication en ligne",
+  'Logiciel de gestion et communication en ligne',
   "Destiné aux établissements d'enseignement artistique",
-  "Gestion quotidienne et en temps réel",
-  "Pilotage complet de votre structure",
+  'Gestion quotidienne et en temps réel',
+  'Pilotage complet de votre structure',
 ]
 
 const pictos: Array<FeaturePicto> = [
   {
-    src: "/images/logiciels/school/picto1.png",
-    text: "Logiciel de gestion et communication full web",
+    src: '/images/pages/opentalent_school/presentation/picto1.png',
+    text: 'Logiciel de gestion et communication full web',
   },
   {
-    src: "/images/logiciels/school/picto2.png",
+    src: '/images/pages/opentalent_school/presentation/picto3.png',
     text: "Site web intégré & simple d'usage",
   },
   {
-    src: "/images/logiciels/school/picto3.png",
-    text: "Boostez votre visibilité & communication",
+    src: '/images/pages/opentalent_school/presentation/picto2.png',
+    text: 'Boostez votre visibilité & communication',
   },
   {
-    src: "/images/logiciels/school/picto4.png",
-    text: "Communiquez en réseau"
+    src: '/images/pages/opentalent_school/presentation/picto4.png',
+    text: 'Communiquez en réseau',
   },
-];
+]
 </script>

+ 14 - 14
components/Logiciels/School/Reviews.vue

@@ -11,39 +11,39 @@
 </template>
 
 <script setup lang="ts">
-import AnchoredSection from "~/components/Layout/AnchoredSection.vue";
-import type { Review } from "~/types/interface";
+import AnchoredSection from '~/components/Layout/AnchoredSection.vue'
+import type { Review } from '~/types/interface'
 
 const cards: Array<Review> = [
   {
     review:
       "C'est un logiciel simple d'utilisation après la formation. Pensé pour la musique, il s'adapte rès bien conçu et efficace avec une équipe ouverte, dynamique et à l'écoute. L’assistance est très réactive, j'ai toujours eu une réponse rapide à mes besoins, ce qui est fort appréciable.",
-    name: "Patrice CATHELIN ",
-    status: "Directeur administratif & pédagogique ",
-    structure: "Conservatoire de Musique & de Danse de Sens (78)",
+    name: 'Patrice CATHELIN ',
+    status: 'Directeur administratif & pédagogique ',
+    structure: 'Conservatoire de Musique & de Danse de Sens (78)',
   },
   {
     review:
       "Étant présente depuis presque le début, je suis fière d'avoir vu grandir ce logiciel et d'avoir évoluée avec lui. De plus, je me suis sentie écoutée lors de mes propositions d'amélioration, car beaucoup ont vu le jour. Enfin, l'accompagnement et la réactivité n'ont jamais faibli depuis toutes ces années",
-    name: "Karine GIRAUD",
-    status: "Secrétaire administrative",
-    structure: "Association Musicale Sainte Cécile de Lagord (17)",
+    name: 'Karine GIRAUD',
+    status: 'Secrétaire administrative',
+    structure: 'Association Musicale Sainte Cécile de Lagord (17)',
   },
   {
     review:
       "Logiciel très complet qui permet de faire beaucoup de choses. J’apprécie particulièrement la réactivité, la bienveillance et le fait que l’équipe soit à l'écoute pour faire évoluer l'outil en fonction de nos besoins. Si besoin, la FAQ est vraiment utile. Elle permet de trouver rapidement une solution face à un problème rencontré..",
-    name: "Laurent BEL",
-    status: "Directeur administratif & pédagogique",
-    structure: " École de Musique EPIC Musique en 4 Rivières (74)",
+    name: 'Laurent BEL',
+    status: 'Directeur administratif & pédagogique',
+    structure: ' École de Musique EPIC Musique en 4 Rivières (74)',
   },
   {
     review:
       "Opentalent est une entreprise avec de vraies valeurs humaines, à l'écoute de chaque structure et qui ne cesse de s'améliorer pour toujours coller aux besoins de ses clients. Plus qu'une relation commerciale, c'est pour nous un véritable partenaire au quotidien..",
-    name: "Philippe BORY",
-    status: "Personnel administratif",
+    name: 'Philippe BORY',
+    status: 'Personnel administratif',
     structure: "École d'Arts de Saint-Michel-sur-Orge (91)",
   },
-];
+]
 </script>
 
 <style scoped>

+ 57 - 63
components/Logiciels/School/SomeNumbers.vue

@@ -3,89 +3,83 @@
     <v-row class="align-center custom-row">
       <v-col cols="12">
         <v-row no-gutters>
-          <LayoutUISubTitle>
-            Quelques chiffres
-          </LayoutUISubTitle>
+          <LayoutUISubTitle> Quelques chiffres </LayoutUISubTitle>
 
           <LayoutUITitle>
-            Pour les petits comme pour les GRANDS établissements d'enseignement artistique
+            Pour les petits comme pour les GRANDS<br />établissements
+            d'enseignement artistique
           </LayoutUITitle>
         </v-row>
       </v-col>
     </v-row>
 
-    <v-container>
-      <v-row class="mb-12 card-container custom-row">
-        <v-col
-          lg="3"
-          class="d-flex justify-center align-center small-padding"
-        >
-          <CommonCardStat
-            number="30 > 1 500"
-            text="Élèves"
-          />
-        </v-col>
-        <v-col
-          lg="3"
-          class="d-flex justify-center align-center"
-        >
-          <CommonCardStat
-            number="234"
-            text="Clients"
-          />
-        </v-col>
-        <v-col
-          lg="3"
-          class="d-flex justify-center align-center"
-        >
-          <CommonCardStat
-            number="20 304"
-            text="Utilisateurs"
-          />
-        </v-col>
-        <v-col
-          lg="3"
-          class="d-flex justify-center align-center"
-        >
-          <CommonCardStat
-            number="13"
-            text="Années d'expérience"
-          />
-        </v-col>
-      </v-row>
-    </v-container>
-    <v-row />
+    <v-row class="mb-12 card-container center-90">
+      <v-col
+        lg="3"
+        md="6"
+        cols="12"
+        class="d-flex justify-center align-center small-padding"
+      >
+        <CommonCardStat number="30 > 1 500" text="Élèves" />
+      </v-col>
+      <v-col lg="3" md="6" cols="12" class="d-flex justify-center align-center">
+        <CommonCardStat number="139" text="Clients" />
+      </v-col>
+      <v-col lg="3" md="6" cols="12" class="d-flex justify-center align-center">
+        <CommonCardStat number="153 602" text="Utilisateurs" />
+      </v-col>
+      <v-col lg="3" md="6" cols="12" class="d-flex justify-center align-center">
+        <CommonCardStat number="17" text="Années d'expérience" />
+      </v-col>
+    </v-row>
 
-    <CommonCarouselClients :items="items" >
-      <template v-slot:title>
-        Plus de <span class="alt-color">5000 structures</span> nous font confiance
+    <CommonCarouselClients :items="items">
+      <template #title>
+        <span class="alt-color">139 structures</span> nous font
+        confiance
       </template>
     </CommonCarouselClients>
   </LayoutContainer>
 </template>
 
 <script setup lang="ts">
-const items: Array<{ src: string, alt: string }> = [
-  { src: "/images/reviews/school/review1.svg", alt: "Logo du Conservatoire « Les ateliers des arts" },
-  { src: "/images/reviews/school/review2.png", alt: "Logo du Conservatoire de Senlis" },
-  { src: "/images/reviews/school/review3.png", alt: "Logo de l’École de musique Sausheim" },
-  { src: "/images/reviews/school/review4.jpeg", alt: "Logo du Conservatoire Marly le Roi Roger Bourdin" },
-  { src: "/images/reviews/school/review5.jpeg", alt: "Logo du Conservatoire de Musique et de Danse du Thouarsais" },
-  { src: "/images/reviews/school/review6.jpeg", alt: "Logo du Conservatoire d’Annemasse" },
-];
+const items: Array<{ src: string; alt: string }> = [
+  {
+    src: '/images/pages/opentalent_school/reviews/Logo_Conservatoire_Les_Ateliers_des_Arts_Agglomeration_du_Puy-en-Velay.svg',
+    alt: 'Logo du Conservatoire « Les ateliers des arts',
+  },
+  {
+    src: '/images/pages/opentalent_school/reviews/Logo_Conservatoire-Senlis.png',
+    alt: 'Logo du Conservatoire de Senlis',
+  },
+  {
+    src: '/images/pages/opentalent_school/reviews/Logo_Ecole_de_Musique-Sausheim.png',
+    alt: 'Logo de l’École de musique Sausheim',
+  },
+  {
+    src: '/images/pages/opentalent_school/reviews/Logo_Conservatoire_Marly_le_Roi-Roger_Bourdin.jpeg',
+    alt: 'Logo du Conservatoire Marly le Roi Roger Bourdin',
+  },
+  {
+    src: '/images/pages/opentalent_school/reviews/Logo_Conservatoire_de_Musiques_et_de_Danses_du_Thouarsais.jpeg',
+    alt: 'Logo du Conservatoire de Musique et de Danse du Thouarsais',
+  },
+  {
+    src: '/images/pages/opentalent_school/reviews/Logo_Conservatoire_de_Musique_d_Annemasse.jpg',
+    alt: 'Logo du Conservatoire d’Annemasse',
+  },
+  {
+    src: '/images/pages/opentalent_school/reviews/Logo_EBAG-Ecole_des_Beaux-Arts_du_Genevois.png',
+    alt: 'Ecole des Beaux-Arts du Genevois',
+  },
+]
 </script>
 
 <style scoped lang="scss">
-.v-container {
+.card-container {
   --on-primary-color-alt: var(--secondary-color);
 }
 
-.custom-row {
-  width: 90%;
-  margin-right: auto;
-  margin-left: auto;
-}
-
 .v-row {
   max-width: 1600px;
   margin: 0 auto;

+ 2 - 4
components/Logiciels/Title.vue

@@ -1,10 +1,9 @@
-
 <template>
   <LayoutContainer>
     <div class="container-title">
       <v-col v-if="mdAndUp" cols="3" class="lateral-text">
         <span>
-          <slot name="left-text"/>
+          <slot name="left-text" />
         </span>
       </v-col>
       <v-col cols="12" md="6">
@@ -22,7 +21,7 @@
 </template>
 
 <script setup lang="ts">
-import { useDisplay } from "vuetify";
+import { useDisplay } from 'vuetify'
 
 const { mdAndUp } = useDisplay()
 </script>
@@ -35,7 +34,6 @@ const { mdAndUp } = useDisplay()
   align-items: center;
   text-align: center;
   letter-spacing: 0.18em;
-  border-bottom: 0.1rem solid var(--on-neutral-color-extra-light);
 }
 
 h1 {

+ 38 - 44
components/News/Details.vue

@@ -1,14 +1,5 @@
 <template>
   <LayoutContainer>
-    <v-row>
-      <v-col cols="12">
-        <CommonBanner
-          imageSrc="/images/actu/pub.png"
-          imageAlt="banner"
-        />
-      </v-col>
-    </v-row>
-
     <div class="news-section">
       <v-row class="mb-6 center-90">
         <v-col class="d-flex align-items-center">
@@ -26,10 +17,7 @@
       <div>
         <div v-if="pending">
           <v-row class="justify-center progress">
-            <v-progress-circular
-              indeterminate
-              color="grey"
-            />
+            <v-progress-circular indeterminate color="grey" />
           </v-row>
         </div>
 
@@ -39,35 +27,42 @@
             :description="newsItem.leadText"
           />
 
-          <v-row class="center-90">
+          <v-row class="center-90 mb-12">
             <v-col cols="12" md="6">
-              <v-img :src="getImageUrl(newsItem.attachment)"/>
+              <v-img :src="getImageUrl(newsItem.attachment)" cover />
             </v-col>
 
-            <v-col cols="12" md="6">
-              <h1>
+            <v-col cols="12" md="6" class="d-flex flex-column justify-center">
+              <h3>
                 {{ newsItem.title }}
-              </h1>
+              </h3>
+
+              <strong>
+                {{ newsItem.leadText }}
+              </strong>
             </v-col>
           </v-row>
 
           <v-row class="center-90">
-            <p
-              v-html="newsItem.bodyText"
-              class="description"
-            />
+            <p class="description" v-html="newsItem.bodyText" />
           </v-row>
 
           <v-row class="d-flex justify-center align-center">
-            <v-btn prepend-icon="fas fa-info" class="btn-plus mb-12" text>
+            <v-btn
+              v-if="newsItem.linkButton"
+              :href="newsItem.linkButton"
+              target="_blank"
+              class="btn-plus mb-12"
+              :text="true"
+            >
               En savoir plus
             </v-btn>
           </v-row>
 
           <v-row class="d-flex justify-space-between center-90">
-            <p>
-              MOTS CLÉS
-            </p>
+            <div>
+              <p v-if="newsItem.tags.length > 0">MOTS CLÉS</p>
+            </div>
             <div v-if="mdAndUp">
               <p>PARTAGER</p>
             </div>
@@ -75,7 +70,7 @@
 
           <v-row class="d-flex justify-space-between mb-8 center-90">
             <p class="key-word mt-3">
-              <span v-for="tag in newsItem.tags" class="mr-2">
+              <span v-for="tag in newsItem.tags" :key="tag.id" class="mr-2">
                 {{ tag.name }}
               </span>
             </p>
@@ -90,19 +85,17 @@
         </div>
       </div>
     </div>
-
-    <CommonAgenda />
   </LayoutContainer>
 </template>
 
 <script setup lang="ts">
-import { useEntityFetch } from "~/composables/data/useEntityFetch";
-import News from "~/models/Maestro/News";
-import { useDisplay } from "vuetify";
+import { useDisplay } from 'vuetify'
+import { useEntityFetch } from '~/composables/data/useEntityFetch'
+import News from '~/models/Maestro/News'
 
 const { mdAndUp, smAndDown } = useDisplay()
 
-const route = useRoute();
+const route = useRoute()
 const { fetch } = useEntityFetch()
 const config = useRuntimeConfig()
 
@@ -124,31 +117,32 @@ const getImageUrl = (attachment: string): string | null => {
 <style scoped>
 .news {
   .v-img {
-    width: 80%;
-    margin-left: 3.5rem;
+    max-height: 600px;
+    margin-left: auto;
     margin-right: auto;
   }
 
-  h1 {
-    margin-top: 11rem;
+  h3 {
     text-decoration: none;
     text-transform: uppercase;
     font-size: 36px;
     font-weight: 600;
+    color: var(--primary-color);
+  }
 
-    @media (max-width: 600px) {
-      margin-top: 3rem;
-    }
+  strong {
+    font-size: 21px;
+    margin-top: 16px;
   }
 
   .description {
     color: var(--primary-color);
-    text-align: justify;
-    font-size: 30px;
+    max-width: 80%;
+    font-size: 21px;
     font-weight: 500;
     line-height: 34px;
-    margin-left: 3.5rem;
-    margin-right: 3.5rem;
+    margin-left: auto;
+    margin-right: auto;
     margin-bottom: 3rem;
   }
 

+ 41 - 33
components/News/List.vue

@@ -1,17 +1,12 @@
 <template>
   <div v-if="pending">
     <v-row class="justify-center progress">
-      <v-progress-circular
-        indeterminate
-        color="grey"
-      />
+      <v-progress-circular indeterminate color="grey" />
     </v-row>
   </div>
 
-  <div v-else-if="!newsCollection || !(newsCollection!.items)">
-    <v-row class="justify-center">
-      Aucun résultat trouvé
-    </v-row>
+  <div v-else-if="!newsCollection || !newsCollection!.items">
+    <v-row class="justify-center"> Aucun résultat trouvé </v-row>
   </div>
 
   <div v-else>
@@ -24,17 +19,16 @@
         <v-card-item>
           <v-container fluid>
             <v-row align="center">
-              <v-col cols="12" md="3">
+              <v-col cols="12" lg="3">
                 <v-img
                   v-if="newsItem.attachment"
                   :src="getImageUrl(newsItem.attachment)"
                   alt="poster"
-                  height="200"
-                  width="400"
+                  cover
                 />
               </v-col>
 
-              <v-col cols="12" md="9">
+              <v-col cols="12" lg="9">
                 <div class="details">
                   <NuxtLink
                     :to="`/actualites/${newsItem.id}`"
@@ -67,7 +61,7 @@
                         <v-card-actions class="justify-end">
                           <v-btn
                             :to="`/actualites/${newsItem.id}`"
-                            class="btn mr-2 mb-1"
+                            class="inv-theme btn mr-2 mb-1"
                           >
                             En savoir plus
                           </v-btn>
@@ -89,8 +83,8 @@
           v-if="newsCollection && newsCollection.pagination"
           :model-value="page"
           :pagination="newsCollection.pagination"
-          @update:model-value="onPageUpdated"
           class="mt-4"
+          @update:model-value="onPageUpdated"
         />
       </v-col>
     </v-row>
@@ -98,28 +92,32 @@
 </template>
 
 <script setup lang="ts">
-import { useEntityFetch } from "~/composables/data/useEntityFetch";
-import News from "~/models/Maestro/News";
+import type { ComputedRef, Ref } from 'vue'
+import { useEntityFetch } from '~/composables/data/useEntityFetch'
+import News from '~/models/Maestro/News'
 
-const i18n = useI18n();
-const config = useRuntimeConfig();
+const config = useRuntimeConfig()
 const { fetchCollection } = useEntityFetch()
 
 const getImageUrl = (attachment: string) =>
-  `${config.public.apiBaseUrl}/uploads/news/${attachment}`;
+  `${config.public.apiBaseUrl}/uploads/news/${attachment}`
 
-const page: Ref<number> = ref(1);
+const page: Ref<number> = ref(1)
 
 const query: ComputedRef<Record<string, string | number>> = computed(() => {
   return {
     page: page.value,
-    type: "ENTREPRISE",
-    "startPublication[before]": "now",
-    "endPublication[after]": "now"
-  };
-});
+    type: 'BUSINESS',
+    'startPublication[before]': 'now',
+    'endPublication[after]': 'now',
+  }
+})
 
-const { data: newsCollection, pending, refresh } = fetchCollection(News, null, query)
+const {
+  data: newsCollection,
+  pending,
+  refresh,
+} = fetchCollection(News, null, query)
 
 const onPageUpdated = async (newVal: number): Promise<void> => {
   page.value = newVal
@@ -154,7 +152,7 @@ h1 {
 
 .news {
   .v-card {
-    border-radius: 10px;
+    border-radius: 14px;
     min-width: 100%;
     margin-bottom: 1rem;
     margin-left: 2rem;
@@ -174,20 +172,26 @@ h1 {
   }
 
   .v-img {
-    width: 80%;
-    margin-left: auto;
-    margin-right: auto;
+    width: 100%;
+    max-height: 160px;
+    margin: 12px;
+    border-radius: 14px;
+
+    @media (max-width: 1240px) {
+      width: 97%;
+      margin: 1.5%;
+    }
   }
 
   .details {
     border: 1px solid var(--neutral-color) !important;
     padding: 9px;
-    border-radius: 20px;
+    border-radius: 24px;
     width: 99%;
 
-    @media (max-width: 600px) {
+    @media (max-width: 1240px) {
       width: 94%;
-      margin: 12px 3%;
+      margin: -18px 3% 12px;
     }
 
     .v-card-title {
@@ -195,6 +199,10 @@ h1 {
       font-size: 36px;
       font-weight: 600;
       line-height: 39px;
+
+      @media (max-width: 1240px) {
+        font-size: 24px;
+      }
     }
 
     .star {

+ 124 - 148
components/Webinaire/Catalogue.vue

@@ -1,39 +1,29 @@
 <template>
   <LayoutContainer>
-    <div class="grey-container">
+    <div>
       <v-row class="center-90">
-        <LayoutUISubTitle>
-          Des webinaires pour tous
-        </LayoutUISubTitle>
+        <LayoutUISubTitle> Des webinaires pour tous </LayoutUISubTitle>
       </v-row>
 
       <v-row class="center-90">
         <v-col cols="12" class="section-title">
-          <h3>
-            SIMPLIFIEZ LA GESTION ET LA COMMUNICATION DE VOTRE STRUCTURE CULTURELLE
-          </h3>
+          <h3>Simplifiez la gestion et la communication de votre structure</h3>
 
           <div class="strong-label">
-            Votre orchestre, école de danse ou votre fédération mérite les outils les plus performants du marché pour briller en toute simplicité.
-            Découvrez comment nos outils peuvent transformer votre quotidien :
+            Votre structure culturelle, établissement d’enseignement artistique
+            ou fédération mérite les outils les plus performants du marché pour
+            briller en toute simplicité. Découvrez comment nos outils peuvent
+            transformer votre quotidien :
           </div>
         </v-col>
       </v-row>
 
       <v-row class="center-90 catalog">
-        <v-col
-          v-for="(course, index) in courses"
-          :key="index"
-          cols="12"
-          md="4"
-        >
+        <v-col v-for="(course, index) in courses" :key="index" cols="12" md="4">
           <v-card class="mb-4">
             <v-card-text>
               <div class="title-card-container">
-                <v-img
-                  :src="course.imageUrl"
-                  :alt="course.imageAlt"
-                />
+                <v-img :src="course.imageUrl" :alt="course.imageAlt" />
 
                 <h4>
                   {{ course.title }}
@@ -45,9 +35,7 @@
               </p>
 
               <div class="objectives mt-6">
-                <h6>
-                  Objectifs
-                </h6>
+                <h6>Objectifs</h6>
 
                 <ul>
                   <li
@@ -59,10 +47,10 @@
                 </ul>
               </div>
 
+              <div class="badge-time">Durée : {{ course.duration }}</div>
+
               <div class="program">
-                <h6>
-                  Programme
-                </h6>
+                <h6>Programme</h6>
 
                 <v-row>
                   <v-col
@@ -82,22 +70,11 @@
                 </v-row>
               </div>
 
-              <v-chip class="badge-time">
-                <span>
-                  Durée : {{ course.duration }}
-                </span>
-              </v-chip>
-
-              <v-chip class="badge-time">
-                <span>
-                  {{ course.price }}
-                </span>
-              </v-chip>
+              <div class="badge-time">
+                {{ course.price }}
+              </div>
 
-              <v-chip
-                class="chip-register"
-                @click="showModal(course.title)"
-              >
+              <v-chip class="chip-register" @click="showModal(course.title)">
                 Inscrivez-vous
               </v-chip>
             </v-card-text>
@@ -110,176 +87,174 @@
     <v-dialog
       v-model="modalShowing"
       max-width="800"
+      :retain-focus="false"
+      :scrollable="true"
       class="calendar-modal"
     >
-      <div class="alt-theme d-flex flex-column align-center">
-        <LayoutUISubTitle>
-          Inscrivez vous
-        </LayoutUISubTitle>
-
-        <h4 class="title-inscription text-center mt-4">
-          Vous y êtes presque !
-        </h4>
-
-        <iframe
-          :src="webinaireCalendars[selectedWebinar]"
-          width="700"
-          height="700"
-        />
-
-        <v-row>
-          <v-col cols="12">
-            <v-btn
-              class="close-button"
-              @click="closeModal()"
+      <template v-slot:default="{ isActive }">
+        <div class="alt-theme d-flex flex-column align-center">
+            <v-card
+              title="Inscrivez vous"
             >
-              Fermer
-            </v-btn>
-          </v-col>
-        </v-row>
-      </div>
+              <v-card-text style="height: 70vh;">
+                <h4 class="title-inscription text-center mt-4">
+                  Vous y êtes presque !
+                </h4>
+
+                <iframe
+                  :src="webinaireCalendars[selectedWebinar]"
+                  width="700"
+                  height="700"
+                />
+              </v-card-text>
+            </v-card>
+
+            <v-row>
+              <v-col cols="12">
+                <v-btn class="close-button" @click="closeModal()"> Fermer </v-btn>
+              </v-col>
+            </v-row>
+        </div>
+      </template>
     </v-dialog>
   </LayoutContainer>
 </template>
 
 <script setup lang="ts">
-import type { Training } from "~/types/interface";
-
-const downloadPdf = (pdfUrl: string) => {
-  window.open(pdfUrl, "_blank");
-};
+import type { Ref } from 'vue'
+import type { Training } from '~/types/interface'
 
 const courses: Array<Training> = [
   {
-    imageUrl: "/images/logo/logiciels/&_Jaune.png",
-    imageAlt: "Esperluette du logo Opentalent Artist",
-    title: "Webinaire Artist ",
+    imageUrl: '/images/logos/opentalent/Logo_Opentalent_Artist_Griffe.png',
+    imageAlt: 'Esperluette du logo Opentalent Artist',
+    title: 'Webinaire Artist ',
     description:
-      "Ce webinaire est destiné aux acteurs culturels tels que les orchestres, les chorales, les compagnies et troupes de danse, théâtre et cirque. Il vous permettra de découvrir les fonctionnalités du logiciels, les avantages et les différentes versions.. ",
+      'Ce webinaire est destiné aux acteurs culturels tels que les orchestres, les chorales, les compagnies et troupes de danse, théâtre et cirque. Il vous permettra de découvrir les fonctionnalités du logiciels, les avantages et les différentes versions.. ',
     objectives: [
-      "Découvrir le logiciel Opentalent Artist",
-      "Présentation des principales fonctionnalités",
-      "Quelles sont les différences entre les versions Standard & Premium ?",
-      "Qu'est ce que l'Agenda culturel et l'annuaire ? ",
+      'Obtenir une présentation du logiciel Opentalent Artist',
+      'Présentation des principales fonctionnalités',
+      "Qu'est ce que l'agenda culturel et l'annuaire ? ",
+      'Quelles différences entre la version Standard & Premium ?',
     ],
-    duration: "1H30",
+    duration: '1H30',
     additionalObjectives: [
       {
         id: 1,
         objectives: [
-          "Accès et interface",
-          "Configuration",
-          "Répertoire",
-          "Agenda",
+          'Accès et interface',
+          'Configuration',
+          'Répertoire',
+          'Agenda',
         ],
       },
       {
         id: 2,
         objectives: [
-          "Parc matériel",
-          "Rapport d’activité",
-          "Site internet",
-          "Communication",
+          'Parc matériel',
+          'Rapport d’activité',
+          'Communication',
+          'Site internet',
         ],
       },
     ],
-    price: "Gratuit",
+    price: 'Gratuit',
     downloadLink:
-      "https://www.opentalent.fr/fileadmin/stockage/stockage/support/programme/PF-School-2023-02_2-jours.pdf",
+      'https://www.opentalent.fr/fileadmin/stockage/stockage/support/programme/PF-School-2023-02_2-jours.pdf',
   },
   {
     // number: "02",
-    title: "Webinaire School",
-    imageUrl: "/images/logo/logiciels/&_Bleu.png",
-    imageAlt: "Esperluette du logo Opentalent School",
+    title: 'Webinaire School',
+    imageUrl: '/images/logos/opentalent/Logo_Opentalent_School_Griffe.png',
+    imageAlt: 'Esperluette du logo Opentalent School',
     description:
       " Rejoignez notre webinaire dédié aux petits comme aux GRANDS établissements d'enseignement artistique et découvrez comment optimiser votre travail grâce à un outil professionnel.",
     objectives: [
-      "Découvrir le logiciel Opentalent School",
+      'Obtenir une présentation du logiciel Opentalent School',
       "Comprendre l'écosystème de l'outil",
-      "Présentation des principales fonctionnalités",
-      "Identifier les avantages de cet outil pour votre structure",
+      "Identifier les avantages qu'offre ce logiciel pour votre structure",
+      'Apprendre à gérer votre propre site internet',
     ],
-    duration: "1h",
+    duration: '1h',
     additionalObjectives: [
       {
         id: 1,
         objectives: [
-          "Accès et interface",
-          "Configuration",
-          "Répertoire",
-          "Agenda",
+          'Accès et interface',
+          'Configuration',
+          'Répertoire',
+          'Agenda',
         ],
       },
       {
         id: 2,
         objectives: [
-          "Parc matériel",
-          "Rapport d’activité",
-          "Site internet",
-          "Communication",
+          'Parc matériel',
+          'Facturation',
+          'Communication',
+          'Site internet',
         ],
       },
     ],
-    price: "Gratuit",
+    price: 'Gratuit',
     downloadLink:
-      "https://www.opentalent.fr/fileadmin/stockage/stockage/support/programme/PF-School-2023-02_1-jour.pdf",
+      'https://www.opentalent.fr/fileadmin/stockage/stockage/support/programme/PF-School-2023-02_1-jour.pdf',
   },
   {
-    title: "Webinaire Manager",
-    imageUrl: "/images/logo/logiciels/&_Rouge.png",
-    imageAlt: "Esperluette du logo Opentalent Manager",
+    title: 'Webinaire Manager',
+    imageUrl: '/images/logos/opentalent/Logo_Opentalent_Manager_Griffe.png',
+    imageAlt: 'Esperluette du logo Opentalent Manager',
     description:
       "Ces webinaires  sont spécialement conçues pour les utilisateurs du logiciel fédéral de la CMF (Confédération Musicale de France). Gagner en temps administratif, booster vos performances et optimiser l'utilisation du logiciel.",
     objectives: [
       "Configurer l'appel de cotisation",
       "Suivre l'appel de cotisation",
-      "Gérer votre site internet (débutants)",
-      "Gérer votre site internet (confirmés)",
+      'Gérer votre site internet (pour les débutants)',
+      'Gérer votre site internet (pour les confirmés)',
     ],
-    duration: "1H30",
+    duration: '1H30',
     additionalObjectives: [
       {
         id: 1,
         objectives: [
-          "Mieux connaitre votre logiciel",
-          "Optimiser votre temps administratif",
+          'Mieux connaitre votre logiciel',
+          'Optimiser votre temps administratif',
         ],
       },
       {
         id: 2,
         objectives: [
-          "Communiquer avec votre réseau",
-          "Promouvoir votre organisation",
+          'Communiquer avec votre réseau',
+          'Promouvoir votre organisation',
         ],
       },
     ],
-    price: "Gratuit",
+    price: 'Gratuit',
     downloadLink:
-      " https://www.opentalent.fr/fileadmin/stockage/stockage/support/programme/PF-Typo3-2023-02_1-jour.pdf",
+      ' https://www.opentalent.fr/fileadmin/stockage/stockage/support/programme/PF-Typo3-2023-02_1-jour.pdf',
   },
-];
+]
 
-const selectedWebinar: Ref<string | null> = ref(null);
+const selectedWebinar: Ref<string | null> = ref(null)
 
 const webinaireCalendars: Record<string, string> = {
-  "Webinaire Artist":
-    "https://widget.weezevent.com/ticket/E920851/?code=62708&locale=fr-FR&width_auto=1&color_primary=0e2d32",
-  "Webinaire School":
-    "https://widget.weezevent.com/ticket/E963899/?code=47365&locale=fr-FR&width_auto=1&color_primary=0e2d32",
-  "Webinaire Manager":
-    "https://widget.weezevent.com/ticket/E923624/?code=4857&locale=fr-FR&width_auto=1&color_primary=0e2d32",
-};
+  'Webinaire Artist':
+    'https://widget.weezevent.com/ticket/E920851/?code=62708&locale=fr-FR&width_auto=1&color_primary=0e2d32',
+  'Webinaire School':
+    'https://widget.weezevent.com/ticket/E963899/?code=47365&locale=fr-FR&width_auto=1&color_primary=0e2d32',
+  'Webinaire Manager':
+    'https://widget.weezevent.com/ticket/E923624/?code=4857&locale=fr-FR&width_auto=1&color_primary=0e2d32',
+}
 
 const showModal = (webinaireTitle: string) => {
-  selectedWebinar.value = webinaireTitle.trim();
-};
+  selectedWebinar.value = webinaireTitle.trim()
+}
 
 const modalShowing = computed(() => selectedWebinar.value)
 
 const closeModal = () => {
-  selectedWebinar.value = null;
-};
+  selectedWebinar.value = null
+}
 </script>
 
 <style scoped lang="scss">
@@ -292,30 +267,27 @@ const closeModal = () => {
 .section-title {
   display: flex;
   flex-direction: column;
-  align-items: center;
 
   h3 {
-    font-size: 2rem;
-    letter-spacing: .1rem;
+    font-size: 42px;
+    letter-spacing: 0.1rem;
     line-height: 3.5rem;
-    margin-bottom: .5rem;
+    margin-bottom: 0.5rem;
     margin-top: 2rem;
-    text-transform: uppercase;
   }
 
   .strong-label {
     font-size: 1.5rem;
     font-weight: 400 !important;
-    letter-spacing: .1rem;
+    letter-spacing: 0.1rem;
     line-height: 2rem;
     margin-bottom: 1rem;
-    text-align: center;
-    text-transform: uppercase;
   }
 }
 
 .catalog {
   padding: 2rem;
+  background: var(--neutral-color-alt-light);
 
   .title-card-container {
     display: flex;
@@ -354,10 +326,11 @@ const closeModal = () => {
     }
   }
 
-  .objectives, .program {
+  .objectives,
+  .program {
     justify-content: space-between;
     align-items: center;
-    background: var(--secondary-color);
+    background: var(--secondary-color-light);
     margin-top: 1rem;
     margin-bottom: 1rem;
     border-radius: 1rem;
@@ -394,17 +367,20 @@ const closeModal = () => {
   }
 
   .badge-time {
-    color: var(--neutral-color);
-    border: 1px solid var(--primary-color);
-  }
-
-  .badge-time span {
     color: var(--primary-color);
+    background: var(--neutral-color);
+    width: 100%;
+    height: 36px;
+    text-align: center;
+    font-size: 18px;
+    font-weight: 500;
+    border-radius: 12px;
+    vertical-align: center;
+    padding-top: 6px;
   }
 }
 
 .calendar-modal {
-
   h4 {
     font-weight: 600;
     font-size: 2rem;
@@ -413,7 +389,7 @@ const closeModal = () => {
   }
 
   .close-button {
-    background-color: #e34461;  /* TODO: pqoi cette couleur ici? */
+    background-color: #e34461; /* TODO: pqoi cette couleur ici? */
     color: var(--on-primary-color);
     font-weight: 500;
     font-size: 14px;

+ 46 - 50
components/Webinaire/FAQ.vue

@@ -4,93 +4,86 @@ Foire aux questions
 <template>
   <LayoutContainer>
     <v-row class="center-90">
-      <LayoutUISubTitle>
-        Des questions ?
-      </LayoutUISubTitle>
+      <LayoutUISubTitle> Des questions ? </LayoutUISubTitle>
     </v-row>
 
     <v-row class="center-90">
       <v-col cols="12" class="section-title">
-        <h3>
-          Tout savoir sur nos webinaire en ligne
-        </h3>
+        <h3>Tout savoir sur nos webinaire en ligne</h3>
 
-        <div class="strong-label">
-          Les questions les plus fréquentes
-        </div>
+        <div class="strong-label">Les questions les plus fréquentes</div>
       </v-col>
     </v-row>
 
-    <div class="faq">
-      <div
-        v-for="(item, index) in faqItems"
-        :key="index"
-        class="faq-item"
-      >
+    <div class="faq center-90">
+      <div v-for="(item, index) in faqItems" :key="index" class="faq-item">
         <div
-          class="question"
+          :class="'question' + (isOpen(index) ? ' open' : '')"
           @click="toggle(index)"
         >
-          <v-icon icon="fas fa-circle" />
+          <v-icon v-if="isOpen(index)" icon="fas fa-angle-down" />
+          <v-icon v-else icon="fas fa-angle-right" />
           {{ item.question }}
         </div>
 
-        <div
-          v-if="isOpen(index)"
-          class="answer"
-        >
-          {{ item.answer }}
-        </div>
+        <div v-if="isOpen(index)" class="answer" v-html="item.answer" />
       </div>
     </div>
   </LayoutContainer>
 </template>
 
 <script setup lang="ts">
-import type { FaqEntry } from "~/types/interface";
+import type { Ref } from 'vue'
+import type { FaqEntry } from '~/types/interface'
 
 const faqItems: Array<FaqEntry> = [
   {
     question: 'Comment s’inscrire à un webinaire?',
-    answer: 'Pour vous inscrire à un webinaire, suivez le lien "Inscrivez-vous" correspondant au cours qui vous intéresse.',
+    answer:
+      'Pour vous inscrire à un webinaire, suivez le lien "Inscrivez-vous" correspondant au cours qui vous intéresse.',
   },
   {
     question: 'Combien de temps dure nos webinaires ?',
-    answer: 'Nos webinaires durent en moyenne 1H30. Les sessions de questions/réponses peuvent parfois prolonger la durée prévue de nos webinaires.',
+    answer:
+      'Nos webinaires durent en moyenne 1H30. Les sessions de questions/réponses peuvent parfois prolonger la durée prévue de nos webinaires.',
   },
   {
     question: 'Comment se passe un webinaire ?',
-    answer: 'Inscrivez-vous à l\'un de nos webinaires en choisissant une date sur l\'agenda et renseignez vos informations. ' +
-            'Vous recevrez à la suite de votre inscription sur notre site, un email de confirmation avec un rappel de la date et de l\'horaire de participation ainsi que l\'URL de connexion pour le webinaire. ' +
-            'Un mail de relance à J-1 vous sera envoyer vous rappelant votre participation au webinaire. ' +
-            'Le jour J, cliquez sur l\'URL de connexion. Nous vous encourageons à arriver quelques minutes en avance pour vous assurer de pouvoir accéder au webinaire sans aucun problème technique. ' +
-            'Lors du début du webinaire, toutes les instructions nécessaires vous seront fournies.'
+    answer:
+      "Inscrivez-vous à l'un de nos webinaires en choisissant une date sur l'agenda et renseignez vos informations. " +
+      "Vous recevrez à la suite de votre inscription sur notre site, un email de confirmation avec un rappel de la date et de l'horaire de participation ainsi que l'URL de connexion pour le webinaire. " +
+      'Un mail de relance à J-1 vous sera envoyer vous rappelant votre participation au webinaire. ' +
+      "Le jour J, cliquez sur l'URL de connexion. Nous vous encourageons à arriver quelques minutes en avance pour vous assurer de pouvoir accéder au webinaire sans aucun problème technique. " +
+      'Lors du début du webinaire, toutes les instructions nécessaires vous seront fournies.',
   },
   {
     question: 'De quel matériel aurais-je besoin pour suivre le webinaire ?',
-    answer: 'Pour plus de confort, il est recommandé d\'être équipé d\'un outil (de préférence un ordinateur) disposant d\'un micro et de haut-parleur.',
+    answer:
+      "Pour plus de confort, il est recommandé d'être équipé d'un outil (de préférence un ordinateur) disposant d'un micro et de haut-parleur.",
   },
   {
-    question: 'Y-a-t\'il une limite de participants ?',
-    answer: 'Il n\'y a pas de limite de participants lors de nos webinaires. Cependant, nous nous réservons le droit d\'annuler une session si le nombre de participants est inférieur à 3 personnes.',
+    question: "Y-a-t'il une limite de participants ?",
+    answer:
+      "Il n'y a pas de limite de participants lors de nos webinaires. Cependant, nous nous réservons le droit d'annuler une session si le nombre de participants est inférieur à 3 personnes.",
   },
   {
-    question: 'J\'ai besoin d\'aide...',
-    answer: 'Notre équipe est là pour vous. <button style="background-color: #0E2D32; color: #fff; border: none;border-radius: 4px;padding: 0.5rem 1rem;cursor: pointer;"   class="contact-btn" onclick="window.location.href=\'/nous-contacter\'">Contactez-nous</button>'
-}];
+    question: "J'ai besoin d'aide...",
+    answer:
+      'Notre équipe est là pour vous. <br/><button style="background-color: #0E2D32; color: #fff; border: none;border-radius: 4px;padding: 0.5rem 1rem;cursor: pointer;margin-top: 6px;"   class="contact-btn" onclick="window.location.href=\'/nous-contacter\'">Contactez-nous</button>',
+  },
+]
 
-const activeIndex: Ref<number | null> = ref(null);
+const activeIndex: Ref<number | null> = ref(null)
 
 function toggle(index: number) {
-  activeIndex.value = activeIndex.value === index ? null : index;
+  activeIndex.value = activeIndex.value === index ? null : index
 }
 
 function isOpen(index: number) {
-  return activeIndex.value === index;
+  return activeIndex.value === index
 }
 </script>
 
-
 <style scoped lang="scss">
 .section-title {
   display: flex;
@@ -98,18 +91,17 @@ function isOpen(index: number) {
   align-items: center;
 
   h3 {
-    font-size: 2rem;
-    letter-spacing: .1rem;
+    font-size: 42px;
+    letter-spacing: 0.1rem;
     line-height: 3.5rem;
-    margin-bottom: .5rem;
+    margin-bottom: 0.5rem;
     margin-top: 2rem;
-    text-transform: uppercase;
   }
 
   .strong-label {
     font-size: 1.5rem;
     font-weight: 400 !important;
-    letter-spacing: .1rem;
+    letter-spacing: 0.1rem;
     line-height: 2rem;
     margin-bottom: 1rem;
     text-align: center;
@@ -143,17 +135,21 @@ function isOpen(index: number) {
   }
 
   .v-icon {
-    font-size: 10px !important;
+    font-size: 16px !important;
     color: var(--on-primary-color-alt);
     margin-right: 0.5rem;
   }
 }
 
+.question.open {
+  border-radius: 4px 4px 0 0;
+}
+
 .answer {
-  background-color: var(--secondary-color);
+  background-color: var(--secondary-color-light);
   padding: 0.5rem 1rem;
-  border: 1px solid var(--neutral-color-alt-strong);
-  border-top: none;
+  border: none;
   border-radius: 0 0 4px 4px;
+  box-shadow: -1px 2px 6px 3px var(--on-neutral-color-extra-light);
 }
 </style>

+ 42 - 26
composables/data/useEntityFetch.ts

@@ -1,42 +1,58 @@
-import {useEntityManager} from "~/composables/data/useEntityManager";
-import ApiResource from "~/models/ApiResource";
-import type {AssociativeArray, Collection} from "~/types/data";
-import type {AsyncData} from "#app";
-import type {ComputedRef, Ref} from "vue";
-import {v4 as uuid4} from "uuid";
+import type { AsyncData } from '#app'
+import type { ComputedRef, Ref } from 'vue'
+import { v4 as uuid4 } from 'uuid'
+import { useEntityManager } from '~/composables/data/useEntityManager'
+import ApiResource from '~/models/ApiResource'
+import type { AssociativeArray, Collection } from '~/types/data'
 
 interface useEntityFetchReturnType {
-  fetch: (model: typeof ApiResource, id: number) => AsyncData<ApiResource, ApiResource | true>,
-  fetchCollection: (model: typeof ApiResource, parent?: ApiResource | null, query?: Ref<AssociativeArray>) => AsyncData<Collection, any>
-  // @ts-ignore
-  getRef: <T extends ApiResource>(model: typeof T, id: Ref<number | null>) => ComputedRef<null | T>
+  fetch: (
+    model: typeof ApiResource,
+    id: number
+  ) => AsyncData<ApiResource | null, Error | null>
+
+  fetchCollection: (
+    model: typeof ApiResource,
+    parent?: ApiResource | null,
+    query?: Ref<AssociativeArray>
+  ) => AsyncData<Collection | null, Error | null>
+
+  getRef: <T extends ApiResource>(
+    model: new () => T,
+    id: Ref<number | null>
+  ) => ComputedRef<null | T>
 }
 
 // TODO: améliorer le typage des fonctions sur le modèle de getRef
-export const useEntityFetch = (lazy: boolean = false): useEntityFetchReturnType => {
+export const useEntityFetch = (
+  lazy: boolean = false
+): useEntityFetchReturnType => {
   const { em } = useEntityManager()
 
-  const fetch = (model: typeof ApiResource, id: number) => useAsyncData(
-    model.entity + '_' + id + '_' + uuid4(),
-    () => em.fetch(model, id, true),
-    { lazy }
-  )
+  const fetch = (model: typeof ApiResource, id: number) =>
+    useAsyncData(
+      model.entity + '_' + id + '_' + uuid4(),
+      () => em.fetch(model, id, true),
+      { lazy }
+    )
 
   const fetchCollection = (
     model: typeof ApiResource,
     parent: ApiResource | null = null,
     query: Ref<AssociativeArray | null> = ref(null)
-  ) => useAsyncData(
-    model.entity + '_many_' + uuid4(),
-    () => em.fetchCollection(model, parent, query.value ?? undefined),
-    { lazy }
-  )
-
-  // @ts-ignore
-  const getRef = <T extends ApiResource>(model: typeof T, id: Ref<number | null>): ComputedRef<T | null> => {
-    return computed(() => (id.value ? em.find(model, id.value) as T : null))
+  ) =>
+    useAsyncData(
+      model.entity + '_many_' + uuid4(),
+      () => em.fetchCollection(model, parent, query.value ?? undefined),
+      { lazy }
+    )
+
+  const getRef = <T extends ApiResource>(
+    model: new () => T,
+    id: Ref<number | null>
+  ): ComputedRef<T | null> => {
+    return computed(() => (id.value ? (em.find(model, id.value) as T) : null))
   }
 
-  //@ts-ignore
   return { fetch, fetchCollection, getRef }
 }

+ 3 - 3
composables/data/useEntityManager.ts

@@ -1,6 +1,6 @@
-import EntityManager from "~/services/data/entityManager";
-import {useMaestroRequestService} from "~/composables/data/useMaestroRequestService";
-import {useRepo} from "pinia-orm";
+import { useRepo } from 'pinia-orm'
+import EntityManager from '~/services/data/entityManager'
+import { useMaestroRequestService } from '~/composables/data/useMaestroRequestService'
 
 let entityManager: EntityManager | null = null
 

+ 7 - 10
composables/data/useEnumFetch.ts

@@ -1,20 +1,17 @@
-import {useEnumManager} from "~/composables/data/useEnumManager";
-import type {Enum} from "~/types/data";
-import type {AsyncData} from "#app";
+import type { AsyncData } from '#app'
+import { useEnumManager } from '~/composables/data/useEnumManager'
+import type { Enum } from '~/types/data'
 
 interface useEnumFetchReturnType {
-  fetch: (enumName: string) => AsyncData<Enum, null | true | Error>,
+  fetch: (enumName: string) => AsyncData<Enum, null | true | Error>
 }
 
 export const useEnumFetch = (lazy: boolean = false): useEnumFetchReturnType => {
   const { enumManager } = useEnumManager()
 
-  const fetch = (enumName: string) => useAsyncData(
-    enumName,
-    () => enumManager.fetch(enumName),
-    { lazy }
-  )
+  const fetch = (enumName: string) =>
+    useAsyncData(enumName, () => enumManager.fetch(enumName), { lazy })
 
-  //@ts-ignore
+  // @ts-ignore
   return { fetch }
 }

Daži faili netika attēloti, jo izmaiņu fails ir pārāk liels