mirror of
https://github.com/Ladebeze66/devsite.git
synced 2026-02-04 03:30:21 +01:00
modifglossaire
This commit is contained in:
parent
395fed7f8c
commit
2b83679a02
@ -1,6 +1,10 @@
|
||||
import { fetchDataCompetences } from "../utils/fetchDataCompetences"; // ✅ Importation du bon fetch
|
||||
"use client";
|
||||
|
||||
import { fetchDataCompetences, fetchDataGlossaire } from "../utils/fetchDataCompetences";
|
||||
import CarouselCompetences from "./CarouselCompetences";
|
||||
import ReactMarkdown from "react-markdown";
|
||||
import { useState, useEffect } from "react";
|
||||
import ModalGlossaire from "./ModalGlossaire"; // ✅ Import de la modale
|
||||
|
||||
interface ContentSectionProps {
|
||||
collection: string;
|
||||
@ -9,32 +13,82 @@ interface ContentSectionProps {
|
||||
contentClass?: string;
|
||||
}
|
||||
|
||||
// ✅ Définition du type Glossaire
|
||||
interface GlossaireItem {
|
||||
mot_clef: string;
|
||||
slug: string;
|
||||
variantes: string[];
|
||||
description: string;
|
||||
images?: any[];
|
||||
}
|
||||
|
||||
export default async function ContentSectionCompetences({ collection, slug, titleClass, contentClass }: ContentSectionProps) {
|
||||
const data = await fetchDataCompetences(collection, slug); // ✅ Utilisation du fetch spécifique
|
||||
const data = await fetchDataCompetences(collection, slug);
|
||||
const glossaireData: GlossaireItem[] = await fetchDataGlossaire();
|
||||
|
||||
const [selectedMot, setSelectedMot] = useState<GlossaireItem | null>(null);
|
||||
|
||||
if (!data) {
|
||||
return <div className="text-red-500 text-center">❌ Compétence introuvable.</div>;
|
||||
}
|
||||
|
||||
const { name, content, picture } = data; // ✅ Assure-toi que `content` est bien récupéré au lieu de `Resum`
|
||||
const { name, content, picture } = data;
|
||||
|
||||
// 🔹 Transformation des images pour le carrousel des compétences
|
||||
const images = picture?.map((img: any) => ({
|
||||
url: `http://localhost:1337${img?.formats?.large?.url || img?.url}`,
|
||||
alt: img.name || "Image de compétence",
|
||||
})) || [];
|
||||
|
||||
// 🔥 Transformation du texte riche avec des <span> cliquables
|
||||
function transformMarkdownWithKeywords(text: string) {
|
||||
if (!glossaireData || glossaireData.length === 0) return text;
|
||||
|
||||
let modifiedText = text;
|
||||
|
||||
glossaireData.forEach(({ mot_clef, variantes }) => {
|
||||
const regexVariants = (variantes || []).map((v: string) => v.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")).join("|");
|
||||
const regex = new RegExp(`\\b(${mot_clef}|${regexVariants})\\b`, "gi");
|
||||
|
||||
modifiedText = modifiedText.replace(regex, (match) => {
|
||||
return `<span class="keyword" data-mot="${mot_clef}">${match}</span>`; // 🔥 Span cliquable
|
||||
});
|
||||
});
|
||||
|
||||
return modifiedText;
|
||||
}
|
||||
|
||||
const contentWithLinks = transformMarkdownWithKeywords(content);
|
||||
|
||||
// ✅ Gestion des clics sur les mots-clés
|
||||
useEffect(() => {
|
||||
function handleKeywordClick(event: any) {
|
||||
const target = event.target as HTMLElement;
|
||||
if (target.classList.contains("keyword")) {
|
||||
const mot = target.getAttribute("data-mot");
|
||||
if (mot) {
|
||||
const glossaireMot = glossaireData.find((g) => g.mot_clef === mot);
|
||||
setSelectedMot(glossaireMot || null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
document.addEventListener("click", handleKeywordClick);
|
||||
return () => document.removeEventListener("click", handleKeywordClick);
|
||||
}, [glossaireData]);
|
||||
|
||||
return (
|
||||
<div className="max-w-3xl mx-auto p-6">
|
||||
<h1 className={titleClass || "text-3xl mb-6 font-bold text-gray-700"}>{name}</h1>
|
||||
|
||||
{/* Carrousel spécifique aux compétences */}
|
||||
<CarouselCompetences images={images} className="w-full h-64" />
|
||||
|
||||
{/* Contenu en Markdown */}
|
||||
{/* 🔥 Affichage du texte riche avec mots-clés cliquables */}
|
||||
<div className={contentClass || "mt-6 text-lg text-black-700"}>
|
||||
<ReactMarkdown>{content}</ReactMarkdown> {/* ✅ Utilisation de `content` au lieu de `Resum` */}
|
||||
<ReactMarkdown>{contentWithLinks}</ReactMarkdown>
|
||||
</div>
|
||||
|
||||
{/* 🚀 Modale pour afficher les infos des mots-clés */}
|
||||
{selectedMot && <ModalGlossaire mot={selectedMot} onClose={() => setSelectedMot(null)} />}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@ -1,55 +1,33 @@
|
||||
import { useState, useEffect } from "react";
|
||||
import CarouselCompetences from "./CarouselCompetences";
|
||||
|
||||
interface ModalGlossaireProps {
|
||||
glossaire: any[]; // Liste complète des mots-clés
|
||||
mot: {
|
||||
mot_clef: string;
|
||||
description: string;
|
||||
images?: any[];
|
||||
};
|
||||
onClose: () => void;
|
||||
}
|
||||
|
||||
export default function ModalGlossaire({ glossaire }: ModalGlossaireProps) {
|
||||
const [selectedMot, setSelectedMot] = useState<any | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
// 🔥 Détecter si un mot-clé est dans l'URL (#glossaire-mot)
|
||||
function checkHash() {
|
||||
const hash = window.location.hash.replace("#glossaire-", "");
|
||||
const mot = glossaire.find((g) => g.mot_clef.toLowerCase() === hash.toLowerCase());
|
||||
setSelectedMot(mot || null);
|
||||
}
|
||||
|
||||
window.addEventListener("hashchange", checkHash);
|
||||
checkHash(); // Vérifier au chargement
|
||||
|
||||
return () => {
|
||||
window.removeEventListener("hashchange", checkHash);
|
||||
};
|
||||
}, [glossaire]);
|
||||
|
||||
if (!selectedMot) return null;
|
||||
|
||||
export default function ModalGlossaire({ mot, onClose }: ModalGlossaireProps) {
|
||||
return (
|
||||
<div className="fixed inset-0 bg-black bg-opacity-75 flex items-center justify-center z-50">
|
||||
<div className="bg-white p-6 rounded-lg shadow-lg max-w-2xl w-full relative">
|
||||
{/* Bouton de fermeture */}
|
||||
<button
|
||||
className="absolute top-3 right-3 text-gray-700 text-2xl"
|
||||
onClick={() => {
|
||||
setSelectedMot(null);
|
||||
window.location.hash = ""; // 🔄 Supprime le hash pour fermer la modale
|
||||
}}
|
||||
>
|
||||
<button className="absolute top-3 right-3 text-gray-700 text-2xl" onClick={onClose}>
|
||||
✖
|
||||
</button>
|
||||
|
||||
{/* Titre */}
|
||||
<h2 className="text-2xl font-bold mb-4">{selectedMot.mot_clef}</h2>
|
||||
<h2 className="text-2xl font-bold mb-4">{mot.mot_clef}</h2>
|
||||
|
||||
{/* Description */}
|
||||
<p className="text-gray-700 mb-4">{selectedMot.description}</p>
|
||||
<p className="text-gray-700 mb-4">{mot.description}</p>
|
||||
|
||||
{/* Carrousel d'images si disponible */}
|
||||
{selectedMot.images && selectedMot.images.length > 0 && (
|
||||
{mot.images && mot.images.length > 0 && (
|
||||
<CarouselCompetences
|
||||
images={selectedMot.images.map((img: any) => ({
|
||||
images={mot.images.map((img: any) => ({
|
||||
url: `http://localhost:1337${img?.formats?.large?.url || img?.url}`,
|
||||
alt: img.name || "Illustration",
|
||||
}))}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user