Skip to content

Commit 5317a94

Browse files
committed
remove saved
1 parent 64657ef commit 5317a94

2 files changed

Lines changed: 74 additions & 68 deletions

File tree

packages/learningmap/src/LearningMapEditor.tsx

Lines changed: 6 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -68,12 +68,11 @@ export function LearningMapEditor({
6868

6969
const parsedRoadmap = parseRoadmapData(roadmapData || "");
7070
const { screenToFlowPosition, zoomIn, zoomOut, setCenter, fitView } = useReactFlow();
71-
71+
7272
// Only get minimal state needed in this component
7373
const nodes = useEditorStore(state => state.nodes);
7474
const edges = useEditorStore(state => state.edges);
7575
const settings = useEditorStore(state => state.settings);
76-
const saved = useEditorStore(state => state.saved);
7776
const previewMode = useEditorStore(state => state.previewMode);
7877
const debugMode = useEditorStore(state => state.debugMode);
7978
const showGrid = useEditorStore(state => state.showGrid);
@@ -88,12 +87,11 @@ export function LearningMapEditor({
8887
const nextNodeId = useEditorStore(state => state.nextNodeId);
8988
const clipboard = useEditorStore(state => state.clipboard);
9089
const pendingExternalId = useEditorStore(state => state.pendingExternalId);
91-
90+
9291
// Store actions
9392
const onNodesChange = useEditorStore(state => state.onNodesChange);
9493
const onEdgesChange = useEditorStore(state => state.onEdgesChange);
9594
const onConnect = useEditorStore(state => state.onConnect);
96-
const setSaved = useEditorStore(state => state.setSaved);
9795
const setHelpOpen = useEditorStore(state => state.setHelpOpen);
9896
const setShowGrid = useEditorStore(state => state.setShowGrid);
9997
const setSelectedNodeId = useEditorStore(state => state.setSelectedNodeId);
@@ -123,7 +121,7 @@ export function LearningMapEditor({
123121
const setNodes = useEditorStore(state => state.setNodes);
124122
const setEdges = useEditorStore(state => state.setEdges);
125123
const setSettings = useEditorStore(state => state.setSettings);
126-
124+
127125
// Temporal store for undo/redo
128126
const { undo, redo, canUndo, canRedo } = useTemporalStore();
129127

@@ -166,7 +164,7 @@ export function LearningMapEditor({
166164
// Filter out existing debug edges, but use the store's edges directly to avoid dependency loop
167165
const baseEdges = useEditorStore.getState().edges.filter((e) => !e.id.startsWith("debug-"));
168166
const newEdges: Edge[] = [...baseEdges];
169-
167+
170168
if (debugMode) {
171169
nodes.forEach((node) => {
172170
if (showCompletionNeeds && node.type === "topic" && node.data?.completion?.needs) {
@@ -331,7 +329,6 @@ export function LearningMapEditor({
331329

332330
const handleSave = useCallback(() => {
333331
const roadmapData = getRoadmapData();
334-
setSaved(true);
335332

336333
if (onChange) {
337334
onChange(roadmapData);
@@ -342,16 +339,7 @@ export function LearningMapEditor({
342339
root.dispatchEvent(new CustomEvent("change", { detail: roadmapData }));
343340
}
344341
}
345-
}, [nodes, edges, settings, onChange, getRoadmapData, setSaved]);
346-
347-
// Auto-save when changes are made
348-
useEffect(() => {
349-
if (!saved) {
350-
setTimeout(() => {
351-
handleSave();
352-
}, 2000);
353-
}
354-
}, [saved, handleSave]);
342+
}, [nodes, edges, settings, onChange, getRoadmapData]);
355343

356344
const togglePreviewMode = useCallback(() => {
357345
handleSave();
@@ -380,7 +368,7 @@ export function LearningMapEditor({
380368

381369
const handleShare = useCallback(() => {
382370
const roadmapData = getRoadmapData();
383-
371+
384372
// Check if map is empty (no nodes)
385373
if (!roadmapData.nodes || roadmapData.nodes.length === 0) {
386374
alert(t.emptyMapCannotBeShared);
@@ -806,9 +794,6 @@ export function LearningMapEditor({
806794
<Info />
807795
</ControlButton>
808796
</Controls>
809-
{!saved && <Panel position="bottom-right" title={t.unsavedChanges} onClick={() => { handleSave(); }}>
810-
<ShieldAlert size={32} color="var(--learningmap-color-coal)" />
811-
</Panel>}
812797
{selectedNodeIds.length > 1 && <MultiNodePanel onUpdate={handleUpdateNodes} />}
813798
</ReactFlow>
814799
</div>

packages/learningmap/src/editorStore.ts

Lines changed: 68 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,22 @@
1-
import { create } from 'zustand';
2-
import { temporal } from 'zundo';
3-
import { Node, Edge, applyNodeChanges, applyEdgeChanges, addEdge, NodeChange, EdgeChange, Connection } from '@xyflow/react';
4-
import { NodeData, RoadmapData, Settings, ImageNodeData, TextNodeData } from './types';
1+
import { create } from "zustand";
2+
import { temporal } from "zundo";
3+
import {
4+
Node,
5+
Edge,
6+
applyNodeChanges,
7+
applyEdgeChanges,
8+
addEdge,
9+
NodeChange,
10+
EdgeChange,
11+
Connection,
12+
} from "@xyflow/react";
13+
import {
14+
NodeData,
15+
RoadmapData,
16+
Settings,
17+
ImageNodeData,
18+
TextNodeData,
19+
} from "./types";
520

621
// Note: This is a global store for the editor. Typically only one editor instance is active at a time.
722
// If you need multiple independent editor instances, consider creating store instances per component or using context.
@@ -10,9 +25,8 @@ export interface EditorState {
1025
nodes: Node<NodeData>[];
1126
edges: Edge[];
1227
settings: Settings;
13-
28+
1429
// UI state
15-
saved: boolean;
1630
previewMode: boolean;
1731
debugMode: boolean;
1832
showGrid: boolean;
@@ -22,24 +36,24 @@ export interface EditorState {
2236
edgeDrawerOpen: boolean;
2337
shareDialogOpen: boolean;
2438
loadExternalDialogOpen: boolean;
25-
39+
2640
// Selected items
2741
selectedNodeId: string | null;
2842
selectedNodeIds: string[];
2943
selectedEdge: Edge | null;
30-
44+
3145
// Other state
3246
nextNodeId: number;
3347
clipboard: { nodes: Node<NodeData>[]; edges: Edge[] } | null;
3448
lastMousePosition: { x: number; y: number } | null;
3549
shareLink: string;
3650
pendingExternalId: string | null;
37-
51+
3852
// Debug settings
3953
showCompletionNeeds: boolean;
4054
showCompletionOptional: boolean;
4155
showUnlockAfter: boolean;
42-
56+
4357
// Actions
4458
onNodesChange: (changes: NodeChange<Node<NodeData>>[]) => void;
4559
onEdgesChange: (changes: EdgeChange<Edge>[]) => void;
@@ -54,9 +68,8 @@ export interface EditorState {
5468
deleteNode: (nodeId: string) => void;
5569
deleteEdge: (edgeId: string) => void;
5670
addNode: (node: Node<NodeData>) => void;
57-
71+
5872
// UI state setters
59-
setSaved: (saved: boolean) => void;
6073
setPreviewMode: (previewMode: boolean) => void;
6174
setDebugMode: (debugMode: boolean) => void;
6275
setShowGrid: (showGrid: boolean) => void;
@@ -70,14 +83,16 @@ export interface EditorState {
7083
setSelectedNodeIds: (nodeIds: string[]) => void;
7184
setSelectedEdge: (edge: Edge | null) => void;
7285
setNextNodeId: (nextNodeId: number) => void;
73-
setClipboard: (clipboard: { nodes: Node<NodeData>[]; edges: Edge[] } | null) => void;
86+
setClipboard: (
87+
clipboard: { nodes: Node<NodeData>[]; edges: Edge[] } | null,
88+
) => void;
7489
setLastMousePosition: (position: { x: number; y: number } | null) => void;
7590
setShareLink: (shareLink: string) => void;
7691
setPendingExternalId: (pendingExternalId: string | null) => void;
7792
setShowCompletionNeeds: (showCompletionNeeds: boolean) => void;
7893
setShowCompletionOptional: (showCompletionOptional: boolean) => void;
7994
setShowUnlockAfter: (showUnlockAfter: boolean) => void;
80-
95+
8196
// Bulk operations
8297
loadRoadmapData: (roadmapData: RoadmapData) => void;
8398
getRoadmapData: () => RoadmapData;
@@ -89,7 +104,6 @@ const initialState = {
89104
nodes: [],
90105
edges: [],
91106
settings: { background: { color: "#ffffff" } },
92-
saved: true,
93107
previewMode: false,
94108
debugMode: false,
95109
showGrid: false,
@@ -121,52 +135,47 @@ export const useEditorStore = create<EditorState>()(
121135
onNodesChange: (changes) => {
122136
set({
123137
nodes: applyNodeChanges(changes, get().nodes),
124-
saved: false,
125138
});
126139
},
127140

128141
onEdgesChange: (changes) => {
129142
set({
130143
edges: applyEdgeChanges(changes, get().edges),
131-
saved: false,
132144
});
133145
},
134146

135147
onConnect: (connection) => {
136148
set({
137149
edges: addEdge(connection, get().edges),
138-
saved: false,
139150
});
140151
},
141152

142153
// Node operations
143154
setNodes: (nodes) => {
144-
set({ nodes, saved: false });
155+
set({ nodes });
145156
},
146157

147158
setEdges: (edges) => {
148-
set({ edges, saved: false });
159+
set({ edges });
149160
},
150161

151162
setSettings: (settings) => {
152-
set({ settings, saved: false });
163+
set({ settings });
153164
},
154165

155166
updateNode: (nodeId, updates) => {
156167
set({
157168
nodes: get().nodes.map((n) =>
158-
n.id === nodeId ? { ...n, ...updates } : n
169+
n.id === nodeId ? { ...n, ...updates } : n,
159170
),
160-
saved: false,
161171
});
162172
},
163173

164174
updateNodeData: (nodeId, dataUpdates) => {
165175
set({
166176
nodes: get().nodes.map((n) =>
167-
n.id === nodeId ? { ...n, data: { ...n.data, ...dataUpdates } } : n
177+
n.id === nodeId ? { ...n, data: { ...n.data, ...dataUpdates } } : n,
168178
),
169-
saved: false,
170179
});
171180
},
172181

@@ -176,16 +185,14 @@ export const useEditorStore = create<EditorState>()(
176185
const updated = updates.find((un) => un.id === n.id);
177186
return updated ? updated : n;
178187
}),
179-
saved: false,
180188
});
181189
},
182190

183191
updateEdge: (edgeId, updates) => {
184192
set({
185193
edges: get().edges.map((e) =>
186-
e.id === edgeId ? { ...e, ...updates } : e
194+
e.id === edgeId ? { ...e, ...updates } : e,
187195
),
188-
saved: false,
189196
});
190197
// Update selected edge if it's the one being updated
191198
const selectedEdge = get().selectedEdge;
@@ -197,36 +204,36 @@ export const useEditorStore = create<EditorState>()(
197204
deleteNode: (nodeId) => {
198205
set({
199206
nodes: get().nodes.filter((n) => n.id !== nodeId),
200-
edges: get().edges.filter((e) => e.source !== nodeId && e.target !== nodeId),
201-
saved: false,
207+
edges: get().edges.filter(
208+
(e) => e.source !== nodeId && e.target !== nodeId,
209+
),
202210
});
203211
},
204212

205213
deleteEdge: (edgeId) => {
206214
set({
207215
edges: get().edges.filter((e) => e.id !== edgeId),
208-
saved: false,
209216
});
210217
},
211218

212219
addNode: (node) => {
213220
set({
214221
nodes: [...get().nodes, node],
215-
saved: false,
216222
});
217223
},
218224

219225
// UI state setters
220-
setSaved: (saved) => set({ saved }),
221226
setPreviewMode: (previewMode) => set({ previewMode }),
222227
setDebugMode: (debugMode) => set({ debugMode }),
223228
setShowGrid: (showGrid) => set({ showGrid }),
224229
setHelpOpen: (helpOpen) => set({ helpOpen }),
225230
setDrawerOpen: (drawerOpen) => set({ drawerOpen }),
226-
setSettingsDrawerOpen: (settingsDrawerOpen) => set({ settingsDrawerOpen }),
231+
setSettingsDrawerOpen: (settingsDrawerOpen) =>
232+
set({ settingsDrawerOpen }),
227233
setEdgeDrawerOpen: (edgeDrawerOpen) => set({ edgeDrawerOpen }),
228234
setShareDialogOpen: (shareDialogOpen) => set({ shareDialogOpen }),
229-
setLoadExternalDialogOpen: (loadExternalDialogOpen) => set({ loadExternalDialogOpen }),
235+
setLoadExternalDialogOpen: (loadExternalDialogOpen) =>
236+
set({ loadExternalDialogOpen }),
230237
setSelectedNodeId: (selectedNodeId) => set({ selectedNodeId }),
231238
setSelectedNodeIds: (selectedNodeIds) => set({ selectedNodeIds }),
232239
setSelectedEdge: (selectedEdge) => set({ selectedEdge }),
@@ -235,14 +242,20 @@ export const useEditorStore = create<EditorState>()(
235242
setLastMousePosition: (lastMousePosition) => set({ lastMousePosition }),
236243
setShareLink: (shareLink) => set({ shareLink }),
237244
setPendingExternalId: (pendingExternalId) => set({ pendingExternalId }),
238-
setShowCompletionNeeds: (showCompletionNeeds) => set({ showCompletionNeeds }),
239-
setShowCompletionOptional: (showCompletionOptional) => set({ showCompletionOptional }),
245+
setShowCompletionNeeds: (showCompletionNeeds) =>
246+
set({ showCompletionNeeds }),
247+
setShowCompletionOptional: (showCompletionOptional) =>
248+
set({ showCompletionOptional }),
240249
setShowUnlockAfter: (showUnlockAfter) => set({ showUnlockAfter }),
241250

242251
// Bulk operations
243252
loadRoadmapData: (roadmapData) => {
244-
const nodesArr = Array.isArray(roadmapData?.nodes) ? roadmapData.nodes : [];
245-
const edgesArr = Array.isArray(roadmapData?.edges) ? roadmapData.edges : [];
253+
const nodesArr = Array.isArray(roadmapData?.nodes)
254+
? roadmapData.nodes
255+
: [];
256+
const edgesArr = Array.isArray(roadmapData?.edges)
257+
? roadmapData.edges
258+
: [];
246259

247260
const rawNodes = nodesArr.map((n) => ({
248261
...n,
@@ -257,15 +270,17 @@ export const useEditorStore = create<EditorState>()(
257270
const maxId = Math.max(
258271
...nodesArr
259272
.map((n) => parseInt(n.id.replace(/\D/g, ""), 10))
260-
.filter((id) => !isNaN(id))
273+
.filter((id) => !isNaN(id)),
261274
);
262275
nextNodeId = maxId + 1;
263276
}
264277

265278
set({
266279
nodes: rawNodes,
267280
edges: edgesArr,
268-
settings: roadmapData?.settings || { background: { color: "#ffffff" } },
281+
settings: roadmapData?.settings || {
282+
background: { color: "#ffffff" },
283+
},
269284
nextNodeId,
270285
});
271286
},
@@ -317,19 +332,25 @@ export const useEditorStore = create<EditorState>()(
317332
// Zundo options
318333
limit: 100,
319334
equality: (a, b) => a === b,
320-
}
321-
)
335+
},
336+
),
322337
);
323338

324339
// Hook for accessing temporal store (undo/redo)
325-
import { useStore } from 'zustand';
340+
import { useStore } from "zustand";
326341

327342
export const useTemporalStore = () => {
328343
const undo = useEditorStore.temporal.getState().undo;
329344
const redo = useEditorStore.temporal.getState().redo;
330-
const pastStates = useStore(useEditorStore.temporal, (state) => state.pastStates);
331-
const futureStates = useStore(useEditorStore.temporal, (state) => state.futureStates);
332-
345+
const pastStates = useStore(
346+
useEditorStore.temporal,
347+
(state) => state.pastStates,
348+
);
349+
const futureStates = useStore(
350+
useEditorStore.temporal,
351+
(state) => state.futureStates,
352+
);
353+
333354
return {
334355
undo,
335356
redo,

0 commit comments

Comments
 (0)