feat(templates): [FR] Améliore l'UI et ajoute des traductions pour plus de contenu dynamique.
```
This commit is contained in:
Serreau Jovann
2025-12-26 12:53:13 +01:00
parent 5e1bd2a749
commit 4f08db7541
20 changed files with 722 additions and 407 deletions

View File

@@ -4,18 +4,18 @@ import '@grafikart/drop-files-element'
import {PaymentForm} from './PaymentForm'
import * as Sentry from "@sentry/browser";
// --- CLÉS DE STOCKAGE ET VAPID ---
// --- CONFIGURATION ET ETAT ---
const VAPID_PUBLIC_KEY = "BKz0kdcsG6kk9KxciPpkfP8kEDAd408inZecij5kBDbQ1ZGZSNwS4KZ8FerC28LFXvgSqpDXtor3ePo0zBCdNqo";
const COOKIE_STORAGE_KEY = 'cookies_accepted';
let userMenuTimeout; // Pour gérer le délai de fermeture du menu
// --- MESSAGES ET TRADUCTIONS ---
const MESSAGES = {
fr: {
notificationTitle: "🔔 Activer les notifications",
notificationText: "Recevez les nouvelles, les promotions et les événements de l'association.",
notificationButton: "Activer",
notificationClose: "Fermer la notification",
cookieText: 'Ce site utilise uniquement des cookies de <strong>fonctionnement</strong> et de <strong>sécurité</strong> essentiels. Aucune donnée personnelle n\'est collectée.',
cookieText: 'Ce site utilise uniquement des cookies de <strong>fonctionnement</strong> et de <strong>sécurité</strong> essentiels.',
cookieLink: "Politique de cookies",
cookieButton: "Accepter",
},
@@ -24,7 +24,7 @@ const MESSAGES = {
notificationText: "Receive news, promotions, and association events.",
notificationButton: "Enable",
notificationClose: "Close notification",
cookieText: 'This website only uses <strong>functional</strong> and <strong>security</strong> cookies. No personal data is collected.',
cookieText: 'This website only uses <strong>functional</strong> and <strong>security</strong> cookies.',
cookieLink: "Cookie Policy",
cookieButton: "Accept",
}
@@ -62,12 +62,10 @@ function toggleMenu(button, menu) {
* Initialisation de l'UI
*/
function initializeUI() {
// Reset des menus au chargement
document.querySelectorAll('#mobile-menu, #userMenuDesktop, #userMenuMobile').forEach(menu => {
menu.classList.add('hidden');
});
// Panier Latéral
const cartSidebar = document.getElementById('cartSidebar');
const cartBackdrop = document.getElementById('cartBackdrop');
@@ -78,7 +76,6 @@ function initializeUI() {
cartSidebar.classList.remove('translate-x-full');
cartSidebar.classList.add('translate-x-0');
};
window.closeCart = () => {
document.body.style.overflow = '';
cartSidebar.classList.remove('translate-x-0');
@@ -89,7 +86,6 @@ function initializeUI() {
};
}
// Update counters
const updateCartDisplay = (count) => {
const desktopCounter = document.getElementById('cartCountDesktop');
const mobileCounter = document.getElementById('cartCountMobile');
@@ -98,20 +94,47 @@ function initializeUI() {
};
updateCartDisplay(0);
// Initialisation spécifique au menu utilisateur (Desktop)
setupUserMenuHover();
if ('Notification' in window && Notification.permission === 'granted') {
subscribeAndSave();
}
}
// --- LOGIQUE PUSH NOTIFICATIONS ---
/**
* Gestion du survol du menu utilisateur pour éviter la fermeture brutale
*/
function setupUserMenuHover() {
const btn = document.getElementById('userMenuButtonDesktop');
const menu = document.getElementById('userMenuDesktop');
if (!btn || !menu) return;
const open = () => {
clearTimeout(userMenuTimeout);
menu.classList.remove('hidden');
};
const close = () => {
userMenuTimeout = setTimeout(() => {
menu.classList.add('hidden');
}, 200); // Délai de 200ms pour laisser le temps de passer du bouton au menu
};
btn.addEventListener('mouseenter', open);
btn.addEventListener('mouseleave', close);
menu.addEventListener('mouseenter', open);
menu.addEventListener('mouseleave', close);
}
// --- LOGIQUE PUSH & BANNIÈRES (Inchangé) ---
async function subscribeAndSave() {
if (!('Notification' in window) || Notification.permission !== 'granted') return;
if (!('serviceWorker' in navigator)) return;
try {
const registration = await navigator.serviceWorker.ready;
let subscription = await registration.pushManager.getSubscription();
if (!subscription) {
const applicationServerKey = urlBase64ToUint8Array(VAPID_PUBLIC_KEY);
subscription = await registration.pushManager.subscribe({
@@ -119,15 +142,12 @@ async function subscribeAndSave() {
applicationServerKey: applicationServerKey
});
}
await fetch('/notificationSub', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ subscription: subscription.toJSON() })
});
} catch (error) {
console.error("Push Error:", error);
}
} catch (error) { console.error("Push Error:", error); }
}
async function promptForPermissionAndSubscribe() {
@@ -135,18 +155,14 @@ async function promptForPermissionAndSubscribe() {
try {
const permission = await Notification.requestPermission();
if (permission === 'granted') await subscribeAndSave();
} catch (error) {
console.error("Permission Error:", error);
}
} catch (error) { console.error("Permission Error:", error); }
}
// --- OPTIMISATION PERFORMANCE ---
function isPerformanceTestAgent() {
const ua = navigator.userAgent;
return ua.includes('Lighthouse') || ua.includes('PageSpeed');
}
// --- BANNIÈRES ---
function handleNotificationBanner() {
if (isPerformanceTestAgent()) return;
const BANNER_ID = 'notification-prompt-banner';
@@ -157,7 +173,6 @@ function handleNotificationBanner() {
const banner = document.createElement('div');
banner.id = BANNER_ID;
banner.className = `fixed bottom-4 left-4 z-50 p-4 max-w-xs bg-indigo-600 text-white rounded-xl shadow-2xl transition-all duration-500 transform opacity-0 translate-y-full md:left-8 md:bottom-8 border-2 border-black`;
banner.innerHTML = `
<div class="flex items-start justify-between italic">
<p class="font-black uppercase text-xs tracking-widest">${M.notificationTitle}</p>
@@ -170,13 +185,11 @@ function handleNotificationBanner() {
${M.notificationButton}
</button>
`;
document.body.appendChild(banner);
setTimeout(() => {
banner.classList.remove('opacity-0', 'translate-y-full');
banner.classList.add('opacity-100', 'translate-y-0');
}, 100);
document.getElementById('closeNotificationBanner').addEventListener('click', () => banner.remove());
document.getElementById('activateNotifications').addEventListener('click', async () => {
await promptForPermissionAndSubscribe();
@@ -189,12 +202,10 @@ function handleCookieBanner() {
if (localStorage.getItem(COOKIE_STORAGE_KEY) === 'true') return;
const BANNER_ID = 'cookie-banner';
if (document.getElementById(BANNER_ID)) return;
const M = getLanguageMessages();
const banner = document.createElement('div');
banner.id = BANNER_ID;
banner.className = `fixed bottom-4 right-4 z-50 p-6 max-w-sm bg-white border-4 border-black shadow-[10px_10px_0px_rgba(0,0,0,1)] transition-all duration-500 transform opacity-0 translate-y-full`;
banner.innerHTML = `
<p class="text-xs font-bold uppercase italic leading-relaxed text-gray-600">${M.cookieText}</p>
<div class="mt-4 flex justify-end items-center gap-4">
@@ -204,78 +215,58 @@ function handleCookieBanner() {
</button>
</div>
`;
document.body.appendChild(banner);
setTimeout(() => {
banner.classList.remove('opacity-0', 'translate-y-full');
banner.classList.add('opacity-100', 'translate-y-0');
}, 200);
document.getElementById('acceptCookies').addEventListener('click', () => {
localStorage.setItem(COOKIE_STORAGE_KEY, 'true');
banner.remove();
});
}
// --- DOM READY & TURBO ---
// --- BOOTSTRAP ---
document.addEventListener('DOMContentLoaded', () => {
if (!customElements.get('payment-don')) {
customElements.define('payment-don', PaymentForm, {extends: 'form'});
}
initializeUI();
if (!isPerformanceTestAgent()) {
handleNotificationBanner();
handleCookieBanner();
// Chatwoot
var BASE_URL_WOOT = "https://chat.esy-web.dev";
let script = document.createElement('script');
script.setAttribute('src', BASE_URL_WOOT + "/packs/js/sdk.js");
script.defer = true;
document.head.append(script);
script.onload = () => {
window.chatwootSDK.run({
websiteToken: '6uFX3g3qybyvSt3PAQUMgkm4',
baseUrl: BASE_URL_WOOT
});
window.chatwootSDK.run({ websiteToken: '6uFX3g3qybyvSt3PAQUMgkm4', baseUrl: BASE_URL_WOOT });
};
}
const env = document.querySelector('meta[name="env"]');
if (env && env.getAttribute('content') === "prod") {
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('/sw.js');
}
if (env && env.getAttribute('content') === "prod" && 'serviceWorker' in navigator) {
navigator.serviceWorker.register('/sw.js');
}
});
document.addEventListener('turbo:load', () => {
initializeUI();
handleNotificationBanner();
handleCookieBanner();
});
// --- DÉLÉGATION D'ÉVÉNEMENTS ---
document.addEventListener('click', (event) => {
const target = event.target;
// Menu Mobile
const mobileMenuButton = target.closest('#mobileMenuButton');
if (mobileMenuButton) {
const menu = document.getElementById('mobile-menu');
toggleMenu(mobileMenuButton, menu);
toggleMenu(mobileMenuButton, document.getElementById('mobile-menu'));
return;
}
// Panier
const openCartBtn = target.closest('#openCartDesktop, #openCartMobile');
if (openCartBtn && window.openCart) {
event.preventDefault();
window.openCart();
return;
}
const closeCartBtn = target.closest('#closeCartButton') || target === document.getElementById('cartBackdrop');
if (closeCartBtn && window.closeCart) {
window.closeCart();

View File

@@ -9,3 +9,8 @@
.epage{
color: orangered;
}
#userMenuDesktop {
margin-top: -4px; /* Remonte légèrement le menu pour toucher le bouton */
padding-top: 10px; /* Ajoute du padding interne pour garder la zone réactive */
}