modif settings backend style map et ajout field étape couleurs

This commit is contained in:
Valentin
2024-08-09 17:04:53 +02:00
parent f61c81c714
commit bdf8011dd2
26 changed files with 1130 additions and 88 deletions

View File

@@ -0,0 +1,5 @@
name: 'Alter Routing'
type: module
description: 'Custom module to alter routing and redirect node/2 to the homepage.'
core_version_requirement: ^8 || ^9 || ^10
package: Custom

View File

@@ -0,0 +1,26 @@
<?php
/**
* Implements hook_preprocess_page().
*/
function alter_routing_preprocess_page(&$variables) {
// Check if the current page is a node page.
if (isset($page['#node']) && $page['#node'] instanceof \Drupal\node\NodeInterface) {
// Load the front page content directly from its path.
$front_page_path = \Drupal::config('system.site')->get('url');
$front_page_node = \Drupal\node\Entity\Node::load(\Drupal::entityTypeManager()->getStorage('node')->getQuery()
->condition('type', 'page') // Change this to the content type if needed
->condition('status', 1)
->sort('created', 'DESC')
->execute()
);
// If front page content is found, replace node content with front page content.
if ($front_page_node) {
$view_builder = \Drupal::entityTypeManager()->getViewBuilder('node');
$rendered_content = $view_builder->view($front_page_node, 'full');
$page['content']['#markup'] = \Drupal::service('renderer')->render($rendered_content);
}
}
}
?>

View File

@@ -53,27 +53,24 @@ import router from './router/router';
app.mount('#content-modale');
processEtapeLinks(store);
processStaticLinks(store)
processStaticLinks(store);
setupEtapeMapPopup(store);
}
function onClickContentLink(e, store, category){
e.preventDefault();
let a = e.currentTarget;
let nid = a.dataset.nodeNid;
// console.log(nid);
let a;
const li = e.target.closest('li');
a = li.querySelector('a');
let nid = a.dataset.nodeNid;
let general_link_fields = document.querySelectorAll('#menu > ul > li > a');
for (let field of general_link_fields) {
if (field.classList.contains('is-active')) {
field.classList.remove('is-active');
}
}
if (category === 'etape') {
store.fetchEtapeData(nid);
} else if (category === 'static') {
e.currentTarget.classList.add('is-active');
store.fetchStaticData(nid);
}
@@ -92,8 +89,9 @@ import router from './router/router';
function processEtapeLinks(store){
let etape_link_fields = document.querySelectorAll('#etapes-liste div.views-field-title');
etape_link_fields.forEach((field) => {
let etape_li = document.querySelectorAll('#etapes-liste li');
etape_li.forEach((li) => {
let field = li.querySelector('div.views-field-title');
let nid = null;
let classList = field.classList;
classList.forEach((classe) => {
@@ -101,18 +99,20 @@ import router from './router/router';
let result = classe.match(reg);
if (result) {
nid = result[1];
console.log(nid);
}
})
if (nid) {
let a = field.querySelector('a');
a.setAttribute('data-node-nid', nid);
a.addEventListener('click', (e) => onClickContentLink(e, store, 'etape'));
li.addEventListener('click', (e) => onClickContentLink(e, store, 'etape'));
}
let couleur = li.querySelector('.views-field-field-couleur .snippets-description').innerText;
let iconElements = li.querySelectorAll('.icone-arret > div');
for (let element of iconElements) {
element.style.backgroundColor = couleur;
}
})
}
@@ -123,7 +123,6 @@ import router from './router/router';
const menuBurger = document.querySelector('#hamburger');
const menuH2 = document.querySelector('#menu > h2');
menuButton.addEventListener('click', (e) => {
// e.preventDefault();
setTimeout(() => {
menuContainer.classList.toggle('open');
menuTitle.classList.toggle('open');
@@ -140,6 +139,42 @@ import router from './router/router';
}
})
}
function setupEtapeMapPopup(store) {
setTimeout(() => {
const icons = document.querySelectorAll('.leaflet-map-divicon');
for (let icon of icons) {
const colorContainer = icon.querySelector('.couleur');
const colorDiv = colorContainer.querySelector('div > div:nth-of-type(4)');
const color = colorDiv.innerText.substring(colorDiv.innerText.indexOf('>') + 1, colorDiv.innerText.indexOf('<', colorDiv.innerText.indexOf('>') + 1)).trim();
const nid = icon.querySelector('.nid');
const nidValue = nid.querySelector('div > div').innerText;
icon.addEventListener('click', function(event) {
store.fetchEtapeData(nidValue);
});
colorContainer.remove();
nid.remove();
const iconElements = icon.querySelectorAll('div');
for (let iconElement of iconElements) {
iconElement.style.backgroundColor = color;
}
icon.removeAttribute('title');
icon.addEventListener('mouseenter', function (event) {
icon.style.transform = `${icon.style.transform} scale(1.1)`;
const popup = document.querySelector('.leaflet-tooltip-center > div');
popup.style.opacity = "1";
});
icon.addEventListener('mouseleave', function (event) {
icon.style.transform = icon.style.transform.split(' ')[0] + icon.style.transform.split(' ')[1] + icon.style.transform.split(' ')[2];
})
}
}, 500);
}
init()
} // end CaravaneTheme()

View File

@@ -43,18 +43,19 @@ export const useContentStore = defineStore('content', {
this.etape.etape_number = etape.attributes.field_arret_numero;
this.etape.dates = etape.attributes.field_dates;
this.etape.geofield = etape.attributes.field_geofield;
this.etape.galeries = await fetchEtapeContent('field_galleries', etape.relationships);
const partiesFetch = await fetchEtapeContent('field_parties', etape.relationships);
this.etape.galeries = await this.fetchEtapeContent('field_galleries', etape.relationships);
const partiesFetch = await this.fetchEtapeContent('field_parties', etape.relationships);
let partiesArray = []
for (let partie of partiesFetch) {
partiesArray.push({ title: partie.attributes.field_titre, text: partie.attributes.field_texte.value });
}
this.etape.parties = partiesArray;
this.etape.saison = await fetchEtapeContent('field_saison', etape.relationships);
this.etape.saison = await fetchEtapeContent('field_saison', etape.relationships);
this.etape.thematiques = await fetchEtapeContent('field_thematiques', etape.relationships);
const vignetteFetch = await fetchEtapeContent('field_vignette', etape.relationships);
this.etape.saison = await this.fetchEtapeContent('field_saison', etape.relationships);
this.etape.saison = await this.fetchEtapeContent('field_saison', etape.relationships);
this.etape.thematiques = await this.fetchEtapeContent('field_thematiques', etape.relationships);
const vignetteFetch = await this.fetchEtapeContent('field_vignette', etape.relationships);
this.etape.vignette = { url: vignetteFetch.attributes.uri.url, alt: etape.attributes.field_vignette_alt };
this.setActiveItemInMenu();
break;
}
}
@@ -76,7 +77,7 @@ export const useContentStore = defineStore('content', {
if (staticContent.attributes.drupal_internal__nid == nid) {
staticContent.attributes.metatag.forEach(item => {
if (item.tag === 'meta') {
this.page.title = item.attributes.content;
this.page.title = item.attributes.content.split(' |')[0];
}
if (item.tag === 'link') {
this.href = item.attributes.href;
@@ -85,6 +86,7 @@ export const useContentStore = defineStore('content', {
this.page.text = staticContent.attributes.field_texte.value;
}
}
this.setActiveItemInMenu();
} catch (error) {
this.error = 'Failed to fetch data';
console.error('Issue with getNodeData', error);
@@ -95,19 +97,55 @@ export const useContentStore = defineStore('content', {
emptyAll() {
this.etape = {};
this.page = {};
this.setActiveItemInMenu();
},
setActiveItemInMenu() {
const title = this.etape.title || this.page.title;
const generalLinks = document.querySelectorAll('#menu > ul > li > a');
if (Object.entries(this.etape).length === 0 && Object.entries(this.page).length === 0) {
for (let link of generalLinks) {
link.classList.remove('is-active');
}
generalLinks[0].classList.add('is-active');
} else {
for (let link of generalLinks) {
if (link.innerText === title) {
link.classList.add('is-active');
} else {
link.classList.remove('is-active');
}
}
}
const etapeLinks = document.querySelectorAll('#etapes-liste li');
for (let link of etapeLinks) {
const a = link.querySelector('a');
if (a.innerText === title) {
link.classList.remove('inactive');
} else {
link.classList.add('inactive');
}
}
const inactiveLinks = document.querySelectorAll('#etapes-liste li.inactive');
if (inactiveLinks.length === etapeLinks.length) {
for (let link of inactiveLinks) {
link.classList.remove('inactive');
}
}
},
async fetchEtapeContent(field, relationships) {
if (relationships[field].data) {
try {
const contentLink = relationships[field].links.related.href;
const contentFetch = await REST.get(contentLink);
return contentFetch.data.data;
} catch (error) {
this.error = 'Failed to fetch data';
console.error('Issue with getNodeData', error);
}
}
}
},
});
async function fetchEtapeContent(field, relationships) {
if (relationships[field].data) {
try {
const contentLink = relationships[field].links.related.href;
const contentFetch = await REST.get(contentLink);
return contentFetch.data.data;
} catch (error) {
this.error = 'Failed to fetch data';
console.error('Issue with getNodeData', error);
}
}
}

View File

@@ -26,6 +26,7 @@
<div><pre><b>GEOFIELD</b>{{etape.geofield}}</pre></div>
<div><pre><b>VIGNETTE</b>{{etape.vignette}}</pre></div>
<div><pre><b>GALERIES</b>{{etape.galeries}}</pre></div>
<div><pre><b>PARTIES</b>{{etape.parties}}</pre></div>
<div><pre><b>SAISON</b>{{etape.saison}}</pre></div>
@@ -61,9 +62,14 @@ const route = useRoute();
const { loading, error, href, etape, page } = storeToRefs(store);
watch(() => route.params.id, (newId) => {
store.fetchEtapeData(newId);
if (!etape.value.data) {
store.fetchStaticData(newId);
if (!newId) {
store.emptyAll();
} else {
store.fetchEtapeData(newId);
if (!etape.value.data) {
store.fetchStaticData(newId);
}
window.scrollTo({top: 0, behavior: 'smooth'});
}
});
@@ -71,12 +77,9 @@ watch(() => href.value, (newHref) => {
const relativePath = newHref.split('.fr')[1];
if (relativePath && (relativePath !== '' || relativePath !== '/')) {
router.push(relativePath);
} else {
store.emptyAll();
}
});
const isEtapeValid = computed(() => {
return etape.value && !isObjectEmpty(etape.value);
});

View File

@@ -2,6 +2,7 @@
$body-margin-x: 30px;
$body-margin-y: 5px;
$body-margin-bottom: 4vh;
$sm-font-size: 0.8rem;
$m-font-size: 1.4rem;
@@ -20,6 +21,7 @@ body{
color: $main-color;
margin: 0;
padding: 0;
overflow-y: scroll;
.layout-container {
> header {
z-index: 2;
@@ -242,6 +244,138 @@ body{
width: 100vw;
.leaflet-container {
// add map style here
.leaflet-control-zoom {
border: none;
margin: 0;
left: $body-margin-x;
bottom: $body-margin-bottom;
> a {
display: flex;
justify-content: center;
align-items: center;
font-size: $m-font-size;
font-family: 'marianne', sans-serif;
font-weight: lighter;
width: 4vh;
height: 4vh;
}
> a:first-of-type {
border-top-left-radius: 2vh;
border-top-right-radius: 2vh;
}
> a:last-of-type {
border-bottom-left-radius: 2vh;
border-bottom-right-radius: 2vh;
> span {
padding-bottom: 10px;
}
}
}
.leaflet-right {
right: unset;
left: 0;
}
.leaflet-map-divicon {
width: 10px;
height: 30px;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
transition: transform 0.3s ease-out;
> div {
background-color: red;
display: block;
width: 20px;
height: 10px;
}
> div:first-of-type {
height: 8px;
clip-path: polygon(0 0, 100% 0, 50% 100%);
transform: rotate(180deg);
}
> div:last-of-type {
height: 8px;
clip-path: polygon(0 0, 100% 0, 50% 100%);
}
}
}
.leaflet-tooltip-center {
width: 20vw;
padding: 0;
border-radius: none;
box-shadow: none;
opacity: 1 !important;
border-radius: 0 !important;
background-color: transparent;
border: none;
pointer-events: none;
> div {
display: grid;
grid-template-columns: minmax(10px, 10vw) 10vw;
grid-template-rows: 1.5fr 0.5fr;
transform: translateY(-60%);
background-color: white;
opacity: 0;
transition: opacity 0.3s ease-out;
> div:first-of-type {
grid-column: 1 / span 1;
grid-row: 1 / span 1;
font-family: 'Joost', sans-serif;
font-size: $m-font-size;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
padding-top: 10px;
padding-left: 20px;
padding-right: 20px;
text-wrap: wrap;
> a {
font-weight: bold;
text-decoration: none;
color: $main-color;
padding-right: 10px;
}
}
> div:nth-of-type(2) {
grid-column: 1 / span 1;
grid-row: 2 / span 1;
text-align: center;
padding: 10px 0;
> time {
font-size: $sm-font-size;
font-family: 'Marianne', sans-serif;
font-weight: lighter;
}
}
> a {
display: block;
grid-column: 2 / span 1;
grid-row: 1 / span 2;
overflow: hidden;
width: 100%;
height: 100%;
padding: 0;
> div {
width: 100%;
display: block;
padding: 0;
background-color: blue;
max-height: 0;
> img {
padding: 0;
width: 100%;
height: auto;
object-fit: cover;
margin: 0;
display: block;
}
}
}
}
}
}
> .layout__region--third {
@@ -259,19 +393,98 @@ body{
pointer-events: auto;
ul {
list-style: none;
> li > div {
> li {
display: flex;
justify-content: flex-end;
a {
text-decoration: none;
color: $main-color;
font-family: 'Joost', sans-serif;
font-weight: bold;
font-size: $m-font-size;
display: inline-block;
margin: 15px 0;
text-align: right;
justify-content: end;
align-items: center;
margin: 30px 0;
transform: scale(1);
opacity: 1;
transition: transform 0.3s ease-out, opacity 0.3s ease-out;
cursor: pointer;
> .infos-arret {
display: grid;
grid-template-columns: auto auto;
grid-template-rows: auto auto;
justify-content: end;
margin-right: 20px;
p {
margin: 0;
}
> .views-field-title {
grid-column: 1 / span 1;
grid-row: 1 / span 1;
margin-right: 10px;
a {
text-decoration: none;
color: $main-color;
font-family: 'Joost', sans-serif;
font-weight: bold;
font-size: $m-font-size;
display: inline-block;
text-align: right;
}
}
> .views-field-field-adresse-postal-code {
grid-column: 2 / span 1;
grid-row: 1 / span 1;
color: $main-color;
font-family: 'Joost', sans-serif;
font-weight: lighter;
font-size: $m-font-size;
align-self: end;
> span {
> p::before {
content: '(';
}
> p::after {
content: ')';
}
}
}
> .views-field-field-dates {
grid-column: 1 / span 2;
grid-row: 2 / span 1;
font-size: $sm-font-size;
font-family: 'Marianne', sans-serif;
font-weight: lighter;
text-align: right;
margin-top: 7px;
}
> .views-field-field-couleur {
display: none;
}
}
> .icone-arret {
width: 10px;
height: 30px;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
> div {
background-color: red;
display: block;
width: 20px;
height: 10px;
}
> div:first-of-type {
height: 8px;
clip-path: polygon(0 0, 100% 0, 50% 100%);
transform: rotate(180deg);
}
> div:last-of-type {
height: 8px;
clip-path: polygon(0 0, 100% 0, 50% 100%);
}
}
}
> li:hover {
transform: scale(1.05);
}
> li.inactive {
opacity: 0.6;
}
}
}

View File

@@ -36,6 +36,26 @@ function caravane_preprocess_node(&$variables) {
}
function your_theme_preprocess_block(&$variables) {
function cavarane_preprocess_block(&$variables) {
}
function caravane_theme_suggestions_views_view_field_alter(array &$suggestions, array $variables) {
$view = $variables['view'];
$display_id = $variables['view']->current_display;
if ($display_id == 'block_1' && $view->id() == 'etapes') {
$suggestions[] = 'views_view_field__block_1__etape_list';
}
if ($display_id == 'block_2') {
$suggestions[] = 'views_view_field__block_2__popup_map';
}
}
function caravane_theme_suggestions_views_view_fields_alter(array &$suggestions, array $variables) {
$view = $variables['view'];
$display_id = $variables['view']->current_display;
$view_id = $view->id();
if ($display_id == 'block_1' && $view_id == 'etapes') {
$suggestions[] = 'views_view_fields__block_2__liste_etapes';
}
}

View File

@@ -0,0 +1,23 @@
{#
/**
* @file
* Default theme implementation for a single field in a view.
*
* Available variables:
* - view: The view that the field belongs to.
* - field: The field handler that can process the input.
* - row: The raw result of the database query that generated this field.
* - output: The processed output that will normally be used.
*
* When fetching output from the row this construct should be used:
* data = row[field.field_alias]
*
* The above will guarantee that you'll always get the correct data, regardless
* of any changes in the aliasing that might happen if the view is modified.
*
* @see template_preprocess_views_view_field()
*
* @ingroup themeable
*/
#}
<p>{{- output -}}</p>

View File

@@ -0,0 +1,32 @@
{#
/**
* @file
* Default theme implementation for a single field in a view.
*
* Available variables:
* - view: The view that the field belongs to.
* - field: The field handler that can process the input.
* - row: The raw result of the database query that generated this field.
* - output: The processed output that will normally be used.
*
* When fetching output from the row this construct should be used:
* data = row[field.field_alias]
*
* The above will guarantee that you'll always get the correct data, regardless
* of any changes in the aliasing that might happen if the view is modified.
*
* @see template_preprocess_views_view_field()
*
* @ingroup themeable
*/
#}
<div>
{% if output %}
{% set separated_contents = output|split('\n') %}
{% for content in separated_contents %}
{% if content != '' %}
<div class="separated-content">{{ content|trim }}</div>
{% endif %}
{% endfor %}
{% endif %}
</div

View File

@@ -0,0 +1,61 @@
{#
/**
* @file
* Default view template to display all the fields in a row.
*
* Available variables:
* - view: The view in use.
* - fields: A list of fields, each one contains:
* - content: The output of the field.
* - raw: The raw data for the field, if it exists. This is NOT output safe.
* - class: The safe class ID to use.
* - handler: The Views field handler controlling this field.
* - inline: Whether or not the field should be inline.
* - wrapper_element: An HTML element for a wrapper.
* - wrapper_attributes: List of attributes for wrapper element.
* - separator: An optional separator that may appear before a field.
* - label: The field's label text.
* - label_element: An HTML element for a label wrapper.
* - label_attributes: List of attributes for label wrapper.
* - label_suffix: Colon after the label.
* - element_type: An HTML element for the field content.
* - element_attributes: List of attributes for HTML element for field content.
* - has_label_colon: A boolean indicating whether to display a colon after
* the label.
* - element_type: An HTML element for the field content.
* - element_attributes: List of attributes for HTML element for field content.
* - row: The raw result from the query, with all data it fetched.
*
* @see template_preprocess_views_view_fields()
*
* @ingroup themeable
*/
#}
<div class="infos-arret">
{% for field in fields -%}
{{ field.separator }}
{%- if field.wrapper_element -%}
<{{ field.wrapper_element }}{{ field.wrapper_attributes }}>
{%- endif %}
{%- if field.label -%}
{%- if field.label_element -%}
<{{ field.label_element }}{{ field.label_attributes }}>{{ field.label }}{{ field.label_suffix }}</{{ field.label_element }}>
{%- else -%}
{{ field.label }}{{ field.label_suffix }}
{%- endif %}
{%- endif %}
{%- if field.element_type -%}
<{{ field.element_type }}{{ field.element_attributes }}>{{ field.content }}</{{ field.element_type }}>
{%- else -%}
{{ field.content }}
{%- endif %}
{%- if field.wrapper_element -%}
</{{ field.wrapper_element }}>
{%- endif %}
{%- endfor %}
</div>
<div class="icone-arret">
<div></div>
<div></div>
<div></div>
</div>