Переглянути джерело

Merge pull request #40 from victorbrambati/main

Add Share Link
Aykut Saraç 2 роки тому
батько
коміт
0d6a9adce7

+ 3 - 1
package.json

@@ -12,6 +12,7 @@
     "deploy": "gh-pages -d out -t true"
   },
   "dependencies": {
+    "js-base64": "^3.7.2",
     "@monaco-editor/react": "^4.4.5",
     "@sentry/nextjs": "^7.1.1",
     "allotment": "^1.14.2",
@@ -27,7 +28,8 @@
     "react-zoom-pan-pinch": "^2.1.3",
     "reaflow": "^5.0.4",
     "save-html-as-image": "^1.7.1",
-    "styled-components": "^5.3.5"
+    "styled-components": "^5.3.5",
+    "usehooks-ts": "^2.5.2"
   },
   "devDependencies": {
     "@testing-library/jest-dom": "^5.16.4",

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

@@ -16,6 +16,7 @@ import {
   AiOutlineTwitter,
   AiOutlineSave,
   AiOutlineFileAdd,
+  AiOutlineLink,
 } from "react-icons/ai";
 
 import { Tooltip } from "src/components/Tooltip";
@@ -24,6 +25,7 @@ import { useConfig } from "src/hocs/config";
 import { useRouter } from "next/router";
 import { ImportModal } from "src/containers/ImportModal";
 import { ClearModal } from "src/containers/ClearModal";
+import { ShareModal } from "src/containers/ShareModal";
 import { IoAlertCircleSharp } from "react-icons/io5";
 
 const StyledSidebar = styled.div`
@@ -138,6 +140,7 @@ export const Sidebar: React.FC = () => {
   const router = useRouter();
   const [uploadVisible, setUploadVisible] = React.useState(false);
   const [clearVisible, setClearVisible] = React.useState(false);
+  const [shareVisible, setShareVisible] = React.useState(false);
 
   const handleSave = () => {
     const a = document.createElement("a");
@@ -207,6 +210,11 @@ export const Sidebar: React.FC = () => {
             <AiOutlineSave />
           </StyledElement>
         </Tooltip>
+        <Tooltip title="Share">
+          <StyledElement onClick={() => setShareVisible(true)}>
+            <AiOutlineLink />
+          </StyledElement>
+        </Tooltip>
         <Tooltip
           title={`${
             settings.performance ? "Disable" : "Enable"
@@ -244,6 +252,7 @@ export const Sidebar: React.FC = () => {
       </StyledBottomWrapper>
       <ImportModal visible={uploadVisible} setVisible={setUploadVisible} />
       <ClearModal visible={clearVisible} setVisible={setClearVisible} />
+      <ShareModal visible={shareVisible} setVisible={setShareVisible} />
     </StyledSidebar>
   );
 };

+ 53 - 0
src/containers/ShareModal/index.tsx

@@ -0,0 +1,53 @@
+import React from "react";
+import toast from "react-hot-toast";
+import styled from "styled-components";
+import { useCopyToClipboard } from "usehooks-ts";
+import { Modal, ModalProps } from "src/components/Modal";
+import { Button } from "src/components/Button";
+import { encode } from "js-base64";
+import { useConfig } from "src/hocs/config";
+
+const StyledInput = styled.input`
+  background: ${({ theme }) => theme.BACKGROUND_TERTIARY};
+  color: ${({ theme }) => theme.INTERACTIVE_NORMAL};
+  outline: none;
+  border: none;
+  border-radius: 4px;
+  line-height: 32px;
+  width: 100%;
+  margin-bottom: 10px;
+  font-size: 16px;
+  padding: 0px 8px;
+  font-family: "Catamaran", sans-serif;
+`;
+
+export const ShareModal: React.FC<ModalProps> = ({ visible, setVisible }) => {
+  const { json } = useConfig();
+  const [url, setURL] = React.useState("");
+  const [value, copy] = useCopyToClipboard();
+
+  React.useEffect(() => {
+    const jsonEncode = encode(json);
+    setURL(`https://jsonvisio.com/editor?json=${jsonEncode}`);
+  }, [json]);
+
+  const handleShare = () => {
+    copy(url);
+    toast.success(`Link copied to clipboard.`);
+    setVisible(false);
+  };
+
+  return (
+    <Modal visible={visible} setVisible={setVisible}>
+      <Modal.Header>Create a Share Link</Modal.Header>
+      <Modal.Content>
+        <StyledInput value={url} type="url" readOnly />
+      </Modal.Content>
+      <Modal.Controls setVisible={setVisible}>
+        <Button status="SECONDARY" onClick={handleShare}>
+          Copy
+        </Button>
+      </Modal.Controls>
+    </Modal>
+  );
+};

+ 16 - 1
src/hocs/config.tsx

@@ -6,6 +6,9 @@ import {
   useConfigReducer,
 } from "src/reducer/reducer";
 import { ReactComponent, StorageConfig } from "src/typings/global";
+import { isValidJson } from "src/utils/isValidJson";
+import { useRouter } from "next/router";
+import { decode } from "js-base64";
 
 export interface AppConfig {
   json: string;
@@ -42,7 +45,19 @@ const WithConfig: ReactComponent = ({ children }) => {
     settings: states.settings,
   };
 
+  const router = useRouter();
+  const { json } = router.query;
+
   React.useEffect(() => {
+    const jsonStored = localStorage.getItem("json");
+    const jsonDecode = decode(String(json));
+
+    if (isValidJson(jsonDecode)) {
+      dispatch({ type: ConfigActionType.SET_JSON, payload: jsonDecode });
+    } else if (jsonStored) {
+      dispatch({ type: ConfigActionType.SET_JSON, payload: jsonStored });
+    }
+
     const configStored = localStorage.getItem("config");
 
     if (configStored) {
@@ -53,7 +68,7 @@ const WithConfig: ReactComponent = ({ children }) => {
     }
 
     setRender(true);
-  }, [dispatch]);
+  }, [dispatch, json]);
 
   React.useEffect(() => {
     if (render)

+ 8 - 0
src/utils/isValidJson.ts

@@ -0,0 +1,8 @@
+export const isValidJson = (str: string) => {
+  try {
+    JSON.parse(str);
+  } catch (e) {
+    return false;
+  }
+  return true;
+};

+ 10 - 0
yarn.lock

@@ -4615,6 +4615,11 @@ jest@^28:
     import-local "^3.0.2"
     jest-cli "^28.0.3"
 
+js-base64@^3.7.2:
+  version "3.7.2"
+  resolved "https://registry.yarnpkg.com/js-base64/-/js-base64-3.7.2.tgz#816d11d81a8aff241603d19ce5761e13e41d7745"
+  integrity sha512-NnRs6dsyqUXejqk/yv2aiXlAvOs56sLkX6nUdeaNezI5LFFLlsZjOThmwnrcwh5ZZRwZlCMnVAY3CvhIhoVEKQ==
+
 "js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0:
   version "4.0.0"
   resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499"
@@ -6612,6 +6617,11 @@ use-resize-observer@^9.0.0:
   dependencies:
     "@juggle/resize-observer" "^3.3.1"
 
+usehooks-ts@^2.5.2:
+  version "2.6.0"
+  resolved "https://registry.yarnpkg.com/usehooks-ts/-/usehooks-ts-2.6.0.tgz#aebab367da2350a0bee1c3749bc6dd4bcce3eaae"
+  integrity sha512-Kj/4oc2nOxRDGTDb2v1ZulF7+tpeXFuqI6cUesM0Vic7TPPDlFORxKh4ivsYg+NTvX/YbM+lhqqkfFTiIt23eg==
+
 util-deprecate@~1.0.1:
   version "1.0.2"
   resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"