mirror of
https://github.com/AykutSarac/jsoncrack.com.git
synced 2025-01-27 15:22:56 +08:00
create click node modal
This commit is contained in:
parent
c91c9d9d8e
commit
129096f25b
@ -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>
|
||||
)
|
||||
)}
|
||||
|
@ -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>
|
||||
|
@ -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,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
src/containers/Modals/NodeModal/index.tsx
Normal file
52
src/containers/Modals/NodeModal/index.tsx
Normal file
@ -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>
|
||||
);
|
||||
};
|
Loading…
x
Reference in New Issue
Block a user