Merge pull request #115 from AykutSarac/mobile-support

Add mobile support for JSON Crack
This commit is contained in:
Aykut Saraç 2022-08-30 16:03:53 +03:00 committed by GitHub
commit aab0265338
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 83 additions and 75 deletions

View File

@ -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&#0045;visio" target="_blank"><img src="https://api.producthunt.com/widgets/embed-image/v1/featured.svg?post_id=332281&theme=light" alt="JSON&#0032;Crack - Simple&#0032;visualization&#0032;tool&#0032;for&#0032;your&#0032;JSON&#0032;data&#0046; | 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&#0045;crack" target="_blank"><img src="https://api.producthunt.com/widgets/embed-image/v1/featured.svg?post_id=332281&theme=light" alt="JSON&#0032;Crack - Simple&#0032;visualization&#0032;tool&#0032;for&#0032;your&#0032;JSON&#0032;data&#0046; | Product Hunt" style="width: 250px; height: 54px;" width="250" height="54" /></a>
</p>
</p>

View File

@ -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": {

View File

@ -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&#0045;crack"
target="_blank"
rel="noreferrer"
>

View File

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

View File

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

View File

@ -10,6 +10,7 @@ const GlobalStyle = createGlobalStyle`
font-weight: 400;
font-size: 16px;
scroll-behavior: smooth;
height: 100%;
background-color: #000000;
opacity: 1;

View File

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

View File

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

View File

@ -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 && (

View File

@ -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>
);
};

View File

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