feat: add showMinimap setting default off
Browse files- 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 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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 |
-
|
| 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; };
|