Files
Anonyme/app/components/TextDisplay.tsx
2025-09-07 12:30:23 +02:00

109 lines
3.3 KiB
TypeScript

import React from "react";
import { generateColorFromName } from "@/app/config/colorPalette";
import { Word } from "./hooks/useTextParsing";
interface TextDisplayProps {
words: Word[];
text: string;
selectedWords: Set<number>;
hoveredWord: number | null;
onWordClick: (index: number, event: React.MouseEvent) => void;
onContextMenu: (event: React.MouseEvent) => void;
onWordHover: (index: number | null) => void;
}
export const TextDisplay: React.FC<TextDisplayProps> = ({
words,
text,
selectedWords,
hoveredWord,
onWordClick,
onContextMenu,
onWordHover,
}) => {
const renderWord = (word: Word, index: number) => {
const isSelected = selectedWords.has(index);
const isHovered = hoveredWord === index;
let className =
"inline-block cursor-pointer transition-all duration-200 px-1 py-0.5 rounded-sm ";
let backgroundColor = "transparent";
if (word.isEntity) {
// Couleur personnalisée ou générée - Niveau 200
if (word.mapping?.customColor) {
backgroundColor = word.mapping.customColor;
} else if (word.mapping?.displayName) {
// Utiliser generateColorFromName pour la cohérence
backgroundColor = generateColorFromName(word.mapping.displayName).value;
} else if (word.entityType) {
backgroundColor = generateColorFromName(word.entityType).value;
} else {
// Couleur par défaut si aucune information disponible
backgroundColor = generateColorFromName("default").value;
}
// Utiliser la classe CSS appropriée
if (word.mapping?.displayName) {
const colorClass = generateColorFromName(word.mapping.displayName);
className += `${colorClass.bgClass} ${colorClass.textClass} border `;
} else if (word.entityType) {
const colorClass = generateColorFromName(word.entityType);
className += `${colorClass.bgClass} ${colorClass.textClass} border `;
}
}
// Gestion du survol et sélection - Couleurs claires
if (isSelected) {
className += "ring-2 ring-blue-400 ";
} else if (isHovered) {
if (!word.isEntity) {
className += "bg-gray-200 ";
backgroundColor = "#E5E7EB"; // gray-200
}
}
className += "brightness-95 ";
return (
<span
key={index}
className={className}
style={{
backgroundColor: backgroundColor,
}}
onMouseEnter={() => onWordHover(index)}
onMouseLeave={() => onWordHover(null)}
onClick={(e) => onWordClick(index, e)}
onContextMenu={onContextMenu}
title={
word.isEntity
? `Entité: ${word.entityType} (Original: ${word.text})`
: "Cliquez pour sélectionner"
}
>
{word.displayText}{" "}
</span>
);
};
return (
<div className="p-4 bg-white border border-gray-200 rounded-lg min-h-[300px] leading-relaxed text-sm">
<div className="whitespace-pre-wrap">
{words.map((word, index) => {
const nextWord = words[index + 1];
const spaceBetween = nextWord
? text.slice(word.end, nextWord.start)
: text.slice(word.end);
return (
<React.Fragment key={index}>
{renderWord(word, index)}
<span>{spaceBetween}</span>
</React.Fragment>
);
})}
</div>
</div>
);
};