feat(lesson-preparation): add anchor canvas design, new blocks, and textbook content node
- Add anchor injector for canvas-based anchor positioning - Add new block components: blackboard, homework, import, key-point, new-teaching, objective, summary - Add textbook content node for React Flow canvas - Update actions (kp, publish, main), data-access (templates, versions, main) - Update editor, node-editor, block-renderer, and picker components - Update schema, types, hooks, and lib utilities (document-migration, node-summary, rf-mappers)
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import type { LessonPlanNode } from "../types";
|
||||
import type { LessonPlanNode, TextbookContentNode } from "../types";
|
||||
|
||||
/**
|
||||
* 节点摘要翻译函数接口。
|
||||
@@ -6,7 +6,17 @@ import type { LessonPlanNode } from "../types";
|
||||
* values 类型对齐 next-intl 的 TranslationValues(string | number | Date)。
|
||||
*/
|
||||
export interface NodeSummaryT {
|
||||
(key: "editor.questionCount" | "editor.charCount" | "editor.nodeSummaryEmpty", values?: Record<string, string | number | Date>): string;
|
||||
(
|
||||
key:
|
||||
| "editor.questionCount"
|
||||
| "editor.charCount"
|
||||
| "editor.nodeSummaryEmpty"
|
||||
| "editor.itemCount"
|
||||
| "editor.pointCount"
|
||||
| "editor.assignmentCount"
|
||||
| "editor.durationMin",
|
||||
values?: Record<string, string | number | Date>,
|
||||
): string;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -16,17 +26,69 @@ export interface NodeSummaryT {
|
||||
*/
|
||||
export function getNodeSummary(node: LessonPlanNode, t: NodeSummaryT): string {
|
||||
const data = node.data as {
|
||||
// 富文本类
|
||||
html?: string;
|
||||
// 文本研习
|
||||
sourceText?: string;
|
||||
annotations?: unknown[];
|
||||
// 练习
|
||||
items?: unknown[];
|
||||
// 教学目标
|
||||
objectives?: unknown[];
|
||||
// 重难点
|
||||
keyPoints?: unknown[];
|
||||
// 导入
|
||||
durationMin?: number;
|
||||
prompt?: string;
|
||||
// 新授
|
||||
teachingPoints?: unknown[];
|
||||
// 小结
|
||||
summaryPoints?: unknown[];
|
||||
// 作业
|
||||
assignments?: unknown[];
|
||||
// 板书
|
||||
content?: string;
|
||||
// 反思
|
||||
reflection?: unknown[];
|
||||
// 知识点
|
||||
knowledgePointIds?: string[];
|
||||
};
|
||||
|
||||
// 按类型优先级提取摘要
|
||||
if (data.items !== undefined) {
|
||||
return t("editor.questionCount", { count: data.items.length });
|
||||
}
|
||||
if (data.objectives !== undefined) {
|
||||
return t("editor.itemCount", { count: data.objectives.length });
|
||||
}
|
||||
if (data.keyPoints !== undefined) {
|
||||
return t("editor.itemCount", { count: data.keyPoints.length });
|
||||
}
|
||||
if (data.teachingPoints !== undefined) {
|
||||
return t("editor.pointCount", { count: data.teachingPoints.length });
|
||||
}
|
||||
if (data.summaryPoints !== undefined) {
|
||||
return t("editor.itemCount", { count: data.summaryPoints.length });
|
||||
}
|
||||
if (data.assignments !== undefined) {
|
||||
return t("editor.assignmentCount", { count: data.assignments.length });
|
||||
}
|
||||
if (data.reflection !== undefined) {
|
||||
return t("editor.itemCount", { count: data.reflection.length });
|
||||
}
|
||||
if (data.durationMin !== undefined) {
|
||||
return t("editor.durationMin", { count: data.durationMin });
|
||||
}
|
||||
if (data.annotations !== undefined && data.sourceText !== undefined) {
|
||||
return t("editor.charCount", { count: data.sourceText.length });
|
||||
}
|
||||
if (data.sourceText !== undefined && data.sourceText) {
|
||||
return t("editor.charCount", { count: data.sourceText.length });
|
||||
}
|
||||
if (data.content !== undefined && data.content) {
|
||||
const text = data.content.replace(/<[^>]+>/g, "").trim();
|
||||
return text.slice(0, 40) || t("editor.nodeSummaryEmpty");
|
||||
}
|
||||
if (data.html) {
|
||||
// 去标签后取前 40 字
|
||||
const text = data.html.replace(/<[^>]+>/g, "").trim();
|
||||
@@ -35,6 +97,17 @@ export function getNodeSummary(node: LessonPlanNode, t: NodeSummaryT): string {
|
||||
return t("editor.nodeSummaryEmpty");
|
||||
}
|
||||
|
||||
/**
|
||||
* 纯函数:获取正文节点摘要。
|
||||
*/
|
||||
export function getTextbookContentSummary(
|
||||
node: TextbookContentNode,
|
||||
t: NodeSummaryT,
|
||||
): string {
|
||||
if (!node.data.content) return t("editor.nodeSummaryEmpty");
|
||||
return t("editor.charCount", { count: node.data.content.length });
|
||||
}
|
||||
|
||||
/**
|
||||
* 节点类型 → 图标颜色(Material Design 色板)。
|
||||
* 供 lesson-node 和 minimap 复用。
|
||||
@@ -52,6 +125,7 @@ export const NODE_COLORS: Record<string, string> = {
|
||||
exercise: "#e91e63",
|
||||
rich_text: "#9e9e9e",
|
||||
reflection: "#cddc39",
|
||||
textbook_content: "#455a64",
|
||||
};
|
||||
|
||||
export function getNodeColor(type: string): string {
|
||||
|
||||
Reference in New Issue
Block a user