mirror of
https://github.com/AykutSarac/jsoncrack.com.git
synced 2025-01-12 19:02:53 +08:00
Merge pull request #115 from AykutSarac/mobile-support
Add mobile support for JSON Crack
This commit is contained in:
commit
aab0265338
@ -20,7 +20,7 @@
|
||||
<p align="center">
|
||||
<i>Simple json visualization tool for your data.</i>
|
||||
<p align="center">
|
||||
<a href="https://www.producthunt.com/posts/json-visio?utm_source=badge-featured&utm_medium=badge&utm_souce=badge-json-visio" target="_blank"><img src="https://api.producthunt.com/widgets/embed-image/v1/featured.svg?post_id=332281&theme=light" alt="JSON Crack - Simple visualization tool for your JSON data. | Product Hunt" style="width: 250px; height: 54px;" width="250" height="54" /></a>
|
||||
<a href="https://www.producthunt.com/posts/json-crack?utm_source=badge-featured&utm_medium=badge&utm_souce=badge-json-crack" target="_blank"><img src="https://api.producthunt.com/widgets/embed-image/v1/featured.svg?post_id=332281&theme=light" alt="JSON Crack - Simple visualization tool for your JSON data. | Product Hunt" style="width: 250px; height: 54px;" width="250" height="54" /></a>
|
||||
</p>
|
||||
</p>
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "json-crack",
|
||||
"private": true,
|
||||
"version": "v2.0.0",
|
||||
"version": "v2.0.1",
|
||||
"author": "https://github.com/AykutSarac",
|
||||
"homepage": "https://jsoncrack.com",
|
||||
"scripts": {
|
||||
|
@ -16,7 +16,7 @@ export const Producthunt = () => {
|
||||
return (
|
||||
<StyledProducthuntWrapper>
|
||||
<a
|
||||
href="https://www.producthunt.com/posts/json-visio?utm_source=badge-featured&utm_medium=badge&utm_souce=badge-json-visio"
|
||||
href="https://www.producthunt.com/posts/json-crack?utm_source=badge-featured&utm_medium=badge&utm_souce=badge-json-crack"
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
>
|
||||
|
@ -12,6 +12,7 @@ import {
|
||||
AiOutlineSave,
|
||||
AiOutlineFileAdd,
|
||||
AiOutlineLink,
|
||||
AiOutlineEdit,
|
||||
} from "react-icons/ai";
|
||||
|
||||
import { Tooltip } from "src/components/Tooltip";
|
||||
@ -23,7 +24,7 @@ import useConfig from "src/hooks/store/useConfig";
|
||||
import { getNextLayout } from "src/containers/Editor/LiveEditor/helpers";
|
||||
import { HiHeart } from "react-icons/hi";
|
||||
import shallow from "zustand/shallow";
|
||||
import { IoAlertCircleSharp } from "react-icons/io5";
|
||||
import { MdCenterFocusWeak } from "react-icons/md";
|
||||
|
||||
const StyledSidebar = styled.div`
|
||||
display: flex;
|
||||
@ -34,6 +35,11 @@ const StyledSidebar = styled.div`
|
||||
background: ${({ theme }) => theme.BACKGROUND_TERTIARY};
|
||||
padding: 4px;
|
||||
border-right: 1px solid ${({ theme }) => theme.BACKGROUND_MODIFIER_ACCENT};
|
||||
|
||||
@media only screen and (max-width: 568px) {
|
||||
flex-direction: row;
|
||||
width: 100%;
|
||||
}
|
||||
`;
|
||||
|
||||
const StyledElement = styled.div<{ beta?: boolean }>`
|
||||
@ -80,6 +86,26 @@ const StyledTopWrapper = styled.nav`
|
||||
& > div:nth-child(n + 1) {
|
||||
border-bottom: 1px solid ${({ theme }) => theme.BACKGROUND_MODIFIER_ACCENT};
|
||||
}
|
||||
|
||||
.mobile {
|
||||
display: none;
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 568px) {
|
||||
flex-direction: row;
|
||||
|
||||
& > div:nth-child(n + 1) {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.mobile {
|
||||
display: initial;
|
||||
}
|
||||
|
||||
.desktop {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
const StyledBottomWrapper = styled.nav`
|
||||
@ -93,6 +119,10 @@ const StyledBottomWrapper = styled.nav`
|
||||
a:nth-child(0) {
|
||||
border-top: 1px solid ${({ theme }) => theme.BACKGROUND_MODIFIER_ACCENT};
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 568px) {
|
||||
display: none;
|
||||
}
|
||||
`;
|
||||
|
||||
const StyledLogo = styled.div`
|
||||
@ -109,13 +139,14 @@ function rotateLayout(layout: CanvasDirection) {
|
||||
export const Sidebar: React.FC = () => {
|
||||
const getJson = useConfig((state) => state.getJson);
|
||||
const setConfig = useConfig((state) => state.setConfig);
|
||||
const centerView = useConfig((state) => state.centerView);
|
||||
const [uploadVisible, setUploadVisible] = React.useState(false);
|
||||
const [clearVisible, setClearVisible] = React.useState(false);
|
||||
const [shareVisible, setShareVisible] = React.useState(false);
|
||||
const { push } = useRouter();
|
||||
|
||||
const [expand, layout] = useConfig(
|
||||
(state) => [state.expand, state.layout],
|
||||
const [expand, layout, hideEditor] = useConfig(
|
||||
(state) => [state.expand, state.layout, state.hideEditor],
|
||||
shallow
|
||||
);
|
||||
|
||||
@ -149,6 +180,11 @@ export const Sidebar: React.FC = () => {
|
||||
</StyledLogo>
|
||||
</StyledElement>
|
||||
</Link>
|
||||
<Tooltip className="mobile" title="Edit JSON">
|
||||
<StyledElement onClick={() => setConfig("hideEditor", !hideEditor)}>
|
||||
<AiOutlineEdit />
|
||||
</StyledElement>
|
||||
</Tooltip>
|
||||
<Tooltip title="Import File">
|
||||
<StyledElement onClick={() => setUploadVisible(true)}>
|
||||
<AiOutlineFileAdd />
|
||||
@ -159,7 +195,15 @@ export const Sidebar: React.FC = () => {
|
||||
<StyledFlowIcon rotate={rotateLayout(layout)} />
|
||||
</StyledElement>
|
||||
</Tooltip>
|
||||
<Tooltip title={expand ? "Shrink Nodes" : "Expand Nodes"}>
|
||||
<Tooltip className="mobile" title="Center View">
|
||||
<StyledElement onClick={centerView}>
|
||||
<MdCenterFocusWeak />
|
||||
</StyledElement>
|
||||
</Tooltip>
|
||||
<Tooltip
|
||||
className="desktop"
|
||||
title={expand ? "Shrink Nodes" : "Expand Nodes"}
|
||||
>
|
||||
<StyledElement
|
||||
title="Toggle Expand/Collapse"
|
||||
onClick={toggleExpandCollapse}
|
||||
@ -167,7 +211,7 @@ export const Sidebar: React.FC = () => {
|
||||
{expand ? <CgArrowsMergeAltH /> : <CgArrowsShrinkH />}
|
||||
</StyledElement>
|
||||
</Tooltip>
|
||||
<Tooltip title="Save JSON">
|
||||
<Tooltip className="desktop" title="Save JSON">
|
||||
<StyledElement onClick={handleSave}>
|
||||
<AiOutlineSave />
|
||||
</StyledElement>
|
||||
@ -177,7 +221,7 @@ export const Sidebar: React.FC = () => {
|
||||
<AiOutlineDelete />
|
||||
</StyledElement>
|
||||
</Tooltip>
|
||||
<Tooltip title="Share">
|
||||
<Tooltip className="desktop" title="Share">
|
||||
<StyledElement onClick={() => setShareVisible(true)}>
|
||||
<AiOutlineLink />
|
||||
</StyledElement>
|
||||
|
@ -1,7 +1,7 @@
|
||||
import React from "react";
|
||||
import styled from "styled-components";
|
||||
|
||||
interface TooltipProps {
|
||||
interface TooltipProps extends React.ComponentPropsWithoutRef<"div"> {
|
||||
title?: string;
|
||||
}
|
||||
|
||||
@ -41,6 +41,10 @@ const StyledTooltip = styled.div<{ visible: boolean }>`
|
||||
border-color: transparent ${({ theme }) => theme.BACKGROUND_PRIMARY}
|
||||
transparent transparent;
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 568px) {
|
||||
display: none;
|
||||
}
|
||||
`;
|
||||
|
||||
const StyledChildren = styled.div``;
|
||||
@ -48,11 +52,12 @@ const StyledChildren = styled.div``;
|
||||
export const Tooltip: React.FC<React.PropsWithChildren<TooltipProps>> = ({
|
||||
children,
|
||||
title,
|
||||
...props
|
||||
}) => {
|
||||
const [visible, setVisible] = React.useState(false);
|
||||
|
||||
return (
|
||||
<StyledTooltipWrapper>
|
||||
<StyledTooltipWrapper {...props}>
|
||||
{title && <StyledTooltip visible={visible}>{title}</StyledTooltip>}
|
||||
|
||||
<StyledChildren
|
||||
|
@ -10,6 +10,7 @@ const GlobalStyle = createGlobalStyle`
|
||||
font-weight: 400;
|
||||
font-size: 16px;
|
||||
scroll-behavior: smooth;
|
||||
height: 100%;
|
||||
|
||||
background-color: #000000;
|
||||
opacity: 1;
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { Allotment } from "allotment";
|
||||
import { Allotment, LayoutPriority } from "allotment";
|
||||
import React from "react";
|
||||
import { JsonEditor } from "src/containers/Editor/JsonEditor";
|
||||
import dynamic from "next/dynamic";
|
||||
@ -18,18 +18,19 @@ const LiveEditor = dynamic(() => import("src/containers/Editor/LiveEditor"), {
|
||||
|
||||
const Panes: React.FC = () => {
|
||||
const hideEditor = useConfig((state) => state.hideEditor);
|
||||
const isMobile = window.innerWidth <= 568;
|
||||
|
||||
return (
|
||||
<StyledEditor>
|
||||
<StyledEditor proportionalLayout={false} vertical={isMobile}>
|
||||
<Allotment.Pane
|
||||
preferredSize={400}
|
||||
minSize={300}
|
||||
maxSize={600}
|
||||
preferredSize={isMobile ? "100%" : 400}
|
||||
minSize={hideEditor ? 0 : 300}
|
||||
maxSize={isMobile ? Infinity : 500}
|
||||
visible={!hideEditor}
|
||||
>
|
||||
<JsonEditor />
|
||||
</Allotment.Pane>
|
||||
<Allotment.Pane>
|
||||
<Allotment.Pane minSize={0} maxSize={isMobile && !hideEditor ? 0 : Infinity}>
|
||||
<LiveEditor />
|
||||
</Allotment.Pane>
|
||||
</StyledEditor>
|
||||
|
@ -25,8 +25,11 @@ export const StyledTools = styled.div`
|
||||
padding: 4px 16px;
|
||||
background: ${({ theme }) => theme.BACKGROUND_PRIMARY};
|
||||
color: ${({ theme }) => theme.SILVER};
|
||||
|
||||
box-shadow: 0 1px 0px ${({ theme }) => theme.BACKGROUND_TERTIARY};
|
||||
|
||||
@media only screen and (max-width: 568px) {
|
||||
display: none;
|
||||
}
|
||||
`;
|
||||
|
||||
const StyledToolElement = styled.button`
|
||||
|
@ -60,11 +60,8 @@ const Home: React.FC = () => {
|
||||
<Styles.StyledMinorTitle>
|
||||
Paste - Import - Fetch!
|
||||
</Styles.StyledMinorTitle>
|
||||
<Styles.StyledButton
|
||||
onClick={() => window.location.replace("/editor")}
|
||||
disabled={isMobile}
|
||||
>
|
||||
{isMobile ? "Incompatible Device" : "GO TO EDITOR"}
|
||||
<Styles.StyledButton onClick={() => window.location.replace("/editor")}>
|
||||
GO TO EDITOR
|
||||
</Styles.StyledButton>
|
||||
|
||||
{!isMobile && (
|
||||
|
@ -1,46 +0,0 @@
|
||||
import { useRouter } from "next/router";
|
||||
import React from "react";
|
||||
import { Button } from "src/components/Button";
|
||||
import styled from "styled-components";
|
||||
|
||||
export const StyledIncompatible = styled.div`
|
||||
display: none;
|
||||
|
||||
@media only screen and (max-width: 568px) {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
background: ${({ theme }) => theme.BLACK_LIGHT};
|
||||
color: ${({ theme }) => theme.SILVER};
|
||||
width: 100%;
|
||||
height: 100vh;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
|
||||
button {
|
||||
margin-top: 60px;
|
||||
}
|
||||
|
||||
&::before {
|
||||
content: "Uh, oh!";
|
||||
font-weight: 600;
|
||||
font-size: 60px;
|
||||
opacity: 0.6;
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
export const Incompatible: React.FC = () => {
|
||||
const { push } = useRouter();
|
||||
|
||||
return (
|
||||
<StyledIncompatible>
|
||||
This app is not compatible with your device!
|
||||
<Button className="incompatible" onClick={() => push("/")}>
|
||||
Go Back
|
||||
</Button>
|
||||
</StyledIncompatible>
|
||||
);
|
||||
};
|
@ -3,20 +3,24 @@ import Head from "next/head";
|
||||
import styled from "styled-components";
|
||||
import Panes from "src/containers/Editor/Panes";
|
||||
import { Sidebar } from "src/components/Sidebar";
|
||||
import { Incompatible } from "src/containers/Incompatible";
|
||||
|
||||
export const StyledPageWrapper = styled.div`
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
height: 100vh;
|
||||
width: 100%;
|
||||
|
||||
@media only screen and (max-width: 568px) {
|
||||
position: fixed;
|
||||
height: -webkit-fill-available;
|
||||
flex-direction: column;
|
||||
}
|
||||
`;
|
||||
|
||||
export const StyledEditorWrapper = styled.div`
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
|
||||
@media only screen and (max-width: 568px) {
|
||||
display: none;
|
||||
}
|
||||
`;
|
||||
|
||||
const EditorPage: React.FC = () => {
|
||||
@ -34,7 +38,6 @@ const EditorPage: React.FC = () => {
|
||||
<StyledEditorWrapper>
|
||||
<Panes />
|
||||
</StyledEditorWrapper>
|
||||
<Incompatible />
|
||||
</StyledPageWrapper>
|
||||
</StyledEditorWrapper>
|
||||
);
|
||||
|
Loading…
x
Reference in New Issue
Block a user