feat(lesson-preparation): 师生交互对话体 inline 渲染
This commit is contained in:
@@ -0,0 +1,91 @@
|
||||
"use client";
|
||||
|
||||
import { useTranslations } from "next-intl";
|
||||
import type { InteractionBlockData, LessonPlanNode, QATurn } from "../../types";
|
||||
import { useLessonPlanEditor } from "../../hooks/use-lesson-plan-editor";
|
||||
|
||||
interface Props {
|
||||
node: LessonPlanNode;
|
||||
}
|
||||
|
||||
/**
|
||||
* V4 师生交互节点的 inline 对话体渲染。
|
||||
* - 师/生 角色标签(JetBrains Mono)
|
||||
* - 教师提问下方 italic 灰色 [预期:...]
|
||||
* - 对话轮次之间 dashed 线分隔
|
||||
*/
|
||||
export function InlineQaDialog({ node }: Props) {
|
||||
const t = useTranslations("lessonPreparation");
|
||||
const toggleExpand = useLessonPlanEditor((s) => s.toggleExpand);
|
||||
const data = node.data as InteractionBlockData;
|
||||
|
||||
return (
|
||||
<div className="lp-inline-node">
|
||||
<div className="lp-inline-node-head">
|
||||
<span
|
||||
style={{
|
||||
width: 5,
|
||||
height: 5,
|
||||
borderRadius: "50%",
|
||||
background: "var(--lp-dot-interaction)",
|
||||
display: "inline-block",
|
||||
}}
|
||||
/>
|
||||
<span>{t("v4.interaction.label")}</span>
|
||||
<span style={{ marginLeft: "auto", fontFamily: "JetBrains Mono, monospace", fontSize: 9, color: "var(--lp-inline-node-meta)" }}>
|
||||
{data.turns?.length ?? 0} 轮
|
||||
</span>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => toggleExpand(node.id)}
|
||||
style={{
|
||||
cursor: "pointer",
|
||||
padding: "2px 6px",
|
||||
borderRadius: 3,
|
||||
color: "var(--lp-inline-node-meta)",
|
||||
fontSize: 11,
|
||||
background: "transparent",
|
||||
border: "none",
|
||||
}}
|
||||
>
|
||||
{t("v4.contextMenu.collapseFromPaper")} ▴
|
||||
</button>
|
||||
</div>
|
||||
<h4 className="lp-inline-node-title">{node.title}</h4>
|
||||
<div className="lp-inline-node-body">
|
||||
{data.designIntent && (
|
||||
<p style={{ fontSize: 13, marginBottom: 8 }}>{data.designIntent}</p>
|
||||
)}
|
||||
<div className="lp-qa-dialog">
|
||||
{(data.turns ?? []).map((turn, idx) => (
|
||||
<QaTurnView key={turn.id} turn={turn} index={idx} />
|
||||
))}
|
||||
{(!data.turns || data.turns.length === 0) && (
|
||||
<p style={{ color: "var(--muted-foreground)", fontSize: 12 }}>
|
||||
—
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function QaTurnView({ turn, index }: { turn: QATurn; index: number }) {
|
||||
const t = useTranslations("lessonPreparation");
|
||||
const roleClass = turn.role === "teacher" ? "teacher" : "student";
|
||||
const roleLabel = turn.role === "teacher" ? t("v4.interaction.roleTeacher") : t("v4.interaction.roleStudent");
|
||||
void index;
|
||||
|
||||
return (
|
||||
<div className="lp-qa-turn">
|
||||
<div className={`lp-qa-role ${roleClass}`}>{roleLabel}</div>
|
||||
<div className="lp-qa-content">
|
||||
{turn.content}
|
||||
{turn.role === "teacher" && turn.expectedAnswer && (
|
||||
<span className="lp-qa-prompt">[预期:{turn.expectedAnswer}]</span>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user