import React, { useState } from 'react'; import { Observation } from '../types'; import { formatDate } from '../utils/formatters'; interface ObservationCardProps { observation: Observation; } // Helper to strip project root from file paths function stripProjectRoot(filePath: string): string { // Try to extract relative path by finding common project markers const markers = ['/Scripts/', '/src/', '/plugin/', '/docs/']; for (const marker of markers) { const index = filePath.indexOf(marker); if (index !== -1) { // Keep the marker and everything after it return filePath.substring(index + 1); } } // Fallback: if path contains project name, strip everything before it const projectIndex = filePath.indexOf('claude-mem/'); if (projectIndex !== -1) { return filePath.substring(projectIndex + 'claude-mem/'.length); } // If no markers found, return basename or original path const parts = filePath.split('/'); return parts.length > 3 ? parts.slice(-3).join('/') : filePath; } export function ObservationCard({ observation }: ObservationCardProps) { const [showFacts, setShowFacts] = useState(false); const [showNarrative, setShowNarrative] = useState(false); const date = formatDate(observation.created_at_epoch); // Parse JSON fields const facts = observation.facts ? JSON.parse(observation.facts) : []; const concepts = observation.concepts ? JSON.parse(observation.concepts) : []; const filesRead = observation.files_read ? JSON.parse(observation.files_read).map(stripProjectRoot) : []; const filesModified = observation.files_modified ? JSON.parse(observation.files_modified).map(stripProjectRoot) : []; // Show summary when both are off const showSummary = !showFacts && !showNarrative; return (
{/* Header with toggle buttons in top right */}
{observation.type} {observation.project}
{facts.length > 0 && ( )} {observation.narrative && ( )}
{/* Title */}
{observation.title || 'Untitled'}
{/* Content based on toggle state */}
{showSummary && observation.subtitle && (
{observation.subtitle}
)} {showFacts && facts.length > 0 && ( )} {showNarrative && observation.narrative && (
{observation.narrative}
)}
{/* Metadata with concepts and files inline */}
#{observation.id} • {date} {concepts.length > 0 && ( • {concepts.join(', ')} )} {filesRead.length > 0 && ( read: {filesRead.join(', ')} )} {filesModified.length > 0 && ( modified: {filesModified.join(', ')} )}
); }