asdf98 commited on
Commit
92f47c3
·
verified ·
1 Parent(s): 9d34bb7

feat: add showMinimap setting default off

Browse files
Files changed (1) hide show
  1. src/store.tsx +11 -20
src/store.tsx CHANGED
@@ -24,6 +24,7 @@ interface AppState {
24
  annotationSize: number; setAnnotationSize: React.Dispatch<React.SetStateAction<number>>;
25
  isEraser: boolean; setIsEraser: React.Dispatch<React.SetStateAction<boolean>>;
26
  isHighlighter: boolean; setIsHighlighter: React.Dispatch<React.SetStateAction<boolean>>;
 
27
  undo: () => void; redo: () => void;
28
  currentScreen: 'hub' | 'board'; setCurrentScreen: React.Dispatch<React.SetStateAction<'hub' | 'board'>>;
29
  updateSelectedNodes: (dx: number, dy: number, explicitTargetId: string) => void;
@@ -60,6 +61,7 @@ export const AppProvider = ({ children }: { children: ReactNode }) => {
60
  const [annotationSize, setAnnotationSize] = useState(4);
61
  const [isEraser, setIsEraser] = useState(false);
62
  const [isHighlighter, setIsHighlighter] = useState(false);
 
63
  const [history, setHistory] = useState<any[]>([]);
64
  const [historyIndex, setHistoryIndex] = useState(-1);
65
  const [isUndoing, setIsUndoing] = useState(false);
@@ -76,7 +78,12 @@ export const AppProvider = ({ children }: { children: ReactNode }) => {
76
  useEffect(() => { panRef.current = pan; }, [pan]);
77
  useEffect(() => { zoomRef.current = zoom; }, [zoom]);
78
 
79
- // Register exactly once. Use refs for current pan/zoom to avoid duplicate listeners.
 
 
 
 
 
80
  useEffect(() => {
81
  const un = listen<any>('board://image_added', (event) => {
82
  const p = event.payload || {};
@@ -93,24 +100,8 @@ export const AppProvider = ({ children }: { children: ReactNode }) => {
93
  const currentPan = panRef.current;
94
  const currentZoom = zoomRef.current;
95
  setImages(prev => {
96
- if (prev.some(img =>
97
- (captureId && img.captureId === captureId) ||
98
- normalizeUrl(img.url) === dataUrl ||
99
- normalizeUrl(img.url) === originalUrl ||
100
- (sourceUrl && normalizeUrl(img.sourceUrl) === sourceUrl) ||
101
- normalizeUrl(img.sourceUrl) === originalUrl
102
- )) return prev;
103
- return [...prev, {
104
- id: crypto.randomUUID(),
105
- captureId,
106
- url: dataUrl,
107
- sourceUrl: sourceUrl || originalUrl,
108
- x: (-currentPan.x + window.innerWidth / 2 - targetW / 2) / currentZoom,
109
- y: (-currentPan.y + window.innerHeight / 2 - targetH / 2) / currentZoom,
110
- width: Math.round(targetW),
111
- height: Math.round(targetH),
112
- aspectRatio: ratio,
113
- }];
114
  });
115
  setCurrentScreen('board');
116
  });
@@ -126,7 +117,7 @@ export const AppProvider = ({ children }: { children: ReactNode }) => {
126
  const redo = useCallback(() => { if (historyIndex < history.length - 1) { setIsUndoing(true); const s = history[historyIndex + 1]; setTextNotes(s.textNotes); setImages(s.images); setAnnotations(s.annotations); setPalettes(s.palettes); setZoom(s.zoom); setPan(s.pan); if (s.valueMirrorIds) setValueMirrorIds(s.valueMirrorIds); setHistoryIndex(historyIndex + 1); } }, [history, historyIndex]);
127
  const updateSelectedNodes = useCallback((dx: number, dy: number, explicitTargetId: string) => { const ids = new Set([...selectedNodeIds, explicitTargetId]); setImages(prev => { const gids = new Set<string>(); prev.forEach(i => { if (ids.has(i.id) && i.groupId) gids.add(i.groupId); }); return prev.map(i => (ids.has(i.id) || (i.groupId && gids.has(i.groupId))) ? { ...i, x: i.x + dx, y: i.y + dy } : i); }); setTextNotes(prev => { const gids = new Set<string>(); prev.forEach(i => { if (ids.has(i.id) && i.groupId) gids.add(i.groupId); }); return prev.map(i => (ids.has(i.id) || (i.groupId && gids.has(i.groupId))) ? { ...i, x: i.x + dx, y: i.y + dy } : i); }); }, [selectedNodeIds]);
128
 
129
- return <AppContext.Provider value={{ textNotes, setTextNotes, images, setImages, annotations, setAnnotations, palettes, setPalettes, zoom, setZoom, pan, setPan, isSettingsOpen, setIsSettingsOpen, isBrowserOpen, setIsBrowserOpen, isLibraryOpen, setIsLibraryOpen, selectedNodeIds, setSelectedNodeIds, globalDesaturate, setGlobalDesaturate, contextMenu, setContextMenu, isAlwaysOnTop, setIsAlwaysOnTop, bgOpacity, setBgOpacity, isClickThrough, setIsClickThrough, isAnnotationMode, setIsAnnotationMode, annotationColor, setAnnotationColor, annotationSize, setAnnotationSize, isEraser, setIsEraser, isHighlighter, setIsHighlighter, undo, redo, currentScreen, setCurrentScreen, updateSelectedNodes, focusedImageId, setFocusedImageId, valueMirrorIds, setValueMirrorIds, isZoomLensActive, setIsZoomLensActive, isWhisperBrowser, setIsWhisperBrowser, activeProjectId, setActiveProjectId, boardTitle, setBoardTitle }}>{children}</AppContext.Provider>;
130
  };
131
 
132
  export const useAppStore = () => { const ctx = useContext(AppContext); if (!ctx) throw new Error('useAppStore must be used within AppProvider'); return ctx; };
 
24
  annotationSize: number; setAnnotationSize: React.Dispatch<React.SetStateAction<number>>;
25
  isEraser: boolean; setIsEraser: React.Dispatch<React.SetStateAction<boolean>>;
26
  isHighlighter: boolean; setIsHighlighter: React.Dispatch<React.SetStateAction<boolean>>;
27
+ showMinimap: boolean; setShowMinimap: React.Dispatch<React.SetStateAction<boolean>>;
28
  undo: () => void; redo: () => void;
29
  currentScreen: 'hub' | 'board'; setCurrentScreen: React.Dispatch<React.SetStateAction<'hub' | 'board'>>;
30
  updateSelectedNodes: (dx: number, dy: number, explicitTargetId: string) => void;
 
61
  const [annotationSize, setAnnotationSize] = useState(4);
62
  const [isEraser, setIsEraser] = useState(false);
63
  const [isHighlighter, setIsHighlighter] = useState(false);
64
+ const [showMinimap, setShowMinimap] = useState(false);
65
  const [history, setHistory] = useState<any[]>([]);
66
  const [historyIndex, setHistoryIndex] = useState(-1);
67
  const [isUndoing, setIsUndoing] = useState(false);
 
78
  useEffect(() => { panRef.current = pan; }, [pan]);
79
  useEffect(() => { zoomRef.current = zoom; }, [zoom]);
80
 
81
+ useEffect(() => {
82
+ const saved = localStorage.getItem('refstudio.showMinimap');
83
+ if (saved === 'true') setShowMinimap(true);
84
+ }, []);
85
+ useEffect(() => { localStorage.setItem('refstudio.showMinimap', String(showMinimap)); }, [showMinimap]);
86
+
87
  useEffect(() => {
88
  const un = listen<any>('board://image_added', (event) => {
89
  const p = event.payload || {};
 
100
  const currentPan = panRef.current;
101
  const currentZoom = zoomRef.current;
102
  setImages(prev => {
103
+ if (prev.some(img => (captureId && img.captureId === captureId) || normalizeUrl(img.url) === dataUrl || normalizeUrl(img.url) === originalUrl || (sourceUrl && normalizeUrl(img.sourceUrl) === sourceUrl) || normalizeUrl(img.sourceUrl) === originalUrl)) return prev;
104
+ return [...prev, { id: crypto.randomUUID(), captureId, url: dataUrl, sourceUrl: sourceUrl || originalUrl, x: (-currentPan.x + window.innerWidth / 2 - targetW / 2) / currentZoom, y: (-currentPan.y + window.innerHeight / 2 - targetH / 2) / currentZoom, width: Math.round(targetW), height: Math.round(targetH), aspectRatio: ratio }];
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
105
  });
106
  setCurrentScreen('board');
107
  });
 
117
  const redo = useCallback(() => { if (historyIndex < history.length - 1) { setIsUndoing(true); const s = history[historyIndex + 1]; setTextNotes(s.textNotes); setImages(s.images); setAnnotations(s.annotations); setPalettes(s.palettes); setZoom(s.zoom); setPan(s.pan); if (s.valueMirrorIds) setValueMirrorIds(s.valueMirrorIds); setHistoryIndex(historyIndex + 1); } }, [history, historyIndex]);
118
  const updateSelectedNodes = useCallback((dx: number, dy: number, explicitTargetId: string) => { const ids = new Set([...selectedNodeIds, explicitTargetId]); setImages(prev => { const gids = new Set<string>(); prev.forEach(i => { if (ids.has(i.id) && i.groupId) gids.add(i.groupId); }); return prev.map(i => (ids.has(i.id) || (i.groupId && gids.has(i.groupId))) ? { ...i, x: i.x + dx, y: i.y + dy } : i); }); setTextNotes(prev => { const gids = new Set<string>(); prev.forEach(i => { if (ids.has(i.id) && i.groupId) gids.add(i.groupId); }); return prev.map(i => (ids.has(i.id) || (i.groupId && gids.has(i.groupId))) ? { ...i, x: i.x + dx, y: i.y + dy } : i); }); }, [selectedNodeIds]);
119
 
120
+ return <AppContext.Provider value={{ textNotes, setTextNotes, images, setImages, annotations, setAnnotations, palettes, setPalettes, zoom, setZoom, pan, setPan, isSettingsOpen, setIsSettingsOpen, isBrowserOpen, setIsBrowserOpen, isLibraryOpen, setIsLibraryOpen, selectedNodeIds, setSelectedNodeIds, globalDesaturate, setGlobalDesaturate, contextMenu, setContextMenu, isAlwaysOnTop, setIsAlwaysOnTop, bgOpacity, setBgOpacity, isClickThrough, setIsClickThrough, isAnnotationMode, setIsAnnotationMode, annotationColor, setAnnotationColor, annotationSize, setAnnotationSize, isEraser, setIsEraser, isHighlighter, setIsHighlighter, showMinimap, setShowMinimap, undo, redo, currentScreen, setCurrentScreen, updateSelectedNodes, focusedImageId, setFocusedImageId, valueMirrorIds, setValueMirrorIds, isZoomLensActive, setIsZoomLensActive, isWhisperBrowser, setIsWhisperBrowser, activeProjectId, setActiveProjectId, boardTitle, setBoardTitle }}>{children}</AppContext.Provider>;
121
  };
122
 
123
  export const useAppStore = () => { const ctx = useContext(AppContext); if (!ctx) throw new Error('useAppStore must be used within AppProvider'); return ctx; };