From 20bcdfef10e47b544885983149930de852053af5 Mon Sep 17 00:00:00 2001 From: AykutSarac Date: Sat, 17 Dec 2022 23:00:37 +0300 Subject: [PATCH] replace useConfig with useGraph --- src/components/CustomNode/ObjectNode.tsx | 4 +- src/components/CustomNode/TextNode.tsx | 3 +- src/components/Graph/index.tsx | 9 ++- src/components/Sidebar/index.tsx | 20 +++--- src/containers/Editor/Panes.tsx | 10 +-- src/containers/Editor/Tools.tsx | 14 ++-- src/containers/Modals/DownloadModal/index.tsx | 12 ++-- src/hooks/useFocusNode.tsx | 10 +-- src/store/useConfig.tsx | 60 ----------------- src/store/useGraph.tsx | 64 ++++++++++++++++--- src/store/useJson.tsx | 4 +- 11 files changed, 98 insertions(+), 112 deletions(-) delete mode 100644 src/store/useConfig.tsx diff --git a/src/components/CustomNode/ObjectNode.tsx b/src/components/CustomNode/ObjectNode.tsx index 4679dfb..82397f3 100644 --- a/src/components/CustomNode/ObjectNode.tsx +++ b/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 = ({ 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; diff --git a/src/components/CustomNode/TextNode.tsx b/src/components/CustomNode/TextNode.tsx index 3ab840d..2caeb89 100644 --- a/src/components/CustomNode/TextNode.tsx +++ b/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 = ({ 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) => { diff --git a/src/components/Graph/index.tsx b/src/components/Graph/index.tsx index b14e872..a6a0fb0 100644 --- a/src/components/Graph/index.tsx +++ b/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( diff --git a/src/components/Sidebar/index.tsx b/src/components/Sidebar/index.tsx index ea577e9..236d6fc 100644 --- a/src/components/Sidebar/index.tsx +++ b/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 = () => { - setConfig("fullscreen", !fullscreen)}> + toggleFullscreen(!fullscreen)}> diff --git a/src/containers/Editor/Panes.tsx b/src/containers/Editor/Panes.tsx index 17432da..75d2ee3 100644 --- a/src/containers/Editor/Panes.tsx +++ b/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 ( diff --git a/src/containers/Editor/Tools.tsx b/src/containers/Editor/Tools.tsx index cfb3143..d5be365 100644 --- a/src/containers/Editor/Tools.tsx +++ b/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 ( <> diff --git a/src/containers/Modals/DownloadModal/index.tsx b/src/containers/Modals/DownloadModal/index.tsx index 37d80b4..b795ee2 100644 --- a/src/containers/Modals/DownloadModal/index.tsx +++ b/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 = { card: { @@ -93,7 +93,7 @@ const StyledColorIndicator = styled.div<{ color: string }>` `; export const DownloadModal: React.FC = ({ 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 = ({ 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 = ({ 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 = ({ visible, setVisible }) => } finally { toast.dismiss("toastDownload"); setVisible(false); - setConfig("performanceMode", true); + togglePerfMode(true); } }; diff --git a/src/hooks/useFocusNode.tsx b/src/hooks/useFocusNode.tsx index f934546..6337f4c 100644 --- a/src/hooks/useFocusNode.tsx +++ b/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; diff --git a/src/store/useConfig.tsx b/src/store/useConfig.tsx deleted file mode 100644 index 1e5d4ca..0000000 --- a/src/store/useConfig.tsx +++ /dev/null @@ -1,60 +0,0 @@ -import { ReactZoomPanPinchRef } from "react-zoom-pan-pinch"; -import create from "zustand"; - -type StateType = keyof typeof initialStates; -type StateKey = typeof initialStates[T]; - -interface ConfigActions { - setConfig: >(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()((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; diff --git a/src/store/useGraph.tsx b/src/store/useGraph.tsx index 655c7cf..1f4aa93 100644 --- a/src/store/useGraph.tsx +++ b/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((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((set, get) => ({ collapsedNodes: [], collapsedEdges: [], graphCollapsed: false, + loading: true }), setLoading: loading => set({ loading }), expandNodes: nodeId => { @@ -141,6 +155,36 @@ const useGraph = create((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; diff --git a/src/store/useJson.tsx b/src/store/useJson.tsx index f007ec6..13aa5b7 100644 --- a/src/store/useJson.tsx +++ b/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()(set => ({ +const useJson = create()((set, get) => ({ ...initialStates, + getJson: () => get().json, fetchJson: async jsonId => { if (jsonId) { const { data } = await altogic.endpoint.get(`json/${jsonId}`);