SPB Git

spb/trouve-ka Public

Trouve-KA — moteur de recherche web indépendant, Québec-first. Crawler distribué, index OpenSearch, ranking bilingue, galerie d'images. En prod : www.trouve-ka.com

Python 76.8% TypeScript 15.7% SQL 3.9% Shell 1.4% CSS 1.3% Dockerfile 0.7%
1.6 KB · 57 lines tsx
Raw Blame History
1/**2 * Trouve-KA — rendu sécurisé des extraits avec surlignage <em>3 * Author: Simon-Pierre Boucher4 * Contact: contact@spboucher.ai5 */67import { Fragment } from "react";8import { cn } from "@/lib/utils";910/** Retire toute balise HTML restante (le contenu distant est non fiable). */11function stripTags(value: string): string {12  return value.replace(/<[^>]*>/g, "");13}1415/** Décode les entités HTML courantes (l'ordre garde `&amp;` en dernier). */16function decodeEntities(value: string): string {17  return value18    .replace(/&lt;/g, "<")19    .replace(/&gt;/g, ">")20    .replace(/&quot;/g, '"')21    .replace(/&#0?39;/g, "'")22    .replace(/&nbsp;/g, " ")23    .replace(/&amp;/g, "&");24}2526interface SnippetProps {27  html: string;28  className?: string;29}3031/**32 * Rend un extrait de recherche sans `dangerouslySetInnerHTML` : seuls les33 * segments `<em>` du backend deviennent des éléments de surlignage; tout le34 * reste est traité comme du texte brut (React échappe automatiquement).35 */36export function Snippet({ html, className }: SnippetProps) {37  const parts = html.split(/<em>([\s\S]*?)<\/em>/g);38  return (39    <p className={cn("break-words", className)}>40      {parts.map((part, index) => {41        const text = decodeEntities(stripTags(part));42        if (!text) return null;43        return index % 2 === 1 ? (44          <em45            key={index}46            className="rounded-[3px] bg-lime-soft px-0.5 not-italic font-semibold text-ink"47          >48            {text}49          </em>50        ) : (51          <Fragment key={index}>{text}</Fragment>52        );53      })}54    </p>55  );56}57