feat(chat): show playful teacher introductions on hover

This commit is contained in:
鲨鱼辣椒 committed 2026-09-28 12:12:10 +08:00
1 parent b26e25c9ed
commit 772da4f8e4
16 files changed
+433 -62

No files matched your search

+43
View File
@@ -0,0 +1,43 @@
import * as Tooltip from '@radix-ui/react-tooltip';
import { Sparkles } from 'lucide-react';
import type { ReactElement, Ref } from 'react';
import type { TeacherDefinition } from '../../../shared/coding-teacher';
import { TeacherAvatar } from './TeacherAvatar';
/** A temporary introduction, separate from the agent's unread messages. */
export function TeacherIntroduction({ definition, children, contentRef, open, onOpenChange }: {
definition: TeacherDefinition | null;
children: ReactElement;
contentRef?: Ref<HTMLDivElement>;
open: boolean;
onOpenChange(open: boolean): void;
}) {
const description = definition?.description?.trim();
return <Tooltip.Root open={Boolean(description) && open} onOpenChange={onOpenChange}>
<Tooltip.Trigger asChild onPointerEnter={(event) => {
// Adjacent entries must switch immediately, even inside the previous
// tooltip's pointer grace area used when moving into its readable card.
if (event.pointerType !== 'touch') onOpenChange(true);
}} onPointerMove={(event) => {
// pointerEnter owns hover opening. Skip Radix's second opening path so
// moving inside an entry after clicking it cannot reopen its introduction.
if (event.pointerType !== 'touch') event.preventDefault();
}}>{children}</Tooltip.Trigger>
{definition && description && <Tooltip.Portal>
<Tooltip.Content ref={contentRef} side="bottom" align="end" sideOffset={10} collisionPadding={12}
className="teacher-introduction no-drag" data-testid="teacher-introduction" aria-label={description}>
<div className="teacher-introduction-heading">
<TeacherAvatar definition={definition} className="teacher-introduction-avatar" />
<div className="min-w-0 flex-1">
<span className="teacher-introduction-eyebrow">认识一下</span>
<p className="teacher-introduction-name">{definition.name}</p>
</div>
<Sparkles className="teacher-introduction-sparkles" aria-hidden="true" />
</div>
<p className="teacher-introduction-description">{description}</p>
<p className="teacher-introduction-hint">点点头像,一起聊聊</p>
<Tooltip.Arrow className="teacher-introduction-arrow" width={18} height={9} />
</Tooltip.Content>
</Tooltip.Portal>}
</Tooltip.Root>;
}