AykutSarac 2 лет назад
Родитель
Сommit
129096f25b

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

@@ -20,15 +20,15 @@ const ObjectNode: React.FC<CustomNodeProps<[string, string][]>> = ({
             (val, idx) =>
               val[1] && (
                 <Styled.StyledRow
-                  data-key={val[1]}
+                  data-key={JSON.stringify(val[1])}
                   data-x={x}
                   data-y={y}
                   key={idx}
                   width={width}
-                  value={val[1]}
+                  value={JSON.stringify(val[1])}
                 >
-                  <Styled.StyledKey objectKey>{val[0]}: </Styled.StyledKey>
-                  <Styled.StyledLinkItUrl>{val[1]}</Styled.StyledLinkItUrl>
+                  <Styled.StyledKey objectKey>{JSON.stringify(val[0]).replaceAll('"', "")}: </Styled.StyledKey>
+                  <Styled.StyledLinkItUrl>{JSON.stringify(val[1])}</Styled.StyledLinkItUrl>
                 </Styled.StyledRow>
               )
           )}

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

@@ -20,10 +20,10 @@ const TextNode: React.FC<CustomNodeProps<string>> = ({
           <Styled.StyledKey
             data-x={x}
             data-y={y}
-            data-key={value}
+            data-key={JSON.stringify(value)}
             parent={isParent}
           >
-            <Styled.StyledLinkItUrl>{value}</Styled.StyledLinkItUrl>
+            <Styled.StyledLinkItUrl>{JSON.stringify(value).replaceAll('"', "")}</Styled.StyledLinkItUrl>
           </Styled.StyledKey>
         </Styled.StyledText>
       </ConditionalWrapper>

+ 50 - 41
src/components/Graph/index.tsx

@@ -13,11 +13,11 @@ import {
   NodeProps,
 } from "reaflow";
 import { CustomNode } from "src/components/CustomNode";
+import { NodeModal } from "src/containers/Modals/NodeModal";
 import { getEdgeNodes } from "src/containers/Editor/LiveEditor/helpers";
 import useConfig from "src/hooks/store/useConfig";
 import styled from "styled-components";
 import shallow from "zustand/shallow";
-import toast from "react-hot-toast";
 
 interface GraphProps {
   json: string;
@@ -48,6 +48,7 @@ export const Graph: React.FC<GraphProps & CanvasContainerProps> = ({
   isWidget = false,
   ...props
 }) => {
+  const [isModalVisible, setModalVisible] = React.useState(false);
   const updateSetting = useConfig((state) => state.updateSetting);
   const [expand, layout] = useConfig(
     (state) => [state.settings.expand, state.settings.layout],
@@ -58,6 +59,7 @@ export const Graph: React.FC<GraphProps & CanvasContainerProps> = ({
     updateSetting("zoomPanPinch", ref);
   };
 
+  const [selectedNode, setSelectedNode] = React.useState<NodeData | null>(null);
   const [nodes, setNodes] = React.useState<NodeData[]>([]);
   const [edges, setEdges] = React.useState<EdgeData[]>([]);
   const [size, setSize] = React.useState({
@@ -86,49 +88,56 @@ export const Graph: React.FC<GraphProps & CanvasContainerProps> = ({
     e: React.MouseEvent<SVGElement>,
     props: NodeProps
   ) => {
-    if (e.detail === 2) {
-      toast("Object copied to clipboard!");
-      navigator.clipboard.writeText(JSON.stringify(props.properties.text));
-    }
+    setSelectedNode(props.properties);
+    setModalVisible(true);
   };
 
   return (
-    <StyledEditorWrapper isWidget={isWidget}>
-      <TransformWrapper
-        maxScale={1.8}
-        minScale={0.4}
-        initialScale={0.7}
-        wheel={wheelOptions}
-        onInit={onInit}
-      >
-        <TransformComponent
-          wrapperStyle={{
-            width: "100%",
-            height: "100%",
-            overflow: "hidden",
-          }}
+    <>
+      <StyledEditorWrapper isWidget={isWidget}>
+        <TransformWrapper
+          maxScale={1.8}
+          minScale={0.4}
+          initialScale={0.7}
+          wheel={wheelOptions}
+          onInit={onInit}
         >
-          <Canvas
-            nodes={nodes}
-            edges={edges}
-            maxWidth={size.width + 100}
-            maxHeight={size.height + 100}
-            direction={layout}
-            key={layout}
-            onCanvasClick={onCanvasClick}
-            onLayoutChange={onLayoutChange}
-            node={(props) => (
-              <CustomNode
-                onClick={(e) => handleNodeClick(e, props)}
-                {...props}
-              />
-            )}
-            zoomable={false}
-            readonly
-            {...props}
-          />
-        </TransformComponent>
-      </TransformWrapper>
-    </StyledEditorWrapper>
+          <TransformComponent
+            wrapperStyle={{
+              width: "100%",
+              height: "100%",
+              overflow: "hidden",
+            }}
+          >
+            <Canvas
+              nodes={nodes}
+              edges={edges}
+              maxWidth={size.width + 100}
+              maxHeight={size.height + 100}
+              direction={layout}
+              key={layout}
+              onCanvasClick={onCanvasClick}
+              onLayoutChange={onLayoutChange}
+              node={(props) => (
+                <CustomNode
+                  onClick={(e) => handleNodeClick(e, props)}
+                  {...props}
+                />
+              )}
+              zoomable={false}
+              readonly
+              {...props}
+            />
+          </TransformComponent>
+        </TransformWrapper>
+      </StyledEditorWrapper>
+      {!isWidget && selectedNode && (
+        <NodeModal
+          selectedNode={selectedNode.text}
+          visible={isModalVisible}
+          setVisible={setModalVisible}
+        />
+      )}
+    </>
   );
 };

+ 1 - 17
src/containers/Editor/LiveEditor/helpers.ts

@@ -1,22 +1,6 @@
 import { CanvasDirection, NodeData, EdgeData } from "reaflow";
 import { parser } from "src/utils/json-editor-parser";
 
-const toString = (value: string | object) => {
-  const isObject = value instanceof Object;
-
-  if (isObject) {
-    const entries = Object.entries(value);
-    const stringObj = entries.map((val) => [
-      JSON.stringify(val[0]).replaceAll('"', ""),
-      JSON.stringify(val[1]),
-    ]);
-
-    return Object.fromEntries(stringObj);
-  }
-
-  return String(value);
-};
-
 export function getEdgeNodes(
   graph: string,
   isExpanded: boolean = true
@@ -44,7 +28,7 @@ export function getEdgeNodes(
 
       nodes.push({
         id: el.id,
-        text: toString(el.text),
+        text: el.text,
         data: {
           isParent: el.parent,
         },

+ 52 - 0
src/containers/Modals/NodeModal/index.tsx

@@ -0,0 +1,52 @@
+import React from "react";
+import toast from "react-hot-toast";
+import { FiCopy } from "react-icons/fi";
+import { Button } from "src/components/Button";
+import { Modal } from "src/components/Modal";
+import styled from "styled-components";
+
+const StyledTextarea = styled.textarea`
+  resize: none;
+  width: 100%;
+  min-height: 200px;
+
+  padding: 10px;
+  background: ${({ theme }) => theme.BACKGROUND_TERTIARY};
+  color: ${({ theme }) => theme.INTERACTIVE_NORMAL};
+  outline: none;
+  border-radius: 4px;
+  line-height: 20px;
+  border: none;
+`;
+
+export const NodeModal = ({ selectedNode, visible = true, setVisible }) => {
+  const handleClipboard = () => {
+    toast("Content copied to clipboard!");
+    navigator.clipboard.writeText(JSON.stringify(selectedNode));
+    setVisible(false);
+  };
+
+
+  return (
+    <Modal visible={visible} setVisible={setVisible}>
+      <Modal.Header>Node Content</Modal.Header>
+      <Modal.Content>
+        <StyledTextarea
+          defaultValue={JSON.stringify(
+            selectedNode,
+            (k, v) => {
+              if (typeof v === "string") return v.replaceAll('"', "");
+              return v;
+            },
+            2
+          )}
+        />
+      </Modal.Content>
+      <Modal.Controls setVisible={setVisible}>
+        <Button status="SECONDARY" onClick={handleClipboard}>
+          <FiCopy size={18} /> Clipboard
+        </Button>
+      </Modal.Controls>
+    </Modal>
+  );
+};