fix: title textarea auto-resize (no overflow), auto-title 10-word check + toast feedback, AI expand = fixed overlay (no compress)

This commit is contained in:
Antigravity
2026-05-07 23:39:19 +00:00
parent 38c637cfac
commit 29e65038b7
2 changed files with 58 additions and 18 deletions

View File

@@ -783,18 +783,23 @@ export function NoteEditor({ note, readOnly = false, onClose, fullPage = false }
</span>
</div>
{/* Title — editable input styled as h1 */}
{/* Title — auto-resizing textarea to prevent overflow */}
<div className="group relative">
<input
<textarea
dir="auto"
type="text"
rows={1}
placeholder={t('notes.titlePlaceholder') || 'Untitled…'}
value={title}
onChange={(e) => { setTitle(e.target.value); setIsDirty(true); setDismissedTitleSuggestions(true) }}
onInput={(e) => {
const el = e.currentTarget
el.style.height = 'auto'
el.style.height = el.scrollHeight + 'px'
}}
disabled={readOnly}
className={cn(
'w-full text-4xl md:text-5xl font-memento-serif font-bold border-0 outline-none px-0 bg-transparent text-foreground leading-tight',
'placeholder:text-foreground/20',
'placeholder:text-foreground/20 resize-none overflow-hidden',
!readOnly && 'pr-12'
)}
/>
@@ -804,7 +809,11 @@ export function NoteEditor({ note, readOnly = false, onClose, fullPage = false }
type="button"
onClick={async () => {
const plain = content.replace(/<[^>]+>/g, ' ').trim()
if (plain.split(/\s+/).filter(Boolean).length < 3) return
const wordCount = plain.split(/\s+/).filter(Boolean).length
if (wordCount < 10) {
toast.error('Ajoutez au moins 10 mots avant de générer un titre.')
return
}
setIsProcessingAI(true)
try {
const res = await fetch('/api/ai/title-suggestions', {
@@ -814,13 +823,21 @@ export function NoteEditor({ note, readOnly = false, onClose, fullPage = false }
})
if (res.ok) {
const data = await res.json()
const s = data.title || data.suggestedTitle || (data.suggestions?.[0]?.title ?? '')
if (s) { setTitle(s); setIsDirty(true) }
const s = data.suggestions?.[0]?.title ?? ''
if (s) {
setTitle(s)
setIsDirty(true)
toast.success('Titre généré !')
} else {
toast.error('Impossible de générer un titre.')
}
} else {
toast.error('Erreur lors de la génération du titre.')
}
} catch {} finally { setIsProcessingAI(false) }
} catch { toast.error('Erreur réseau.') } finally { setIsProcessingAI(false) }
}}
disabled={isProcessingAI}
className="absolute right-0 top-1/2 -translate-y-1/2 opacity-0 group-hover:opacity-60 hover:!opacity-100 transition-opacity rounded-lg p-2 text-foreground/50 hover:bg-black/5"
className="absolute right-0 top-2 opacity-0 group-hover:opacity-60 hover:!opacity-100 transition-opacity rounded-lg p-2 text-foreground/50 hover:bg-black/5"
title="Générer un titre automatique avec l'IA"
>
{isProcessingAI ? <Loader2 className="h-5 w-5 animate-spin" /> : <Sparkles className="h-5 w-5" />}
@@ -918,7 +935,11 @@ export function NoteEditor({ note, readOnly = false, onClose, fullPage = false }
diagramInsertFormat={noteType === 'richtext' ? 'html' : 'markdown'}
onGenerateTitle={async () => {
const plain = content.replace(/<[^>]+>/g, ' ').trim()
if (plain.split(/\s+/).filter(Boolean).length < 3) return
const wordCount = plain.split(/\s+/).filter(Boolean).length
if (wordCount < 10) {
toast.error('Ajoutez au moins 10 mots avant de générer un titre.')
return
}
setIsProcessingAI(true)
try {
const res = await fetch('/api/ai/title-suggestions', {
@@ -928,10 +949,18 @@ export function NoteEditor({ note, readOnly = false, onClose, fullPage = false }
})
if (res.ok) {
const data = await res.json()
const s = data.title || data.suggestedTitle || (data.suggestions?.[0]?.title ?? '')
if (s) { setTitle(s); setIsDirty(true) }
const s = data.suggestions?.[0]?.title ?? ''
if (s) {
setTitle(s)
setIsDirty(true)
toast.success('Titre généré !')
} else {
toast.error('Impossible de générer un titre.')
}
} else {
toast.error('Erreur lors de la génération du titre.')
}
} catch {} finally { setIsProcessingAI(false) }
} catch { toast.error('Erreur réseau.') } finally { setIsProcessingAI(false) }
}}
/>
</div>