/* Styles spécifiques et personnalisations Tailwind pour le tableau comparateur Beauval */
/* Utilisez @layer base pour intégrer des styles de base dans le système de Tailwind */
@layer base {
h1, h2, h3, h4, h5, h6 {
@apply font-bold; /* Rend tous les titres gras par défaut */
}
}
/* Conteneur principal du tableau : dimensions, fond, ombres et gestion du débordement */
.beauval-table-container {
@apply font-sans p-4 md:p-8 bg-gray-50 rounded-lg shadow-xl max-w-4xl mx-auto mb-10;
max-height: 2000px; /* CONTRAINTE : Hauteur maximale de l’outil */
overflow-y: auto; /* Permet le défilement vertical si le contenu dépasse la hauteur maximale */
scrollbar-width: thin; /* Pour Firefox */
scrollbar-color: #9ca3af #f3f4f6; /* Pour Firefox */
}
/* Style de la barre de défilement pour les navigateurs basés sur Webkit */
.beauval-table-container::-webkit-scrollbar {
width: 8px;
}
.beauval-table-container::-webkit-scrollbar-track {
background: #f3f4f6; /* bg-gray-100 */
border-radius: 10px;
}
.beauval-table-container::-webkit-scrollbar-thumb {
background-color: #9ca3af; /* bg-gray-400 */
border-radius: 10px;
border: 2px solid #f3f4f6;
}
/* En-têtes de section (ex: “Points Forts”) */
.beauval-section-header {
@apply text-2xl md:text-3xl text-indigo-800 font-extrabold mb-6 pb-2 border-b-2 border-indigo-200;
}
/* Chaque élément cliquable (un point fort ou à améliorer) */
.beauval-point-item {
@apply bg-white p-5 rounded-lg shadow-md mb-4 cursor-pointer transition-all duration-300 ease-in-out hover:shadow-lg hover:bg-indigo-50 flex flex-col;
/* Styles pour rendre l’élément focusable et visuellement réactif au clavier */
outline: none; /* Cache l’outline par défaut du navigateur */
}
.beauval-point-item:focus-visible {
@apply ring-2 ring-indigo-400 ring-offset-2; /* Ajoute un anneau de focus pour l’accessibilité au clavier */
}
/* Titre de chaque point (ex: “Propreté et entretien impeccable”) */
.beauval-point-title {
@apply text-xl font-semibold text-gray-800 flex justify-between items-center;
}
/* Description détaillée de chaque point, initialement cachée */
.beauval-point-description {
@apply mt-3 text-gray-600 leading-relaxed transition-all duration-300 ease-in-out max-h-0 overflow-hidden opacity-0;
}
/* Classe ajoutée par JS pour afficher la description */
.beauval-point-description.expanded {
@apply max-h-screen opacity-100 mt-4; /* max-h-screen permet de gérer des descriptions de taille variable */
}
/* Icône de bascule (+/-) pour les descriptions */
.beauval-toggle-icon {
@apply text-indigo-500 text-2xl ml-3 transform transition-transform duration-300 ease-in-out;
}
/* Rotation de l’icône lorsque la description est ouverte */
.beauval-toggle-icon.expanded {
@apply rotate-180; /* Fait pivoter le “+” en “x” ou un indicateur de fermeture */
}
/* Barre de recherche */
.beauval-search-input {
@apply w-full p-3 mb-6 border-2 border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-indigo-400 transition-all duration-200;
}
// Bloc JavaScript pour la logique interactive du tableau comparateur Beauval
document.addEventListener(‘DOMContentLoaded’, () => {
// — 1. Données pour le Tableau Comparateur (fournies par l’utilisateur) —
// Ces données sont statiques et ne nécessitent pas d’appel API pour le contenu principal.
// Elles sont structurées pour différencier les points positifs et les points à améliorer.
const beauvalData = [
{
header: “Points Forts des Installations”,
rows: [
[“Propreté et entretien impeccable”, “Des allées sans faille et des enclos immaculés garantissent un environnement agréable et sûr pour tous.”],
[“Sécurité et confort optimaux”, “Chemins larges, zones ombragées, points de repos fréquents pour une visite détendue.”],
[“Architecture innovante des enclos”, “Des habitats spacieux et réalistes pour le bien-être animal et une observation naturelle.”],
[“Funiculaires pour la navigation”, “Facilitent les déplacements et offrent des vues panoramiques sur le parc.”]
]
},
{
header: “Points à Améliorer selon les Avis”,
rows: [
[“Temps d’attente aux attractions”, “Les files peuvent être longues, surtout en haute saison, réduisant le temps d’exploration.”],
[“Tarifs des services annexes élevés”, “Nourriture, boissons et souvenirs sont jugés coûteux par de nombreux visiteurs.”],
[“Affluence et sensation de foule”, “Le parc est victime de son succès, rendant certaines zones bondées.”],
[“Gestion des flux de visiteurs”, “Manque de personnel pour orienter ou fluidifier la circulation à certains moments.”]
]
}
];
// — 2. Exemple de connexion à une API Externe (pour répondre à la contrainte) —
// Si l’outil avait besoin de données EXTERNES SUPPLÉMENTAIRES (par exemple, météo actuelle à Beauval,
// actualités du parc, etc.), voici comment on pourrait interagir avec une API publique gratuite.
// Pour ce tableau comparatif précis, les données `beauvalData` étant fournies, cette fonction n’est pas appelée
// pour le contenu principal du tableau, mais démontre la capacité technique.
/*
async function fetchExampleExternalData() {
// API publique gratuite choisie pour la démonstration : JSONPlaceholder
// Elle fournit des données de test (posts, commentaires, etc.).
// URL de l’API pour un post fictif : https://jsonplaceholder.typicode.com/posts/1
//
// Exemple de réponse JSON attendue (pour le post id=1) :
// {
// “userId”: 1,
// “id”: 1,
// “title”: “sunt aut facere repellat provident occaecati excepturi optio reprehenderit”,
// “body”: “quia et suscipitnsuscipit recusandae consequuntur expedita et cumnreprehenderit molestiae ut ut quas totamnnostrum rerum est autem sunt rem eveniet architecto”
// }
try {
const apiUrl = ‘https://jsonplaceholder.typicode.com/posts/1’;
const response = await fetch(apiUrl);
if (!response.ok) { // Vérifie si la requête a échoué (ex: 404, 500)
throw new Error(`Erreur HTTP! Statut: ${response.status} pour l’URL: ${apiUrl}`);
}
const data = await response.json(); // Parse la réponse JSON
console.log(“Données externes de simulation API (JSONPlaceholder):”, data);
// Ici, vous pourriez utiliser ‘data’ pour dynamiser une autre partie de votre page,
// par exemple, afficher une petite boîte “Le saviez-vous ?” ou une actualité du jour
// en relation avec un thème animalier si l’API le permettait.
// const externalInfoDiv = document.createElement(‘div’);
// externalInfoDiv.textContent = `Actualité du jour (via API fictive): ${data.title}`;
// document.getElementById(‘some-other-div-id’).appendChild(externalInfoDiv);
} catch (error) {
console.error(“Erreur lors de la récupération des données externes de simulation:”, error);
}
}
// Décommenter la ligne ci-dessous si vous souhaitez appeler cette fonction
// au chargement de la page pour observer l’appel API dans la console.
// fetchExampleExternalData();
*/
// — 3. Références aux éléments DOM —
const beauvalContent = document.getElementById(‘beauval-content’);
const searchInput = document.getElementById(‘search-beauval-points’);
// — 4. Fonction principale pour générer et afficher le tableau interactif —
function renderBeauvalTable(dataToRender, searchTerm = ”) {
beauvalContent.innerHTML = ”; // Nettoie le contenu existant avant de le reconstruire
const lowerCaseSearchTerm = searchTerm.toLowerCase().trim();
let totalResultsFound = 0; // Compteur pour savoir si des résultats ont été trouvés globalement
dataToRender.forEach((section, sectionIndex) => {
// Crée l’en-tête de la section (ex: “Points Forts des Installations”)
const sectionHeader = document.createElement(‘h2’);
sectionHeader.className = `beauval-section-header ${sectionIndex === 0 ? ‘mt-0’ : ‘mt-10’}`;
sectionHeader.textContent = section.header;
beauvalContent.appendChild(sectionHeader);
// Conteneur pour les points spécifiques de cette section
const pointsContainer = document.createElement(‘div’);
pointsContainer.className = ‘grid gap-4’; // Utilise CSS Grid pour une meilleure présentation (peut être ajusté pour plusieurs colonnes si désiré)
beauvalContent.appendChild(pointsContainer);
let sectionResultsFound = 0; // Compteur pour les résultats dans la section actuelle
section.rows.forEach((row, rowIndex) => {
const [title, description] = row;
// Logique de filtrage : Si un terme de recherche est présent, on filtre les lignes.
if (lowerCaseSearchTerm && !(title.toLowerCase().includes(lowerCaseSearchTerm) || description.toLowerCase().includes(lowerCaseSearchTerm))) {
return; // Si le terme de recherche n’est ni dans le titre ni dans la description, passe à la ligne suivante
}
sectionResultsFound++;
totalResultsFound++;
// Crée l’élément HTML pour chaque point (ex: “Propreté et entretien impeccable”)
const pointItem = document.createElement(‘div’);
pointItem.className = ‘beauval-point-item’;
pointItem.setAttribute(‘tabindex’, ‘0’); // Rend l’élément focusable au clavier
pointItem.setAttribute(‘role’, ‘button’); // Indique son rôle pour les lecteurs d’écran
pointItem.setAttribute(‘aria-expanded’, ‘false’); // État initial : la description est cachée
pointItem.id = `beauval-point-${sectionIndex}-${rowIndex}`; // ID unique pour l’accessibilité
const pointTitleDiv = document.createElement(‘div’);
pointTitleDiv.className = ‘beauval-point-title’;
// Ajoute le titre et une icône de bascule (+)
pointTitleDiv.innerHTML = `${title} +`;
const pointDescriptionP = document.createElement(‘p’);
pointDescriptionP.className = ‘beauval-point-description’;
pointDescriptionP.textContent = description;
pointDescriptionP.id = `beauval-description-${sectionIndex}-${rowIndex}`; // ID unique pour associer avec aria-controls
pointItem.setAttribute(‘aria-controls’, pointDescriptionP.id); // Lie le bouton à sa description
// Ajoute les éléments au DOM
pointItem.appendChild(pointTitleDiv);
pointItem.appendChild(pointDescriptionP);
pointsContainer.appendChild(pointItem);
// Ajoute les écouteurs d’événements pour l’interaction (clic et clavier)
pointItem.addEventListener(‘click’, (event) => toggleDescription(pointItem, pointDescriptionP, pointTitleDiv.querySelector(‘.beauval-toggle-icon’)));
pointItem.addEventListener(‘keydown’, (event) => {
if (event.key === ‘Enter’ || event.key === ‘ ‘) { // Active avec Entrée ou Espace
event.preventDefault(); // Empêche le défilement de la page avec la touche Espace
toggleDescription(pointItem, pointDescriptionP, pointTitleDiv.querySelector(‘.beauval-toggle-icon’));
}
});
});
// Message si aucun résultat n’est trouvé pour la section actuelle lors d’une recherche
if (lowerCaseSearchTerm && sectionResultsFound === 0) {
const noResults = document.createElement(‘p’);
noResults.className = ‘text-gray-500 italic mt-4 px-4’;
noResults.textContent = `Aucun résultat trouvé pour “${searchTerm}” dans “${section.header}”.`;
beauvalContent.appendChild(noResults);
}
});
// Message global si absolument aucun résultat n’est trouvé pour la recherche dans tout le tableau
if (lowerCaseSearchTerm && totalResultsFound === 0) {
const noGlobalResults = document.createElement(‘p’);
noGlobalResults.className = ‘text-gray-700 font-semibold text-center mt-10 text-xl’;
noGlobalResults.textContent = `Désolé, aucun point ne correspond à votre recherche “${searchTerm}” dans tout le tableau.`;
beauvalContent.innerHTML = ”; // Nettoie tout si aucune section n’a de résultats
beauvalContent.appendChild(noGlobalResults);
}
}
// — 5. Fonction pour basculer la visibilité de la description d’un point —
function toggleDescription(itemElement, descriptionElement, iconElement) {
const isExpanded = itemElement.getAttribute(‘aria-expanded’) === ‘true’;
if (isExpanded) {
// Rétracte la description
descriptionElement.classList.remove(‘expanded’);
iconElement.classList.remove(‘expanded’);
itemElement.setAttribute(‘aria-expanded’, ‘false’);
} else {
// Développe la description
descriptionElement.classList.add(‘expanded’);
iconElement.classList.add(‘expanded’);
itemElement.setAttribute(‘aria-expanded’, ‘true’);
}
}
// — 6. Initialisation et Écouteurs d’événements globaux —
// Rend le tableau avec toutes les données au chargement initial de la page
renderBeauvalTable(beauvalData);
// Ajoute un écouteur d’événement pour la barre de recherche
searchInput.addEventListener(‘input’, (event) => {
const searchTerm = event.target.value; // Récupère le texte de la barre de recherche
renderBeauvalTable(beauvalData, searchTerm); // Re-rend le tableau en filtrant avec le terme de recherche
});
}); // Fin de DOMContentLoaded
{“@context”:”https://schema.org”,”@type”:”FAQPage”,”mainEntity”:[{“@type”:”Question”,”name”:”Quel est le meilleur moment pour visiter le Zoo de Beauval afin d’u00e9viter la foule ? “,”acceptedAnswer”:{“@type”:”Answer”,”text”:”Pour profiter au maximum de votre visite au Zoo de Beauval et u00e9viter les grandes foules, il est fortement recommandu00e9 de privilu00e9gier les journu00e9es en semaine en dehors des vacances scolaires et des ponts. Arriver du00e8s l’ouverture du parc permet u00e9galement d’explorer les zones les plus populaires dans un calme relatif.”}},{“@type”:”Question”,”name”:”Le Zoo de Beauval est-il adaptu00e9 pour une visite en famille avec de jeunes enfants ? “,”acceptedAnswer”:{“@type”:”Answer”,”text”:”Absolument ! Le Zoo de Beauval est particuliu00e8rement bien adaptu00e9 pour les familles. Il propose de nombreuses aires de jeux, des spectacles u00e9ducatifs captivants et des services pratiques comme la location de poussettes. Des zones de pique-nique et des restaurants avec menus enfants facilitent u00e9galement la journu00e9e.”}},{“@type”:”Question”,”name”:”Faut-il acheter ses billets en ligne pour le Zoo de Beauval ? “,”acceptedAnswer”:{“@type”:”Answer”,”text”:”Oui, il est vivement conseillu00e9 d’acheter vos billets pour le Zoo de Beauval en ligne et u00e0 l’avance. Cela vous permettra non seulement d’u00e9conomiser du temps en u00e9vitant les longues files d’attente u00e0 l’entru00e9e, mais aussi de bu00e9nu00e9ficier parfois de tarifs pru00e9fu00e9rentiels.”}},{“@type”:”Question”,”name”:”Quels sont les animaux emblu00e9matiques u00e0 ne pas manquer lors d’une visite au Zoo de Beauval ? “,”acceptedAnswer”:{“@type”:”Answer”,”text”:”Lors de votre visite au Zoo de Beauval, ne manquez surtout pas les cu00e9lu00e8bres pandas gu00e9ants, vu00e9ritables stars du parc. D’autres animaux emblu00e9matiques incluent les koalas, les tigres blancs, les lions, les okapis, et bien su00fbr, les nombreux animaux pru00e9sentu00e9s dans le Du00f4me u00c9quatorial et les plaines africaines.”}},{“@type”:”Question”,”name”:”Le parc propose-t-il des options d’hu00e9bergement sur place ou u00e0 proximitu00e9 ? “,”acceptedAnswer”:{“@type”:”Answer”,”text”:”Oui, le Zoo de Beauval propose plusieurs options d’hu00e9bergement thu00e9matiques situu00e9es u00e0 proximitu00e9 immu00e9diate ou intu00e9gru00e9es au parc, comme les Hu00f4tels des Jardins de Beauval ou les Rivages de Beauval. Su00e9journer sur place peut offrir des avantages comme l’accu00e8s anticipu00e9 au parc ou des packages de visite optimisu00e9s.”}}]}