From e42808149d5171135a3cbca9e3608f13d6081334 Mon Sep 17 00:00:00 2001 From: "fefe.clochette" Date: Sun, 19 Apr 2026 20:45:53 +0200 Subject: [PATCH] vue mobile --- global.css | 28 ++++++-- modules/holidays/holidays.css | 62 ++++++++++++----- modules/holidays/holidays.js | 111 +++++++++++++++++++++++++----- modules/holidays/views/detail.php | 14 +++- modules/home/home.css | 2 +- 5 files changed, 172 insertions(+), 45 deletions(-) diff --git a/global.css b/global.css index 3b2062c..ca9a6b2 100644 --- a/global.css +++ b/global.css @@ -125,7 +125,9 @@ body { top: 64px; left: 0; right: 0; - bottom: 0; + height: calc(100vh - 64px); /* Remplace le bottom: 0 pour éviter le bug iOS */ + overflow-y: auto; /* Permet le scroll si le menu contient beaucoup d'items */ + -webkit-overflow-scrolling: touch; /* Fluidité sur iOS */ background: white; padding: 20px; flex-direction: column; @@ -306,16 +308,30 @@ p { } .pf-nav { display: none; - } /* Caché sur mobile, activé via burger */ + } .pf-header-actions { display: none; - } /* Caché sur mobile, dans le menu */ - + } .pf-burger-btn { display: block; - } /* Affiché sur mobile */ + } + + /* Ajustements d'espacement pour petits écrans */ + .pf-main { + padding: 16px; + } + + .pf-modules-grid { + /* Sécurité : force 1 colonne sur mobile au lieu du auto-fill */ + grid-template-columns: 1fr; + gap: 16px; + } + + .pf-login-container { + margin: 30px 16px; /* Évite de toucher les bords de l'écran */ + padding: 24px; + } - /* Menu Mobile Ouvert */ .pf-mobile-nav-link { font-size: 1.2rem; font-weight: 600; diff --git a/modules/holidays/holidays.css b/modules/holidays/holidays.css index 6770b3f..a0d75ef 100644 --- a/modules/holidays/holidays.css +++ b/modules/holidays/holidays.css @@ -141,7 +141,7 @@ body.no-scroll { /* --- 4. CARTES --- */ .hol-ideas-grid { display: grid; - grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); + grid-template-columns: repeat(auto-fill, minmax(min(100%, 280px), 1fr)); gap: 24px; margin-bottom: 40px; } @@ -459,48 +459,74 @@ body.no-scroll { flex-direction: column; align-items: flex-start; } + + /* On empile proprement les boutons d'action */ .hol-title-actions { width: 100%; + flex-direction: column; /* Essentiel pour que les boutons width: 100% ne s'écrasent pas */ + gap: 10px; } .hol-add-btn, .hol-map-toggle { width: 100%; + justify-content: center; /* Centre le texte et l'icône */ } + .form-row { flex-direction: column; gap: 10px; } - /* Sur mobile, les colonnes s'empilent */ + .hol-columns-wrapper { grid-template-columns: 1fr; } + /* Modale 100% écran avec scroll natif fluide */ .pf-modal-content { padding: 16px; width: 100%; height: 100%; max-height: 100vh; border-radius: 0; + overflow-y: auto; + -webkit-overflow-scrolling: touch; } - @media (max-width: 768px) { - .hol-date-weather-wrapper { - gap: 6px; /* On rapproche la météo de la date sur mobile */ - } - /* On aligne le haut de la carte au cas où le contenu passe sur 2 lignes */ - .hol-cp-header { - align-items: flex-start; - } + /* Adaptation des lignes de budget sur mobile pour éviter qu'elles ne soient compressées */ + .savings-line-item { + flex-wrap: wrap; + gap: 10px; + } + .savings-line-item input[type="text"] { + min-width: 100%; /* Le nom de la dépense prend toute la ligne */ + } + .savings-line-item input[type="number"] { + flex-grow: 1; /* Le prix s'ajuste sur la 2ème ligne */ + } - /* On autorise le titre et les dates à prendre la place nécessaire */ - .hol-cp-info-group { - flex: 1; - min-width: 0; /* Empêche le flexbox de "déborder" de l'écran */ - } + .hol-date-weather-wrapper { + gap: 6px; + } - .hol-cp-title { - white-space: normal; /* Permet au titre de l'étape de passer à la ligne si besoin */ - } + .hol-cp-header { + align-items: flex-start; + flex-direction: column; /* On passe le titre et le prix l'un sous l'autre si besoin */ + } + + .hol-cp-info-group { + flex: 1; + min-width: 0; + width: 100%; + } + + .hol-cp-title { + white-space: normal; + } + + .hol-cp-actions-group { + width: 100%; + justify-content: flex-end; + margin-top: 8px; } } diff --git a/modules/holidays/holidays.js b/modules/holidays/holidays.js index 75acdbc..b9a06bf 100644 --- a/modules/holidays/holidays.js +++ b/modules/holidays/holidays.js @@ -580,16 +580,63 @@ function deleteCheckpoint() { } // ============================================================================ -// 5. GLISSER-DÉPOSER POUR RÉORDONNER LES ÉTAPES +// 5. RÉORDONNANCEMENT DES ÉTAPES (DRAG & DROP PC + FLÈCHES MOBILE) // ============================================================================ + +// On sort cette fonction pour pouvoir l'appeler depuis les boutons fléchés sur mobile +function saveCheckpointOrder() { + const locations = [ + ...document.querySelectorAll(".hol-checkpoint-draggable"), + ].map((el) => el.getAttribute("data-location")); + const holidayId = document.querySelector('input[name="holiday_id"]').value; + + const formData = new FormData(); + formData.append("holiday_id", holidayId); + formData.append("locations", JSON.stringify(locations)); + + fetch("/modules/holidays/includes/api/reorder_checkpoints.php", { + method: "POST", + body: formData, + }).then(() => window.location.reload()); +} + +// Fonction appelée par les flèches Haut/Bas sur mobile +function moveStepMobile(btn, direction) { + const item = btn.closest(".hol-checkpoint-draggable"); + const container = item.parentElement; + + if ( + direction === -1 && + item.previousElementSibling && + item.previousElementSibling.classList.contains("hol-checkpoint-draggable") + ) { + container.insertBefore(item, item.previousElementSibling); + saveCheckpointOrder(); + } else if ( + direction === 1 && + item.nextElementSibling && + item.nextElementSibling.classList.contains("hol-checkpoint-draggable") + ) { + container.insertBefore(item, item.nextElementSibling.nextElementSibling); + saveCheckpointOrder(); + } +} + document.addEventListener("DOMContentLoaded", () => { const checkpoints = document.querySelectorAll(".hol-checkpoint-draggable"); const container = checkpoints[0]?.parentElement; if (!container) return; + const isMobile = window.innerWidth <= 768; let draggedItem = null; checkpoints.forEach((item) => { + // Si on est sur mobile, on supprime l'attribut draggable pour éviter les conflits de scroll + if (isMobile) { + item.removeAttribute("draggable"); + return; + } + item.addEventListener("dragstart", function (e) { draggedItem = this; setTimeout(() => (this.style.opacity = "0.4"), 0); @@ -633,22 +680,6 @@ document.addEventListener("DOMContentLoaded", () => { { offset: Number.NEGATIVE_INFINITY }, ).element; } - - function saveCheckpointOrder() { - const locations = [ - ...document.querySelectorAll(".hol-checkpoint-draggable"), - ].map((el) => el.getAttribute("data-location")); - const holidayId = document.querySelector('input[name="holiday_id"]').value; - - const formData = new FormData(); - formData.append("holiday_id", holidayId); - formData.append("locations", JSON.stringify(locations)); - - fetch("/modules/holidays/includes/api/reorder_checkpoints.php", { - method: "POST", - body: formData, - }).then(() => window.location.reload()); - } }); // ============================================================================ @@ -702,7 +733,11 @@ function openPlanningModal(step) { html += `
-
${dayName}
${dayNum}
+
+
${dayName}
+
${dayNum}
+
+
`; @@ -722,6 +757,10 @@ function openPlanningModal(step) { html += `
`; container.innerHTML = html; + // 1. On détecte si on est sur mobile juste avant la boucle + const isMobile = window.innerWidth <= 768; + const dragAttr = isMobile ? "" : 'draggable="true"'; + validItems.forEach((it) => { let icon = "🏷️"; let catClass = "cat-activity"; @@ -739,8 +778,9 @@ function openPlanningModal(step) { ? `
${it.notes}
` : ""; + // 2. MODIFICATION ICI : On remplace le texte en dur draggable="true" par la variable ${dragAttr} const elHtml = ` -
@@ -774,6 +814,10 @@ function openPlanningModal(step) { document.getElementById("planningModal").style.display = "flex"; document.body.classList.add("no-scroll"); + + datesToDisplay.forEach((dateStr) => { + loadWeatherForPlanning(step.lat, step.lng, dateStr); + }); } function changeDuration(e, itemId, delta) { @@ -883,3 +927,32 @@ function saveItemDateTime(itemId, dateStr, timeStr) { body: formData, }).catch((err) => console.error("Erreur:", err)); } + +// ============================================================================ +// MÉTÉO SPÉCIFIQUE AU HEADER DU PLANNING +// ============================================================================ +async function loadWeatherForPlanning(lat, lng, dateStr) { + const container = document.getElementById(`plan-weather-${dateStr}`); + if (!container || !lat || !lng) return; + + try { + const resp = await fetch( + `/modules/holidays/includes/api/get_weather.php?lat=${lat}&lng=${lng}&date=${dateStr}`, + ); + const res = await resp.json(); + + if (res.success) { + const info = getWeatherInfo(res.data.code); + const approxSymbol = res.data.is_historical ? "~" : ""; + + container.innerHTML = ` +
+ ${info.icon} + ${approxSymbol}${Math.round(res.data.temp_min)}° / ${Math.round(res.data.temp_max)}°C +
+ `; + } + } catch (e) { + console.error("Erreur météo planning", e); + } +} diff --git a/modules/holidays/views/detail.php b/modules/holidays/views/detail.php index 5ee8228..9bf6581 100644 --- a/modules/holidays/views/detail.php +++ b/modules/holidays/views/detail.php @@ -74,6 +74,14 @@ $pctSaved = $cost > 0 ? min(100 - $pctPaid, ($saved / $cost) * 100) : 0; + +
@@ -197,7 +205,11 @@ $pctSaved = $cost > 0 ? min(100 - $pctPaid, ($saved / $cost) * 100) : 0;
- + +
+ + +
📍 diff --git a/modules/home/home.css b/modules/home/home.css index 1d75386..971e51d 100644 --- a/modules/home/home.css +++ b/modules/home/home.css @@ -129,7 +129,7 @@ body.pf-home .pf-modules-grid { } .pf-hero h1 { - font-size: 2rem; + font-size: clamp(1.8rem, 6vw, 2.5rem); /* Typographie fluide */ } /* Ajustement header mobile */