## Translation Files - Add 11 new language files (es, de, pt, ru, zh, ja, ko, ar, hi, nl, pl) - Add 100+ missing translation keys across all 15 languages - New sections: notebook, pagination, ai.batchOrganization, ai.autoLabels - Update nav section with workspace, quickAccess, myLibrary keys ## Component Updates - Update 15+ components to use translation keys instead of hardcoded text - Components: notebook dialogs, sidebar, header, note-input, ghost-tags, etc. - Replace 80+ hardcoded English/French strings with t() calls - Ensure consistent UI across all supported languages ## Code Quality - Remove 77+ console.log statements from codebase - Clean up API routes, components, hooks, and services - Keep only essential error handling (no debugging logs) ## UI/UX Improvements - Update Keep logo to yellow post-it style (from-yellow-400 to-amber-500) - Change selection colors to #FEF3C6 (notebooks) and #EFB162 (nav items) - Make "+" button permanently visible in notebooks section - Fix grammar and syntax errors in multiple components ## Bug Fixes - Fix JSON syntax errors in it.json, nl.json, pl.json, zh.json - Fix syntax errors in notebook-suggestion-toast.tsx - Fix syntax errors in use-auto-tagging.ts - Fix syntax errors in paragraph-refactor.service.ts - Fix duplicate "fusion" section in nl.json 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com> Ou une version plus courte si vous préférez : feat(i18n): Add 15 languages, remove logs, update UI components - Create 11 new translation files (es, de, pt, ru, zh, ja, ko, ar, hi, nl, pl) - Add 100+ translation keys: notebook, pagination, AI features - Update 15+ components to use translations (80+ strings) - Remove 77+ console.log statements from codebase - Fix JSON syntax errors in 4 translation files - Fix component syntax errors (toast, hooks, services) - Update logo to yellow post-it style - Change selection colors (#FEF3C6, #EFB162) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
176 lines
6.3 KiB
TypeScript
176 lines
6.3 KiB
TypeScript
'use client'
|
|
|
|
import { useState } from 'react'
|
|
import { Dialog, DialogContent } from '@/components/ui/dialog'
|
|
import { Button } from '@/components/ui/button'
|
|
import { X, Sparkles, ThumbsUp, ThumbsDown } from 'lucide-react'
|
|
import { cn } from '@/lib/utils'
|
|
import { Note } from '@/lib/types'
|
|
import { useLanguage } from '@/lib/i18n/LanguageProvider'
|
|
|
|
interface ComparisonModalProps {
|
|
isOpen: boolean
|
|
onClose: () => void
|
|
notes: Array<Partial<Note>>
|
|
similarity?: number
|
|
onOpenNote?: (noteId: string) => void
|
|
}
|
|
|
|
export function ComparisonModal({
|
|
isOpen,
|
|
onClose,
|
|
notes,
|
|
similarity,
|
|
onOpenNote
|
|
}: ComparisonModalProps) {
|
|
const { t } = useLanguage()
|
|
const [feedback, setFeedback] = useState<'thumbs_up' | 'thumbs_down' | null>(null)
|
|
|
|
const handleFeedback = async (type: 'thumbs_up' | 'thumbs_down') => {
|
|
setFeedback(type)
|
|
// TODO: Send feedback to backend
|
|
setTimeout(() => {
|
|
onClose()
|
|
}, 500)
|
|
}
|
|
|
|
const getNoteColor = (index: number) => {
|
|
const colors = [
|
|
'border-blue-200 dark:border-blue-800 hover:border-blue-300 dark:hover:border-blue-700',
|
|
'border-purple-200 dark:border-purple-800 hover:border-purple-300 dark:hover:border-purple-700',
|
|
'border-green-200 dark:border-green-800 hover:border-green-300 dark:hover:border-green-700'
|
|
]
|
|
return colors[index % colors.length]
|
|
}
|
|
|
|
const getTitleColor = (index: number) => {
|
|
const colors = [
|
|
'text-blue-600 dark:text-blue-400',
|
|
'text-purple-600 dark:text-purple-400',
|
|
'text-green-600 dark:text-green-400'
|
|
]
|
|
return colors[index % colors.length]
|
|
}
|
|
|
|
const maxModalWidth = notes.length === 2 ? 'max-w-6xl' : 'max-w-7xl'
|
|
const similarityPercentage = similarity ? Math.round(similarity * 100) : 0
|
|
|
|
return (
|
|
<Dialog open={isOpen} onOpenChange={onClose}>
|
|
<DialogContent className={cn(
|
|
"max-h-[90vh] overflow-hidden flex flex-col p-0",
|
|
maxModalWidth
|
|
)}>
|
|
{/* Header */}
|
|
<div className="flex items-center justify-between p-6 border-b dark:border-zinc-700">
|
|
<div className="flex items-center gap-3">
|
|
<div className="p-2 bg-amber-100 dark:bg-amber-900/30 rounded-full">
|
|
<Sparkles className="h-5 w-5 text-amber-600 dark:text-amber-400" />
|
|
</div>
|
|
<div>
|
|
<h2 className="text-xl font-semibold">
|
|
{t('memoryEcho.comparison.title')}
|
|
</h2>
|
|
<p className="text-sm text-gray-600 dark:text-gray-400">
|
|
{t('memoryEcho.comparison.similarityInfo', { similarity: similarityPercentage })}
|
|
</p>
|
|
</div>
|
|
</div>
|
|
<button
|
|
onClick={onClose}
|
|
className="text-gray-500 hover:text-gray-700 dark:hover:text-gray-300"
|
|
>
|
|
<X className="h-6 w-6" />
|
|
</button>
|
|
</div>
|
|
|
|
{/* AI Insight Section - Optional for now */}
|
|
{similarityPercentage >= 80 && (
|
|
<div className="px-6 py-4 bg-amber-50 dark:bg-amber-950/20 border-b dark:border-zinc-700">
|
|
<div className="flex items-start gap-2">
|
|
<Sparkles className="h-4 w-4 text-amber-600 dark:text-amber-400 mt-0.5 flex-shrink-0" />
|
|
<p className="text-sm text-gray-700 dark:text-gray-300">
|
|
{t('memoryEcho.comparison.highSimilarityInsight')}
|
|
</p>
|
|
</div>
|
|
</div>
|
|
)}
|
|
|
|
{/* Notes Grid */}
|
|
<div className={cn(
|
|
"flex-1 overflow-y-auto p-6",
|
|
notes.length === 2 ? "grid grid-cols-2 gap-6" : "grid grid-cols-3 gap-4"
|
|
)}>
|
|
{notes.map((note, index) => {
|
|
const title = note.title || t('memoryEcho.comparison.untitled')
|
|
const noteColor = getNoteColor(index)
|
|
const titleColor = getTitleColor(index)
|
|
|
|
return (
|
|
<div
|
|
key={note.id || index}
|
|
onClick={() => {
|
|
if (onOpenNote && note.id) {
|
|
onOpenNote(note.id)
|
|
onClose()
|
|
}
|
|
}}
|
|
className={cn(
|
|
"cursor-pointer border dark:border-zinc-700 rounded-lg p-4 transition-all hover:shadow-md",
|
|
noteColor
|
|
)}
|
|
>
|
|
<h3 className={cn("font-semibold text-lg mb-3", titleColor)}>
|
|
{title}
|
|
</h3>
|
|
<div className="text-sm text-gray-600 dark:text-gray-400 line-clamp-8 whitespace-pre-wrap">
|
|
{note.content}
|
|
</div>
|
|
<div className="mt-4 pt-3 border-t dark:border-zinc-700">
|
|
<p className="text-xs text-gray-500 flex items-center gap-1">
|
|
{t('memoryEcho.comparison.clickToView')}
|
|
<span className="transform rotate-[-45deg]">→</span>
|
|
</p>
|
|
</div>
|
|
</div>
|
|
)
|
|
})}
|
|
</div>
|
|
|
|
{/* Footer - Feedback */}
|
|
<div className="px-6 py-4 border-t dark:border-zinc-700 bg-gray-50 dark:bg-zinc-800/50">
|
|
<div className="flex items-center justify-between">
|
|
<p className="text-sm text-gray-600 dark:text-gray-400">
|
|
{t('memoryEcho.comparison.helpfulQuestion')}
|
|
</p>
|
|
<div className="flex items-center gap-2">
|
|
<Button
|
|
size="sm"
|
|
variant={feedback === 'thumbs_up' ? 'default' : 'outline'}
|
|
onClick={() => handleFeedback('thumbs_up')}
|
|
className={cn(
|
|
feedback === 'thumbs_up' && "bg-green-600 hover:bg-green-700 text-white"
|
|
)}
|
|
>
|
|
<ThumbsUp className="h-4 w-4 mr-2" />
|
|
{t('memoryEcho.comparison.helpful')}
|
|
</Button>
|
|
<Button
|
|
size="sm"
|
|
variant={feedback === 'thumbs_down' ? 'default' : 'outline'}
|
|
onClick={() => handleFeedback('thumbs_down')}
|
|
className={cn(
|
|
feedback === 'thumbs_down' && "bg-red-600 hover:bg-red-700 text-white"
|
|
)}
|
|
>
|
|
<ThumbsDown className="h-4 w-4 mr-2" />
|
|
{t('memoryEcho.comparison.notHelpful')}
|
|
</Button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</DialogContent>
|
|
</Dialog>
|
|
)
|
|
}
|