feat(lesson-preparation): 树节点行组件
This commit is contained in:
@@ -0,0 +1,149 @@
|
||||
"use client";
|
||||
|
||||
import { useTranslations } from "next-intl";
|
||||
import type { Block } from "../../types";
|
||||
import { useLessonPlanEditor } from "../../hooks/use-lesson-plan-editor";
|
||||
|
||||
interface Props {
|
||||
node: Block;
|
||||
/** 是否展开到正文 */
|
||||
isExpanded: boolean;
|
||||
/** 是否有子节点(如师生交互的对话轮次) */
|
||||
hasChildren?: boolean;
|
||||
isChildrenExpanded?: boolean;
|
||||
onToggleChildren?: () => void;
|
||||
/** 子节点(如对话轮次) */
|
||||
children?: { id: string; label: string; kind: string }[];
|
||||
}
|
||||
|
||||
export function TreeNodeRow({
|
||||
node,
|
||||
isExpanded,
|
||||
hasChildren,
|
||||
isChildrenExpanded,
|
||||
onToggleChildren,
|
||||
children,
|
||||
}: Props) {
|
||||
const t = useTranslations("lessonPreparation");
|
||||
const selectedNodeId = useLessonPlanEditor((s) => s.selectedNodeId);
|
||||
const selectNode = useLessonPlanEditor((s) => s.selectNode);
|
||||
const toggleExpand = useLessonPlanEditor((s) => s.toggleExpand);
|
||||
|
||||
const isActive = selectedNodeId === node.id;
|
||||
const dotColor = `var(--lp-dot-${node.type})`;
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div
|
||||
role="button"
|
||||
tabIndex={0}
|
||||
onClick={() => selectNode(node.id)}
|
||||
onKeyDown={(e) => {
|
||||
if (e.key === "Enter" || e.key === " ") {
|
||||
e.preventDefault();
|
||||
selectNode(node.id);
|
||||
}
|
||||
}}
|
||||
style={{
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
gap: 6,
|
||||
padding: "6px 8px",
|
||||
borderRadius: 5,
|
||||
cursor: "pointer",
|
||||
background: isActive ? "var(--muted)" : "transparent",
|
||||
lineHeight: 1.3,
|
||||
fontSize: 13,
|
||||
}}
|
||||
className="lp-tree-row"
|
||||
>
|
||||
<span
|
||||
style={{
|
||||
width: 14,
|
||||
height: 14,
|
||||
display: "inline-flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
fontSize: 9,
|
||||
color: "var(--muted-foreground)",
|
||||
cursor: hasChildren ? "pointer" : "default",
|
||||
visibility: hasChildren ? "visible" : "hidden",
|
||||
}}
|
||||
onClick={(e) => {
|
||||
if (hasChildren && onToggleChildren) {
|
||||
e.stopPropagation();
|
||||
onToggleChildren();
|
||||
}
|
||||
}}
|
||||
>
|
||||
{hasChildren ? (isChildrenExpanded ? "▾" : "▸") : ""}
|
||||
</span>
|
||||
<span style={{ width: 6, height: 6, borderRadius: "50%", background: dotColor, flexShrink: 0 }} />
|
||||
<span
|
||||
style={{
|
||||
flex: 1,
|
||||
overflow: "hidden",
|
||||
textOverflow: "ellipsis",
|
||||
whiteSpace: "nowrap",
|
||||
color: "var(--foreground)",
|
||||
}}
|
||||
>
|
||||
{node.title}
|
||||
</span>
|
||||
<span style={{ fontSize: 10, color: "var(--muted-foreground)", fontWeight: 500 }}>
|
||||
{node.type}
|
||||
</span>
|
||||
{isExpanded && (
|
||||
<button
|
||||
type="button"
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
toggleExpand(node.id);
|
||||
}}
|
||||
style={{
|
||||
fontSize: 9,
|
||||
color: "var(--foreground)",
|
||||
background: "var(--muted)",
|
||||
padding: "1px 5px",
|
||||
borderRadius: 2,
|
||||
fontWeight: 500,
|
||||
border: "none",
|
||||
cursor: "pointer",
|
||||
}}
|
||||
>
|
||||
{t("v4.tree.onPaper")}
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{hasChildren && isChildrenExpanded && children && (
|
||||
<div
|
||||
style={{
|
||||
marginLeft: 10,
|
||||
paddingLeft: 8,
|
||||
borderLeft: "1px solid var(--border)",
|
||||
}}
|
||||
>
|
||||
{children.map((c) => (
|
||||
<div
|
||||
key={c.id}
|
||||
style={{
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
gap: 6,
|
||||
padding: "6px 8px",
|
||||
borderRadius: 5,
|
||||
fontSize: 12,
|
||||
color: "var(--muted-foreground)",
|
||||
}}
|
||||
>
|
||||
<span style={{ width: 6, height: 6, borderRadius: "50%", background: "var(--lp-dot-default)", opacity: 0.5 }} />
|
||||
<span style={{ flex: 1 }}>{c.label}</span>
|
||||
<span style={{ fontSize: 10 }}>{c.kind}</span>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user