diff --git a/memento-note/components/contextual-ai-chat.tsx b/memento-note/components/contextual-ai-chat.tsx index 5a7a87a..85ca171 100644 --- a/memento-note/components/contextual-ai-chat.tsx +++ b/memento-note/components/contextual-ai-chat.tsx @@ -151,7 +151,9 @@ export function ContextualAIChat({ const { messages, sendMessage, status, stop } = useChat({ transport }) - const isLoading = status === 'submitted' || status === 'streaming' + const lastMsg = messages[messages.length - 1] + const lastMsgHasContent = lastMsg?.role === 'assistant' && !!getMessageContent(lastMsg) + const isLoading = (status === 'submitted' || status === 'streaming') && !lastMsgHasContent useEffect(() => { messagesEndRef.current?.scrollIntoView({ behavior: 'smooth' }) @@ -304,16 +306,15 @@ export function ContextualAIChat({ /** Called from chat hover-actions: inject a chat message into the note */ const handleInjectFromChat = async (msgText: string, mode: 'replace' | 'complete' | 'merge') => { if (mode === 'replace') { + // Stay on chat tab — show preview inline via resourcePreview without switching tabs setResourceText(msgText) setResourceMode('replace') setResourcePreview({ text: msgText, source: 'chat' }) - setActiveTab('resource') return } setResourceText(msgText) setResourceMode(mode) - setActiveTab('resource') - // Auto-launch enrichment + // Do NOT switch tabs — enrich and show preview in current tab setResourceEnriching(true) try { const res = await fetch('/api/ai/enrich-from-resource', { diff --git a/memento-note/components/note-input.tsx b/memento-note/components/note-input.tsx index 6841148..bae5d93 100644 --- a/memento-note/components/note-input.tsx +++ b/memento-note/components/note-input.tsx @@ -56,6 +56,30 @@ import { useSession } from 'next-auth/react' import { useSearchParams } from 'next/navigation' import { useLanguage } from '@/lib/i18n' +/** Convert basic markdown to HTML for richtext injection from AI chat */ +function markdownToBasicHtml(md: string): string { + return md + .replace(/^#{6}\s(.+)$/gm, '
$1
') + .replace(/^#{5}\s(.+)$/gm, '
$1
') + .replace(/^#{4}\s(.+)$/gm, '

$1

') + .replace(/^#{3}\s(.+)$/gm, '

$1

') + .replace(/^#{2}\s(.+)$/gm, '

$1

') + .replace(/^#\s(.+)$/gm, '

$1

') + .replace(/\*\*\*(.+?)\*\*\*/g, '$1') + .replace(/\*\*(.+?)\*\*/g, '$1') + .replace(/\*(.+?)\*/g, '$1') + .replace(/__(.+?)__/g, '$1') + .replace(/_(.+?)_/g, '$1') + .replace(/`([^`]+)`/g, '$1') + .replace(/~~(.+?)~~/g, '$1') + .replace(/^[-*]\s(.+)$/gm, '
  • $1
  • ') + .replace(/^\d+\.\s(.+)$/gm, '
  • $1
  • ') + .replace(/^>\s(.+)$/gm, '
    $1
    ') + .replace(/\n{2,}/g, '

    ') + .replace(/^(?!<[hH1-6]|$1

    ') + .replace(/

    <\/p>/g, '') +} + interface HistoryState { title: string content: string @@ -1044,7 +1068,15 @@ export function NoteInput({ noteTitle={title} noteContent={content} noteImages={allImages} - onApplyToNote={(newContent) => setContent(newContent)} + onApplyToNote={(newContent) => { + if (type === 'richtext') { + // If content looks like markdown, convert to HTML before injecting into richtext + const looksLikeMarkdown = /^#{1,6}\s|^[-*]\s|\*\*[^*]+\*\*|^>\s/.test(newContent) + setContent(looksLikeMarkdown ? markdownToBasicHtml(newContent) : newContent) + } else { + setContent(newContent) + } + }} lastActionApplied={false} notebooks={notebooks.map(nb => ({ id: nb.id, name: nb.name }))} className="border border-border border-l-0 rounded-r-xl overflow-hidden shadow-sm"