Files
NextEdu/src/modules/lesson-preparation/components/blocks/objective-block.tsx
SpecialX 2197e68069 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)
2026-06-23 17:37:19 +08:00

88 lines
2.5 KiB
TypeScript

"use client";
import { useTranslations } from "next-intl";
import { Plus, Trash2 } from "lucide-react";
import type { ObjectiveBlockData, ObjectiveItem } from "../../types";
import { Button } from "@/shared/components/ui/button";
interface Props {
data: ObjectiveBlockData;
onUpdate: (data: ObjectiveBlockData) => void;
}
const DIMENSIONS: ObjectiveItem["dimension"][] = ["knowledge", "process", "emotion"];
export function ObjectiveBlock({ data, onUpdate }: Props) {
const t = useTranslations("lessonPreparation");
function updateItem(index: number, patch: Partial<ObjectiveItem>) {
const next = data.objectives.map((it, i) =>
i === index ? { ...it, ...patch } : it,
);
onUpdate({ ...data, objectives: next });
}
function addItem() {
onUpdate({
...data,
objectives: [
...data.objectives,
{ dimension: "knowledge", text: "" },
],
});
}
function removeItem(index: number) {
onUpdate({
...data,
objectives: data.objectives.filter((_, i) => i !== index),
});
}
return (
<div className="space-y-2">
<div className="text-xs text-on-surface-variant">
{t("objective.hint")}
</div>
{data.objectives.map((item, idx) => (
<div key={idx} className="flex items-start gap-2">
<select
value={item.dimension}
onChange={(e) =>
updateItem(idx, {
dimension: e.target.value as ObjectiveItem["dimension"],
})
}
className="text-xs border border-outline-variant rounded px-1 py-1 bg-surface"
>
{DIMENSIONS.map((d) => (
<option key={d} value={d}>
{t(`objective.dimension.${d}`)}
</option>
))}
</select>
<textarea
value={item.text}
onChange={(e) => updateItem(idx, { text: e.target.value })}
className="flex-1 text-sm border border-outline-variant rounded px-2 py-1 resize-y min-h-[40px]"
placeholder={t("objective.textPlaceholder")}
/>
<Button
variant="ghost"
size="sm"
className="!p-1 text-error"
onClick={() => removeItem(idx)}
aria-label={t("action.delete")}
>
<Trash2 className="w-3 h-3" />
</Button>
</div>
))}
<Button variant="outline" size="sm" onClick={addItem}>
<Plus className="w-3 h-3 mr-1" />
{t("objective.addItem")}
</Button>
</div>
);
}