From 458723b2d66004414afdc749deca1c1d7a0cdfea Mon Sep 17 00:00:00 2001
From: AykutSarac
Date: Thu, 22 Dec 2022 22:13:40 +0300
Subject: [PATCH] improve embeds
---
.../Editor/LiveEditor/GraphCanvas.tsx | 12 +--
src/containers/Home/index.tsx | 22 +++--
src/containers/Modals/ShareModal/index.tsx | 7 +-
src/pages/_error.tsx | 2 +-
src/pages/widget.tsx | 97 ++++---------------
src/store/useGraph.tsx | 16 +--
src/store/useJson.tsx | 26 ++++-
7 files changed, 71 insertions(+), 111 deletions(-)
diff --git a/src/containers/Editor/LiveEditor/GraphCanvas.tsx b/src/containers/Editor/LiveEditor/GraphCanvas.tsx
index 18939f9..7c04662 100644
--- a/src/containers/Editor/LiveEditor/GraphCanvas.tsx
+++ b/src/containers/Editor/LiveEditor/GraphCanvas.tsx
@@ -33,13 +33,11 @@ export const GraphCanvas = ({ isWidget = false }: { isWidget?: boolean }) => {
return (
<>
- {!isWidget && (
- setModalVisible(false)}
- />
- )}
+ setModalVisible(false)}
+ />
>
);
};
diff --git a/src/containers/Home/index.tsx b/src/containers/Home/index.tsx
index d360720..af3d0ff 100644
--- a/src/containers/Home/index.tsx
+++ b/src/containers/Home/index.tsx
@@ -15,7 +15,7 @@ import { CarbonAds } from "src/components/CarbonAds";
import { Producthunt } from "src/components/Producthunt";
import { Sponsors } from "src/components/Sponsors";
import { SupportButton } from "src/components/SupportButton";
-import { defaultJson } from "src/constants/data";
+import { baseURL } from "src/constants/data";
import { GoalsModal } from "src/containers/Modals/GoalsModal";
import pkg from "../../../package.json";
import * as Styles from "./styles";
@@ -52,9 +52,9 @@ const HeroSection = () => {
instantly into graphs.
-
+
GO TO EDITOR
-
+
@@ -149,8 +149,9 @@ const GitHubSection = () => (
Looking to understand or explore some JSON? Just paste or upload to visualize it as a
graph with https://t.co/HlKSrhKryJ 😍
- Thanks to @aykutsarach!{" "}
- pic.twitter.com/0LyPUL8Ezz
+ Thanks to
+ @aykutsarach
+ ! pic.twitter.com/0LyPUL8Ezz
— GitHub (@github){" "}
@@ -207,16 +208,21 @@ const EmbedSection = () => (
{
const frame = e.currentTarget.contentWindow;
setTimeout(() => {
frame?.postMessage(
{
- json: defaultJson,
+ json: JSON.stringify({
+ "random images": [
+ "https://random.imagecdn.app/50/50?.png",
+ "https://random.imagecdn.app/80/80?.png",
+ "https://random.imagecdn.app/100/100?.png",
+ ],
+ }),
options: {
theme: "dark",
- direction: "DOWN",
},
},
"*"
diff --git a/src/containers/Modals/ShareModal/index.tsx b/src/containers/Modals/ShareModal/index.tsx
index 45747e2..fcbbf3a 100644
--- a/src/containers/Modals/ShareModal/index.tsx
+++ b/src/containers/Modals/ShareModal/index.tsx
@@ -39,6 +39,11 @@ export const ShareModal: React.FC = ({ visible, setVisible }) => {
setVisible(false);
};
+ const onEmbedClick = () => {
+ push("/embed");
+ setVisible(false);
+ }
+
return (
Create a Share Link
@@ -55,7 +60,7 @@ export const ShareModal: React.FC = ({ visible, setVisible }) => {
Embed into your website
-
diff --git a/src/pages/_error.tsx b/src/pages/_error.tsx
index 8d64f25..7cad8aa 100644
--- a/src/pages/_error.tsx
+++ b/src/pages/_error.tsx
@@ -15,7 +15,7 @@ const StyledNotFound = styled.div`
const StyledMessage = styled.h4`
color: ${({ theme }) => theme.FULL_WHITE};
font-size: 25px;
- font-weight: 600;
+ font-weight: 800;
margin: 10px 0;
`;
diff --git a/src/pages/widget.tsx b/src/pages/widget.tsx
index 3af4d14..e3080af 100644
--- a/src/pages/widget.tsx
+++ b/src/pages/widget.tsx
@@ -4,14 +4,16 @@ import { useRouter } from "next/router";
import toast from "react-hot-toast";
import { baseURL } from "src/constants/data";
import { darkTheme, lightTheme } from "src/constants/theme";
-import { NodeModal } from "src/containers/Modals/NodeModal";
import useGraph from "src/store/useGraph";
-import { parser } from "src/utils/jsonParser";
+import useJson from "src/store/useJson";
import styled, { ThemeProvider } from "styled-components";
-const Graph = dynamic(() => import("src/components/Graph").then(c => c.Graph), {
- ssr: false,
-});
+const GraphCanvas = dynamic(
+ () => import("src/containers/Editor/LiveEditor/GraphCanvas").then(c => c.GraphCanvas),
+ {
+ ssr: false,
+ }
+);
const StyledAttribute = styled.a`
position: fixed;
@@ -45,71 +47,28 @@ interface EmbedMessage {
};
}
-const StyledDeprecated = styled.div`
- display: flex;
- flex-direction: column;
- justify-content: center;
- align-items: center;
- width: 100%;
- height: 100vh;
-
- a {
- text-decoration: underline;
- }
-`;
-
const WidgetPage = () => {
- const { query, push } = useRouter();
-
- const [isModalVisible, setModalVisible] = React.useState(false);
- const [selectedNode, setSelectedNode] = React.useState<[string, string][]>([]);
+ const { query, push, isReady } = useRouter();
const [theme, setTheme] = React.useState("dark");
-
- const collapsedNodes = useGraph(state => state.collapsedNodes);
- const collapsedEdges = useGraph(state => state.collapsedEdges);
- const loading = useGraph(state => state.loading);
- const setNodeEdges = useGraph(state => state.setNodeEdges);
- const setDirection = useGraph(state => state.setDirection);
-
- const openModal = React.useCallback(() => setModalVisible(true), []);
+ const fetchJson = useJson(state => state.fetchJson);
+ const setGraph = useGraph(state => state.setGraph);
React.useEffect(() => {
- const nodeList = collapsedNodes.map(id => `[id$="node-${id}"]`);
- const edgeList = collapsedEdges.map(id => `[class$="edge-${id}"]`);
-
- const hiddenItems = document.querySelectorAll(".hide");
- hiddenItems.forEach(item => item.classList.remove("hide"));
-
- if (nodeList.length) {
- const selectedNodes = document.querySelectorAll(nodeList.join(","));
- selectedNodes.forEach(node => node.classList.add("hide"));
+ if (isReady) {
+ fetchJson(query.json);
+ if (!inIframe()) push("/");
}
-
- if (edgeList.length) {
- const selectedEdges = document.querySelectorAll(edgeList.join(","));
- selectedEdges.forEach(edge => edge.classList.add("hide"));
- }
-
- if (!inIframe()) push("/");
- }, [collapsedNodes, collapsedEdges, loading, push]);
+ }, [fetchJson, isReady, push, query.json]);
React.useEffect(() => {
const handler = (event: EmbedMessage) => {
try {
if (!event.data?.json) return;
+ if (event.data?.options?.theme === "light" || event.data?.options?.theme === "dark") {
+ setTheme(event.data.options.theme);
+ }
- const { nodes, edges } = parser(event.data.json);
-
- const options = {
- direction: "RIGHT",
- theme,
- ...event.data.options,
- };
-
- setDirection(options.direction);
- if (options.theme === "light" || options.theme === "dark") setTheme(options.theme);
-
- setNodeEdges(nodes, edges);
+ setGraph(event.data.json, event.data.options);
} catch (error) {
console.error(error);
toast.error("Invalid JSON!");
@@ -118,27 +77,11 @@ const WidgetPage = () => {
window.addEventListener("message", handler);
return () => window.removeEventListener("message", handler);
- }, [setDirection, setNodeEdges, theme]);
-
- if (query.json)
- return (
-
- ⚠️ Deprecated ⚠️
-
-
- https://jsoncrack.com/embed
-
-
- );
+ }, [setGraph, theme]);
return (
-
- setModalVisible(false)}
- />
+
jsoncrack.com
diff --git a/src/store/useGraph.tsx b/src/store/useGraph.tsx
index c119a27..0eaf31f 100644
--- a/src/store/useGraph.tsx
+++ b/src/store/useGraph.tsx
@@ -25,8 +25,7 @@ const initialStates = {
export type Graph = typeof initialStates;
interface GraphActions {
- setGraph: (json?: string) => void;
- setNodeEdges: (nodes: NodeData[], edges: EdgeData[]) => void;
+ setGraph: (json?: string, options?: Partial[]) => void;
setLoading: (loading: boolean) => void;
setDirection: (direction: CanvasDirection) => void;
setZoomPanPinch: (ref: ReactZoomPanPinchRef) => void;
@@ -44,7 +43,7 @@ interface GraphActions {
const useGraph = create((set, get) => ({
...initialStates,
- setGraph: (data?: string) => {
+ setGraph: (data, options) => {
const { nodes, edges } = parser(data ?? useJson.getState().json);
set({
@@ -55,19 +54,10 @@ const useGraph = create((set, get) => ({
collapsedEdges: [],
graphCollapsed: false,
loading: true,
+ ...options,
});
},
setDirection: direction => set({ direction }),
- setNodeEdges: (nodes, edges) =>
- set({
- nodes,
- edges,
- collapsedParents: [],
- collapsedNodes: [],
- collapsedEdges: [],
- graphCollapsed: false,
- loading: true,
- }),
setLoading: loading => set({ loading }),
expandNodes: nodeId => {
const [childrenNodes, matchingNodes] = getOutgoers(
diff --git a/src/store/useJson.tsx b/src/store/useJson.tsx
index 5c83058..c99a38a 100644
--- a/src/store/useJson.tsx
+++ b/src/store/useJson.tsx
@@ -1,4 +1,5 @@
import { decompressFromBase64 } from "lz-string";
+import toast from "react-hot-toast";
import { altogic } from "src/api/altogic";
import { defaultJson } from "src/constants/data";
import useGraph from "src/store/useGraph";
@@ -35,7 +36,24 @@ const useJson = create()((set, get) => ({
...initialStates,
getJson: () => get().json,
fetchJson: async jsonId => {
- if (jsonId) {
+ const isURL = new RegExp(
+ /^https?:\/\/(?:www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b(?:[-a-zA-Z0-9()@:%_\+.~#?&\/=]*)$/
+ );
+
+ if (typeof jsonId === "string" && isURL.test(jsonId)) {
+ try {
+ const res = await fetch(jsonId);
+ const json = await res.json();
+ const jsonStr = JSON.stringify(json, null, 2);
+
+ useGraph.getState().setGraph(jsonStr);
+ set({ json: jsonStr, loading: false });
+ } catch (error) {
+ useGraph.getState().setGraph(defaultJson);
+ set({ json: defaultJson, loading: false });
+ toast.error('Failed to fetch JSON from URL!');
+ }
+ } else if (jsonId) {
const { data, errors } = await altogic.endpoint.get(`json/${jsonId}`);
if (!errors) {
@@ -49,10 +67,10 @@ const useJson = create()((set, get) => ({
});
}
}
+ } else {
+ useGraph.getState().setGraph(defaultJson);
+ set({ json: defaultJson, loading: false });
}
-
- useGraph.getState().setGraph(defaultJson);
- set({ json: defaultJson, loading: false });
},
setJson: json => {
useGraph.getState().setGraph(json);