feat(room): render AI mentions as 🤖 button with click-to-insert action
AI mentions now render as "🤖 AI: name" buttons instead of plain text. Clicking a 🤖 button inserts the @ai:mention into the message input at the cursor position, enabling users to summon that AI model into the conversation. Implementation: - MessageMentions renders AI mentions as styled buttons with 🤖 icon - Click dispatches 'mention-click' CustomEvent on document - ChatInputArea listens and inserts the mention HTML at cursor
This commit is contained in:
parent
3a24022972
commit
b96ef0342c
@ -127,8 +127,40 @@ function renderNode(
|
|||||||
}
|
}
|
||||||
if (node.type === 'mention') {
|
if (node.type === 'mention') {
|
||||||
const displayName = resolveName(node.mentionType, node.id, node.label);
|
const displayName = resolveName(node.mentionType, node.id, node.label);
|
||||||
|
const baseClass = mentionStyles[node.mentionType] ?? mentionStyles.user;
|
||||||
|
|
||||||
|
if (node.mentionType === 'ai') {
|
||||||
|
return (
|
||||||
|
<button
|
||||||
|
key={index}
|
||||||
|
type="button"
|
||||||
|
className={cn(
|
||||||
|
baseClass,
|
||||||
|
'inline-flex items-center gap-1 cursor-pointer border-0 bg-transparent p-0',
|
||||||
|
'hover:opacity-80 transition-opacity',
|
||||||
|
)}
|
||||||
|
onClick={() => {
|
||||||
|
document.dispatchEvent(
|
||||||
|
new CustomEvent('mention-click', {
|
||||||
|
detail: {
|
||||||
|
type: 'ai',
|
||||||
|
id: node.id,
|
||||||
|
label: displayName,
|
||||||
|
},
|
||||||
|
bubbles: true,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<span className="text-sm">🤖</span>
|
||||||
|
<span>AI:</span>
|
||||||
|
<span className="font-medium">{displayName}</span>
|
||||||
|
</button>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<span key={index} className={mentionStyles[node.mentionType] ?? mentionStyles.user}>
|
<span key={index} className={baseClass}>
|
||||||
@{displayName}
|
@{displayName}
|
||||||
</span>
|
</span>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -230,6 +230,35 @@ const ChatInputArea = memo(function ChatInputArea({
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Listen for mention-click events from message content (e.g. 🤖 AI button)
|
||||||
|
useEffect(() => {
|
||||||
|
const onMentionClick = (e: Event) => {
|
||||||
|
const { type, id, label } = (e as CustomEvent<{ type: string; id: string; label: string }>).detail;
|
||||||
|
if (!textareaRef.current) return;
|
||||||
|
const textarea = textareaRef.current;
|
||||||
|
const cursorPos = textarea.selectionStart;
|
||||||
|
const textBefore = textarea.value.substring(0, cursorPos);
|
||||||
|
|
||||||
|
if (type === 'ai') {
|
||||||
|
// Insert @ai:mention at cursor position
|
||||||
|
const html = buildMentionHtml('ai', id, label);
|
||||||
|
const spacer = ' ';
|
||||||
|
const newValue = textBefore + html + spacer + textarea.value.substring(cursorPos);
|
||||||
|
const newCursorPos = cursorPos + html.length + spacer.length;
|
||||||
|
onDraftChange(newValue);
|
||||||
|
setTimeout(() => {
|
||||||
|
if (textareaRef.current) {
|
||||||
|
textareaRef.current.value = newValue;
|
||||||
|
textareaRef.current.setSelectionRange(newCursorPos, newCursorPos);
|
||||||
|
textareaRef.current.focus();
|
||||||
|
}
|
||||||
|
}, 0);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
document.addEventListener('mention-click', onMentionClick);
|
||||||
|
return () => document.removeEventListener('mention-click', onMentionClick);
|
||||||
|
}, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="border-t border-border/70 bg-background p-3">
|
<div className="border-t border-border/70 bg-background p-3">
|
||||||
{replyingTo && (
|
{replyingTo && (
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user