mirror of
https://github.com/AykutSarac/jsoncrack.com.git
synced 2025-02-04 01:32:54 +08:00
feat: UI improvements
This commit is contained in:
parent
b83917c6bb
commit
e6cb91bb74
32
src/components/Loading/index.tsx
Normal file
32
src/components/Loading/index.tsx
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
import React from "react";
|
||||||
|
import { useRouter } from "next/router";
|
||||||
|
import { LoadingOverlay } from "@mantine/core";
|
||||||
|
|
||||||
|
export const Loading = () => {
|
||||||
|
const router = useRouter();
|
||||||
|
const [loading, setLoading] = React.useState(false);
|
||||||
|
|
||||||
|
React.useEffect(() => {
|
||||||
|
const handleStart = (url: string) => {
|
||||||
|
return url !== router.asPath && url === "/editor" && setLoading(true);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleComplete = (url: string) => url === router.asPath && setLoading(false);
|
||||||
|
|
||||||
|
router.events.on("routeChangeStart", handleStart);
|
||||||
|
router.events.on("routeChangeComplete", handleComplete);
|
||||||
|
router.events.on("routeChangeError", handleComplete);
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
router.events.off("routeChangeStart", handleStart);
|
||||||
|
router.events.off("routeChangeComplete", handleComplete);
|
||||||
|
router.events.off("routeChangeError", handleComplete);
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
if (loading) {
|
||||||
|
return <LoadingOverlay visible loaderProps={{ color: "orange", type: "oval" }} />;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
};
|
@ -1,7 +1,7 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
|
import { LoadingOverlay } from "@mantine/core";
|
||||||
import styled from "styled-components";
|
import styled from "styled-components";
|
||||||
import Editor, { loader, useMonaco } from "@monaco-editor/react";
|
import Editor, { loader, useMonaco } from "@monaco-editor/react";
|
||||||
import { Loading } from "src/layout/Loading";
|
|
||||||
import useConfig from "src/store/useConfig";
|
import useConfig from "src/store/useConfig";
|
||||||
import useFile from "src/store/useFile";
|
import useFile from "src/store/useFile";
|
||||||
|
|
||||||
@ -81,7 +81,7 @@ export const MonacoEditor = () => {
|
|||||||
options={editorOptions}
|
options={editorOptions}
|
||||||
onValidate={errors => setError(errors[0]?.message)}
|
onValidate={errors => setError(errors[0]?.message)}
|
||||||
onChange={contents => setContents({ contents, skipUpdate: true })}
|
onChange={contents => setContents({ contents, skipUpdate: true })}
|
||||||
loading={<Loading message="Loading Monaco Editor..." loading />}
|
loading={<LoadingOverlay visible />}
|
||||||
/>
|
/>
|
||||||
</StyledWrapper>
|
</StyledWrapper>
|
||||||
);
|
);
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import { Menu, Text } from "@mantine/core";
|
|
||||||
import styled from "styled-components";
|
import styled from "styled-components";
|
||||||
import { firaMono } from "src/constants/fonts";
|
import { firaMono } from "src/constants/fonts";
|
||||||
import { Graph } from "src/containers/Views/GraphView";
|
import { Graph } from "src/containers/Views/GraphView";
|
||||||
@ -32,44 +31,8 @@ const View = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const LiveEditor: React.FC = () => {
|
const LiveEditor: React.FC = () => {
|
||||||
const [contextOpened, setContextOpened] = React.useState(false);
|
|
||||||
const [contextPosition, setContextPosition] = React.useState({
|
|
||||||
x: 0,
|
|
||||||
y: 0,
|
|
||||||
});
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<StyledLiveEditor
|
<StyledLiveEditor onContextMenuCapture={e => e.preventDefault()}>
|
||||||
onContextMenuCapture={e => {
|
|
||||||
e.preventDefault();
|
|
||||||
setContextOpened(true);
|
|
||||||
setContextPosition({ x: e.pageX, y: e.pageY });
|
|
||||||
}}
|
|
||||||
onClick={() => setContextOpened(false)}
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
position: "fixed",
|
|
||||||
top: contextPosition.y,
|
|
||||||
left: contextPosition.x,
|
|
||||||
zIndex: 100,
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Menu opened={false} shadow="sm">
|
|
||||||
<Menu.Dropdown>
|
|
||||||
<Menu.Item>
|
|
||||||
<Text size="xs">Download as Image</Text>
|
|
||||||
</Menu.Item>
|
|
||||||
<Menu.Item>
|
|
||||||
<Text size="xs">Zoom to Fit</Text>
|
|
||||||
</Menu.Item>
|
|
||||||
<Menu.Item>
|
|
||||||
<Text size="xs">Rotate</Text>
|
|
||||||
</Menu.Item>
|
|
||||||
</Menu.Dropdown>
|
|
||||||
</Menu>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<View />
|
<View />
|
||||||
</StyledLiveEditor>
|
</StyledLiveEditor>
|
||||||
);
|
);
|
||||||
|
@ -55,41 +55,34 @@ export const TypeModal: React.FC<ModalProps> = ({ opened, onClose }) => {
|
|||||||
return typeOptions[typeOptions.findIndex(o => o.value === selectedType)]?.lang;
|
return typeOptions[typeOptions.findIndex(o => o.value === selectedType)]?.lang;
|
||||||
}, [selectedType]);
|
}, [selectedType]);
|
||||||
|
|
||||||
const transformer = React.useCallback(
|
|
||||||
async ({ value }) => {
|
|
||||||
const { run } = await import("json_typegen_wasm");
|
|
||||||
return run(
|
|
||||||
"Root",
|
|
||||||
value,
|
|
||||||
JSON.stringify({
|
|
||||||
output_mode: selectedType,
|
|
||||||
})
|
|
||||||
);
|
|
||||||
},
|
|
||||||
[selectedType]
|
|
||||||
);
|
|
||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
if (opened) {
|
if (opened) {
|
||||||
try {
|
(async () => {
|
||||||
setLoading(true);
|
try {
|
||||||
if (selectedType === Language.Go) {
|
setLoading(true);
|
||||||
import("src/lib/utils/json2go").then(jtg => {
|
const json = getJson();
|
||||||
import("gofmt.js").then(gofmt => {
|
|
||||||
const types = jtg.default(getJson());
|
if (selectedType === Language.Go) {
|
||||||
setType(gofmt.default(types.go));
|
const jtg = await import("src/lib/utils/json2go");
|
||||||
});
|
const gofmt = await import("gofmt.js");
|
||||||
});
|
|
||||||
} else {
|
const types = jtg.default(json);
|
||||||
transformer({ value: getJson() }).then(setType);
|
setType(gofmt.default(types.go));
|
||||||
|
} else {
|
||||||
|
const { run } = await import("json_typegen_wasm");
|
||||||
|
const output_mode = selectedType;
|
||||||
|
const types = run("Root", json, JSON.stringify({ output_mode }));
|
||||||
|
|
||||||
|
setType(types);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error);
|
||||||
|
} finally {
|
||||||
|
setLoading(false);
|
||||||
}
|
}
|
||||||
} catch (error) {
|
})();
|
||||||
console.error(error);
|
|
||||||
} finally {
|
|
||||||
setLoading(false);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}, [getJson, opened, selectedType, transformer]);
|
}, [getJson, opened, selectedType]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Modal title="Generate Types" size="md" opened={opened} onClose={onClose} centered>
|
<Modal title="Generate Types" size="md" opened={opened} onClose={onClose} centered>
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import { Badge, Flex, Group, Select, Text } from "@mantine/core";
|
import { Badge, Flex, Group, Indicator, Select, Text } from "@mantine/core";
|
||||||
|
import { useSessionStorage } from "@mantine/hooks";
|
||||||
import toast from "react-hot-toast";
|
import toast from "react-hot-toast";
|
||||||
import { AiOutlineFullscreen } from "react-icons/ai";
|
import { AiOutlineFullscreen } from "react-icons/ai";
|
||||||
import { AiFillGift } from "react-icons/ai";
|
import { AiFillGift } from "react-icons/ai";
|
||||||
@ -35,6 +36,10 @@ export const Toolbar: React.FC<{ isWidget?: boolean }> = ({ isWidget = false })
|
|||||||
const setFormat = useFile(state => state.setFormat);
|
const setFormat = useFile(state => state.setFormat);
|
||||||
const format = useFile(state => state.format);
|
const format = useFile(state => state.format);
|
||||||
const premium = useUser(state => state.premium);
|
const premium = useUser(state => state.premium);
|
||||||
|
const [seenPremium, setSeenPremium] = useSessionStorage({
|
||||||
|
key: "seenPremium",
|
||||||
|
defaultValue: false,
|
||||||
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Styles.StyledTools>
|
<Styles.StyledTools>
|
||||||
@ -74,11 +79,30 @@ export const Toolbar: React.FC<{ isWidget?: boolean }> = ({ isWidget = false })
|
|||||||
)}
|
)}
|
||||||
<Group gap="xs" justify="right" w="100%" style={{ flexWrap: "nowrap" }}>
|
<Group gap="xs" justify="right" w="100%" style={{ flexWrap: "nowrap" }}>
|
||||||
{!premium && !isWidget && (
|
{!premium && !isWidget && (
|
||||||
<Styles.StyledToolElement onClick={() => setVisible("premium")(true)}>
|
<Styles.StyledToolElement
|
||||||
<Text display="flex" c="teal" fz="xs" fw={600} style={{ textAlign: "center", gap: 4 }}>
|
onClick={() => {
|
||||||
<AiFillGift size="18" />
|
setSeenPremium(true);
|
||||||
Get Premium
|
setVisible("premium")(true);
|
||||||
</Text>
|
}}
|
||||||
|
>
|
||||||
|
<Indicator
|
||||||
|
size={5}
|
||||||
|
color="green"
|
||||||
|
position="top-start"
|
||||||
|
processing
|
||||||
|
disabled={seenPremium}
|
||||||
|
>
|
||||||
|
<Text
|
||||||
|
display="flex"
|
||||||
|
c="teal"
|
||||||
|
fz="xs"
|
||||||
|
fw={600}
|
||||||
|
style={{ textAlign: "center", gap: 4 }}
|
||||||
|
>
|
||||||
|
<AiFillGift size="18" />
|
||||||
|
Get Premium
|
||||||
|
</Text>
|
||||||
|
</Indicator>
|
||||||
</Styles.StyledToolElement>
|
</Styles.StyledToolElement>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
@ -1,10 +1,5 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import dynamic from "next/dynamic";
|
import { Edge, EdgeProps } from "reaflow";
|
||||||
import { EdgeProps } from "reaflow/dist/symbols/Edge";
|
|
||||||
|
|
||||||
const Edge = dynamic(() => import("reaflow").then(r => r.Edge), {
|
|
||||||
ssr: false,
|
|
||||||
});
|
|
||||||
|
|
||||||
const CustomEdgeWrapper = (props: EdgeProps) => {
|
const CustomEdgeWrapper = (props: EdgeProps) => {
|
||||||
return <Edge containerClassName={`edge-${props.id}`} {...props} />;
|
return <Edge containerClassName={`edge-${props.id}`} {...props} />;
|
||||||
|
@ -1,16 +1,11 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import dynamic from "next/dynamic";
|
import { Node, NodeProps } from "reaflow";
|
||||||
import { NodeProps } from "reaflow";
|
|
||||||
import useGraph from "src/store/useGraph";
|
import useGraph from "src/store/useGraph";
|
||||||
import useModal from "src/store/useModal";
|
import useModal from "src/store/useModal";
|
||||||
import { NodeData } from "src/types/graph";
|
import { NodeData } from "src/types/graph";
|
||||||
import { ObjectNode } from "./ObjectNode";
|
import { ObjectNode } from "./ObjectNode";
|
||||||
import { TextNode } from "./TextNode";
|
import { TextNode } from "./TextNode";
|
||||||
|
|
||||||
const Node = dynamic(() => import("reaflow").then(r => r.Node), {
|
|
||||||
ssr: false,
|
|
||||||
});
|
|
||||||
|
|
||||||
export interface CustomNodeProps {
|
export interface CustomNodeProps {
|
||||||
node: NodeData;
|
node: NodeData;
|
||||||
x: number;
|
x: number;
|
||||||
|
@ -1,22 +1,18 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import dynamic from "next/dynamic";
|
import { LoadingOverlay } from "@mantine/core";
|
||||||
import styled from "styled-components";
|
import styled from "styled-components";
|
||||||
import debounce from "lodash.debounce";
|
import debounce from "lodash.debounce";
|
||||||
import { Space } from "react-zoomable-ui";
|
import { Space } from "react-zoomable-ui";
|
||||||
|
import { Canvas } from "reaflow";
|
||||||
import { ElkRoot } from "reaflow/dist/layout/useLayout";
|
import { ElkRoot } from "reaflow/dist/layout/useLayout";
|
||||||
import { useLongPress } from "use-long-press";
|
import { useLongPress } from "use-long-press";
|
||||||
import { CustomNode } from "src/containers/Views/GraphView/CustomNode";
|
import { CustomNode } from "src/containers/Views/GraphView/CustomNode";
|
||||||
import useToggleHide from "src/hooks/useToggleHide";
|
import useToggleHide from "src/hooks/useToggleHide";
|
||||||
import { Loading } from "src/layout/Loading";
|
|
||||||
import useConfig from "src/store/useConfig";
|
import useConfig from "src/store/useConfig";
|
||||||
import useGraph from "src/store/useGraph";
|
import useGraph from "src/store/useGraph";
|
||||||
import { CustomEdge } from "./CustomEdge";
|
import { CustomEdge } from "./CustomEdge";
|
||||||
import { PremiumView } from "./PremiumView";
|
import { PremiumView } from "./PremiumView";
|
||||||
|
|
||||||
const Canvas = dynamic(() => import("reaflow").then(r => r.Canvas), {
|
|
||||||
ssr: false,
|
|
||||||
});
|
|
||||||
|
|
||||||
interface GraphProps {
|
interface GraphProps {
|
||||||
isWidget?: boolean;
|
isWidget?: boolean;
|
||||||
}
|
}
|
||||||
@ -175,7 +171,7 @@ export const Graph = ({ isWidget = false }: GraphProps) => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Loading loading={loading} message="Painting graph..." />
|
<LoadingOverlay visible={loading} />
|
||||||
<StyledEditorWrapper
|
<StyledEditorWrapper
|
||||||
$widget={isWidget}
|
$widget={isWidget}
|
||||||
onContextMenu={e => e.preventDefault()}
|
onContextMenu={e => e.preventDefault()}
|
||||||
|
@ -1,57 +0,0 @@
|
|||||||
import React from "react";
|
|
||||||
import { Center, Stack, Text } from "@mantine/core";
|
|
||||||
import styled, { keyframes } from "styled-components";
|
|
||||||
import { JSONCrackLogo } from "../JsonCrackLogo";
|
|
||||||
|
|
||||||
interface LoadingProps {
|
|
||||||
loading?: boolean;
|
|
||||||
message?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
const fadeIn = keyframes`
|
|
||||||
99% {
|
|
||||||
visibility: hidden;
|
|
||||||
}
|
|
||||||
100% {
|
|
||||||
visibility: visible;
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
|
|
||||||
const StyledLoading = styled.div<{ $visible: boolean }>`
|
|
||||||
display: ${({ $visible }) => ($visible ? "grid" : "none")};
|
|
||||||
position: fixed;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
place-content: center;
|
|
||||||
width: 100%;
|
|
||||||
height: 100vh;
|
|
||||||
text-align: center;
|
|
||||||
z-index: 100;
|
|
||||||
pointer-events: visiblePainted;
|
|
||||||
animation: 200ms ${fadeIn};
|
|
||||||
animation-fill-mode: forwards;
|
|
||||||
visibility: hidden;
|
|
||||||
background: ${({ theme }) => theme.BACKGROUND_NODE};
|
|
||||||
opacity: 0.8;
|
|
||||||
color: ${({ theme }) => theme.INTERACTIVE_HOVER};
|
|
||||||
cursor: wait;
|
|
||||||
|
|
||||||
img {
|
|
||||||
transform: rotate(45deg);
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
|
|
||||||
export const Loading = ({ loading = false, message }: LoadingProps) => {
|
|
||||||
return (
|
|
||||||
<Center mx="auto">
|
|
||||||
<StyledLoading $visible={loading}>
|
|
||||||
<Stack>
|
|
||||||
<JSONCrackLogo fontSize="3rem" />
|
|
||||||
<Text fz="lg" fw="bold">
|
|
||||||
{message ?? "Preparing the environment for you..."}
|
|
||||||
</Text>
|
|
||||||
</Stack>
|
|
||||||
</StyledLoading>
|
|
||||||
</Center>
|
|
||||||
);
|
|
||||||
};
|
|
@ -1,6 +1,6 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import { Box, Burger, Button, Flex, Overlay } from "@mantine/core";
|
import { Button } from "@mantine/core";
|
||||||
import { useDisclosure } from "@mantine/hooks";
|
import { useDisclosure } from "@mantine/hooks";
|
||||||
import styled from "styled-components";
|
import styled from "styled-components";
|
||||||
import useUser from "src/store/useUser";
|
import useUser from "src/store/useUser";
|
||||||
@ -26,18 +26,6 @@ const StyledNavbar = styled.nav`
|
|||||||
@media only screen and (max-width: 768px) {
|
@media only screen and (max-width: 768px) {
|
||||||
padding: 16px 24px;
|
padding: 16px 24px;
|
||||||
}
|
}
|
||||||
|
|
||||||
@media only screen and (max-width: 1024px) {
|
|
||||||
.desktop {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@media only screen and (max-width: 768px) {
|
|
||||||
.hide-mobile {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const Left = styled.div``;
|
const Left = styled.div``;
|
||||||
@ -98,74 +86,28 @@ export const Navbar = () => {
|
|||||||
</Button>
|
</Button>
|
||||||
</Left>
|
</Left>
|
||||||
<Right>
|
<Right>
|
||||||
{!hasSession && (
|
<Button
|
||||||
<>
|
component="a"
|
||||||
<Button
|
href="https://app.jsoncrack.com/sign-in"
|
||||||
component="a"
|
variant="subtle"
|
||||||
href="https://app.jsoncrack.com/sign-in"
|
color="gray"
|
||||||
variant="outline"
|
radius="xl"
|
||||||
color="gray"
|
visibleFrom="sm"
|
||||||
className="hide-mobile"
|
size="md"
|
||||||
radius="md"
|
>
|
||||||
visibleFrom="sm"
|
Login
|
||||||
size="md"
|
</Button>
|
||||||
>
|
<Button
|
||||||
Login
|
component={Link}
|
||||||
</Button>
|
prefetch={false}
|
||||||
<Button
|
href={premium ? "https://app.jsoncrack.com/editor" : "/editor"}
|
||||||
component={Link}
|
color="dark"
|
||||||
prefetch={false}
|
visibleFrom="sm"
|
||||||
href={premium ? "https://app.jsoncrack.com/editor" : "/editor"}
|
radius="xl"
|
||||||
color="dark"
|
size="md"
|
||||||
className="hide-mobile"
|
>
|
||||||
visibleFrom="sm"
|
Editor
|
||||||
radius="md"
|
</Button>
|
||||||
size="md"
|
|
||||||
>
|
|
||||||
Editor
|
|
||||||
</Button>
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
{hasSession && (
|
|
||||||
<Button
|
|
||||||
color="dark"
|
|
||||||
size="md"
|
|
||||||
radius="md"
|
|
||||||
component={Link}
|
|
||||||
href="/editor"
|
|
||||||
prefetch={false}
|
|
||||||
visibleFrom="sm"
|
|
||||||
>
|
|
||||||
Editor
|
|
||||||
</Button>
|
|
||||||
)}
|
|
||||||
<Burger opened={opened} onClick={toggle} aria-label="Toggle navigation" hiddenFrom="sm" />
|
|
||||||
{opened && (
|
|
||||||
<Overlay top={56} h="100dvh">
|
|
||||||
<Box
|
|
||||||
bg="white"
|
|
||||||
top={56}
|
|
||||||
left={0}
|
|
||||||
pos="fixed"
|
|
||||||
w="100%"
|
|
||||||
pb="lg"
|
|
||||||
style={{ zIndex: 3, borderBottom: "1px solid black" }}
|
|
||||||
>
|
|
||||||
<Flex pt="lg" direction="column" align="center" justify="center" gap="lg">
|
|
||||||
<Button
|
|
||||||
component={Link}
|
|
||||||
href="/pricing"
|
|
||||||
variant="transparent"
|
|
||||||
color="dark"
|
|
||||||
radius="md"
|
|
||||||
onClick={toggle}
|
|
||||||
>
|
|
||||||
Pricing
|
|
||||||
</Button>
|
|
||||||
</Flex>
|
|
||||||
</Box>
|
|
||||||
</Overlay>
|
|
||||||
)}
|
|
||||||
</Right>
|
</Right>
|
||||||
</StyledNavbar>
|
</StyledNavbar>
|
||||||
</StyledNavbarWrapper>
|
</StyledNavbarWrapper>
|
||||||
|
@ -8,12 +8,14 @@ import "@mantine/core/styles.css";
|
|||||||
import "@mantine/code-highlight/styles.css";
|
import "@mantine/code-highlight/styles.css";
|
||||||
import { ThemeProvider } from "styled-components";
|
import { ThemeProvider } from "styled-components";
|
||||||
import ReactGA from "react-ga4";
|
import ReactGA from "react-ga4";
|
||||||
|
import { Loading } from "src/components/Loading";
|
||||||
import GlobalStyle from "src/constants/globalStyle";
|
import GlobalStyle from "src/constants/globalStyle";
|
||||||
import { lightTheme } from "src/constants/theme";
|
import { lightTheme } from "src/constants/theme";
|
||||||
import { supabase } from "src/lib/api/supabase";
|
import { supabase } from "src/lib/api/supabase";
|
||||||
import useUser from "src/store/useUser";
|
import useUser from "src/store/useUser";
|
||||||
|
|
||||||
const Toaster = dynamic(() => import("react-hot-toast").then(c => c.Toaster));
|
const Toaster = dynamic(() => import("react-hot-toast").then(c => c.Toaster));
|
||||||
|
const ExternalMode = dynamic(() => import("src/layout/ExternalMode"));
|
||||||
|
|
||||||
const mantineTheme = createTheme({
|
const mantineTheme = createTheme({
|
||||||
primaryShade: 8,
|
primaryShade: 8,
|
||||||
@ -24,8 +26,6 @@ const GA_TRACKING_ID = process.env.NEXT_PUBLIC_GA_ID;
|
|||||||
|
|
||||||
ReactGA.initialize(GA_TRACKING_ID, { testMode: isDevelopment });
|
ReactGA.initialize(GA_TRACKING_ID, { testMode: isDevelopment });
|
||||||
|
|
||||||
const ExternalMode = dynamic(() => import("src/layout/ExternalMode"));
|
|
||||||
|
|
||||||
function JsonCrack({ Component, pageProps }: AppProps) {
|
function JsonCrack({ Component, pageProps }: AppProps) {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const setSession = useUser(state => state.setSession);
|
const setSession = useUser(state => state.setSession);
|
||||||
@ -72,6 +72,7 @@ function JsonCrack({ Component, pageProps }: AppProps) {
|
|||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<GlobalStyle />
|
<GlobalStyle />
|
||||||
|
<Loading />
|
||||||
<Component {...pageProps} />
|
<Component {...pageProps} />
|
||||||
<ExternalMode />
|
<ExternalMode />
|
||||||
</ThemeProvider>
|
</ThemeProvider>
|
||||||
|
@ -1,16 +1,12 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import dynamic from "next/dynamic";
|
|
||||||
import Head from "next/head";
|
import Head from "next/head";
|
||||||
import { useRouter } from "next/router";
|
import { useRouter } from "next/router";
|
||||||
import styled from "styled-components";
|
import styled from "styled-components";
|
||||||
import { BottomBar } from "src/containers/Editor/BottomBar";
|
import { BottomBar } from "src/containers/Editor/BottomBar";
|
||||||
|
import Panes from "src/containers/Editor/Panes";
|
||||||
import { Toolbar } from "src/containers/Toolbar";
|
import { Toolbar } from "src/containers/Toolbar";
|
||||||
import { EditorWrapper } from "src/layout/EditorWrapper";
|
import { EditorWrapper } from "src/layout/EditorWrapper";
|
||||||
import { Loading } from "src/layout/Loading";
|
|
||||||
import useFile from "src/store/useFile";
|
import useFile from "src/store/useFile";
|
||||||
import useJson from "src/store/useJson";
|
|
||||||
|
|
||||||
const Panes = dynamic(() => import("src/containers/Editor/Panes"));
|
|
||||||
|
|
||||||
export const StyledPageWrapper = styled.div`
|
export const StyledPageWrapper = styled.div`
|
||||||
height: calc(100vh - 27px);
|
height: calc(100vh - 27px);
|
||||||
@ -29,7 +25,6 @@ export const StyledEditorWrapper = styled.div`
|
|||||||
|
|
||||||
const EditorPage: React.FC = () => {
|
const EditorPage: React.FC = () => {
|
||||||
const { query, isReady } = useRouter();
|
const { query, isReady } = useRouter();
|
||||||
const loading = useJson(state => state.loading);
|
|
||||||
const hasQuery = React.useMemo(() => Object.keys(query).length > 0, [query]);
|
const hasQuery = React.useMemo(() => Object.keys(query).length > 0, [query]);
|
||||||
const checkEditorSession = useFile(state => state.checkEditorSession);
|
const checkEditorSession = useFile(state => state.checkEditorSession);
|
||||||
|
|
||||||
@ -37,24 +32,13 @@ const EditorPage: React.FC = () => {
|
|||||||
if (isReady) checkEditorSession(query?.json);
|
if (isReady) checkEditorSession(query?.json);
|
||||||
}, [checkEditorSession, isReady, query]);
|
}, [checkEditorSession, isReady, query]);
|
||||||
|
|
||||||
if (loading) {
|
|
||||||
return (
|
|
||||||
<StyledEditorWrapper>
|
|
||||||
<Head>
|
|
||||||
<title>Editor | JSON Crack</title>
|
|
||||||
{hasQuery && <meta name="robots" content="noindex,nofollow" />}
|
|
||||||
</Head>
|
|
||||||
<Loading message="Preparing the editor for you..." loading />
|
|
||||||
</StyledEditorWrapper>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<EditorWrapper>
|
<EditorWrapper>
|
||||||
<StyledEditorWrapper>
|
<StyledEditorWrapper>
|
||||||
<Head>
|
<Head>
|
||||||
<title>Editor | JSON Crack</title>
|
<title>Editor | JSON Crack</title>
|
||||||
<link rel="canonical" href="https://jsoncrack.com/editor" />
|
<link rel="canonical" href="https://jsoncrack.com/editor" />
|
||||||
|
{hasQuery && <meta name="robots" content="noindex,nofollow" />}
|
||||||
</Head>
|
</Head>
|
||||||
<StyledPageWrapper>
|
<StyledPageWrapper>
|
||||||
<Toolbar />
|
<Toolbar />
|
||||||
|
@ -8,7 +8,6 @@ import {
|
|||||||
Center,
|
Center,
|
||||||
Flex,
|
Flex,
|
||||||
Grid,
|
Grid,
|
||||||
Group,
|
|
||||||
Image,
|
Image,
|
||||||
Paper,
|
Paper,
|
||||||
Stack,
|
Stack,
|
||||||
@ -21,7 +20,6 @@ import { Carousel } from "@mantine/carousel";
|
|||||||
import "@mantine/carousel/styles.css";
|
import "@mantine/carousel/styles.css";
|
||||||
import styled from "styled-components";
|
import styled from "styled-components";
|
||||||
import { BiChevronDown } from "react-icons/bi";
|
import { BiChevronDown } from "react-icons/bi";
|
||||||
import { FaRocket } from "react-icons/fa";
|
|
||||||
import {
|
import {
|
||||||
MdChevronRight,
|
MdChevronRight,
|
||||||
MdCompare,
|
MdCompare,
|
||||||
@ -78,19 +76,19 @@ const StyledHeroSectionBody = styled.div`
|
|||||||
|
|
||||||
const StyledHeroText = styled.p`
|
const StyledHeroText = styled.p`
|
||||||
font-size: 0.8rem;
|
font-size: 0.8rem;
|
||||||
color: #414141;
|
color: #5b5b5b;
|
||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
max-width: 100%;
|
max-width: 100%;
|
||||||
min-width: 400px;
|
min-width: 400px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
|
||||||
@media only screen and (min-width: 576px) {
|
@media only screen and (min-width: 576px) {
|
||||||
font-size: 1.3rem;
|
font-size: 1.2rem;
|
||||||
max-width: 80%;
|
max-width: 80%;
|
||||||
}
|
}
|
||||||
|
|
||||||
@media only screen and (min-width: 1400px) {
|
@media only screen and (min-width: 1400px) {
|
||||||
font-size: 1.4rem;
|
font-size: 1.3rem;
|
||||||
max-width: 60%;
|
max-width: 60%;
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
@ -212,77 +210,51 @@ export const HomePage = () => {
|
|||||||
Experience the ultimate online editor designed to empower you in visualizing,
|
Experience the ultimate online editor designed to empower you in visualizing,
|
||||||
refining, and formatting data effortlessly.
|
refining, and formatting data effortlessly.
|
||||||
</StyledHeroText>
|
</StyledHeroText>
|
||||||
<Group justify="center">
|
|
||||||
<Button
|
|
||||||
component={Link}
|
|
||||||
prefetch={false}
|
|
||||||
href="/editor"
|
|
||||||
size="xl"
|
|
||||||
fw="bold"
|
|
||||||
color="indigo"
|
|
||||||
rightSection={<MdChevronRight size={30} />}
|
|
||||||
visibleFrom="sm"
|
|
||||||
radius="md"
|
|
||||||
>
|
|
||||||
Go To Editor
|
|
||||||
</Button>
|
|
||||||
<Button
|
|
||||||
component={Link}
|
|
||||||
prefetch={false}
|
|
||||||
href="/editor"
|
|
||||||
fw="bold"
|
|
||||||
size="md"
|
|
||||||
color="indigo"
|
|
||||||
rightSection={<MdChevronRight size={24} />}
|
|
||||||
hiddenFrom="sm"
|
|
||||||
radius="md"
|
|
||||||
>
|
|
||||||
Go To Editor
|
|
||||||
</Button>
|
|
||||||
<Button
|
|
||||||
component="a"
|
|
||||||
href="/#features"
|
|
||||||
size="xl"
|
|
||||||
fw="bold"
|
|
||||||
variant="outline"
|
|
||||||
color="gray.7"
|
|
||||||
leftSection={<FaRocket />}
|
|
||||||
visibleFrom="sm"
|
|
||||||
radius="md"
|
|
||||||
>
|
|
||||||
Explore Premium
|
|
||||||
</Button>
|
|
||||||
<Button
|
|
||||||
component="a"
|
|
||||||
href="/#features"
|
|
||||||
fw="bold"
|
|
||||||
size="md"
|
|
||||||
variant="outline"
|
|
||||||
color="gray.7"
|
|
||||||
leftSection={<FaRocket />}
|
|
||||||
hiddenFrom="sm"
|
|
||||||
radius="md"
|
|
||||||
>
|
|
||||||
Explore Premium
|
|
||||||
</Button>
|
|
||||||
</Group>
|
|
||||||
<Flex gap="xs">
|
<Flex gap="xs">
|
||||||
<Badge color="dark" radius="sm" variant="light">
|
<Badge size="xs" color="dark" radius="sm" variant="light">
|
||||||
JSON
|
JSON
|
||||||
</Badge>
|
</Badge>
|
||||||
<Badge color="dark" radius="sm" variant="light">
|
<Badge size="xs" color="dark" radius="sm" variant="light">
|
||||||
YAML
|
YAML
|
||||||
</Badge>
|
</Badge>
|
||||||
<Badge color="dark" radius="sm" variant="light">
|
<Badge size="xs" color="dark" radius="sm" variant="light">
|
||||||
CSV
|
CSV
|
||||||
</Badge>
|
</Badge>
|
||||||
<Badge color="dark" radius="sm" variant="light">
|
<Badge size="xs" color="dark" radius="sm" variant="light">
|
||||||
XML
|
XML
|
||||||
</Badge>
|
</Badge>
|
||||||
<Badge color="dark" radius="sm" variant="light">
|
<Badge size="xs" color="dark" radius="sm" variant="light">
|
||||||
TOML
|
TOML
|
||||||
</Badge>
|
</Badge>
|
||||||
</Flex>
|
</Flex>
|
||||||
|
<Button
|
||||||
|
component={Link}
|
||||||
|
prefetch={false}
|
||||||
|
href="/editor"
|
||||||
|
size="xl"
|
||||||
|
fw="bold"
|
||||||
|
color="orange"
|
||||||
|
rightSection={<MdChevronRight size={30} />}
|
||||||
|
visibleFrom="sm"
|
||||||
|
radius="xl"
|
||||||
|
mt="lg"
|
||||||
|
>
|
||||||
|
Go to Editor
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
component={Link}
|
||||||
|
prefetch={false}
|
||||||
|
href="/editor"
|
||||||
|
fw="bold"
|
||||||
|
size="md"
|
||||||
|
color="indigo"
|
||||||
|
rightSection={<MdChevronRight size={24} />}
|
||||||
|
hiddenFrom="sm"
|
||||||
|
radius="xl"
|
||||||
|
mt="lg"
|
||||||
|
>
|
||||||
|
Go to Editor
|
||||||
|
</Button>
|
||||||
</Stack>
|
</Stack>
|
||||||
</StyledHeroSectionBody>
|
</StyledHeroSectionBody>
|
||||||
</StyledHeroSection>
|
</StyledHeroSection>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user