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/**2 * Trouve-KA — filtres de recherche en pastilles3 * Author: Simon-Pierre Boucher4 * Contact: contact@spboucher.ai5 */67"use client";89import { cn } from "@/lib/utils";1011/** Filtres actifs de la page de résultats. */12export interface SearchFilters {13 category?: string;14 language?: string;15 quebecOnly: boolean;16 images?: boolean;17}1819interface FilterPillsProps {20 filters: SearchFilters;21 onChange: (next: SearchFilters) => void;22}2324interface Pill {25 label: string;26 active: boolean;27 next: SearchFilters;28}2930export function FilterPills({ filters, onChange }: FilterPillsProps) {31 const allActive =32 !filters.category && !filters.language && !filters.quebecOnly && !filters.images;3334 const pills: Pill[] = [35 { label: "Tout", active: allActive, next: { quebecOnly: false } },36 {37 label: "Images",38 active: Boolean(filters.images),39 next: { ...filters, images: !filters.images },40 },41 {42 label: "Actualités",43 active: filters.category === "news",44 next: {45 ...filters,46 category: filters.category === "news" ? undefined : "news",47 },48 },49 {50 label: "Gouvernement",51 active: filters.category === "government",52 next: {53 ...filters,54 category: filters.category === "government" ? undefined : "government",55 },56 },57 {58 label: "Français",59 active: filters.language === "fr",60 next: {61 ...filters,62 language: filters.language === "fr" ? undefined : "fr",63 },64 },65 {66 label: "English",67 active: filters.language === "en",68 next: {69 ...filters,70 language: filters.language === "en" ? undefined : "en",71 },72 },73 {74 label: "Québec seulement",75 active: filters.quebecOnly,76 next: { ...filters, quebecOnly: !filters.quebecOnly },77 },78 ];7980 return (81 <div82 role="group"83 aria-label="Filtres de recherche"84 className="flex flex-wrap gap-2"85 >86 {pills.map((pill) => (87 <button88 key={pill.label}89 type="button"90 aria-pressed={pill.active}91 onClick={() => onChange(pill.next)}92 className={cn(93 "gk-mono whitespace-nowrap rounded-full border-[1.5px] border-ink px-3.5 py-1.5 text-[11px] font-bold uppercase tracking-[0.08em] shadow-[2px_2px_0_rgba(20,24,20,0.12)] transition-[background,color,transform,box-shadow] duration-150 hover:-translate-y-px hover:shadow-[3px_3px_0_rgba(20,24,20,0.2)] active:translate-y-0 active:shadow-none",94 pill.active95 ? "bg-ink text-lime"96 : "bg-surface text-ink-2 hover:bg-lime hover:text-ink",97 )}98 >99 {pill.label}100 </button>101 ))}102 </div>103 );104}105