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:
SpecialX
2026-06-23 17:37:19 +08:00
parent 1fcef5c3aa
commit 2197e68069
34 changed files with 3190 additions and 402 deletions

View File

@@ -32,25 +32,37 @@ export function LessonPlanCard({ plan }: { plan: LessonPlanListItem }) {
const service = ctx?.service ?? null;
async function handleArchive() {
const res = service
? await service.deleteLessonPlan(plan.id)
: await deleteLessonPlanAction(plan.id);
if (res.success) {
tracker.track("lesson_plan.archive", { planId: plan.id });
toast.success(t("status.archived"));
router.refresh();
} else {
toast.error(res.message ?? t("error.delete"));
try {
const res = service
? await service.deleteLessonPlan(plan.id)
: await deleteLessonPlanAction(plan.id);
if (res.success) {
tracker.track("lesson_plan.archive", { planId: plan.id });
toast.success(t("status.archived"));
router.refresh();
} else {
toast.error(res.message ?? t("error.delete"));
}
} catch (e) {
console.error("[LessonPlanCard] archive failed", e);
toast.error(t("error.delete"));
}
}
async function handleDuplicate() {
const res = service
? await service.duplicateLessonPlan(plan.id)
: await duplicateLessonPlanAction(plan.id);
if (res.success) {
tracker.track("lesson_plan.duplicate", { planId: plan.id });
router.refresh();
try {
const res = service
? await service.duplicateLessonPlan(plan.id)
: await duplicateLessonPlanAction(plan.id);
if (res.success) {
tracker.track("lesson_plan.duplicate", { planId: plan.id });
router.refresh();
} else {
toast.error(res.message ?? t("error.duplicate"));
}
} catch (e) {
console.error("[LessonPlanCard] duplicate failed", e);
toast.error(t("error.duplicate"));
}
}