improve embeds

This commit is contained in:
AykutSarac 2022-12-22 22:13:40 +03:00
parent 1548d6d4dd
commit 458723b2d6
7 changed files with 71 additions and 111 deletions

View File

@ -33,13 +33,11 @@ export const GraphCanvas = ({ isWidget = false }: { isWidget?: boolean }) => {
return (
<>
<Graph openModal={openModal} setSelectedNode={setSelectedNode} isWidget={isWidget} />
{!isWidget && (
<NodeModal
selectedNode={selectedNode}
visible={isModalVisible}
closeModal={() => setModalVisible(false)}
/>
)}
<NodeModal
selectedNode={selectedNode}
visible={isModalVisible}
closeModal={() => setModalVisible(false)}
/>
</>
);
};

View File

@ -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 = () => {
<Styles.StyledHighlightedText>instantly</Styles.StyledHighlightedText> into graphs.
</Styles.StyledSubTitle>
<Styles.StyledButton rel="prefetch" href="/editor" link>
<Styles.StyledButton href="/editor" link>
GO TO EDITOR
<AiOutlineRight strokeWidth="30px" />
<AiOutlineRight strokeWidth="80" />
</Styles.StyledButton>
<Styles.StyledButtonWrapper>
@ -149,8 +149,9 @@ const GitHubSection = () => (
Looking to understand or explore some JSON? Just paste or upload to visualize it as a
graph with <a href="https://t.co/HlKSrhKryJ">https://t.co/HlKSrhKryJ</a> 😍 <br />
<br />
Thanks to <a href="https://twitter.com/aykutsarach?ref_src=twsrc%5Etfw">@aykutsarach</a>!{" "}
<a href="https://t.co/0LyPUL8Ezz">pic.twitter.com/0LyPUL8Ezz</a>
Thanks to <a href="https://twitter.com/aykutsarach?ref_src=twsrc%5Etfw">
@aykutsarach
</a>! <a href="https://t.co/0LyPUL8Ezz">pic.twitter.com/0LyPUL8Ezz</a>
</p>
&mdash; GitHub (@github){" "}
<a href="https://twitter.com/github/status/1519363257794015233?ref_src=twsrc%5Etfw">
@ -207,16 +208,21 @@ const EmbedSection = () => (
</Styles.StyledSectionArea>
<div>
<Styles.StyledIframge
src="https://jsoncrack.com/widget"
src={`${baseURL}/widget`}
onLoad={e => {
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",
},
},
"*"

View File

@ -39,6 +39,11 @@ export const ShareModal: React.FC<ModalProps> = ({ visible, setVisible }) => {
setVisible(false);
};
const onEmbedClick = () => {
push("/embed");
setVisible(false);
}
return (
<Modal visible={visible} setVisible={setVisible}>
<Modal.Header>Create a Share Link</Modal.Header>
@ -55,7 +60,7 @@ export const ShareModal: React.FC<ModalProps> = ({ visible, setVisible }) => {
<StyledContainer>
Embed into your website
<StyledFlex>
<Button status="SUCCESS" onClick={() => push("/embed")} block>
<Button status="SUCCESS" onClick={onEmbedClick} block>
Learn How to Embed
</Button>
</StyledFlex>

View File

@ -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;
`;

View File

@ -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<any>(() => 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 (
<StyledDeprecated>
<h1> Deprecated </h1>
<br />
<a href="https://jsoncrack.com/embed" target="_blank" rel="noreferrer">
https://jsoncrack.com/embed
</a>
</StyledDeprecated>
);
}, [setGraph, theme]);
return (
<ThemeProvider theme={theme === "dark" ? darkTheme : lightTheme}>
<Graph openModal={openModal} setSelectedNode={setSelectedNode} isWidget />
<NodeModal
selectedNode={selectedNode}
visible={isModalVisible}
closeModal={() => setModalVisible(false)}
/>
<GraphCanvas isWidget />
<StyledAttribute href={`${baseURL}/editor`} target="_blank" rel="noreferrer">
jsoncrack.com
</StyledAttribute>

View File

@ -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<Graph>[]) => void;
setLoading: (loading: boolean) => void;
setDirection: (direction: CanvasDirection) => void;
setZoomPanPinch: (ref: ReactZoomPanPinchRef) => void;
@ -44,7 +43,7 @@ interface GraphActions {
const useGraph = create<Graph & GraphActions>((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<Graph & GraphActions>((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(

View File

@ -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<JsonStates & JsonActions>()((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<JsonStates & JsonActions>()((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);