fix(chat): buttons always visible on last msg + preview panel outside scroll zone
Some checks failed
Deploy to Production / Build and Deploy (push) Has been cancelled
Some checks failed
Deploy to Production / Build and Deploy (push) Has been cancelled
This commit is contained in:
@@ -462,11 +462,14 @@ export function ContextualAIChat({
|
||||
? <MarkdownContent content={content} />
|
||||
: <p>{content}</p>}
|
||||
</div>
|
||||
{/* Hover-actions — visible only on assistant messages */}
|
||||
{isAssistant && onApplyToNote && (
|
||||
{/* Inject buttons — always visible on last assistant msg */}
|
||||
{isAssistant && onApplyToNote && (() => {
|
||||
const lastAssistantId = messages.filter(m => m.role === 'assistant').at(-1)?.id
|
||||
const alwaysShow = msg.id === lastAssistantId
|
||||
return (
|
||||
<div className={cn(
|
||||
'flex gap-1 transition-all duration-150',
|
||||
isHovered ? 'opacity-100 translate-y-0' : 'opacity-0 -translate-y-1 pointer-events-none',
|
||||
(alwaysShow || isHovered) ? 'opacity-100' : 'opacity-0 pointer-events-none',
|
||||
)}>
|
||||
<button
|
||||
onClick={() => handleInjectFromChat(content, 'replace')}
|
||||
@@ -490,7 +493,8 @@ export function ContextualAIChat({
|
||||
<GitMerge className="h-2.5 w-2.5" /> {t('ai.injectMerge')}
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
)
|
||||
})()}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
@@ -560,6 +564,54 @@ export function ContextualAIChat({
|
||||
<div ref={messagesEndRef} />
|
||||
</div>
|
||||
|
||||
{/* ══ Inject Preview Panel — fixed, always visible, NO scroll needed ══ */}
|
||||
{resourceEnriching && (
|
||||
<div className="shrink-0 mx-3 mb-2 flex items-center gap-2 rounded-xl border border-emerald-500/30 bg-emerald-50/50 dark:bg-emerald-950/20 p-3">
|
||||
<Loader2 className="h-3.5 w-3.5 animate-spin text-emerald-600 shrink-0" />
|
||||
<span className="text-xs text-emerald-700 dark:text-emerald-400">Traitement IA en cours...</span>
|
||||
</div>
|
||||
)}
|
||||
{resourcePreview && !resourceEnriching && (
|
||||
<div className="shrink-0 mx-3 mb-2 rounded-xl border border-primary/30 bg-primary/5 overflow-hidden">
|
||||
<div className="flex items-center justify-between px-3 py-2 border-b border-primary/20">
|
||||
<span className="text-[10px] font-semibold uppercase tracking-wider text-primary">
|
||||
{resourcePreview.source === 'complete' ? 'Complété par IA'
|
||||
: resourcePreview.source === 'merge' ? 'Fusionné par IA'
|
||||
: 'Aperçu'}
|
||||
</span>
|
||||
<button onClick={() => setResourcePreview(null)} className="text-muted-foreground hover:text-foreground">
|
||||
<X className="h-3 w-3" />
|
||||
</button>
|
||||
</div>
|
||||
<div className="px-3 py-2 max-h-36 overflow-y-auto text-sm">
|
||||
<MarkdownContent content={resourcePreview.text} />
|
||||
</div>
|
||||
<div className="flex gap-2 px-3 py-2 border-t border-primary/20">
|
||||
<button
|
||||
onClick={() => setResourcePreview(null)}
|
||||
className="flex-1 text-[11px] py-1.5 rounded-lg border border-border/60 text-muted-foreground hover:bg-muted transition-colors"
|
||||
>
|
||||
Annuler
|
||||
</button>
|
||||
<button
|
||||
onClick={() => {
|
||||
if (onApplyToNote && resourcePreview) {
|
||||
onApplyToNote(resourcePreview.text)
|
||||
setResourcePreview(null)
|
||||
setResourceText('')
|
||||
toast.success('Appliqué à la note')
|
||||
}
|
||||
}}
|
||||
disabled={!onApplyToNote}
|
||||
className="flex-1 text-[11px] py-1.5 rounded-lg bg-primary text-primary-foreground font-medium hover:bg-primary/90 transition-colors disabled:opacity-50 flex items-center justify-center gap-1"
|
||||
>
|
||||
<Check className="h-3 w-3" />
|
||||
Appliquer à la note
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Scope & Tone Control Area */}
|
||||
<div className="border-t border-border/20 shrink-0 bg-muted/10">
|
||||
{/* Scope bar */}
|
||||
|
||||
Reference in New Issue
Block a user