feat: add slides generation tool with multiple slide types
- Add slides.tool.ts with support for title, bullets, chart, stats, table, cards, timeline, quote, comparison, equation, image, summary slide types - Chart types: bar, horizontal-bar, line, donut, radar - Integrate with agent executor and canvas system - Add multilingual support (en/fr) - Various UI improvements and bug fixes Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -10,7 +10,7 @@ import { NotesEditorialView } from '@/components/notes-editorial-view'
|
||||
import { MemoryEchoNotification } from '@/components/memory-echo-notification'
|
||||
import { NotebookSuggestionToast } from '@/components/notebook-suggestion-toast'
|
||||
import { Button } from '@/components/ui/button'
|
||||
import { Plus, ArrowUpDown, Search, Sparkles, FileText, FolderOpen, ChevronRight, Tag as TagIcon, X } from 'lucide-react'
|
||||
import { Plus, ArrowUpDown, Search, Sparkles, FileText, FolderOpen, ChevronRight, Tag as TagIcon, X, Menu } from 'lucide-react'
|
||||
import { useNoteRefresh } from '@/context/NoteRefreshContext'
|
||||
import { useRefresh } from '@/lib/use-refresh'
|
||||
import { useReminderCheck } from '@/hooks/use-reminder-check'
|
||||
@@ -81,7 +81,9 @@ export function HomeClient({ initialNotes, initialSettings }: HomeClientProps) {
|
||||
const [showSortMenu, setShowSortMenu] = useState(false)
|
||||
const [showInlineSearch, setShowInlineSearch] = useState(false)
|
||||
const [inlineSearchQuery, setInlineSearchQuery] = useState('')
|
||||
const [isSearching, setIsSearching] = useState(false)
|
||||
const inlineSearchRef = useRef<HTMLInputElement>(null)
|
||||
const searchDebounceRef = useRef<ReturnType<typeof setTimeout> | null>(null)
|
||||
const notesRef = useRef(notes)
|
||||
notesRef.current = notes
|
||||
const { refreshKey, triggerRefresh } = useNoteRefresh()
|
||||
@@ -98,13 +100,6 @@ export function HomeClient({ initialNotes, initialSettings }: HomeClientProps) {
|
||||
const [isTagsExpanded, setIsTagsExpanded] = useState(false)
|
||||
const [tagSearchQuery, setTagSearchQuery] = useState('')
|
||||
|
||||
useEffect(() => {
|
||||
// Auto-trigger disabled — user opens manually from AI panel
|
||||
// if (shouldSuggestLabels && suggestNotebookId) {
|
||||
// setAutoLabelOpen(true)
|
||||
// }
|
||||
}, [shouldSuggestLabels, suggestNotebookId])
|
||||
|
||||
// Sidebar carnet / inbox: fermer l'éditeur plein écran (comme la ref. architectural-grid)
|
||||
useEffect(() => {
|
||||
if (searchParams.get('forceList') === '1') {
|
||||
@@ -473,10 +468,18 @@ export function HomeClient({ initialNotes, initialSettings }: HomeClientProps) {
|
||||
) : (
|
||||
<div className="flex-1 overflow-y-auto min-h-0 bg-memento-paper dark:bg-background flex flex-col">
|
||||
<div
|
||||
className="px-12 pt-12 pb-8 flex flex-col gap-6 sticky top-0 bg-memento-paper/90 dark:bg-background/90 backdrop-blur-md z-30"
|
||||
className="px-4 sm:px-8 md:px-12 pt-6 sm:pt-10 md:pt-12 pb-8 flex flex-col gap-6 sticky top-0 bg-memento-paper/90 dark:bg-background/90 backdrop-blur-md z-30"
|
||||
>
|
||||
<div className="flex justify-between items-start">
|
||||
<div>
|
||||
<div className="flex justify-between items-start gap-3">
|
||||
{/* Hamburger mobile — ouvre la sidebar */}
|
||||
<button
|
||||
className="md:hidden p-2 -ms-2 text-foreground hover:bg-foreground/5 rounded-lg transition-colors shrink-0 self-start mt-1"
|
||||
onClick={() => window.dispatchEvent(new CustomEvent('open-mobile-sidebar'))}
|
||||
aria-label="Open menu"
|
||||
>
|
||||
<Menu size={22} />
|
||||
</button>
|
||||
<div className="flex-1 min-w-0">
|
||||
{currentNotebook && notebookPath.length > 0 && (
|
||||
<div
|
||||
className="flex items-center gap-2 text-[12px] uppercase tracking-[.2em] font-bold mb-2 text-ink/60"
|
||||
@@ -491,7 +494,7 @@ export function HomeClient({ initialNotes, initialSettings }: HomeClientProps) {
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
<h1 className="font-memento-serif text-4xl font-medium tracking-tight text-foreground leading-tight pe-12">
|
||||
<h1 className="font-memento-serif text-2xl sm:text-3xl md:text-4xl font-medium tracking-tight text-foreground leading-tight pe-4 sm:pe-12">
|
||||
{currentNotebook
|
||||
? currentNotebook.name
|
||||
: searchParams.get('shared') === '1'
|
||||
@@ -527,7 +530,11 @@ export function HomeClient({ initialNotes, initialSettings }: HomeClientProps) {
|
||||
{/* Inline search — toggles an input within the toolbar */}
|
||||
{showInlineSearch ? (
|
||||
<div className="flex items-center gap-2">
|
||||
<Search size={14} className="text-muted-foreground shrink-0" />
|
||||
{isSearching ? (
|
||||
<div className="w-3.5 h-3.5 border border-muted-foreground/50 border-t-foreground rounded-full animate-spin shrink-0" />
|
||||
) : (
|
||||
<Search size={14} className="text-muted-foreground shrink-0" />
|
||||
)}
|
||||
<input
|
||||
ref={inlineSearchRef}
|
||||
autoFocus
|
||||
@@ -536,13 +543,18 @@ export function HomeClient({ initialNotes, initialSettings }: HomeClientProps) {
|
||||
onChange={e => {
|
||||
const q = e.target.value
|
||||
setInlineSearchQuery(q)
|
||||
const params = new URLSearchParams(searchParams.toString())
|
||||
if (q.trim()) {
|
||||
params.set('search', q)
|
||||
} else {
|
||||
params.delete('search')
|
||||
}
|
||||
router.push(`/home?${params.toString()}`)
|
||||
setIsSearching(true)
|
||||
if (searchDebounceRef.current) clearTimeout(searchDebounceRef.current)
|
||||
searchDebounceRef.current = setTimeout(() => {
|
||||
const params = new URLSearchParams(searchParams.toString())
|
||||
if (q.trim()) {
|
||||
params.set('search', q)
|
||||
} else {
|
||||
params.delete('search')
|
||||
}
|
||||
router.push(`/home?${params.toString()}`)
|
||||
setIsSearching(false)
|
||||
}, 300)
|
||||
}}
|
||||
onBlur={() => {
|
||||
if (!inlineSearchQuery) {
|
||||
@@ -551,28 +563,32 @@ export function HomeClient({ initialNotes, initialSettings }: HomeClientProps) {
|
||||
}}
|
||||
onKeyDown={e => {
|
||||
if (e.key === 'Escape') {
|
||||
if (searchDebounceRef.current) clearTimeout(searchDebounceRef.current)
|
||||
setShowInlineSearch(false)
|
||||
setInlineSearchQuery('')
|
||||
setIsSearching(false)
|
||||
const params = new URLSearchParams(searchParams.toString())
|
||||
params.delete('search')
|
||||
router.push(`/home?${params.toString()}`)
|
||||
}
|
||||
}}
|
||||
placeholder={t('search.placeholder')}
|
||||
className="w-48 bg-transparent border-b border-foreground/20 focus:border-foreground outline-none text-[13px] text-foreground placeholder:text-muted-foreground/50 py-0.5 transition-colors"
|
||||
className="w-36 sm:w-48 bg-transparent border-b border-foreground/20 focus:border-foreground outline-none text-[13px] text-foreground placeholder:text-muted-foreground/50 py-0.5 transition-colors"
|
||||
/>
|
||||
{inlineSearchQuery && (
|
||||
<button
|
||||
onClick={() => {
|
||||
if (searchDebounceRef.current) clearTimeout(searchDebounceRef.current)
|
||||
setShowInlineSearch(false)
|
||||
setInlineSearchQuery('')
|
||||
setIsSearching(false)
|
||||
const params = new URLSearchParams(searchParams.toString())
|
||||
params.delete('search')
|
||||
router.push(`/home?${params.toString()}`)
|
||||
}}
|
||||
className="text-muted-foreground hover:text-foreground transition-colors"
|
||||
>
|
||||
<span className="text-[11px]">×</span>
|
||||
<X size={12} />
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
@@ -714,7 +730,7 @@ export function HomeClient({ initialNotes, initialSettings }: HomeClientProps) {
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="px-12 flex-1 pb-20">
|
||||
<div className="px-4 sm:px-8 md:px-12 flex-1 pb-10 sm:pb-16 md:pb-20">
|
||||
{isLoading ? (
|
||||
<div className="text-center py-8 text-muted-foreground">{t('general.loading')}</div>
|
||||
) : (
|
||||
@@ -760,7 +776,7 @@ export function HomeClient({ initialNotes, initialSettings }: HomeClientProps) {
|
||||
)}
|
||||
</div>
|
||||
|
||||
<footer className="px-12 py-6 border-t border-foreground/5 text-center mt-auto">
|
||||
<footer className="px-4 sm:px-8 md:px-12 py-4 sm:py-6 border-t border-foreground/5 text-center mt-auto">
|
||||
<p className="text-[11px] text-muted-foreground uppercase tracking-[0.2em] font-medium">
|
||||
Memento — {new Date().getFullYear()}
|
||||
</p>
|
||||
|
||||
Reference in New Issue
Block a user