draw path | draw area | localstorage layer state | add entities property parallel | timeline bar

This commit is contained in:
taDuc
2026-04-08 20:03:16 +07:00
parent 5ac5c4c0af
commit 4969c8cc57
15 changed files with 2056 additions and 74 deletions

View File

@@ -2,11 +2,20 @@
import { UndoAction } from "@/lib/useEditorState";
type Mode = "draw" | "select" | "idle" | "add-point";
type Mode = "draw" | "select" | "idle" | "add-point" | "add-path" | "add-circle";
type EntityOption = {
id: string;
name: string;
geometry_count?: number;
};
type Props = {
mode: Mode;
setMode: (mode: Mode) => void;
entities: EntityOption[];
selectedEntityId: string | null;
onSelectEntityId: (entityId: string | null) => void;
entityStatus?: string | null;
onUndo: () => void;
onSave: () => void;
isSaving: boolean;
@@ -17,6 +26,10 @@ type Props = {
export default function Editor({
mode,
setMode,
entities,
selectedEntityId,
onSelectEntityId,
entityStatus,
onUndo,
onSave,
isSaving,
@@ -95,9 +108,76 @@ export default function Editor({
Add point
</button>
<button
style={getButtonStyle("add-path")}
onClick={() => setMode("add-path")}
>
Add path
</button>
<button
style={getButtonStyle("add-circle")}
onClick={() => setMode("add-circle")}
>
Add circle
</button>
<div style={{ marginTop: "12px", fontSize: "14px" }}>
Mode: <b>{mode}</b>
</div>
{mode === "add-path" ? (
<div style={{ marginTop: "6px", fontSize: "12px", color: "#93c5fd" }}>
Click đ thêm điểm, Enter đ hoàn tất, Esc đ hủy.
</div>
) : null}
{mode === "add-circle" ? (
<div style={{ marginTop: "6px", fontSize: "12px", color: "#93c5fd" }}>
Giữ chuột trái kéo đ mở bán kính, thả chuột đ hoàn tất.
</div>
) : null}
<div
style={{
marginTop: "12px",
padding: "10px",
background: "#0b1220",
borderRadius: "6px",
border: "1px solid #1f2937",
}}
>
<div style={{ marginBottom: "6px", fontWeight: 600, fontSize: "13px", color: "#e2e8f0" }}>
Entity mặc đnh cho geometry mới
</div>
<select
value={selectedEntityId || ""}
onChange={(event) => onSelectEntityId(event.target.value || null)}
style={{
width: "100%",
padding: "6px 8px",
borderRadius: "4px",
border: "1px solid #334155",
background: "#111827",
color: "#f8fafc",
fontSize: "13px",
}}
>
<option value="">Không gắn entity</option>
{entities.map((entity) => (
<option key={entity.id} value={entity.id}>
{entity.name}
{typeof entity.geometry_count === "number" ? ` (${entity.geometry_count})` : ""}
</option>
))}
</select>
<div style={{ marginTop: "6px", color: "#94a3b8", fontSize: "12px" }}>
Geometry mới tạo sẽ gắn sẵn entity này, bạn thể thêm nhiều entity panel bên phải.
</div>
{entityStatus ? (
<div style={{ marginTop: "6px", color: "#fca5a5", fontSize: "12px" }}>
{entityStatus}
</div>
) : null}
</div>
<div style={{ marginTop: "12px", display: "flex", gap: "8px" }}>
<button