mirror of
https://github.com/AykutSarac/jsoncrack.com.git
synced 2025-01-27 15:22:56 +08:00
replace useConfig with useGraph
This commit is contained in:
parent
a26b94f584
commit
20bcdfef10
@ -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;
|
||||
|
@ -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>) => {
|
||||
|
@ -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(
|
||||
|
@ -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>
|
||||
|
@ -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}>
|
||||
|
@ -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 (
|
||||
<>
|
||||
|
@ -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);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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;
|
@ -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;
|
||||
|
@ -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}`);
|
||||
|
Loading…
x
Reference in New Issue
Block a user