Przeglądaj źródła

replace useConfig with useGraph

AykutSarac 2 lat temu
rodzic
commit
20bcdfef10

+ 2 - 2
src/components/CustomNode/ObjectNode.tsx

@@ -1,7 +1,7 @@
 import React from "react";
 // import { useInViewport } from "react-in-viewport";
 import { CustomNodeProps } from "src/components/CustomNode";
-import useConfig from "src/store/useConfig";
+import useGraph from "src/store/useGraph";
 import * as Styled from "./styles";
 
 const inViewport = true;
@@ -9,7 +9,7 @@ const inViewport = true;
 const ObjectNode: React.FC<CustomNodeProps> = ({ node, x, y }) => {
   const { text, width, height, data } = node;
   const ref = React.useRef(null);
-  const performanceMode = useConfig(state => state.performanceMode);
+  const performanceMode = useGraph(state => state.performanceMode);
   // const { inViewport } = useInViewport(ref);
 
   if (data.isEmpty) return null;

+ 1 - 2
src/components/CustomNode/TextNode.tsx

@@ -2,7 +2,6 @@ import React from "react";
 import { MdLink, MdLinkOff } from "react-icons/md";
 // import { useInViewport } from "react-in-viewport";
 import { CustomNodeProps } from "src/components/CustomNode";
-import useConfig from "src/store/useConfig";
 import useGraph from "src/store/useGraph";
 import useStored from "src/store/useStored";
 import styled from "styled-components";
@@ -48,7 +47,7 @@ const TextNode: React.FC<CustomNodeProps> = ({
   const expandNodes = useGraph(state => state.expandNodes);
   const collapseNodes = useGraph(state => state.collapseNodes);
   const isExpanded = useGraph(state => state.collapsedParents.includes(id));
-  const performanceMode = useConfig(state => state.performanceMode);
+  const performanceMode = useGraph(state => state.performanceMode);
   // const { inViewport } = useInViewport(ref);
 
   const handleExpand = (e: React.MouseEvent<HTMLButtonElement>) => {

+ 4 - 5
src/components/Graph/index.tsx

@@ -6,7 +6,6 @@ import {
 } from "react-zoom-pan-pinch";
 import { Canvas, Edge, ElkRoot } from "reaflow";
 import { CustomNode } from "src/components/CustomNode";
-import useConfig from "src/store/useConfig";
 import useGraph from "src/store/useGraph";
 import styled from "styled-components";
 import { Loading } from "../Loading";
@@ -47,8 +46,8 @@ const GraphComponent = ({
   setSelectedNode,
 }: GraphProps) => {
   const setLoading = useGraph(state => state.setLoading);
-  const setConfig = useConfig(state => state.setConfig);
-  const centerView = useConfig(state => state.centerView);
+  const setZoomPanPinch = useGraph(state => state.setZoomPanPinch);
+  const centerView = useGraph(state => state.centerView);
 
   const loading = useGraph(state => state.loading);
   const direction = useGraph(state => state.direction);
@@ -70,9 +69,9 @@ const GraphComponent = ({
 
   const onInit = React.useCallback(
     (ref: ReactZoomPanPinchRef) => {
-      setConfig("zoomPanPinch", ref);
+      setZoomPanPinch(ref);
     },
-    [setConfig]
+    [setZoomPanPinch]
   );
 
   const onLayoutChange = React.useCallback(

+ 11 - 9
src/components/Sidebar/index.tsx

@@ -19,11 +19,11 @@ import {
   VscSettingsGear,
 } from "react-icons/vsc";
 import { Tooltip } from "src/components/Tooltip";
-import useConfig from "src/store/useConfig";
 import useGraph from "src/store/useGraph";
 import useModal from "src/store/useModal";
 import { getNextDirection } from "src/utils/getNextDirection";
 import styled from "styled-components";
+import useJson from "src/store/useJson";
 
 const StyledSidebar = styled.div`
   display: flex;
@@ -140,17 +140,19 @@ function rotateLayout(direction: "LEFT" | "RIGHT" | "DOWN" | "UP") {
 
 export const Sidebar: React.FC = () => {
   const setVisible = useModal(state => state.setVisible);
-  const getJson = useGraph(state => state.getJson);
   const setDirection = useGraph(state => state.setDirection);
-  const setConfig = useConfig(state => state.setConfig);
-  const centerView = useConfig(state => state.centerView);
+  const getJson = useJson(state => state.getJson);
+  
   const collapseGraph = useGraph(state => state.collapseGraph);
   const expandGraph = useGraph(state => state.expandGraph);
+  const centerView = useGraph(state => state.centerView);
+  const toggleFold = useGraph(state => state.toggleFold);
+  const toggleFullscreen = useGraph(state => state.toggleFullscreen);
 
-  const graphCollapsed = useGraph(state => state.graphCollapsed);
   const direction = useGraph(state => state.direction);
-  const foldNodes = useConfig(state => state.foldNodes);
-  const fullscreen = useConfig(state => state.fullscreen);
+  const foldNodes = useGraph(state => state.foldNodes);
+  const fullscreen = useGraph(state => state.fullscreen);
+  const graphCollapsed = useGraph(state => state.graphCollapsed);
 
   const handleSave = () => {
     const a = document.createElement("a");
@@ -162,7 +164,7 @@ export const Sidebar: React.FC = () => {
   };
 
   const toggleFoldNodes = () => {
-    setConfig("foldNodes", !foldNodes);
+    toggleFold(!foldNodes);
     toast(`${foldNodes ? "Unfolded" : "Folded"} nodes`);
   };
 
@@ -189,7 +191,7 @@ export const Sidebar: React.FC = () => {
         </Link>
 
         <Tooltip className="mobile" title="Edit JSON">
-          <StyledElement onClick={() => setConfig("fullscreen", !fullscreen)}>
+          <StyledElement onClick={() => toggleFullscreen(!fullscreen)}>
             <AiOutlineEdit />
           </StyledElement>
         </Tooltip>

+ 5 - 5
src/containers/Editor/Panes.tsx

@@ -3,8 +3,8 @@ import dynamic from "next/dynamic";
 import { Allotment } from "allotment";
 import "allotment/dist/style.css";
 import { JsonEditor } from "src/containers/Editor/JsonEditor";
-import useConfig from "src/store/useConfig";
 import styled from "styled-components";
+import useGraph from "src/store/useGraph";
 
 export const StyledEditor = styled(Allotment)`
   position: relative !important;
@@ -17,13 +17,13 @@ const LiveEditor = dynamic(() => import("src/containers/Editor/LiveEditor"), {
 });
 
 const Panes: React.FC = () => {
-  const fullscreen = useConfig(state => state.fullscreen);
-  const setConfig = useConfig(state => state.setConfig);
+  const fullscreen = useGraph(state => state.fullscreen);
+  const toggleFullscreen = useGraph(state => state.toggleFullscreen);
   const isMobile = React.useMemo(() => window.innerWidth <= 768, []);
 
   React.useEffect(() => {
-    if (isMobile) setConfig("fullscreen", true);
-  }, [isMobile, setConfig]);
+    if (isMobile) toggleFullscreen(true);
+  }, [isMobile, toggleFullscreen]);
 
   return (
     <StyledEditor proportionalLayout={false} vertical={isMobile}>

+ 7 - 7
src/containers/Editor/Tools.tsx

@@ -3,7 +3,7 @@ import { AiOutlineFullscreen, AiOutlineMinus, AiOutlinePlus } from "react-icons/
 import { FiDownload } from "react-icons/fi";
 import { MdCenterFocusWeak } from "react-icons/md";
 import { SearchInput } from "src/components/SearchInput";
-import useConfig from "src/store/useConfig";
+import useGraph from "src/store/useGraph";
 import useModal from "src/store/useModal";
 import styled from "styled-components";
 
@@ -48,13 +48,13 @@ const StyledToolElement = styled.button`
 export const Tools: React.FC = () => {
   const setVisible = useModal(state => state.setVisible);
 
-  const fullscreen = useConfig(state => state.fullscreen);
-  const setConfig = useConfig(state => state.setConfig);
+  const fullscreen = useGraph(state => state.fullscreen);
+  const toggleFullscreen = useGraph(state => state.toggleFullscreen);
 
-  const zoomIn = useConfig(state => state.zoomIn);
-  const zoomOut = useConfig(state => state.zoomOut);
-  const centerView = useConfig(state => state.centerView);
-  const toggleEditor = () => setConfig("fullscreen", !fullscreen);
+  const zoomIn = useGraph(state => state.zoomIn);
+  const zoomOut = useGraph(state => state.zoomOut);
+  const centerView = useGraph(state => state.centerView);
+  const toggleEditor = () => toggleFullscreen(!fullscreen);
 
   return (
     <>

+ 6 - 6
src/containers/Modals/DownloadModal/index.tsx

@@ -7,8 +7,8 @@ import { FiCopy, FiDownload } from "react-icons/fi";
 import { Button } from "src/components/Button";
 import { Input } from "src/components/Input";
 import { Modal, ModalProps } from "src/components/Modal";
-import useConfig from "src/store/useConfig";
 import styled from "styled-components";
+import useGraph from "src/store/useGraph";
 
 const ColorPickerStyles: Partial<TwitterPickerStylesProps> = {
   card: {
@@ -93,7 +93,7 @@ const StyledColorIndicator = styled.div<{ color: string }>`
 `;
 
 export const DownloadModal: React.FC<ModalProps> = ({ visible, setVisible }) => {
-  const setConfig = useConfig(state => state.setConfig);
+  const togglePerfMode = useGraph(state => state.togglePerfMode);
   const [fileDetails, setFileDetails] = React.useState({
     filename: "jsoncrack.com",
     backgroundColor: "transparent",
@@ -103,7 +103,7 @@ export const DownloadModal: React.FC<ModalProps> = ({ visible, setVisible }) =>
   const clipboardImage = async () => {
     try {
       toast.loading("Copying to clipboard...", { id: "toastClipboard" });
-      setConfig("performanceMode", false);
+      togglePerfMode(false);
 
       const imageElement = document.querySelector("svg[id*='ref']") as HTMLElement;
 
@@ -126,14 +126,14 @@ export const DownloadModal: React.FC<ModalProps> = ({ visible, setVisible }) =>
     } finally {
       toast.dismiss("toastClipboard");
       setVisible(false);
-      setConfig("performanceMode", true);
+      togglePerfMode(true);
     }
   };
 
   const exportAsImage = async () => {
     try {
       toast.loading("Downloading...", { id: "toastDownload" });
-      setConfig("performanceMode", false);
+      togglePerfMode(false);
 
       const imageElement = document.querySelector("svg[id*='ref']") as HTMLElement;
 
@@ -148,7 +148,7 @@ export const DownloadModal: React.FC<ModalProps> = ({ visible, setVisible }) =>
     } finally {
       toast.dismiss("toastDownload");
       setVisible(false);
-      setConfig("performanceMode", true);
+      togglePerfMode(true);
     }
   };
 

+ 5 - 5
src/hooks/useFocusNode.tsx

@@ -1,14 +1,14 @@
 import React from "react";
+import useGraph from "src/store/useGraph";
 import {
   searchQuery,
   cleanupHighlight,
   highlightMatchedNodes,
 } from "src/utils/search";
-import useConfig from "../store/useConfig";
 
 export const useFocusNode = () => {
-  const setConfig = useConfig(state => state.setConfig);
-  const zoomPanPinch = useConfig(state => state.zoomPanPinch);
+  const togglePerfMode = useGraph(state => state.togglePerfMode);
+  const zoomPanPinch = useGraph(state => state.zoomPanPinch);
   const [selectedNode, setSelectedNode] = React.useState(0);
   const [content, setContent] = React.useState({
     value: "",
@@ -18,14 +18,14 @@ export const useFocusNode = () => {
   const skip = () => setSelectedNode(current => current + 1);
 
   React.useEffect(() => {
-    setConfig("performanceMode", !content.value.length);
+    togglePerfMode(!content.value.length);
 
     const debouncer = setTimeout(() => {
       setContent(val => ({ ...val, debounced: content.value }));
     }, 800);
 
     return () => clearTimeout(debouncer);
-  }, [content.value, setConfig]);
+  }, [content.value, togglePerfMode]);
 
   React.useEffect(() => {
     if (!zoomPanPinch) return;

+ 0 - 60
src/store/useConfig.tsx

@@ -1,60 +0,0 @@
-import { ReactZoomPanPinchRef } from "react-zoom-pan-pinch";
-import create from "zustand";
-
-type StateType = keyof typeof initialStates;
-type StateKey<T extends StateType> = typeof initialStates[T];
-
-interface ConfigActions {
-  setConfig: <T extends StateType, K extends StateKey<T>>(key: T, value: K) => void;
-  zoomIn: () => void;
-  zoomOut: () => void;
-  centerView: () => void;
-}
-
-const initialStates = {
-  foldNodes: false,
-  fullscreen: false,
-  performanceMode: true,
-  zoomPanPinch: undefined as ReactZoomPanPinchRef | undefined,
-};
-
-export type Config = typeof initialStates;
-
-const useConfig = create<Config & ConfigActions>()((set, get) => ({
-  ...initialStates,
-  zoomIn: () => {
-    const zoomPanPinch = get().zoomPanPinch;
-    if (zoomPanPinch) {
-      zoomPanPinch.setTransform(
-        zoomPanPinch?.state.positionX,
-        zoomPanPinch?.state.positionY,
-        zoomPanPinch?.state.scale + 0.4
-      );
-    }
-  },
-  zoomOut: () => {
-    const zoomPanPinch = get().zoomPanPinch;
-    if (zoomPanPinch) {
-      zoomPanPinch.setTransform(
-        zoomPanPinch?.state.positionX,
-        zoomPanPinch?.state.positionY,
-        zoomPanPinch?.state.scale - 0.4
-      );
-    }
-  },
-  centerView: () => {
-    const zoomPanPinch = get().zoomPanPinch;
-    const canvas = document.querySelector(".jsoncrack-canvas") as HTMLElement;
-    if (zoomPanPinch && canvas) zoomPanPinch.zoomToElement(canvas);
-  },
-  setConfig: (setting, value) => {
-    if (setting === "fullscreen" && value) {
-      set({ fullscreen: true });
-      return get().centerView();
-    }
-
-    set({ [setting]: value });
-  },
-}));
-
-export default useConfig;

+ 54 - 10
src/store/useGraph.tsx

@@ -1,17 +1,19 @@
-import { parse } from "jsonc-parser";
+import { ReactZoomPanPinchRef } from "react-zoom-pan-pinch";
 import { CanvasDirection } from "reaflow";
 import { Graph } from "src/components/Graph";
 import { getChildrenEdges } from "src/utils/getChildrenEdges";
 import { getOutgoers } from "src/utils/getOutgoers";
 import { parser } from "src/utils/jsonParser";
 import create from "zustand";
-import useConfig from "./useConfig";
 
 const initialStates = {
-  json: null as unknown as string,
-  loading: true,
+  zoomPanPinch: undefined as ReactZoomPanPinchRef | undefined,
   direction: "RIGHT" as CanvasDirection,
+  loading: true,
   graphCollapsed: false,
+  foldNodes: false,
+  fullscreen: false,
+  performanceMode: true,
   nodes: [] as NodeData[],
   edges: [] as EdgeData[],
   collapsedNodes: [] as string[],
@@ -23,25 +25,36 @@ export type Graph = typeof initialStates;
 
 interface GraphActions {
   setGraph: (json: string) => void;
-  getJson: () => string;
   setNodeEdges: (nodes: NodeData[], edges: EdgeData[]) => void;
   setLoading: (loading: boolean) => void;
   setDirection: (direction: CanvasDirection) => void;
+  setZoomPanPinch: (ref: ReactZoomPanPinchRef) => void;
   expandNodes: (nodeId: string) => void;
   collapseNodes: (nodeId: string) => void;
   collapseGraph: () => void;
   expandGraph: () => void;
+  toggleFold: (value: boolean) => void;
+  toggleFullscreen: (value: boolean) => void;
+  togglePerfMode: (value: boolean) => void;
+  zoomIn: () => void;
+  zoomOut: () => void;
+  centerView: () => void;
 }
 
 const useGraph = create<Graph & GraphActions>((set, get) => ({
   ...initialStates,
-  getJson: () => get().json,
   setGraph: (data: string) => {
-    const { nodes, edges } = parser(data, useConfig.getState().foldNodes);
-    const json = JSON.stringify(parse(data), null, 2);
+    const { nodes, edges } = parser(data, get().foldNodes);
 
-    set({ json, loading: true });
-    get().setNodeEdges(nodes, edges);
+    set({
+      nodes,
+      edges,
+      collapsedParents: [],
+      collapsedNodes: [],
+      collapsedEdges: [],
+      graphCollapsed: false,
+      loading: true
+    });
   },
   setDirection: direction => set({ direction }),
   setNodeEdges: (nodes, edges) =>
@@ -52,6 +65,7 @@ const useGraph = create<Graph & GraphActions>((set, get) => ({
       collapsedNodes: [],
       collapsedEdges: [],
       graphCollapsed: false,
+      loading: true
     }),
   setLoading: loading => set({ loading }),
   expandNodes: nodeId => {
@@ -141,6 +155,36 @@ const useGraph = create<Graph & GraphActions>((set, get) => ({
       graphCollapsed: false,
     });
   },
+
+  zoomIn: () => {
+    const zoomPanPinch = get().zoomPanPinch;
+    if (zoomPanPinch) {
+      zoomPanPinch.setTransform(
+        zoomPanPinch?.state.positionX,
+        zoomPanPinch?.state.positionY,
+        zoomPanPinch?.state.scale + 0.4
+      );
+    }
+  },
+  zoomOut: () => {
+    const zoomPanPinch = get().zoomPanPinch;
+    if (zoomPanPinch) {
+      zoomPanPinch.setTransform(
+        zoomPanPinch?.state.positionX,
+        zoomPanPinch?.state.positionY,
+        zoomPanPinch?.state.scale - 0.4
+      );
+    }
+  },
+  centerView: () => {
+    const zoomPanPinch = get().zoomPanPinch;
+    const canvas = document.querySelector(".jsoncrack-canvas") as HTMLElement;
+    if (zoomPanPinch && canvas) zoomPanPinch.zoomToElement(canvas);
+  },
+  toggleFold: foldNodes => set({ foldNodes }),
+  togglePerfMode: performanceMode => set({ performanceMode }),
+  toggleFullscreen: fullscreen => set({ fullscreen }),
+  setZoomPanPinch: zoomPanPinch => set({ zoomPanPinch }),
 }));
 
 export default useGraph;

+ 3 - 1
src/store/useJson.tsx

@@ -15,6 +15,7 @@ interface Json {
 
 interface JsonActions {
   setJson: (json: string) => void;
+  getJson: () => string;
   fetchJson: (jsonId: string | string[] | undefined) => void;
   setError: (hasError: boolean) => void;
   setHasChanges: (hasChanges: boolean) => void;
@@ -30,8 +31,9 @@ const initialStates = {
 
 export type JsonStates = typeof initialStates;
 
-const useJson = create<JsonStates & JsonActions>()(set => ({
+const useJson = create<JsonStates & JsonActions>()((set, get) => ({
   ...initialStates,
+  getJson: () => get().json,
   fetchJson: async jsonId => {
     if (jsonId) {
       const { data } = await altogic.endpoint.get(`json/${jsonId}`);