feat: AI chat tone selector + graph node pinning
- ai-chat: sélecteur tone (Professional/Créatif/Académique/Décontracté) passé via noteContext.tone dans le body vers /api/chat - network-graph: dragended garde fx/fy → nœud épinglé après drag double-clic sur nœud pour désépingler (fx=null, fy=null) - sprint-status: 6-2 et 6-3 passés en done Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
@@ -64,8 +64,8 @@ development_status:
|
||||
# Epic 6 — Croissance & Activation (PLG) — ajouté 2026-05-29
|
||||
epic-6: in-progress
|
||||
6-1-onboarding-activation: done # story-onboarding-activation.md
|
||||
6-2-markdown-roundtrip: review # brief-markdown-roundtrip.md
|
||||
6-3-brainstorm-canvas-finalize: review # story: 6-3-brainstorm-canvas-finalize.md
|
||||
6-2-markdown-roundtrip: done # brief-markdown-roundtrip.md
|
||||
6-3-brainstorm-canvas-finalize: done # story: 6-3-brainstorm-canvas-finalize.md
|
||||
6-4-chat-with-pdf: done # already implemented: document-qa-overlay.tsx + document-ingestion + document-search tool
|
||||
6-5-pptx-export-watermark: done # story: 6-5-pptx-export-watermark.md
|
||||
epic-6-retrospective: optional
|
||||
|
||||
@@ -42,6 +42,7 @@ export function AIChat({ showFloatingTrigger = true }: { showFloatingTrigger?: b
|
||||
const [input, setInput] = useState('')
|
||||
const [conversationId, setConversationId] = useState<string | undefined>()
|
||||
const [isContextualAIVisible, setIsContextualAIVisible] = useState(false)
|
||||
const [tone, setTone] = useState<'professional' | 'creative' | 'academic' | 'casual'>('professional')
|
||||
|
||||
const [history, setHistory] = useState<any[]>([])
|
||||
const [historyLoading, setHistoryLoading] = useState(false)
|
||||
@@ -97,6 +98,7 @@ export function AIChat({ showFloatingTrigger = true }: { showFloatingTrigger?: b
|
||||
webSearch: webSearch && webSearchAvailable,
|
||||
conversationId: convId,
|
||||
language,
|
||||
noteContext: { title: '', content: '', tone },
|
||||
}
|
||||
}
|
||||
)
|
||||
@@ -273,6 +275,32 @@ export function AIChat({ showFloatingTrigger = true }: { showFloatingTrigger?: b
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Tone selector */}
|
||||
<div className="flex items-center gap-1.5 flex-wrap">
|
||||
{(['professional', 'creative', 'academic', 'casual'] as const).map((t_) => {
|
||||
const labels: Record<typeof t_, string> = {
|
||||
professional: '💼 Pro',
|
||||
creative: '✨ Créatif',
|
||||
academic: '🎓 Académique',
|
||||
casual: '😊 Décontracté',
|
||||
}
|
||||
return (
|
||||
<button
|
||||
key={t_}
|
||||
onClick={() => setTone(t_)}
|
||||
className={cn(
|
||||
'px-2.5 py-1 rounded-full text-[10px] font-bold border transition-all',
|
||||
tone === t_
|
||||
? 'bg-brand-accent/10 border-brand-accent/40 text-brand-accent'
|
||||
: 'border-border/40 text-concrete hover:border-ink/20 hover:text-ink/60'
|
||||
)}
|
||||
>
|
||||
{labels[t_]}
|
||||
</button>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
|
||||
{/* Messages */}
|
||||
{messages.length === 0 && (
|
||||
<div className="h-48 flex flex-col items-center justify-center text-center space-y-3 text-concrete/30">
|
||||
|
||||
@@ -241,6 +241,11 @@ export function NetworkGraph({
|
||||
return String(d.clusterId) === selectedClusterId ? 1 : 0.15
|
||||
})
|
||||
.on('click', (event, d) => onNoteSelect(d.id))
|
||||
.on('dblclick', (event, d) => {
|
||||
d.fx = null
|
||||
d.fy = null
|
||||
simulation.alphaTarget(0.1).restart()
|
||||
})
|
||||
.call(d3.drag<SVGGElement, D3Node>()
|
||||
.on('start', dragstarted)
|
||||
.on('drag', dragged)
|
||||
@@ -328,8 +333,8 @@ export function NetworkGraph({
|
||||
|
||||
function dragended(event: any, d: D3Node) {
|
||||
if (!event.active) simulation.alphaTarget(0)
|
||||
d.fx = null
|
||||
d.fy = null
|
||||
// Garder le nœud épinglé à sa position après drag (fx/fy non remis à null)
|
||||
// Double-clic pour désépingler → géré via dblclick ci-dessous
|
||||
}
|
||||
|
||||
return () => {
|
||||
|
||||
Reference in New Issue
Block a user