feat(brainstorm): Option D — toast + peek panel + navigation volontaire
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:
@@ -1,4 +1,5 @@
|
|||||||
'use client'
|
'use client'
|
||||||
|
import { toast } from 'sonner'
|
||||||
|
|
||||||
import React, { useState, useMemo, useEffect, useRef, useCallback } from 'react'
|
import React, { useState, useMemo, useEffect, useRef, useCallback } from 'react'
|
||||||
import { useRouter, useSearchParams } from 'next/navigation'
|
import { useRouter, useSearchParams } from 'next/navigation'
|
||||||
@@ -26,9 +27,11 @@ import {
|
|||||||
LayoutGrid,
|
LayoutGrid,
|
||||||
X,
|
X,
|
||||||
Edit2,
|
Edit2,
|
||||||
|
Maximize2,
|
||||||
} from 'lucide-react'
|
} from 'lucide-react'
|
||||||
import dynamic from 'next/dynamic'
|
import dynamic from 'next/dynamic'
|
||||||
import { useLanguage } from '@/lib/i18n'
|
import { useLanguage } from '@/lib/i18n'
|
||||||
|
import { useNotePeek, NotePeekPanel } from '@/components/note-peek'
|
||||||
import {
|
import {
|
||||||
useBrainstormSession,
|
useBrainstormSession,
|
||||||
useBrainstormSessions,
|
useBrainstormSessions,
|
||||||
@@ -76,6 +79,7 @@ const WAVE_COLORS: Record<number, { border: string; bg: string; text: string }>
|
|||||||
|
|
||||||
export function BrainstormPage() {
|
export function BrainstormPage() {
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
|
const peek = useNotePeek()
|
||||||
const searchParams = useSearchParams()
|
const searchParams = useSearchParams()
|
||||||
const { t, language } = useLanguage()
|
const { t, language } = useLanguage()
|
||||||
const { data: authSession } = useSession()
|
const { data: authSession } = useSession()
|
||||||
@@ -132,8 +136,7 @@ export function BrainstormPage() {
|
|||||||
const renameSession = useRenameBrainstormSession(activeSessionId || '')
|
const renameSession = useRenameBrainstormSession(activeSessionId || '')
|
||||||
const [impactToast, setImpactToast] = useState<{ notesEnriched: number; notesMarkedDry: number } | null>(null)
|
const [impactToast, setImpactToast] = useState<{ notesEnriched: number; notesMarkedDry: number } | null>(null)
|
||||||
const [exportError, setExportError] = useState<string | 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 [remoteMove, setRemoteMove] = useState<{ ideaId: string; x: number; y: number; _seq: number } | null>(null)
|
||||||
const [playbackIdeas, setPlaybackIdeas] = useState<any[] | null>(null)
|
const [playbackIdeas, setPlaybackIdeas] = useState<any[] | null>(null)
|
||||||
const [viewMode, setViewMode] = useState<'canvas' | 'list'>('canvas')
|
const [viewMode, setViewMode] = useState<'canvas' | 'list'>('canvas')
|
||||||
@@ -242,11 +245,15 @@ export function BrainstormPage() {
|
|||||||
try {
|
try {
|
||||||
const result = await convertIdea.mutateAsync(idea.id)
|
const result = await convertIdea.mutateAsync(idea.id)
|
||||||
if (result?.id) {
|
if (result?.id) {
|
||||||
setConvertToast({ noteTitle: result.title || idea.title, noteId: result.id })
|
toast.success(t('brainstorm.noteCreated') || 'Note created', {
|
||||||
setTimeout(() => {
|
description: result.title || idea.title,
|
||||||
setConvertToast(null)
|
action: {
|
||||||
router.push(`/home?openNote=${result.id}`)
|
label: t('notePeek.openFully') || 'Open',
|
||||||
}, 2000)
|
onClick: () => router.push(`/home?openNote=${result.id}`),
|
||||||
|
},
|
||||||
|
duration: 10000,
|
||||||
|
})
|
||||||
|
peek.open(result.id)
|
||||||
}
|
}
|
||||||
} catch {}
|
} catch {}
|
||||||
}
|
}
|
||||||
@@ -287,11 +294,15 @@ export function BrainstormPage() {
|
|||||||
const result = await exportBrainstorm.mutateAsync()
|
const result = await exportBrainstorm.mutateAsync()
|
||||||
if (result?.id) {
|
if (result?.id) {
|
||||||
const notebookName = result._notebookName || t('brainstorm.exportDefaultNotebookName')
|
const notebookName = result._notebookName || t('brainstorm.exportDefaultNotebookName')
|
||||||
setExportToast({ noteTitle: result.title || t('brainstorm.exportDefaultNoteTitle'), notebookName })
|
toast.success(t('brainstorm.noteCreated') || 'Note created', {
|
||||||
setTimeout(() => {
|
description: `${result.title || t('brainstorm.exportDefaultNoteTitle')} — ${notebookName}`,
|
||||||
setExportToast(null)
|
action: {
|
||||||
router.push(`/home?openNote=${result.id}`)
|
label: t('notePeek.openFully') || 'Open',
|
||||||
}, 2000)
|
onClick: () => router.push(`/home?openNote=${result.id}`),
|
||||||
|
},
|
||||||
|
duration: 10000,
|
||||||
|
})
|
||||||
|
peek.open(result.id)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
const impact = await finalizeBrainstorm.mutateAsync()
|
const impact = await finalizeBrainstorm.mutateAsync()
|
||||||
@@ -846,7 +857,7 @@ export function BrainstormPage() {
|
|||||||
</div>
|
</div>
|
||||||
{ref.noteId && (
|
{ref.noteId && (
|
||||||
<button
|
<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"
|
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'}
|
{t('brainstorm.viewNote') || 'View'}
|
||||||
@@ -1124,49 +1135,15 @@ export function BrainstormPage() {
|
|||||||
)}
|
)}
|
||||||
</AnimatePresence>
|
</AnimatePresence>
|
||||||
|
|
||||||
<AnimatePresence>
|
{/* Peek panel — drawer latéral pour aperçu note sans quitter le brainstorm */}
|
||||||
{exportToast && (
|
<NotePeekPanel
|
||||||
<motion.div
|
note={peek.note}
|
||||||
initial={{ y: 100, opacity: 0 }}
|
blockId={peek.blockId}
|
||||||
animate={{ y: 0, opacity: 1 }}
|
loading={peek.loading}
|
||||||
exit={{ y: 100, opacity: 0 }}
|
mode="overlay"
|
||||||
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"
|
onClose={peek.close}
|
||||||
>
|
onOpenFully={(n) => { router.push(`/home?openNote=${n.id}`); peek.close() }}
|
||||||
<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>
|
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user