فهرست منبع

code structure

AykutSarac 3 سال پیش
والد
کامیت
4e44b26107

+ 13 - 0
src/components/Sidebar/index.tsx

@@ -8,8 +8,10 @@ import {
   AiOutlineTwitter,
   AiOutlineTwitter,
 } from "react-icons/ai";
 } from "react-icons/ai";
 import { FaFileImport } from "react-icons/fa";
 import { FaFileImport } from "react-icons/fa";
+import { MdAutoGraph } from "react-icons/md";
 import { useLocalStorage } from "usehooks-ts";
 import { useLocalStorage } from "usehooks-ts";
 import { defaultValue } from "src/containers/JsonEditor";
 import { defaultValue } from "src/containers/JsonEditor";
+import { getNextLayout } from "src/containers/LiveEditor/helpers";
 
 
 const StyledSidebar = styled.div`
 const StyledSidebar = styled.div`
   display: flex;
   display: flex;
@@ -95,6 +97,10 @@ const fileToJson = (file: File, setJson: (val: string) => void) => {
 export const Sidebar = () => {
 export const Sidebar = () => {
   const [jsonFile, setJsonFile] = React.useState<File | any>(null);
   const [jsonFile, setJsonFile] = React.useState<File | any>(null);
   const [_, setJson] = useLocalStorage("json", JSON.stringify(defaultValue));
   const [_, setJson] = useLocalStorage("json", JSON.stringify(defaultValue));
+  const [layout, setLayout] = useLocalStorage<"TB" | "BT" | "RL" | "LR">(
+    "layout",
+    "TB"
+  );
 
 
   const handleClear = () => {
   const handleClear = () => {
     setJson("[]");
     setJson("[]");
@@ -144,6 +150,13 @@ export const Sidebar = () => {
             </StyledImportFile>
             </StyledImportFile>
           </a>
           </a>
         </StyledElement>
         </StyledElement>
+        <StyledElement
+          as="a"
+          onClick={() => setLayout(getNextLayout(layout))}
+          title="Change Layout"
+        >
+          <MdAutoGraph />
+        </StyledElement>
       </StyledTopWrapper>
       </StyledTopWrapper>
       <StyledBottomWrapper>
       <StyledBottomWrapper>
         <StyledElement>
         <StyledElement>

+ 63 - 0
src/containers/LiveEditor/FlowWrapper.tsx

@@ -0,0 +1,63 @@
+import React from "react";
+import ReactFlow, {
+  ControlButton,
+  Controls,
+  Elements,
+  NodeExtent,
+} from "react-flow-renderer";
+import { useLocalStorage } from "usehooks-ts";
+import { defaultValue } from "../JsonEditor";
+import { getLayout, getLayoutPosition } from "./helpers";
+import { CustomNodeComponent } from "./Node";
+
+const nodeExtent: NodeExtent = [
+  [0, 0],
+  [1000, 1000],
+];
+
+const nodeTypes = {
+  special: CustomNodeComponent,
+};
+
+export const FlowWrapper: React.FC = () => {
+  const [json] = useLocalStorage("json", JSON.stringify(defaultValue));
+  const [layout] = useLocalStorage("layout", "TB");
+
+  const [elements, setElements] = React.useState<Elements>([]);
+  const [rfInstance, setRfInstance] = React.useState<any>(null);
+  const [valid, setValid] = React.useState(true);
+
+  React.useEffect(() => {
+    if (rfInstance) rfInstance.fitView();
+  }, [rfInstance]);
+
+  React.useEffect(() => {
+    try {
+      const layoutedElements = getLayout(layout, json);
+      setElements(layoutedElements);
+      setValid(true);
+    } catch (error) {
+      setValid(false);
+    }
+  }, [rfInstance, json, layout]);
+
+  if (!valid) return null;
+
+  return (
+    <ReactFlow
+      nodeExtent={nodeExtent}
+      elements={elements}
+      nodeTypes={nodeTypes}
+      onLoad={(rf: any) => setRfInstance(rf)}
+    >
+      <Controls>
+        <ControlButton
+          onClick={() => setElements(getLayoutPosition(layout, elements))}
+          style={{ gridColumn: "1 / 3", width: "auto" }}
+        >
+          Format
+        </ControlButton>
+      </Controls>
+    </ReactFlow>
+  );
+};

+ 31 - 8
src/containers/LiveEditor/helpers.ts

@@ -1,20 +1,20 @@
 import dagre from "dagre";
 import dagre from "dagre";
 import { Elements, isNode, Position } from "react-flow-renderer";
 import { Elements, isNode, Position } from "react-flow-renderer";
+import { parser } from "src/utils/json-editor-parser";
 
 
 const dagreGraph = new dagre.graphlib.Graph();
 const dagreGraph = new dagre.graphlib.Graph();
 dagreGraph.setDefaultEdgeLabel(() => ({}));
 dagreGraph.setDefaultEdgeLabel(() => ({}));
 
 
-export const onLayout = (
-  direction: string,
-  elements: Elements,
-  setElements: React.Dispatch<Elements>
-) => {
+export const getLayoutPosition = (direction: string, elements: Elements, dynamic = false) => {
   const isHorizontal = direction === "LR";
   const isHorizontal = direction === "LR";
   dagreGraph.setGraph({ rankdir: direction });
   dagreGraph.setGraph({ rankdir: direction });
 
 
   elements.forEach((el) => {
   elements.forEach((el) => {
     if (isNode(el)) {
     if (isNode(el)) {
-      dagreGraph.setNode(el.id, { width: 175, height: 50 });
+      dagreGraph.setNode(el.id, {
+        width: dynamic ? el.__rf.width : 200,
+        height: dynamic ? el.__rf.height : 100,
+      });
     } else {
     } else {
       dagreGraph.setEdge(el.source, el.target);
       dagreGraph.setEdge(el.source, el.target);
     }
     }
@@ -36,5 +36,28 @@ export const onLayout = (
     return el;
     return el;
   });
   });
 
 
-  setElements(layoutedElements);
-};
+  return layoutedElements;
+};
+
+export function getNextLayout(layout: "TB" | "BT" | "RL" | "LR") {
+  switch (layout) {
+    case "TB":
+      return "BT";
+
+    case "BT":
+      return "RL";
+
+    case "RL":
+      return "LR";
+
+    default:
+      return "TB";
+  }
+}
+
+export function getLayout(layout: string, json: string, dynamic = false) {
+  const jsonToGraph = parser(json);
+  const layoutedElements = getLayoutPosition(layout, jsonToGraph, dynamic);
+
+  return layoutedElements;
+}

+ 5 - 61
src/containers/LiveEditor/index.tsx

@@ -1,21 +1,7 @@
 import React from "react";
 import React from "react";
 import styled from "styled-components";
 import styled from "styled-components";
-import ReactFlow, {
-  ControlButton,
-  Controls,
-  Elements,
-  NodeExtent,
-} from "react-flow-renderer";
-import { defaultValue } from "../JsonEditor";
-import { parser } from "src/utils/json-editor-parser";
-import { useLocalStorage } from "usehooks-ts";
-import { CustomNodeComponent } from "./Node";
-import { onLayout } from "./helpers";
-
-const nodeExtent: NodeExtent = [
-  [0, 0],
-  [1000, 1000],
-];
+import { ReactFlowProvider } from "react-flow-renderer";
+import { FlowWrapper } from "./FlowWrapper";
 
 
 const StyledLiveEditor = styled.div`
 const StyledLiveEditor = styled.div`
   width: 100%;
   width: 100%;
@@ -44,54 +30,12 @@ const StyledLiveEditor = styled.div`
   }
   }
 `;
 `;
 
 
-const nodeTypes = {
-  special: CustomNodeComponent,
-};
-
 export const LiveEditor: React.FC = () => {
 export const LiveEditor: React.FC = () => {
-  const [json] = useLocalStorage("json", JSON.stringify(defaultValue));
-  const [rfInstance, setRfInstance] = React.useState<any>(null);
-  const [valid, setValid] = React.useState(true);
-  const [elements, setElements] = React.useState<Elements>(parser(json));
-
-  React.useEffect(() => {
-    try {
-      JSON.parse(json);
-      onLayout("RL", parser(json), setElements);
-      setValid(true);
-    } catch (error) {
-      setValid(false);
-    }
-  }, [json]);
-
-  React.useEffect(() => {
-    if (rfInstance) {
-      rfInstance.fitView();
-    }
-  }, [elements, rfInstance]);
-
-  if (!valid) return null;
-
   return (
   return (
     <StyledLiveEditor>
     <StyledLiveEditor>
-      <ReactFlow
-        nodeExtent={nodeExtent}
-        elements={elements}
-        nodeTypes={nodeTypes}
-        onLoad={(rf: any) => {
-          setRfInstance(rf);
-          onLayout("RL", elements, setElements);
-        }}
-      >
-        <Controls>
-          <ControlButton
-            onClick={() => onLayout("RL", elements, setElements)}
-            style={{ gridColumn: "1 / 3", width: "auto" }}
-          >
-            Format
-          </ControlButton>
-        </Controls>
-      </ReactFlow>
+      <ReactFlowProvider>
+        <FlowWrapper />
+      </ReactFlowProvider>
     </StyledLiveEditor>
     </StyledLiveEditor>
   );
   );
 };
 };

+ 1 - 1
src/pages/editor/index.tsx

@@ -75,7 +75,7 @@ const Editor: React.FC = () => {
       </Head>
       </Head>
       <Sidebar />
       <Sidebar />
       <StyledEditorWrapper>
       <StyledEditorWrapper>
-        <StyledTools>Tools</StyledTools>
+        <StyledTools>Editor</StyledTools>
         <StyledEditor>
         <StyledEditor>
           <JsonEditor />
           <JsonEditor />
           <LiveEditor />
           <LiveEditor />