import React from 'react'; import { Sparkles, ChevronRight, MessageSquare, FileCode, Globe, Send, Scissors, Zap, Languages, Layout, ArrowRightLeft, BookOpen, History, Target, Network, Clock, AlertCircle } from 'lucide-react'; import { motion, AnimatePresence } from 'motion/react'; import { AITab, AITone, Note, Carnet } from '../types'; import { HierarchicalCarnetSelector } from './HierarchicalCarnetSelector'; interface AISidebarProps { isOpen: boolean; setIsOpen: (open: boolean) => void; activeNote: Note | undefined; aiTab: AITab; setAiTab: (tab: AITab) => void; selectedTone: AITone; setSelectedTone: (tone: AITone) => void; carnets: Carnet[]; notes?: Note[]; onOpenNote?: (noteId: string) => void; onUpdateNote?: (note: Note) => void; } export const AISidebar: React.FC = ({ isOpen, setIsOpen, activeNote, aiTab, setAiTab, selectedTone, setSelectedTone, carnets, notes = [], onOpenNote = (_noteId: string) => {}, onUpdateNote }) => { const [selectedContextId, setSelectedContextId] = React.useState(null); const [hoveredOrbitNode, setHoveredOrbitNode] = React.useState(null); const explicitWikiLinks = React.useMemo(() => [ { source: 'n1', target: 'n1-b' }, { source: 'n3', target: 'n3-b' }, { source: 'bridge-1', target: 'n1' }, { source: 'bridge-1', target: 'n2' }, ], []); const CARNET_COLOR_PALETTE: { [key: string]: string } = { '1': '#D97706', // Daily Notes - Warm Amber '2': '#059669', // Project: Neo - Soft Emerald '3': '#4F46E5', // Shared Docs - Rich Indigo '4': '#0891B2', // Architecture Research - Clean Cyan '5': '#EA580C', // History of Architecture - Deep Orange '6': '#DB2777', // Modernism - Vibrant Rose '7': '#65A30D', // Sustainable Design - Cool Lime }; const DEFAULT_CARNET_COLOR = '#71717A'; const backlinks = React.useMemo(() => { if (!activeNote || !notes) return []; return notes.filter(n => { if (n.id === activeNote.id || n.isDeleted) return false; const isExplicit = explicitWikiLinks.some(link => (link.source === n.id && link.target === activeNote.id) ); const isContentLink = n.content.toLowerCase().includes(`[[${activeNote.title.toLowerCase()}]]`); return isExplicit || isContentLink; }); }, [activeNote, notes, explicitWikiLinks]); const outboundLinks = React.useMemo(() => { if (!activeNote || !notes) return []; return notes.filter(n => { if (n.id === activeNote.id || n.isDeleted) return false; const isExplicit = explicitWikiLinks.some(link => (link.source === activeNote.id && link.target === n.id) ); const isContentLink = activeNote.content.toLowerCase().includes(`[[${n.title.toLowerCase()}]]`); return isExplicit || isContentLink; }); }, [activeNote, notes, explicitWikiLinks]); const unlinkedMentions = React.useMemo(() => { if (!activeNote || !notes) return []; return notes.filter(n => { if (n.id === activeNote.id || n.isDeleted) return false; const isLinked = [...backlinks, ...outboundLinks].some(link => link.id === n.id); if (isLinked) return false; return n.content.toLowerCase().includes(activeNote.title.toLowerCase()); }); }, [activeNote, notes, backlinks, outboundLinks]); const orbitNodes = React.useMemo(() => { const list: { id: string; title: string; color: string; carnetName: string; relationship: 'backlink' | 'outbound' | 'mention' }[] = []; backlinks.forEach(n => { const carnet = carnets.find(c => c.id === n.carnetId); list.push({ id: n.id, title: n.title, color: CARNET_COLOR_PALETTE[n.carnetId] || DEFAULT_CARNET_COLOR, carnetName: carnet?.name || 'Carnet', relationship: 'backlink' }); }); outboundLinks.forEach(n => { const carnet = carnets.find(c => c.id === n.carnetId); list.push({ id: n.id, title: n.title, color: CARNET_COLOR_PALETTE[n.carnetId] || DEFAULT_CARNET_COLOR, carnetName: carnet?.name || 'Carnet', relationship: 'outbound' }); }); unlinkedMentions.forEach(n => { const carnet = carnets.find(c => c.id === n.carnetId); list.push({ id: n.id, title: n.title, color: CARNET_COLOR_PALETTE[n.carnetId] || DEFAULT_CARNET_COLOR, carnetName: carnet?.name || 'Carnet', relationship: 'mention' }); }); return list.slice(0, 8); }, [backlinks, outboundLinks, unlinkedMentions, carnets]); const getSnippetWithHighlight = (content: string, term: string) => { const index = content.toLowerCase().indexOf(term.toLowerCase()); if (index === -1) { return {content.substring(0, 80)}...; } const start = Math.max(0, index - 40); const end = Math.min(content.length, index + term.length + 40); const before = content.substring(start, index); const match = content.substring(index, index + term.length); const after = content.substring(index + term.length, end); return ( {start > 0 && "..."} {before} {match} {after} {end < content.length && "..."} ); }; return ( {isOpen && (

IA Assistant

"{activeNote?.title}"

{(['discussion', 'actions', 'explore', 'resources', 'relations'] as AITab[]).map((tab) => ( ))}
{aiTab === 'explore' && (

Intelligence Modules

Ces modules utilisent les embeddings du modèle Gemini pour analyser graphiquement vos pensées.

)} {aiTab === 'discussion' && (
{(['Professional', 'Creative', 'Academic', 'Casual'] as AITone[]).map((tone) => ( ))}
Note Active
Auto

Conversation prête. Posez votre question ci-dessous.

)} {aiTab === 'actions' && (

Transformations

{[ { icon: , label: 'Clarifier', color: 'ochre' }, { icon: , label: 'Raccourcir', color: 'rust' }, { icon: , label: 'Améliorer', color: 'sage' }, { icon: , label: 'Traduire', color: 'slate' }, ].map((action, i) => ( ))}

Generation Tools

Présentation

Convertir en slides interactives

Thème
Style
Diagramme

Visualisation de structure

Type
Style
Auto-Save Enabled
)} {aiTab === 'relations' && (

Vue Graphe Locale

{activeNote ? ( <> {/* Interactive local graph SVG container */}
{/* Dotted circle boundary helper */} {/* Connections */} {orbitNodes.map((node, i) => { const angle = i * (orbitNodes.length > 0 ? (2 * Math.PI) / orbitNodes.length : 0); const nx = 160 + 70 * Math.cos(angle); const ny = 110 + 62 * Math.sin(angle); return ( {node.relationship === 'outbound' && ( )} {node.relationship === 'backlink' && ( )} ); })} {/* Center node (Active Note) */} {/* Orbit nodes */} {orbitNodes.map((node, i) => { const angle = i * (orbitNodes.length > 0 ? (2 * Math.PI) / orbitNodes.length : 0); const nx = 160 + 70 * Math.cos(angle); const ny = 110 + 62 * Math.sin(angle); const isHovered = hoveredOrbitNode?.id === node.id; return ( onOpenNote(node.id)} onMouseEnter={() => setHoveredOrbitNode(node)} onMouseLeave={() => setHoveredOrbitNode(null)} > {node.title.length > 10 ? node.title.substring(0, 8) + '...' : node.title} ); })} {/* Interactive local tooltip card info */}
{hoveredOrbitNode ? (
{hoveredOrbitNode.carnetName} {hoveredOrbitNode.relationship === 'backlink' ? 'Lien Entrant' : hoveredOrbitNode.relationship === 'outbound' ? 'Lien Sortant' : 'Mention Simple'}

{hoveredOrbitNode.title}

Cliquez pour ouvrir la note

) : (
Survolez un nœud, cliquez pour ouvrir
)}
{/* Lists of backlinks & unlinked mentions */}
{/* 1. Backlinks */}
Liens Entrans ({backlinks.length})
{backlinks.length > 0 ? (
{backlinks.map(n => (
onOpenNote(n.id)} className="p-3 bg-white dark:bg-zinc-950 border border-border hover:border-accent/40 rounded-xl cursor-pointer transition-all space-y-1.5 hover:shadow-sm" >
{n.title} Réf

{getSnippetWithHighlight(n.content, activeNote.title)}

))}
) : (

Aucun lien entrant explicite pointant vers cette note.

)}
{/* 2. Outbound Links */}
Liens Sortants ({outboundLinks.length})
{outboundLinks.length > 0 ? (
{outboundLinks.map(n => (
onOpenNote(n.id)} className="p-3 bg-white dark:bg-zinc-950 border border-border hover:border-accent/40 rounded-xl cursor-pointer transition-all space-y-1.5 hover:shadow-sm animate-fadeIn" >
{n.title} Cible

{getSnippetWithHighlight(activeNote.content, n.title)}

))}
) : (

Cette note ne pointe vers aucun lien sortant explicite.

)}
{/* 3. Unlinked Mentions */}
Mentions Simples ({unlinkedMentions.length})
{unlinkedMentions.length > 0 ? (
{unlinkedMentions.map(n => (
onOpenNote(n.id)} className="p-3 bg-white dark:bg-zinc-950 border border-border hover:border-accent/40 rounded-xl cursor-pointer transition-all space-y-1.5 hover:shadow-sm" >
{n.title} Mention

{getSnippetWithHighlight(n.content, activeNote.title)}

))}
) : (

Aucune mention textuelle non-liée trouvée dans vos autres notes.

)}
) : (

Veuillez sélectionner une note pour explorer son graphe relationnel.

)} )} {aiTab === 'resources' && (