rerefactor du fetching de contenus une mielleure ux au load des modales (description dans le readme)
This commit is contained in:
		@@ -1,3 +1,8 @@
 | 
			
		||||
## Routing flow
 | 
			
		||||
 | 
			
		||||

 | 
			
		||||

 | 
			
		||||
 | 
			
		||||
<img alt="Drupal Logo" src="https://www.drupal.org/files/Wordmark_blue_RGB.png" height="60px">
 | 
			
		||||
 | 
			
		||||
Drupal is an open source content management platform supporting a variety of
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,6 @@
 | 
			
		||||
import { initVueContentModale } from './utils/vue-setup';
 | 
			
		||||
import { processClickableElements } from './utils/process-clickable-elements';
 | 
			
		||||
import { handleReactiveness, setMenuToggle, setHamburgerWhenLogged } from './utils/layout-setup';
 | 
			
		||||
import { handleReactiveness, setMenuToggle, setRightSectionsWhenLogged } from './utils/layout-setup';
 | 
			
		||||
import { initFirstLoadRouting, handleClickableElements, handleBrowserNavigation } from './utils/handle-navigation';
 | 
			
		||||
import { setupMapStore, preloadEtapesTiles } from './utils/map-setup';
 | 
			
		||||
 | 
			
		||||
@@ -13,16 +13,15 @@ import '../scss/main.scss'
 | 
			
		||||
(function ($, Drupal, drupalSettings) {
 | 
			
		||||
    const CaravaneTheme = function () {
 | 
			
		||||
        function init () {            
 | 
			
		||||
            console.log('07/04 ci-cd fonctionne, import des configs ?')
 | 
			
		||||
            // console.log('DrupalSettings', drupalSettings);
 | 
			
		||||
            
 | 
			
		||||
            const baseUrl = window.location.protocol + "//" + window.location.host;
 | 
			
		||||
            const siteName = document.querySelector('#site_name').innerText;
 | 
			
		||||
            const { store, mapStore, router, route } = initVueContentModale();
 | 
			
		||||
            const router = initVueContentModale();
 | 
			
		||||
 | 
			
		||||
            handleReactiveness();
 | 
			
		||||
            setMenuToggle();
 | 
			
		||||
            setHamburgerWhenLogged(drupalSettings);
 | 
			
		||||
            setRightSectionsWhenLogged(drupalSettings);
 | 
			
		||||
 | 
			
		||||
            // https://www.drupal.org/docs/extending-drupal/contributed-modules/contributed-module-documentation/leaflet/leaflet-api
 | 
			
		||||
 | 
			
		||||
@@ -44,22 +43,21 @@ import '../scss/main.scss'
 | 
			
		||||
                        } = processClickableElements();
 | 
			
		||||
                        const clickableElements = [...etapeListLinks, ...generalListLinks, logoLink, ...mapIcons, mapContainer];                        
 | 
			
		||||
 | 
			
		||||
                        setupMapStore(mapStore, map, settings);
 | 
			
		||||
                        setupMapStore(map, settings);
 | 
			
		||||
 | 
			
		||||
                        // preloadEtapesTiles(mapStore, map);
 | 
			
		||||
                        // preloadEtapesTiles(map);
 | 
			
		||||
 | 
			
		||||
                        initFirstLoadRouting(store, router, baseUrl, siteName);
 | 
			
		||||
                        initFirstLoadRouting(router, baseUrl, siteName);
 | 
			
		||||
 | 
			
		||||
                        handleClickableElements(clickableElements, store, router, baseUrl, siteName, mapStore);
 | 
			
		||||
                        handleClickableElements(clickableElements, router, baseUrl, siteName);
 | 
			
		||||
 | 
			
		||||
                        window.addEventListener("popstate", () => {
 | 
			
		||||
                          handleBrowserNavigation(store, baseUrl, siteName, mapStore);
 | 
			
		||||
                          handleBrowserNavigation(baseUrl, siteName);
 | 
			
		||||
                        });
 | 
			
		||||
                    });
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        init()
 | 
			
		||||
    }
 | 
			
		||||
    CaravaneTheme()
 | 
			
		||||
 
 | 
			
		||||
@@ -1,201 +1,68 @@
 | 
			
		||||
// query et traitement des contenus
 | 
			
		||||
 | 
			
		||||
import { defineStore } from 'pinia';
 | 
			
		||||
import REST from '../api/rest-axios';
 | 
			
		||||
 | 
			
		||||
import { useLayoutStore } from './layout';
 | 
			
		||||
 | 
			
		||||
import { findContentByPath } from '../utils/content/findContentByPath';
 | 
			
		||||
import { getCleanDate, fetchFromRelationships, getRelatedEtape, getRelatedRessources } from '../utils/content/contentFetchUtils';
 | 
			
		||||
import { getCarteSensible, getTitreTexte, getChiffresCles, getDiaporama, getEntretien, getVideos, getDocument, getGallerie } from '../utils/content/cleanParties';
 | 
			
		||||
import { getPartenaires, getGouvernance, getRessources } from '../utils/content/multiItemPages';
 | 
			
		||||
import { fetchSingletonFullContent, fetchSingletonPartialContent } from '../utils/content/fetchSingleton';
 | 
			
		||||
import { fetchMultipleFullContent, fetchMultiplePartialContent } from '../utils/content/fetchMultiple';
 | 
			
		||||
 | 
			
		||||
export const useContentStore = defineStore('content', {
 | 
			
		||||
    state: () => ({
 | 
			
		||||
        contentType: '',
 | 
			
		||||
        rawContent: {},
 | 
			
		||||
        pageTitle: '',
 | 
			
		||||
        content: {},
 | 
			
		||||
        partialLoading: false,
 | 
			
		||||
        loading: false,
 | 
			
		||||
        error: null,
 | 
			
		||||
    }),
 | 
			
		||||
    actions: {
 | 
			
		||||
        async fetchContentData(path) {
 | 
			
		||||
        // pages etape, statiques et ressource ont un seul item par page (singuliers)
 | 
			
		||||
        // pages gouvernance (contact), ressources et partenaire ont plusieurs items par pages (multiples)
 | 
			
		||||
        async fetchPartialContentData(path) {
 | 
			
		||||
            this.resetStore(false);
 | 
			
		||||
            const contentTypes = ['etape', 'static', 'gouvernance', 'partenaire', 'ressource'];
 | 
			
		||||
 | 
			
		||||
            try {
 | 
			
		||||
                const { contentType, rawContent } = await findContentByPath(contentTypes, path);
 | 
			
		||||
                this.contentType = contentType;
 | 
			
		||||
                this.rawContent = rawContent;
 | 
			
		||||
 | 
			
		||||
                if (
 | 
			
		||||
                    this.contentType === 'etape'
 | 
			
		||||
                    || this.contentType === 'static'
 | 
			
		||||
                    || this.contentType === 'ressourceItem'
 | 
			
		||||
                ) {        
 | 
			
		||||
                    const vignettePromise = fetchFromRelationships('field_vignette', rawContent.relationships);
 | 
			
		||||
                    const partiesPromise = fetchFromRelationships(this.contentType === 'ressourceItem' ? 'field_parties_ressource' : 'field_parties', rawContent.relationships);
 | 
			
		||||
 | 
			
		||||
                    let previousEtapePromise, nextEtapePromise;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
                    if (this.contentType === 'etape') {
 | 
			
		||||
                        previousEtapePromise = getRelatedEtape('previous', path);
 | 
			
		||||
                        nextEtapePromise = getRelatedEtape('next', path);
 | 
			
		||||
 | 
			
		||||
                        this.content.coordinates = {
 | 
			
		||||
                            lat: rawContent.attributes.field_geofield.lat,
 | 
			
		||||
                            lon: rawContent.attributes.field_geofield.lon,
 | 
			
		||||
                        };
 | 
			
		||||
                        this.content.adresse = rawContent.attributes.field_adresse;
 | 
			
		||||
                        this.content.etape_number = rawContent.attributes.field_arret_numero;
 | 
			
		||||
                        this.content.couleur = rawContent.attributes.field_couleur;
 | 
			
		||||
                        this.content.dates = {
 | 
			
		||||
                            start: getCleanDate(rawContent.attributes.field_dates.value),
 | 
			
		||||
                            end: getCleanDate(rawContent.attributes.field_dates.end_value),
 | 
			
		||||
                        }
 | 
			
		||||
                        this.content.relatedRessources = await getRelatedRessources(rawContent.id);
 | 
			
		||||
                    }
 | 
			
		||||
                    
 | 
			
		||||
                    if (this.contentType === 'ressourceItem') {
 | 
			
		||||
                        console.log(rawContent);
 | 
			
		||||
                        
 | 
			
		||||
                        this.content.ressourceType = rawContent.attributes.field_type_de_ressource;
 | 
			
		||||
                        this.content.auteurice = rawContent.attributes.field_autheurice;
 | 
			
		||||
                        this.content.date = getCleanDate(rawContent.attributes.field_date_ressource);
 | 
			
		||||
                        this.content.introduction = rawContent.attributes.field_introduction?.processed;                        
 | 
			
		||||
                        if (rawContent.relationships.field_etape.data) {
 | 
			
		||||
                            const relatedEtapeFetch = fetchFromRelationships('field_etape', rawContent.relationships);
 | 
			
		||||
                            const relatedEtape = await Promise.resolve(relatedEtapeFetch);
 | 
			
		||||
                            const relatedEtapeUrl = relatedEtape.attributes.metatag.find(tag => tag.tag === "link")?.attributes.href;
 | 
			
		||||
                            this.content.relatedEtape = await getRelatedEtape('', relatedEtapeUrl);                        
 | 
			
		||||
                        }
 | 
			
		||||
                        
 | 
			
		||||
                        useLayoutStore().hideEtapeList(true);
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    this.pageTitle = rawContent.attributes.metatag.find(tag => tag.tag === "meta")?.attributes.content;
 | 
			
		||||
                    this.content.contentTitle = rawContent.attributes.title;
 | 
			
		||||
 | 
			
		||||
                    const [vignetteData, partiesData] = await Promise.all([vignettePromise, partiesPromise]);
 | 
			
		||||
 | 
			
		||||
                    if (vignetteData) {
 | 
			
		||||
                        this.content.vignette = {
 | 
			
		||||
                            url: {
 | 
			
		||||
                                original: vignetteData.attributes.uri.url,
 | 
			
		||||
                                small: vignetteData.attributes.image_style_uri.content_small,
 | 
			
		||||
                                medium: vignetteData.attributes.image_style_uri.content_medium,
 | 
			
		||||
                                large: vignetteData.attributes.image_style_uri.content_large,
 | 
			
		||||
                            },
 | 
			
		||||
                            alt: rawContent.relationships.field_vignette.data.meta.alt
 | 
			
		||||
                        };
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    if (partiesData) {
 | 
			
		||||
                        const partiesPromises = partiesData.map(async (partie) => {
 | 
			
		||||
                            const partieType = partie.type.replace(/^paragraph--/, "");
 | 
			
		||||
                            let partieContent = { type: partieType };                            
 | 
			
		||||
 | 
			
		||||
                            switch (partieType) {
 | 
			
		||||
                                case 'carte_sensible':
 | 
			
		||||
                                    partieContent.carteSensible = await getCarteSensible(partie);
 | 
			
		||||
                                    break;
 | 
			
		||||
                                case 'titre_texte':
 | 
			
		||||
                                    const { titre, texte } = await getTitreTexte(partie);
 | 
			
		||||
                                    partieContent.titre = titre;
 | 
			
		||||
                                    partieContent.texte = texte;
 | 
			
		||||
                                    break;
 | 
			
		||||
                                case 'chiffres_cles':
 | 
			
		||||
                                    partieContent.chiffresCles = await getChiffresCles(partie);
 | 
			
		||||
                                    break;
 | 
			
		||||
                                case 'diaporama':
 | 
			
		||||
                                    partieContent.diaporama = await getDiaporama(partie);
 | 
			
		||||
                                    break;
 | 
			
		||||
                                case 'entretien':
 | 
			
		||||
                                    partieContent.entretien = await getEntretien(partie);
 | 
			
		||||
                                    break;
 | 
			
		||||
                                case 'exergue':
 | 
			
		||||
                                    partieContent.exergue = partie.attributes.field_texte_exergue.value;
 | 
			
		||||
                                    break;
 | 
			
		||||
                                case 'video':
 | 
			
		||||
                                    partieContent.videos = getVideos(partie);
 | 
			
		||||
                                    break;
 | 
			
		||||
                                case 'document':
 | 
			
		||||
                                    partieContent.document = await getDocument(partie);
 | 
			
		||||
                                    break;
 | 
			
		||||
                                case 'galleries':
 | 
			
		||||
                                    partieContent.gallerie = await getGallerie(partie);
 | 
			
		||||
                                    break;
 | 
			
		||||
                            }
 | 
			
		||||
                            return partieContent;
 | 
			
		||||
                        });
 | 
			
		||||
 | 
			
		||||
                        // liens
 | 
			
		||||
                        if (rawContent.attributes.field_liens?.length) {
 | 
			
		||||
                            this.content.liens = [];
 | 
			
		||||
                            for (let lien of rawContent.attributes.field_liens) {
 | 
			
		||||
                                this.content.liens.push({
 | 
			
		||||
                                    title: lien.title,
 | 
			
		||||
                                    url: lien.uri,
 | 
			
		||||
                                });
 | 
			
		||||
                            }                            
 | 
			
		||||
                        }
 | 
			
		||||
                        // pièces jointes
 | 
			
		||||
                        if (rawContent.relationships.field_pieces_jointes?.data.length) {
 | 
			
		||||
                            this.content.pieces_jointes = [];
 | 
			
		||||
                            for (let pieceJointe of rawContent.relationships.field_pieces_jointes.data) {
 | 
			
		||||
                                if (pieceJointe.meta.display) {
 | 
			
		||||
                                    const uuid = pieceJointe.id;
 | 
			
		||||
                                    const response = await REST.get(`/jsonapi/file/file/${uuid}`);
 | 
			
		||||
                                    this.content.pieces_jointes.push({
 | 
			
		||||
                                        title: pieceJointe.meta.description,
 | 
			
		||||
                                        url: response.data.data.attributes.uri.url,
 | 
			
		||||
                                    });
 | 
			
		||||
                                }
 | 
			
		||||
                            }
 | 
			
		||||
                        } 
 | 
			
		||||
 | 
			
		||||
                        this.content.parties = await Promise.all(partiesPromises);
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    // related étapes
 | 
			
		||||
                    if (contentType === 'etape') {
 | 
			
		||||
                        const [prevContent, nextContent] = await Promise.all([previousEtapePromise, nextEtapePromise]);
 | 
			
		||||
                        this.content.previous = prevContent;
 | 
			
		||||
                        this.content.next = nextContent;
 | 
			
		||||
                    }
 | 
			
		||||
                ) {
 | 
			
		||||
                    let { pageTitle, partialContent } = fetchSingletonPartialContent(this.contentType, this.rawContent);
 | 
			
		||||
                    this.pageTitle = pageTitle;
 | 
			
		||||
                    this.content = partialContent;
 | 
			
		||||
                } else {
 | 
			
		||||
                    // pages gouvernance (contact), ressources et partenaire
 | 
			
		||||
                    // ont plusieurs items par pages                    
 | 
			
		||||
                    const intro = await REST.get(`/jsonapi/config_pages/intro_${this.contentType}/`);
 | 
			
		||||
                    const introContent = intro.data.data[0];
 | 
			
		||||
 | 
			
		||||
                    this.pageTitle =
 | 
			
		||||
                        `${introContent.attributes.field_titre} ${introContent.attributes.metatag.find(tag => tag.tag === "meta")?.attributes.content}`;                    
 | 
			
		||||
 | 
			
		||||
                    this.content.contentTitle = introContent.attributes.field_titre;
 | 
			
		||||
                    this.content.intro = introContent.attributes.field_intro?.value;
 | 
			
		||||
 | 
			
		||||
                    let multiItemPageArray = [];                    
 | 
			
		||||
 | 
			
		||||
                    switch (this.contentType) {
 | 
			
		||||
                        case 'ressource':
 | 
			
		||||
                            multiItemPageArray = await getRessources(rawContent);                            
 | 
			
		||||
                            this.content.ressourceTypes = new Set(multiItemPageArray.map(item => item.ressourceType));
 | 
			
		||||
                            useLayoutStore().hideEtapeList(true);
 | 
			
		||||
                            break;
 | 
			
		||||
                        case 'partenaire':
 | 
			
		||||
                            multiItemPageArray = await getPartenaires(rawContent);
 | 
			
		||||
                            break;
 | 
			
		||||
                        case 'gouvernance':
 | 
			
		||||
                            multiItemPageArray = await getGouvernance(rawContent);
 | 
			
		||||
                            break;
 | 
			
		||||
                        }
 | 
			
		||||
 | 
			
		||||
                    this.content[`${this.contentType}s`] = multiItemPageArray;
 | 
			
		||||
                    
 | 
			
		||||
                    let { pageTitle, partialContent } = await fetchMultiplePartialContent(this.contentType);
 | 
			
		||||
                    this.pageTitle = pageTitle;
 | 
			
		||||
                    this.content = partialContent;
 | 
			
		||||
                }
 | 
			
		||||
            } catch (error) {
 | 
			
		||||
                this.error = 'Failed to fetch data';
 | 
			
		||||
                console.error('Issue with getNodeData', error);
 | 
			
		||||
            } catch(error) {
 | 
			
		||||
                this.error = 'Failed to fetch partial data';
 | 
			
		||||
                console.error('Issue with fetchPartialContentData', error);
 | 
			
		||||
            } finally {
 | 
			
		||||
                this.partialLoading = false;
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        async fetchFullContentData(path) {
 | 
			
		||||
            try {
 | 
			
		||||
                if (
 | 
			
		||||
                    this.contentType === 'etape'
 | 
			
		||||
                    || this.contentType === 'static'
 | 
			
		||||
                    || this.contentType === 'ressourceItem'
 | 
			
		||||
                ) {
 | 
			
		||||
                    this.content = { ...this.content, ...await fetchSingletonFullContent(this.contentType, this.rawContent, path) };
 | 
			
		||||
                } else {
 | 
			
		||||
                    this.content = { ...this.content, ...await fetchMultipleFullContent(this.contentType, this.rawContent) };
 | 
			
		||||
                }
 | 
			
		||||
            } catch(error) {
 | 
			
		||||
                this.error = 'Failed to fetch full data';
 | 
			
		||||
                console.error('Issue with fetchFullContentData', error);
 | 
			
		||||
            } finally {
 | 
			
		||||
                this.loading = false;
 | 
			
		||||
            }
 | 
			
		||||
@@ -204,6 +71,7 @@ export const useContentStore = defineStore('content', {
 | 
			
		||||
            this.contentType = '';
 | 
			
		||||
            this.pageTitle = '';
 | 
			
		||||
            this.content = {};
 | 
			
		||||
            this.partialLoading = !forFrontDisplay;
 | 
			
		||||
            this.loading = !forFrontDisplay;
 | 
			
		||||
            this.error = null;
 | 
			
		||||
            useLayoutStore().hideEtapeList(false);
 | 
			
		||||
 
 | 
			
		||||
@@ -128,6 +128,14 @@ export const useLayoutStore = defineStore('layout', {
 | 
			
		||||
        setHeaderPosition(currentPageIsIndex) {
 | 
			
		||||
          const header = document.querySelector('.layout-container > header');
 | 
			
		||||
          header.style.position = currentPageIsIndex ? 'fixed' : 'relative';
 | 
			
		||||
        }
 | 
			
		||||
        },
 | 
			
		||||
        toggleModaleTransition(shouldModaleTransition, enterDelay) {
 | 
			
		||||
          if (shouldModaleTransition) {
 | 
			
		||||
            document.documentElement.style.setProperty('--modale-enter-delay', `${enterDelay}s`);
 | 
			
		||||
          } else {
 | 
			
		||||
            document.documentElement.style.setProperty('margin-top', '0');
 | 
			
		||||
            document.documentElement.style.setProperty('transition', 'none');
 | 
			
		||||
          }
 | 
			
		||||
        },
 | 
			
		||||
    },
 | 
			
		||||
})
 | 
			
		||||
 
 | 
			
		||||
@@ -16,6 +16,39 @@ export const useMapStore = defineStore('mapState', {
 | 
			
		||||
        animationDuration: 3,
 | 
			
		||||
    }),
 | 
			
		||||
    actions: {
 | 
			
		||||
        handleMapMovement(isModaleEtape, wasModaleEtape, lat = this.defaultMapCenter.lat, lon = this.defaultMapCenter.lng) {
 | 
			
		||||
          if (this.animationsAreEnabled) {
 | 
			
		||||
            if (isModaleEtape) {
 | 
			
		||||
              if (!wasModaleEtape) {
 | 
			
		||||
                // national -> détail
 | 
			
		||||
                useLayoutStore().toggleModaleTransition(true, this.animationDuration);
 | 
			
		||||
                this.zoomToPlace(lat, lon);
 | 
			
		||||
              } else {
 | 
			
		||||
                // détail -> détail
 | 
			
		||||
                useLayoutStore().toggleModaleTransition(true, this.animationDuration);
 | 
			
		||||
                this.zoomToPlace(lat, lon);
 | 
			
		||||
              }
 | 
			
		||||
            } else {
 | 
			
		||||
              if (wasModaleEtape) {
 | 
			
		||||
                // détail -> national
 | 
			
		||||
                useLayoutStore().toggleModaleTransition(true, this.animationDuration);
 | 
			
		||||
                this.resetMap();
 | 
			
		||||
              } else {
 | 
			
		||||
                // national -> national
 | 
			
		||||
                useLayoutStore().toggleModaleTransition(true, 0);
 | 
			
		||||
              }
 | 
			
		||||
            }
 | 
			
		||||
          } else {
 | 
			
		||||
            if (isModaleEtape) {
 | 
			
		||||
              // ? -> détail
 | 
			
		||||
              this.zoomToPlace(lat, lon);
 | 
			
		||||
            } else {
 | 
			
		||||
              // ? -> national
 | 
			
		||||
              this.resetMap();
 | 
			
		||||
            }
 | 
			
		||||
            useLayoutStore().toggleModaleTransition(false);
 | 
			
		||||
          }
 | 
			
		||||
        },
 | 
			
		||||
        zoomToPlace(lat, long) {          
 | 
			
		||||
            if (useLayoutStore().isDesktop) long = long - 0.03;           
 | 
			
		||||
            this.map.flyTo(
 | 
			
		||||
 
 | 
			
		||||
@@ -122,7 +122,7 @@ export async function getRessourceItemCard(item) {
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        const relatedEtape = await REST.get(item.relationships.field_etape.links.related.href);
 | 
			
		||||
        console.log(item);
 | 
			
		||||
        // console.log(item);
 | 
			
		||||
        
 | 
			
		||||
        
 | 
			
		||||
        return {
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1,43 @@
 | 
			
		||||
import REST from '../../api/rest-axios';
 | 
			
		||||
import { useLayoutStore } from '../../stores/layout';
 | 
			
		||||
import { getPartenaires, getGouvernance, getRessources } from './multiItemPages';
 | 
			
		||||
 | 
			
		||||
export async function fetchMultiplePartialContent(contentType) {
 | 
			
		||||
    let partialContent = {};
 | 
			
		||||
    let pageTitle = '';
 | 
			
		||||
 | 
			
		||||
    const intro = await REST.get(`/jsonapi/config_pages/intro_${contentType}/`);
 | 
			
		||||
    const introContent = intro.data.data[0];
 | 
			
		||||
 | 
			
		||||
    pageTitle =
 | 
			
		||||
        `${introContent.attributes.field_titre} ${introContent.attributes.metatag.find(tag => tag.tag === "meta")?.attributes.content}`;                    
 | 
			
		||||
 | 
			
		||||
    partialContent.contentTitle = introContent.attributes.field_titre;
 | 
			
		||||
    partialContent.intro = introContent.attributes.field_intro?.value;
 | 
			
		||||
 | 
			
		||||
    return { pageTitle, partialContent };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export async function fetchMultipleFullContent(contentType, rawContent) {
 | 
			
		||||
    let content = {};
 | 
			
		||||
    
 | 
			
		||||
    let multiItemPageArray = [];                    
 | 
			
		||||
 | 
			
		||||
    switch (contentType) {
 | 
			
		||||
        case 'ressource':
 | 
			
		||||
            multiItemPageArray = await getRessources(rawContent);                            
 | 
			
		||||
            content.ressourceTypes = new Set(multiItemPageArray.map(item => item.ressourceType));
 | 
			
		||||
            useLayoutStore().hideEtapeList(true);
 | 
			
		||||
            break;
 | 
			
		||||
        case 'partenaire':
 | 
			
		||||
            multiItemPageArray = await getPartenaires(rawContent);
 | 
			
		||||
            break;
 | 
			
		||||
        case 'gouvernance':
 | 
			
		||||
            multiItemPageArray = await getGouvernance(rawContent);
 | 
			
		||||
            break;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    content[`${contentType}s`] = multiItemPageArray;
 | 
			
		||||
    
 | 
			
		||||
    return content;
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,153 @@
 | 
			
		||||
import REST from '../../api/rest-axios';
 | 
			
		||||
 | 
			
		||||
import { getCleanDate, fetchFromRelationships, getRelatedEtape, getRelatedRessources } from './contentFetchUtils';
 | 
			
		||||
import { getCarteSensible, getTitreTexte, getChiffresCles, getDiaporama, getEntretien, getVideos, getDocument, getGallerie } from './cleanParties';
 | 
			
		||||
import { useLayoutStore } from '../../stores/layout';
 | 
			
		||||
 | 
			
		||||
export function fetchSingletonPartialContent(contentType, rawContent) {
 | 
			
		||||
    let partialContent = {};
 | 
			
		||||
 | 
			
		||||
    let pageTitle = rawContent.attributes.metatag.find(tag => tag.tag === "meta")?.attributes.content;
 | 
			
		||||
 | 
			
		||||
    partialContent.contentTitle = rawContent.attributes.title;
 | 
			
		||||
 | 
			
		||||
    if (contentType === 'etape') {
 | 
			
		||||
        partialContent.coordinates = {
 | 
			
		||||
            lat: rawContent.attributes.field_geofield.lat,
 | 
			
		||||
            lon: rawContent.attributes.field_geofield.lon,
 | 
			
		||||
        };
 | 
			
		||||
        partialContent.adresse = rawContent.attributes.field_adresse;
 | 
			
		||||
        partialContent.etape_number = rawContent.attributes.field_arret_numero;
 | 
			
		||||
        partialContent.couleur = rawContent.attributes.field_couleur;
 | 
			
		||||
        partialContent.dates = {
 | 
			
		||||
            start: getCleanDate(rawContent.attributes.field_dates.value),
 | 
			
		||||
            end: getCleanDate(rawContent.attributes.field_dates.end_value),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (contentType === 'ressourceItem') {   
 | 
			
		||||
        partialContent.ressourceType = rawContent.attributes.field_type_de_ressource;
 | 
			
		||||
        partialContent.auteurice = rawContent.attributes.field_autheurice;
 | 
			
		||||
        partialContent.date = getCleanDate(rawContent.attributes.field_date_ressource);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    return { pageTitle, partialContent };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export async function fetchSingletonFullContent(contentType, rawContent, path) {
 | 
			
		||||
    let content = {};
 | 
			
		||||
 | 
			
		||||
    const vignettePromise = fetchFromRelationships('field_vignette', rawContent.relationships);
 | 
			
		||||
    const partiesPromise = fetchFromRelationships(contentType === 'ressourceItem' ? 'field_parties_ressource' : 'field_parties', rawContent.relationships);
 | 
			
		||||
 | 
			
		||||
    let previousEtapePromise, nextEtapePromise;
 | 
			
		||||
 | 
			
		||||
    if (contentType === 'etape') {
 | 
			
		||||
        previousEtapePromise = getRelatedEtape('previous', path);
 | 
			
		||||
        nextEtapePromise = getRelatedEtape('next', path);
 | 
			
		||||
        content.relatedRessources = await getRelatedRessources(rawContent.id);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (contentType === 'ressourceItem') {
 | 
			
		||||
        content.introduction = rawContent.attributes.field_introduction?.processed;                        
 | 
			
		||||
        if (rawContent.relationships.field_etape.data) {
 | 
			
		||||
            const relatedEtapeFetch = fetchFromRelationships('field_etape', rawContent.relationships);
 | 
			
		||||
            const relatedEtape = await Promise.resolve(relatedEtapeFetch);
 | 
			
		||||
            const relatedEtapeUrl = relatedEtape.attributes.metatag.find(tag => tag.tag === "link")?.attributes.href;
 | 
			
		||||
            content.relatedEtape = await getRelatedEtape('', relatedEtapeUrl);                        
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        useLayoutStore().hideEtapeList(true);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const [vignetteData, partiesData] = await Promise.all([vignettePromise, partiesPromise]);
 | 
			
		||||
 | 
			
		||||
    if (vignetteData) {
 | 
			
		||||
        content.vignette = {
 | 
			
		||||
            url: {
 | 
			
		||||
                original: vignetteData.attributes.uri.url,
 | 
			
		||||
                small: vignetteData.attributes.image_style_uri.content_small,
 | 
			
		||||
                medium: vignetteData.attributes.image_style_uri.content_medium,
 | 
			
		||||
                large: vignetteData.attributes.image_style_uri.content_large,
 | 
			
		||||
            },
 | 
			
		||||
            alt: rawContent.relationships.field_vignette.data.meta.alt
 | 
			
		||||
        };
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    if (partiesData) {
 | 
			
		||||
        const partiesPromises = partiesData.map(async (partie) => {
 | 
			
		||||
            const partieType = partie.type.replace(/^paragraph--/, "");
 | 
			
		||||
            let partieContent = { type: partieType };                            
 | 
			
		||||
 | 
			
		||||
            switch (partieType) {
 | 
			
		||||
                case 'carte_sensible':
 | 
			
		||||
                    partieContent.carteSensible = await getCarteSensible(partie);
 | 
			
		||||
                    break;
 | 
			
		||||
                case 'titre_texte':
 | 
			
		||||
                    const { titre, texte } = await getTitreTexte(partie);
 | 
			
		||||
                    partieContent.titre = titre;
 | 
			
		||||
                    partieContent.texte = texte;
 | 
			
		||||
                    break;
 | 
			
		||||
                case 'chiffres_cles':
 | 
			
		||||
                    partieContent.chiffresCles = await getChiffresCles(partie);
 | 
			
		||||
                    break;
 | 
			
		||||
                case 'diaporama':
 | 
			
		||||
                    partieContent.diaporama = await getDiaporama(partie);
 | 
			
		||||
                    break;
 | 
			
		||||
                case 'entretien':
 | 
			
		||||
                    partieContent.entretien = await getEntretien(partie);
 | 
			
		||||
                    break;
 | 
			
		||||
                case 'exergue':
 | 
			
		||||
                    partieContent.exergue = partie.attributes.field_texte_exergue.value;
 | 
			
		||||
                    break;
 | 
			
		||||
                case 'video':
 | 
			
		||||
                    partieContent.videos = getVideos(partie);
 | 
			
		||||
                    break;
 | 
			
		||||
                case 'document':
 | 
			
		||||
                    partieContent.document = await getDocument(partie);
 | 
			
		||||
                    break;
 | 
			
		||||
                case 'galleries':
 | 
			
		||||
                    partieContent.gallerie = await getGallerie(partie);
 | 
			
		||||
                    break;
 | 
			
		||||
            }
 | 
			
		||||
            return partieContent;
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        // liens
 | 
			
		||||
        if (rawContent.attributes.field_liens?.length) {
 | 
			
		||||
            content.liens = [];
 | 
			
		||||
            for (let lien of rawContent.attributes.field_liens) {
 | 
			
		||||
                content.liens.push({
 | 
			
		||||
                    title: lien.title,
 | 
			
		||||
                    url: lien.uri,
 | 
			
		||||
                });
 | 
			
		||||
            }                            
 | 
			
		||||
        }
 | 
			
		||||
        // pièces jointes
 | 
			
		||||
        if (rawContent.relationships.field_pieces_jointes?.data.length) {
 | 
			
		||||
            content.pieces_jointes = [];
 | 
			
		||||
            for (let pieceJointe of rawContent.relationships.field_pieces_jointes.data) {
 | 
			
		||||
                if (pieceJointe.meta.display) {
 | 
			
		||||
                    const uuid = pieceJointe.id;
 | 
			
		||||
                    const response = await REST.get(`/jsonapi/file/file/${uuid}`);
 | 
			
		||||
                    content.pieces_jointes.push({
 | 
			
		||||
                        title: pieceJointe.meta.description,
 | 
			
		||||
                        url: response.data.data.attributes.uri.url,
 | 
			
		||||
                    });
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        } 
 | 
			
		||||
 | 
			
		||||
        content.parties = await Promise.all(partiesPromises);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // related étapes
 | 
			
		||||
    if (contentType === 'etape') {
 | 
			
		||||
        const [prevContent, nextContent] = await Promise.all([previousEtapePromise, nextEtapePromise]);
 | 
			
		||||
        content.previous = prevContent;
 | 
			
		||||
        content.next = nextContent;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return content;
 | 
			
		||||
}
 | 
			
		||||
@@ -55,7 +55,7 @@ export async function getGouvernance(rawContent) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export async function getRessources(rawContent) {
 | 
			
		||||
    console.log(rawContent);
 | 
			
		||||
    // console.log(rawContent);
 | 
			
		||||
    
 | 
			
		||||
    const ressourcesPromises = rawContent.map(item => getRessourceItemCard(item));        
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,23 +1,27 @@
 | 
			
		||||
import { setActiveNavItem } from "./set-active-nav-item";
 | 
			
		||||
import { useContentStore } from "../stores/content";
 | 
			
		||||
import { useMapStore } from "../stores/map";
 | 
			
		||||
import { useLayoutStore } from '../stores/layout';
 | 
			
		||||
 | 
			
		||||
export async function initFirstLoadRouting(store, router, baseUrl, siteName) {
 | 
			
		||||
export async function initFirstLoadRouting(router, baseUrl, siteName) {
 | 
			
		||||
    const store = useContentStore();
 | 
			
		||||
    const decoupled_origin = JSON.parse(window.localStorage.getItem('decoupled_origin'));
 | 
			
		||||
 | 
			
		||||
    if(decoupled_origin) {
 | 
			
		||||
        router.push(decoupled_origin.url);
 | 
			
		||||
        await store.fetchContentData(baseUrl + decoupled_origin.url);
 | 
			
		||||
        await store.fetchPartialContentData(baseUrl + decoupled_origin.url);
 | 
			
		||||
        window.localStorage.removeItem("decoupled_origin");
 | 
			
		||||
        document.title = store.pageTitle;
 | 
			
		||||
        setActiveNavItem(store.contentType, decoupled_origin.url);
 | 
			
		||||
        useLayoutStore().setHeaderPosition(false);
 | 
			
		||||
        await store.fetchFullContentData(baseUrl + decoupled_origin.url);
 | 
			
		||||
    } else {
 | 
			
		||||
        document.title = siteName;
 | 
			
		||||
        useLayoutStore().setHeaderPosition(true);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function handleClickableElements(clickableElements, store, router, baseUrl, siteName, mapStore) {
 | 
			
		||||
export function handleClickableElements(clickableElements, router, baseUrl, siteName) {
 | 
			
		||||
    for (const link of clickableElements) {
 | 
			
		||||
        let href = link.href || link.dataset.href;
 | 
			
		||||
        if (href.startsWith(baseUrl)) href = href.replace(baseUrl, '');
 | 
			
		||||
@@ -25,26 +29,29 @@ export function handleClickableElements(clickableElements, store, router, baseUr
 | 
			
		||||
        link.onclick = async function (e) {            
 | 
			
		||||
            if (href !== window.location.pathname) {
 | 
			
		||||
                router.push(href);
 | 
			
		||||
                pageChange(href, store, siteName, mapStore, baseUrl);
 | 
			
		||||
                pageChange(href, siteName, baseUrl);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export async function handleBrowserNavigation(store, baseUrl, siteName, mapStore) {
 | 
			
		||||
  let href = window.location.pathname;
 | 
			
		||||
  if (href.startsWith(baseUrl)) href = href.replace(baseUrl, '');
 | 
			
		||||
  pageChange(href, store, siteName, mapStore, baseUrl)
 | 
			
		||||
export async function handleBrowserNavigation(baseUrl, siteName) {
 | 
			
		||||
    let href = window.location.pathname;
 | 
			
		||||
    if (href.startsWith(baseUrl)) href = href.replace(baseUrl, '');
 | 
			
		||||
    pageChange(href, siteName, baseUrl)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export async function pageChange(href, store, siteName, mapStore, baseUrl) {
 | 
			
		||||
export async function pageChange(href, siteName, baseUrl) {
 | 
			
		||||
    const store = useContentStore();
 | 
			
		||||
    const mapStore = useMapStore();
 | 
			
		||||
 | 
			
		||||
  if (href === '/') {
 | 
			
		||||
      store.resetStore(true);
 | 
			
		||||
      document.title = siteName;
 | 
			
		||||
      mapStore.resetMap();
 | 
			
		||||
      useLayoutStore().setHeaderPosition(true);
 | 
			
		||||
  } else {
 | 
			
		||||
      await store.fetchContentData(baseUrl + href);
 | 
			
		||||
      await store.fetchPartialContentData(baseUrl + href);
 | 
			
		||||
      document.title = store.pageTitle;
 | 
			
		||||
      useLayoutStore().setHeaderPosition(false);
 | 
			
		||||
  }
 | 
			
		||||
@@ -53,4 +60,8 @@ export async function pageChange(href, store, siteName, mapStore, baseUrl) {
 | 
			
		||||
  const listeEtape = document.querySelector('#etapes-liste');
 | 
			
		||||
  const animationToggle = document.querySelector('#animation-toggle');
 | 
			
		||||
  if (!useLayoutStore().isDesktop) useLayoutStore().collapseEtapeListe(listeEtape, animationToggle);
 | 
			
		||||
 | 
			
		||||
  if (href !== '/') {
 | 
			
		||||
      await store.fetchFullContentData(baseUrl + href);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -56,7 +56,7 @@ export function setMenuToggle() {
 | 
			
		||||
    layoutStore.setUpHamburgerToggle(menuBurger, menuContainer);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function setHamburgerWhenLogged(drupalSettings) {
 | 
			
		||||
export function setRightSectionsWhenLogged(drupalSettings) {
 | 
			
		||||
    if (drupalSettings.user.uid != 0) {
 | 
			
		||||
      const menuBurger = document.querySelector('#hamburger');
 | 
			
		||||
      const menuTitle = document.querySelector('#menu-title');
 | 
			
		||||
@@ -65,7 +65,11 @@ export function setHamburgerWhenLogged(drupalSettings) {
 | 
			
		||||
      const headerTop = header.getBoundingClientRect().top;
 | 
			
		||||
 | 
			
		||||
      menuTitle.style.top = `${headerTop}px`;
 | 
			
		||||
      menuBurger.style.top = `${headerTop}px`;
 | 
			
		||||
      menuContainer.style.paddingTop = `${headerTop}px`;
 | 
			
		||||
      menuContainer.style.paddingTop = `${headerTop + 10}px`;
 | 
			
		||||
      menuBurger.style.top = `${headerTop + 2}px`;
 | 
			
		||||
 | 
			
		||||
      const etapesListContainer = document.querySelector('.block-region-third');
 | 
			
		||||
      etapesListContainer.style.paddingTop = `50px`;
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,7 +1,10 @@
 | 
			
		||||
import { useLayoutStore } from '../stores/layout';
 | 
			
		||||
import { useMapStore } from '../stores/map';
 | 
			
		||||
import REST from '../api/rest-axios';
 | 
			
		||||
 | 
			
		||||
export function setupMapStore(mapStore, map, settings) {
 | 
			
		||||
export function setupMapStore(map, settings) {
 | 
			
		||||
    const mapStore = useMapStore();
 | 
			
		||||
 | 
			
		||||
    mapStore.map = map;
 | 
			
		||||
    mapStore.defaultMapCenter = map.getCenter();
 | 
			
		||||
    mapStore.maxZoom = settings.settings.maxZoom;
 | 
			
		||||
@@ -13,7 +16,9 @@ export function setupMapStore(mapStore, map, settings) {
 | 
			
		||||
 | 
			
		||||
// not working
 | 
			
		||||
// may or may not rework on it later
 | 
			
		||||
export async function preloadEtapesTiles(mapStore, map) {
 | 
			
		||||
export async function preloadEtapesTiles(map) {
 | 
			
		||||
    const mapStore = useMapStore();
 | 
			
		||||
    
 | 
			
		||||
    function waitForEvent(el, eventName) {
 | 
			
		||||
        return new Promise((resolve) => {
 | 
			
		||||
            el.once(eventName, resolve);
 | 
			
		||||
 
 | 
			
		||||
@@ -11,13 +11,19 @@ export function setActiveNavItem(contentType, href) {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (href === '/' || href === '') {
 | 
			
		||||
        staticNavItems[0].classList.add('is-active');
 | 
			
		||||
        staticNavItems[1].classList.add('is-active');
 | 
			
		||||
        for (let item of etapeNavItems) {
 | 
			
		||||
            item.closest('li').classList.remove('inactive');
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    } else {
 | 
			
		||||
        if (contentType === 'static') {
 | 
			
		||||
        
 | 
			
		||||
        if (
 | 
			
		||||
            contentType === 'static'
 | 
			
		||||
            || contentType === 'partenaire'
 | 
			
		||||
            || contentType === 'gouvernance'
 | 
			
		||||
            || contentType === 'ressource'
 | 
			
		||||
        ) {
 | 
			
		||||
            for (let item of staticNavItems) {
 | 
			
		||||
                if (item.getAttribute('href') === href) {
 | 
			
		||||
                    item.classList.add('is-active');
 | 
			
		||||
@@ -26,9 +32,12 @@ export function setActiveNavItem(contentType, href) {
 | 
			
		||||
        } else if (contentType === 'etape') {
 | 
			
		||||
            for (let item of etapeNavItems) {
 | 
			
		||||
                if (item.getAttribute('href') === href) {
 | 
			
		||||
                    item.closest('li').classList.remove('inactive');
 | 
			
		||||
                    item.closest('li').classList.remove('inactive');                    
 | 
			
		||||
                    document.querySelector('#etapes-liste').scrollTo(0, item.closest('li').offsetTop);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        } else if (contentType === "ressourceItem") {
 | 
			
		||||
            staticNavItems[2].classList.add('is-active');
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -6,9 +6,6 @@ import AnimationToggle from '../vuejs/AnimationToggle.vue';
 | 
			
		||||
import VueImageZoomer from 'vue-image-zoomer';
 | 
			
		||||
import 'vue-image-zoomer/dist/style.css';
 | 
			
		||||
 | 
			
		||||
import { useContentStore } from '../stores/content';
 | 
			
		||||
import { useMapStore } from '../stores/map';
 | 
			
		||||
 | 
			
		||||
export function initVueContentModale() {
 | 
			
		||||
    const pinia = createPinia();
 | 
			
		||||
 | 
			
		||||
@@ -16,14 +13,12 @@ export function initVueContentModale() {
 | 
			
		||||
      .use(pinia)
 | 
			
		||||
      .use(router)
 | 
			
		||||
      .use(VueImageZoomer);
 | 
			
		||||
 | 
			
		||||
    const store = useContentStore();
 | 
			
		||||
    const mapStore = useMapStore();
 | 
			
		||||
      
 | 
			
		||||
    app.mount('#content-modale');
 | 
			
		||||
 | 
			
		||||
    const animationToggle = createApp(AnimationToggle)
 | 
			
		||||
      .use(pinia)
 | 
			
		||||
      .mount('#animation-toggle');
 | 
			
		||||
 | 
			
		||||
  return { store, mapStore, router };
 | 
			
		||||
  return router;
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -3,9 +3,15 @@
 | 
			
		||||
      :enter-active-class="animationsAreEnabled ? 'v-enter-active' : 'no-transition'"
 | 
			
		||||
      :leave-active-class="animationsAreEnabled ? 'v-leave-active' : 'no-transition'"
 | 
			
		||||
    >
 | 
			
		||||
        <div v-if="!loading && contentType != ''">
 | 
			
		||||
            <div class="content-wrapper">
 | 
			
		||||
        <div v-if="!partialLoading && contentType != ''">
 | 
			
		||||
            <div
 | 
			
		||||
              class="content-wrapper"
 | 
			
		||||
              :class="
 | 
			
		||||
                contentType === 'ressource' || contentType === 'ressourceItem' 
 | 
			
		||||
                ? 'ressource' : ''"
 | 
			
		||||
              >
 | 
			
		||||
                <ModaleHeader
 | 
			
		||||
                    :loading="loading"
 | 
			
		||||
                    :contentType="contentType"
 | 
			
		||||
                    :content="content"
 | 
			
		||||
                    :couleur="content.couleur || brandColor" />
 | 
			
		||||
@@ -14,7 +20,7 @@
 | 
			
		||||
                        v-if="contentType === 'ressourceItem'"
 | 
			
		||||
                        :content="content"
 | 
			
		||||
                        :couleur="brandColor" />
 | 
			
		||||
                    <div v-for="partie in content.parties" class="partie">
 | 
			
		||||
                    <div v-if="!loading" v-for="partie in content.parties" class="partie">
 | 
			
		||||
                        <ModaleCarteSensible
 | 
			
		||||
                            v-if="partie.type === 'carte_sensible'"
 | 
			
		||||
                            :partie="partie" />
 | 
			
		||||
@@ -50,21 +56,27 @@
 | 
			
		||||
                            :partie="partie"
 | 
			
		||||
                            :couleur="content.couleur || brandColor" />
 | 
			
		||||
                    </div>
 | 
			
		||||
                    <EquipeContent
 | 
			
		||||
                      v-if="contentType === 'gouvernance'"
 | 
			
		||||
                      :content="content"
 | 
			
		||||
                      :couleur="brandColor" />
 | 
			
		||||
                    <PartenairesContent
 | 
			
		||||
                      v-if="contentType === 'partenaire'"
 | 
			
		||||
                      :content="content" />
 | 
			
		||||
                    <CentreDeRessource
 | 
			
		||||
                      v-if="contentType === 'ressource'"
 | 
			
		||||
                      :content="content"
 | 
			
		||||
                      :couleur="brandColor" />
 | 
			
		||||
                    <RelatedRessources
 | 
			
		||||
                      v-if="contentType === 'etape' && content.relatedRessources.length"
 | 
			
		||||
                      :relatedRessources="content.relatedRessources"
 | 
			
		||||
                      :couleur="content.couleur || brandColor" />
 | 
			
		||||
                    <div class="content-loading" v-else>
 | 
			
		||||
                      <div></div>
 | 
			
		||||
                      <p>Chargement du contenu...</p>
 | 
			
		||||
                    </div>
 | 
			
		||||
                    <template v-if="!loading">
 | 
			
		||||
                      <EquipeContent
 | 
			
		||||
                        v-if="contentType === 'gouvernance'"
 | 
			
		||||
                        :content="content"
 | 
			
		||||
                        :couleur="brandColor" />
 | 
			
		||||
                      <PartenairesContent
 | 
			
		||||
                        v-if="contentType === 'partenaire'"
 | 
			
		||||
                        :content="content" />
 | 
			
		||||
                      <CentreDeRessource
 | 
			
		||||
                        v-if="contentType === 'ressource'"
 | 
			
		||||
                        :content="content"
 | 
			
		||||
                        :couleur="brandColor" />
 | 
			
		||||
                      <RelatedRessources
 | 
			
		||||
                        v-if="contentType === 'etape' && content.relatedRessources?.length"
 | 
			
		||||
                        :relatedRessources="content.relatedRessources"
 | 
			
		||||
                        :couleur="content.couleur || brandColor" />
 | 
			
		||||
                    </template>
 | 
			
		||||
                </main>
 | 
			
		||||
                <PiecesJointes
 | 
			
		||||
                  v-if="content.pieces_jointes || content.liens"
 | 
			
		||||
@@ -111,123 +123,55 @@ const mapState = useMapStore();
 | 
			
		||||
const {
 | 
			
		||||
    contentType,
 | 
			
		||||
    content,
 | 
			
		||||
    partialLoading,
 | 
			
		||||
    loading,
 | 
			
		||||
    error,
 | 
			
		||||
} = storeToRefs(store);
 | 
			
		||||
 | 
			
		||||
const { defaultMapCenter, animationDuration, animationsAreEnabled } = storeToRefs(mapState);
 | 
			
		||||
const { animationsAreEnabled } = storeToRefs(mapState);
 | 
			
		||||
 | 
			
		||||
let isModaleEtape, wasModaleEtape;
 | 
			
		||||
 | 
			
		||||
const brandColor = "#80c8bf";
 | 
			
		||||
 | 
			
		||||
const handleColorChange = () => {
 | 
			
		||||
  watch(
 | 
			
		||||
    () => content.value.couleur,
 | 
			
		||||
    () => {
 | 
			
		||||
        if (contentType.value === 'etape' && content.value.couleur) {
 | 
			
		||||
            document.documentElement.style.setProperty('--etape-couleur', content.value.couleur || brandColor);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
  );
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const handleMapMovement = () => {
 | 
			
		||||
  watch(
 | 
			
		||||
    () => loading.value,
 | 
			
		||||
    () => {
 | 
			
		||||
        if (!loading.value) {
 | 
			
		||||
          isModaleEtape = contentType.value === 'etape';
 | 
			
		||||
          console.log(contentType.value);
 | 
			
		||||
          
 | 
			
		||||
 | 
			
		||||
          // Define helper functions in variables
 | 
			
		||||
          const disableModaleTransition = () => {
 | 
			
		||||
            document.documentElement.style.setProperty('margin-top', '0');
 | 
			
		||||
            document.documentElement.style.setProperty('transition', 'none');
 | 
			
		||||
          }
 | 
			
		||||
          const setModaleTransition = (enterDelay) => {
 | 
			
		||||
            document.documentElement.style.setProperty('--modale-enter-delay', `${enterDelay}s`);
 | 
			
		||||
          };
 | 
			
		||||
 | 
			
		||||
          const zoomToContentPlace = () => {
 | 
			
		||||
            mapState.zoomToPlace(
 | 
			
		||||
              content.value.coordinates.lat ? content.value.coordinates.lat : defaultMapCenter.value.lat,
 | 
			
		||||
              content.value.coordinates.lon ? content.value.coordinates.lon : defaultMapCenter.value.lng
 | 
			
		||||
            );
 | 
			
		||||
          };
 | 
			
		||||
 | 
			
		||||
          if (animationsAreEnabled.value) {
 | 
			
		||||
            if (isModaleEtape) {
 | 
			
		||||
              if (!wasModaleEtape) {
 | 
			
		||||
                // national -> détail
 | 
			
		||||
                setModaleTransition(animationDuration.value);
 | 
			
		||||
                zoomToContentPlace();
 | 
			
		||||
              } else {
 | 
			
		||||
                // détail -> détail
 | 
			
		||||
                setModaleTransition(animationDuration.value);
 | 
			
		||||
                zoomToContentPlace();
 | 
			
		||||
              }
 | 
			
		||||
            } else {
 | 
			
		||||
              if (wasModaleEtape) {
 | 
			
		||||
                // détail -> national
 | 
			
		||||
                setModaleTransition(animationDuration.value);
 | 
			
		||||
                mapState.resetMap();
 | 
			
		||||
              } else {
 | 
			
		||||
                // national -> national
 | 
			
		||||
                setModaleTransition(0);
 | 
			
		||||
              }
 | 
			
		||||
            }
 | 
			
		||||
          } else {
 | 
			
		||||
            if (isModaleEtape) {
 | 
			
		||||
              // ? -> détail
 | 
			
		||||
              zoomToContentPlace();
 | 
			
		||||
            } else {
 | 
			
		||||
              // ? -> national
 | 
			
		||||
              mapState.resetMap();
 | 
			
		||||
            }
 | 
			
		||||
            disableModaleTransition();
 | 
			
		||||
          }
 | 
			
		||||
 | 
			
		||||
          scrollTo(0, 0);
 | 
			
		||||
 | 
			
		||||
          wasModaleEtape = isModaleEtape;
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
  );
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
watch(() => contentType.value, () => {
 | 
			
		||||
  if (contentType.value === '') {
 | 
			
		||||
    handleMapLock(false);
 | 
			
		||||
  } else {
 | 
			
		||||
    handleMapLock(true);  
 | 
			
		||||
  }
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
const handleMapLock = (shoudLock) => {
 | 
			
		||||
  const checkAndExecute = () => {
 | 
			
		||||
    const leafletLayer = document.querySelector('.leaflet-layer');
 | 
			
		||||
    
 | 
			
		||||
    if (leafletLayer) {
 | 
			
		||||
      if (shoudLock) {
 | 
			
		||||
        mapState.lockMap();
 | 
			
		||||
      } else {
 | 
			
		||||
        mapState.unlockMap();
 | 
			
		||||
      }
 | 
			
		||||
    } else {
 | 
			
		||||
      setTimeout(checkAndExecute, 100);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  checkAndExecute();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
onMounted(() => {
 | 
			
		||||
  nextTick(() => {
 | 
			
		||||
    watch(
 | 
			
		||||
      () => content.value.couleur,
 | 
			
		||||
      () => {
 | 
			
		||||
        if (contentType.value === 'etape' && content.value.couleur) {
 | 
			
		||||
          document.documentElement.style.setProperty('--etape-couleur', content.value.couleur || brandColor);
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    );
 | 
			
		||||
    isModaleEtape = contentType.value === 'etape';
 | 
			
		||||
    wasModaleEtape = isModaleEtape;
 | 
			
		||||
    handleColorChange();
 | 
			
		||||
    handleMapMovement();
 | 
			
		||||
    watch(
 | 
			
		||||
      () => partialLoading.value,
 | 
			
		||||
      () => {
 | 
			
		||||
        if (!partialLoading.value) {
 | 
			
		||||
          isModaleEtape = contentType.value === 'etape';
 | 
			
		||||
          mapState.handleMapMovement(
 | 
			
		||||
            isModaleEtape,
 | 
			
		||||
            wasModaleEtape,
 | 
			
		||||
            content.value.coordinates?.lat,
 | 
			
		||||
            content.value.coordinates?.lon
 | 
			
		||||
          );
 | 
			
		||||
          scrollTo(0, 0);
 | 
			
		||||
          wasModaleEtape = isModaleEtape;
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    );
 | 
			
		||||
    watch(
 | 
			
		||||
      () => contentType.value,
 | 
			
		||||
      () => {
 | 
			
		||||
        if (contentType.value === '') {
 | 
			
		||||
          mapState.unlockMap();
 | 
			
		||||
        } else {
 | 
			
		||||
          mapState.lockMap();
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    );
 | 
			
		||||
  });
 | 
			
		||||
});
 | 
			
		||||
</script>
 | 
			
		||||
 
 | 
			
		||||
@@ -22,18 +22,13 @@ const props = defineProps({
 | 
			
		||||
import { onMounted } from 'vue';
 | 
			
		||||
import router from '../../router/router';
 | 
			
		||||
 | 
			
		||||
import { useContentStore } from '../../stores/content';
 | 
			
		||||
import { useMapStore } from '../../stores/map';
 | 
			
		||||
 | 
			
		||||
import { handleClickableElements } from '../../utils/handle-navigation.js';
 | 
			
		||||
 | 
			
		||||
const store = useContentStore();
 | 
			
		||||
const mapStore = useMapStore();
 | 
			
		||||
const siteName = document.querySelector('#site_name').innerText;
 | 
			
		||||
 | 
			
		||||
onMounted(() => {
 | 
			
		||||
    const relatedEtapesCards = document.querySelectorAll('.card');
 | 
			
		||||
    const baseUrl = window.location.protocol + "//" + window.location.host;
 | 
			
		||||
    handleClickableElements(relatedEtapesCards, store, router, baseUrl, siteName, mapStore);
 | 
			
		||||
    handleClickableElements(relatedEtapesCards, router, baseUrl, siteName);
 | 
			
		||||
});
 | 
			
		||||
</script>
 | 
			
		||||
@@ -1,7 +1,7 @@
 | 
			
		||||
<template>
 | 
			
		||||
    <header :class="{ 'not-etape': contentType !== 'etape' }">
 | 
			
		||||
        <div class="cover">
 | 
			
		||||
            <img v-if="content.vignette" :src="content.vignette.url.medium" :alt="content.vignette.alt">
 | 
			
		||||
        <div v-if="contentType === 'etape'" class="cover" :style="{ backgroundColor: `${couleur.substring(0, 7)}99`, aspectRatio: '3 / 2' }">
 | 
			
		||||
            <img v-if="!loading && content.vignette" :src="content.vignette.url.medium" :alt="content.vignette.alt">
 | 
			
		||||
        </div>
 | 
			
		||||
        <div v-if="contentType === 'etape' && content.dates" class="cartouche" :style="{ backgroundColor: couleur }">
 | 
			
		||||
            <p>Étape n°{{content.etape_number}}</p>
 | 
			
		||||
@@ -23,6 +23,7 @@
 | 
			
		||||
 | 
			
		||||
<script setup>
 | 
			
		||||
const props = defineProps({
 | 
			
		||||
  loading: Boolean,
 | 
			
		||||
  contentType: String,
 | 
			
		||||
  content: Object,
 | 
			
		||||
  couleur: String,
 | 
			
		||||
 
 | 
			
		||||
@@ -4,12 +4,12 @@
 | 
			
		||||
    :id="`ressource-${index}`"
 | 
			
		||||
    :class="ressource.promoted ? 'promoted' : ''">
 | 
			
		||||
        <figure>
 | 
			
		||||
            <img :src="ressource.vignette.url" :alt="ressource.vignette.alt" />
 | 
			
		||||
            <img :src="ressource?.vignette.url" :alt="ressource?.vignette.alt" />
 | 
			
		||||
        </figure>
 | 
			
		||||
        <div>
 | 
			
		||||
            <h4>{{ ressource.title }}</h4>
 | 
			
		||||
            <p>Le {{ ressource.date.d }} {{ ressource.date.m }} {{ ressource.date.y }}</p>
 | 
			
		||||
            <p>Par {{ ressource.auteurice }}</p>
 | 
			
		||||
            <p>Le {{ ressource?.date.d }} {{ ressource?.date.m }} {{ ressource?.date.y }}</p>
 | 
			
		||||
            <p>Par {{ ressource?.auteurice }}</p>
 | 
			
		||||
        </div>
 | 
			
		||||
    </div>
 | 
			
		||||
</template>
 | 
			
		||||
@@ -19,14 +19,8 @@ import { onMounted } from 'vue';
 | 
			
		||||
import router from '../../router/router';
 | 
			
		||||
import { handleClickableElements } from '../../utils/handle-navigation.js';
 | 
			
		||||
 | 
			
		||||
import { useContentStore } from '../../stores/content';
 | 
			
		||||
import { useMapStore } from '../../stores/map';
 | 
			
		||||
 | 
			
		||||
const store = useContentStore();
 | 
			
		||||
const mapStore = useMapStore();
 | 
			
		||||
const siteName = document.querySelector('#site_name').innerText;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
let relatedItemCards, baseUrl;
 | 
			
		||||
 | 
			
		||||
onMounted(() => {
 | 
			
		||||
@@ -36,7 +30,7 @@ onMounted(() => {
 | 
			
		||||
 | 
			
		||||
const setClickableElements = () => {
 | 
			
		||||
    relatedItemCards = document.querySelector(`#ressource-${props.index}`);
 | 
			
		||||
    handleClickableElements([relatedItemCards], store, router, baseUrl, siteName, mapStore);
 | 
			
		||||
    handleClickableElements([relatedItemCards], router, baseUrl, siteName);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
defineExpose({
 | 
			
		||||
 
 | 
			
		||||
@@ -3,14 +3,16 @@
 | 
			
		||||
    <div class="retour">
 | 
			
		||||
      <p data-href="/ressources">← Retour au centre de ressources</p>
 | 
			
		||||
    </div>
 | 
			
		||||
    <div class="type">{{ content.displayedType }}</div>
 | 
			
		||||
    <div class="type">{{ content?.displayedType }}</div>
 | 
			
		||||
    <div class="title">
 | 
			
		||||
      <h2
 | 
			
		||||
      :style="{ background: `linear-gradient(transparent 70%, ${couleur} 70%)` }">
 | 
			
		||||
        {{ content.contentTitle }}
 | 
			
		||||
        {{ content?.contentTitle }}
 | 
			
		||||
      </h2>
 | 
			
		||||
    </div>
 | 
			
		||||
    <div class="meta">Par {{ content.auteurice }}, le {{ content.date.d }} {{ content.date.m }} {{ content.date.y }}</div>
 | 
			
		||||
    <div v-if="content.auteurice && content.date" class="meta">
 | 
			
		||||
      Par {{ content?.auteurice }}, le {{ content?.date.d }} {{ content?.date.m }} {{ content?.date.y }}
 | 
			
		||||
    </div>
 | 
			
		||||
  </header>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
@@ -18,14 +20,9 @@
 | 
			
		||||
import { onMounted } from 'vue';
 | 
			
		||||
import router from '../../router/router';
 | 
			
		||||
 | 
			
		||||
import { useContentStore } from '../../stores/content';
 | 
			
		||||
import { useMapStore } from '../../stores/map';
 | 
			
		||||
 | 
			
		||||
import { handleClickableElements } from '../../utils/handle-navigation.js';
 | 
			
		||||
 | 
			
		||||
const store = useContentStore();
 | 
			
		||||
const mapStore = useMapStore();
 | 
			
		||||
const siteName = document.querySelector('#site_name').innerText;
 | 
			
		||||
const siteName = document.querySelector('#site_name')?.innerText;
 | 
			
		||||
 | 
			
		||||
const props = defineProps({
 | 
			
		||||
  content: Object,
 | 
			
		||||
@@ -33,7 +30,7 @@ const props = defineProps({
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
function setDisplayedType() {
 | 
			
		||||
    const ressourceType = props.content.ressourceType;
 | 
			
		||||
    const ressourceType = props.content?.ressourceType;
 | 
			
		||||
    switch (ressourceType) {
 | 
			
		||||
      case 'cartes_blanches':
 | 
			
		||||
        props.content.displayedType = 'Carte blanche';
 | 
			
		||||
@@ -57,7 +54,7 @@ function setDisplayedType() {
 | 
			
		||||
onMounted(() => {
 | 
			
		||||
    const backToRessourcesLink = document.querySelectorAll('.retour > p');
 | 
			
		||||
    const baseUrl = window.location.protocol + "//" + window.location.host;
 | 
			
		||||
    handleClickableElements(backToRessourcesLink, store, router, baseUrl, siteName, mapStore);
 | 
			
		||||
    handleClickableElements(backToRessourcesLink, router, baseUrl, siteName);
 | 
			
		||||
    setDisplayedType();
 | 
			
		||||
});
 | 
			
		||||
</script>
 | 
			
		||||
							
								
								
									
										1
									
								
								web/themes/custom/caravane/assets/pictograms/90-ring.svg
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								web/themes/custom/caravane/assets/pictograms/90-ring.svg
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1 @@
 | 
			
		||||
<svg width="24" height="24" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><style>.spinner_P7sC{transform-origin:center;animation:spinner_svv2 .75s infinite linear}@keyframes spinner_svv2{100%{transform:rotate(360deg)}}</style><path d="M10.14,1.16a11,11,0,0,0-9,8.92A1.59,1.59,0,0,0,2.46,12,1.52,1.52,0,0,0,4.11,10.7a8,8,0,0,1,6.66-6.61A1.42,1.42,0,0,0,12,2.69h0A1.57,1.57,0,0,0,10.14,1.16Z" class="spinner_P7sC"/></svg>
 | 
			
		||||
| 
		 After Width: | Height: | Size: 428 B  | 
@@ -754,6 +754,7 @@ body{
 | 
			
		||||
              }
 | 
			
		||||
            }
 | 
			
		||||
            > #content-modale {
 | 
			
		||||
              pointer-events: none;
 | 
			
		||||
              padding-bottom: 20vh;
 | 
			
		||||
              @media screen and (min-width: $desktop-min-width) {
 | 
			
		||||
                z-index: 6;
 | 
			
		||||
@@ -761,6 +762,7 @@ body{
 | 
			
		||||
              > div:not(.image-viewer-wrapper, .image-modale) {
 | 
			
		||||
                padding-bottom: 5vh;
 | 
			
		||||
                > .content-wrapper {
 | 
			
		||||
                  pointer-events: all;
 | 
			
		||||
                  left: 1.5vw;
 | 
			
		||||
                  width: calc($modale-width-mobile);
 | 
			
		||||
                  top: 15vh;
 | 
			
		||||
@@ -768,21 +770,20 @@ body{
 | 
			
		||||
                  position: relative;
 | 
			
		||||
                  background-color: white;
 | 
			
		||||
                  font-size: $labeur-font-size-mobile;
 | 
			
		||||
                  &:has(#centre-de-ressource, #ressource-item-header) {
 | 
			
		||||
                  &.ressource {
 | 
			
		||||
                    left: 5vw;
 | 
			
		||||
                  }
 | 
			
		||||
                  @media screen and (min-width: $desktop-min-width) {
 | 
			
		||||
                    font-size: $labeur-font-size-desktop;
 | 
			
		||||
                    width: $modale-width-desktop;
 | 
			
		||||
                  }
 | 
			
		||||
                  &:has(#centre-de-ressource),
 | 
			
		||||
                  &:has(#ressource-item-header) {
 | 
			
		||||
                  &.ressource {
 | 
			
		||||
                    @media screen and (min-width: $tablet-min-width) {
 | 
			
		||||
                      left: 8vw;
 | 
			
		||||
                      width: 84vw;
 | 
			
		||||
                      .locality-title {
 | 
			
		||||
                        width: 42vw;
 | 
			
		||||
                        margin-left: 21vw;
 | 
			
		||||
                        width: 42vw !important;
 | 
			
		||||
                        margin-left: 21vw !important;
 | 
			
		||||
                      }
 | 
			
		||||
                    }
 | 
			
		||||
                    @media screen and (min-width: $desktop-min-width) {
 | 
			
		||||
@@ -924,6 +925,7 @@ body{
 | 
			
		||||
                    }
 | 
			
		||||
                  }
 | 
			
		||||
                  > main {
 | 
			
		||||
                    min-height: 30vh;
 | 
			
		||||
                    z-index: 1;
 | 
			
		||||
                    position: relative;
 | 
			
		||||
                    width: 100%;
 | 
			
		||||
@@ -938,6 +940,26 @@ body{
 | 
			
		||||
                        padding: 0 calc($modale-x-padding * 4);
 | 
			
		||||
                      }
 | 
			
		||||
                    }
 | 
			
		||||
                    .content-loading {
 | 
			
		||||
                      width: 100%;
 | 
			
		||||
                      text-align: center;
 | 
			
		||||
                      padding-top: 2rem;
 | 
			
		||||
                      display: flex;
 | 
			
		||||
                      flex-direction: column;
 | 
			
		||||
                      align-items: center;
 | 
			
		||||
                      > div {
 | 
			
		||||
                        display: block;
 | 
			
		||||
                        width: 24px;
 | 
			
		||||
                        height: 24px;
 | 
			
		||||
                        background-image: url(/themes/custom/caravane/assets/pictograms/90-ring.svg);
 | 
			
		||||
                        background-size: 24px;
 | 
			
		||||
                        background-size: no-repeat;
 | 
			
		||||
                        margin-bottom: 1rem;
 | 
			
		||||
                      }
 | 
			
		||||
                      > p {
 | 
			
		||||
                        display: block;
 | 
			
		||||
                      }
 | 
			
		||||
                    }
 | 
			
		||||
                    > .partie,
 | 
			
		||||
                    > #equipe {
 | 
			
		||||
                      width: 100%;
 | 
			
		||||
@@ -1375,8 +1397,9 @@ body{
 | 
			
		||||
                      > .title {
 | 
			
		||||
                        width: 100%;
 | 
			
		||||
                        text-align: center;
 | 
			
		||||
                        margin-bottom: 1.5rem;
 | 
			
		||||
                        > h2 {
 | 
			
		||||
                          display: inline-block;
 | 
			
		||||
                          display: inline;
 | 
			
		||||
                          margin-top: 1rem;
 | 
			
		||||
                          font-size: $xl-font-size-mobile;
 | 
			
		||||
                          font-family: 'Joost', sans-serif;
 | 
			
		||||
@@ -1388,7 +1411,7 @@ body{
 | 
			
		||||
                    }
 | 
			
		||||
                  }
 | 
			
		||||
                  > .pieces-jointes {
 | 
			
		||||
                    z-index: 1;
 | 
			
		||||
                    z-index: 0;
 | 
			
		||||
                    position: relative;
 | 
			
		||||
                    padding: 0 $modale-x-padding;
 | 
			
		||||
                    box-sizing: border-box;
 | 
			
		||||
@@ -1443,7 +1466,8 @@ body{
 | 
			
		||||
                  }
 | 
			
		||||
                  > footer {
 | 
			
		||||
                    position: relative;
 | 
			
		||||
                    z-index: 0;
 | 
			
		||||
                    z-index: -1;
 | 
			
		||||
                    overflow: hidden;
 | 
			
		||||
                    .pattern-bottom {
 | 
			
		||||
                      mask-image: linear-gradient(to top, rgba(0,0,0,1), rgba(0,0,0,0));
 | 
			
		||||
                      height: $modale-bottom-padding;
 | 
			
		||||
@@ -1741,4 +1765,14 @@ body{
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  &.toolbar-fixed {
 | 
			
		||||
    #content-modale .content-wrapper {
 | 
			
		||||
      top: 20vh !important;
 | 
			
		||||
    }
 | 
			
		||||
    &.toolbar-vertical.toolbar-tray-open {
 | 
			
		||||
      #content-modale .content-wrapper {
 | 
			
		||||
        left: 15vw !important;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user