feat(brainstorm): Option D — toast + peek panel + navigation volontaire
Some checks failed
CI / Lint, Unit Tests & Build (push) Failing after 4m37s
CI / Deploy production (on server) (push) Has been skipped

3 points corrigés (plus d'éjection automatique du brainstorm):

1. Convertir idée → note:
   - Avant: setTimeout 2s → router.push (éjection forcée)
   - Après: toast.success persistant 10s + peek.open (drawer latéral)

2. Exporter session → note synthèse:
   - Avant: setTimeout 2s → router.push (éjection forcée)
   - Après: toast.success + peek.open

3. Voir note référencée:
   - Avant: router.push (éjection immédiate)
   - Après: peek.open (drawer latéral)

Comportement:
- Toast sonner avec bouton 'Ouvrir' (navigation volontaire)
- NotePeekPanel mode overlay (slide droite, lecture seule, KaTeX)
- Canvas brainstorm reste interactif derrière
- Bouton Maximize2 dans le peek → router.push (choix explicite)
- Anciens convertToast/exportToast supprimés (45 lignes JSX retirées)
This commit is contained in:
Antigravity
2026-07-05 19:09:26 +00:00
parent 6e13b6d207
commit d1336b1fea

View File

@@ -1,4 +1,5 @@
'use client'
import { toast } from 'sonner'
import React, { useState, useMemo, useEffect, useRef, useCallback } from 'react'
import { useRouter, useSearchParams } from 'next/navigation'
@@ -26,9 +27,11 @@ import {
LayoutGrid,
X,
Edit2,
Maximize2,
} from 'lucide-react'
import dynamic from 'next/dynamic'
import { useLanguage } from '@/lib/i18n'
import { useNotePeek, NotePeekPanel } from '@/components/note-peek'
import {
useBrainstormSession,
useBrainstormSessions,
@@ -76,6 +79,7 @@ const WAVE_COLORS: Record<number, { border: string; bg: string; text: string }>
export function BrainstormPage() {
const router = useRouter()
const peek = useNotePeek()
const searchParams = useSearchParams()
const { t, language } = useLanguage()
const { data: authSession } = useSession()
@@ -132,8 +136,7 @@ export function BrainstormPage() {
const renameSession = useRenameBrainstormSession(activeSessionId || '')
const [impactToast, setImpactToast] = useState<{ notesEnriched: number; notesMarkedDry: number } | null>(null)
const [exportError, setExportError] = useState<string | null>(null)
const [exportToast, setExportToast] = useState<{ noteTitle: string; notebookName: string } | null>(null)
const [convertToast, setConvertToast] = useState<{ noteTitle: string; noteId: string } | null>(null)
const [remoteMove, setRemoteMove] = useState<{ ideaId: string; x: number; y: number; _seq: number } | null>(null)
const [playbackIdeas, setPlaybackIdeas] = useState<any[] | null>(null)
const [viewMode, setViewMode] = useState<'canvas' | 'list'>('canvas')
@@ -242,11 +245,15 @@ export function BrainstormPage() {
try {
const result = await convertIdea.mutateAsync(idea.id)
if (result?.id) {
setConvertToast({ noteTitle: result.title || idea.title, noteId: result.id })
setTimeout(() => {
setConvertToast(null)
router.push(`/home?openNote=${result.id}`)
}, 2000)
toast.success(t('brainstorm.noteCreated') || 'Note created', {
description: result.title || idea.title,
action: {
label: t('notePeek.openFully') || 'Open',
onClick: () => router.push(`/home?openNote=${result.id}`),
},
duration: 10000,
})
peek.open(result.id)
}
} catch {}
}
@@ -287,11 +294,15 @@ export function BrainstormPage() {
const result = await exportBrainstorm.mutateAsync()
if (result?.id) {
const notebookName = result._notebookName || t('brainstorm.exportDefaultNotebookName')
setExportToast({ noteTitle: result.title || t('brainstorm.exportDefaultNoteTitle'), notebookName })
setTimeout(() => {
setExportToast(null)
router.push(`/home?openNote=${result.id}`)
}, 2000)
toast.success(t('brainstorm.noteCreated') || 'Note created', {
description: `${result.title || t('brainstorm.exportDefaultNoteTitle')}${notebookName}`,
action: {
label: t('notePeek.openFully') || 'Open',
onClick: () => router.push(`/home?openNote=${result.id}`),
},
duration: 10000,
})
peek.open(result.id)
return
}
const impact = await finalizeBrainstorm.mutateAsync()
@@ -846,7 +857,7 @@ export function BrainstormPage() {
</div>
{ref.noteId && (
<button
onClick={() => router.push(`/home?openNote=${ref.noteId}`)}
onClick={() => ref.noteId && peek.open(ref.noteId)}
className="shrink-0 px-2 py-1 text-[9px] font-bold uppercase tracking-wider rounded-lg bg-foreground/5 hover:bg-foreground/10 text-muted-foreground hover:text-foreground transition-all"
>
{t('brainstorm.viewNote') || 'View'}
@@ -1124,49 +1135,15 @@ export function BrainstormPage() {
)}
</AnimatePresence>
<AnimatePresence>
{exportToast && (
<motion.div
initial={{ y: 100, opacity: 0 }}
animate={{ y: 0, opacity: 1 }}
exit={{ y: 100, opacity: 0 }}
className="fixed bottom-8 left-1/2 -translate-x-1/2 z-50 px-6 py-4 bg-emerald-600 text-white rounded-2xl shadow-2xl flex items-center gap-3 text-sm font-medium"
>
<Wind size={18} />
<div className="flex flex-col">
<span className="font-bold">{exportToast.noteTitle}</span>
<span className="text-[11px] text-emerald-100">
{t('brainstorm.exportNotebookPrefix')} {exportToast.notebookName}
</span>
</div>
<div className="ml-3 flex items-center gap-1.5 text-emerald-200 text-[10px]">
<div className="w-1.5 h-1.5 rounded-full bg-emerald-300 animate-pulse" />
{t('brainstorm.exportOpening')}
</div>
</motion.div>
)}
</AnimatePresence>
<AnimatePresence>
{convertToast && (
<motion.div
initial={{ y: 100, opacity: 0 }}
animate={{ y: 0, opacity: 1 }}
exit={{ y: 100, opacity: 0 }}
className="fixed bottom-8 left-1/2 -translate-x-1/2 z-50 px-6 py-4 bg-emerald-600 text-white rounded-2xl shadow-2xl flex items-center gap-3 text-sm font-medium"
>
<FileText size={18} />
<div className="flex flex-col">
<span className="font-bold">{convertToast.noteTitle}</span>
<span className="text-[11px] text-emerald-100">{t('brainstorm.noteCreated') || 'Note Created'}</span>
</div>
<div className="ml-3 flex items-center gap-1.5 text-emerald-200 text-[10px]">
<div className="w-1.5 h-1.5 rounded-full bg-emerald-300 animate-pulse" />
{t('brainstorm.exportOpening')}
</div>
</motion.div>
)}
</AnimatePresence>
{/* Peek panel — drawer latéral pour aperçu note sans quitter le brainstorm */}
<NotePeekPanel
note={peek.note}
blockId={peek.blockId}
loading={peek.loading}
mode="overlay"
onClose={peek.close}
onOpenFully={(n) => { router.push(`/home?openNote=${n.id}`); peek.close() }}
/>
</div>
)
}