index.tsx 2.8 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697
  1. import React from "react";
  2. import dynamic from "next/dynamic";
  3. import toast from "react-hot-toast";
  4. import { FiCopy } from "react-icons/fi";
  5. import vs from "react-syntax-highlighter/dist/cjs/styles/prism/vs";
  6. import vscDarkPlus from "react-syntax-highlighter/dist/cjs/styles/prism/vsc-dark-plus";
  7. import { Button } from "src/components/Button";
  8. import { Modal } from "src/components/Modal";
  9. import useGraph from "src/store/useGraph";
  10. import useStored from "src/store/useStored";
  11. import styled from "styled-components";
  12. const SyntaxHighlighter = dynamic(() => import("react-syntax-highlighter/dist/cjs/prism-async"), {
  13. ssr: false,
  14. });
  15. interface NodeModalProps {
  16. visible: boolean;
  17. closeModal: () => void;
  18. }
  19. const StyledTitle = styled.div`
  20. line-height: 16px;
  21. font-size: 12px;
  22. font-weight: 600;
  23. padding: 16px 0;
  24. &:first-of-type {
  25. padding-top: 0;
  26. }
  27. `;
  28. export const NodeModal = ({ visible, closeModal }: NodeModalProps) => {
  29. const lightmode = useStored(state => state.lightmode);
  30. const path = useGraph(state => state.path);
  31. const nodeData = useGraph(state =>
  32. Array.isArray(state.selectedNode) ? Object.fromEntries(state.selectedNode) : state.selectedNode
  33. );
  34. const handleClipboard = (content: string) => {
  35. try {
  36. navigator.clipboard?.writeText(content);
  37. toast.success("Content copied to clipboard!");
  38. closeModal();
  39. } catch (error) {
  40. toast.error("Failed to save to clipboard.");
  41. }
  42. };
  43. return (
  44. <Modal visible={visible} setVisible={closeModal} size="lg">
  45. <Modal.Header>Node Content</Modal.Header>
  46. <Modal.Content>
  47. <StyledTitle>Content</StyledTitle>
  48. <SyntaxHighlighter
  49. style={lightmode ? vs : vscDarkPlus}
  50. customStyle={{
  51. borderRadius: "4px",
  52. fontSize: "14px",
  53. margin: "0",
  54. }}
  55. language="json"
  56. showLineNumbers
  57. >
  58. {JSON.stringify(
  59. nodeData,
  60. (_, v) => {
  61. if (typeof v === "string") return v.replaceAll('"', "");
  62. return v;
  63. },
  64. 2
  65. )}
  66. </SyntaxHighlighter>
  67. <StyledTitle>Node Path</StyledTitle>
  68. <SyntaxHighlighter
  69. style={lightmode ? vs : vscDarkPlus}
  70. customStyle={{
  71. borderRadius: "4px",
  72. fontSize: "14px",
  73. margin: "0",
  74. }}
  75. language="javascript"
  76. >
  77. {path}
  78. </SyntaxHighlighter>
  79. </Modal.Content>
  80. <Modal.Controls setVisible={closeModal}>
  81. <Button status="SECONDARY" onClick={() => handleClipboard(JSON.stringify(nodeData))}>
  82. <FiCopy size={18} /> Clipboard
  83. </Button>
  84. <Button status="SECONDARY" onClick={() => handleClipboard(path)}>
  85. <FiCopy size={18} /> Copy Path
  86. </Button>
  87. </Modal.Controls>
  88. </Modal>
  89. );
  90. };