mirror of
https://github.com/AykutSarac/jsoncrack.com.git
synced 2025-01-12 19:02:53 +08:00
new design implementations
This commit is contained in:
parent
5ca31703a6
commit
4f74321303
@ -28,14 +28,31 @@ const StyledButton = styled.button<{
|
||||
color: #ffffff;
|
||||
padding: 8px 16px;
|
||||
min-width: 60px;
|
||||
min-height: 32px;
|
||||
border-radius: 3px;
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
font-family: "Catamaran", sans-serif;
|
||||
width: ${({ block }) => (block ? "100%" : "fit-content")};
|
||||
height: 40px;
|
||||
background-image: none;
|
||||
|
||||
:disabled {
|
||||
cursor: not-allowed;
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
div {
|
||||
white-space: normal;
|
||||
margin: 0 auto;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background-image: linear-gradient(rgba(0, 0, 0, 0.1) 0 0);
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 768px) {
|
||||
font-size: 14px;
|
||||
}
|
||||
|
@ -12,6 +12,7 @@ const StyledErrorWrapper = styled.div`
|
||||
`;
|
||||
|
||||
const StyledErrorExpand = styled.button<{ error: boolean }>`
|
||||
position: relative;
|
||||
display: flex;
|
||||
width: 100%;
|
||||
padding: 4px 16px;
|
||||
@ -25,10 +26,10 @@ const StyledErrorExpand = styled.button<{ error: boolean }>`
|
||||
background: ${({ theme }) => theme.BACKGROUND_SECONDARY};
|
||||
box-shadow: 0 1px 0px ${({ theme }) => theme.BACKGROUND_TERTIARY};
|
||||
cursor: pointer;
|
||||
z-index: 100;
|
||||
|
||||
&:hover {
|
||||
color: ${({ theme }) => theme.TEXT_DANGER};
|
||||
box-shadow: none;
|
||||
}
|
||||
`;
|
||||
|
||||
|
@ -24,6 +24,9 @@ const StyledEditorWrapper = styled.div<{ isWidget: boolean }>`
|
||||
width: 100%;
|
||||
height: ${({ isWidget }) => (isWidget ? "100vh" : "calc(100vh - 36px)")};
|
||||
background: ${({ theme }) => theme.BACKGROUND_SECONDARY};
|
||||
background-image: ${({ theme }) => `radial-gradient(#505050 0.5px, ${theme.BACKGROUND_SECONDARY} 0.5px)`};
|
||||
background-size: 10px 10px;
|
||||
z-index: 0;
|
||||
|
||||
:active {
|
||||
cursor: move;
|
||||
|
@ -15,7 +15,7 @@ export const ModalWrapper = styled.div`
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
background: rgba(0, 0, 0, 0.85);
|
||||
z-index: 36;
|
||||
z-index: 100;
|
||||
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
|
@ -13,6 +13,7 @@ import {
|
||||
AiOutlineLink,
|
||||
AiOutlineEdit,
|
||||
} from "react-icons/ai";
|
||||
import { FiDownload } from "react-icons/fi";
|
||||
|
||||
import { Tooltip } from "src/components/Tooltip";
|
||||
import { useRouter } from "next/router";
|
||||
@ -24,6 +25,7 @@ import { HiHeart } from "react-icons/hi";
|
||||
import shallow from "zustand/shallow";
|
||||
import { MdCenterFocusWeak } from "react-icons/md";
|
||||
import { getNextLayout } from "src/utils/getNextLayout";
|
||||
import { DownloadModal } from "src/containers/Modals/DownloadModal";
|
||||
|
||||
const StyledSidebar = styled.div`
|
||||
display: flex;
|
||||
@ -41,19 +43,19 @@ const StyledSidebar = styled.div`
|
||||
}
|
||||
`;
|
||||
|
||||
const StyledElement = styled.div<{ beta?: boolean }>`
|
||||
const StyledElement = styled.button`
|
||||
position: relative;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
text-align: center;
|
||||
font-size: 26px;
|
||||
font-weight: 600;
|
||||
width: 100%;
|
||||
color: ${({ theme }) => theme.INTERACTIVE_NORMAL};
|
||||
width: fit-content;
|
||||
color: ${({ theme }) => theme.SIDEBAR_ICONS};
|
||||
cursor: pointer;
|
||||
|
||||
svg {
|
||||
padding: 8px;
|
||||
padding: 12px 8px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
@ -64,11 +66,20 @@ const StyledElement = styled.div<{ beta?: boolean }>`
|
||||
&:hover :is(a, svg) {
|
||||
color: ${({ theme }) => theme.INTERACTIVE_HOVER};
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 768px) {
|
||||
font-size: 22px;
|
||||
|
||||
svg {
|
||||
padding: 8px 4px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
const StyledText = styled.span<{ secondary?: boolean }>`
|
||||
color: ${({ theme, secondary }) =>
|
||||
secondary ? theme.INTERACTIVE_NORMAL : theme.ORANGE};
|
||||
secondary ? theme.INTERACTIVE_HOVER : theme.ORANGE};
|
||||
`;
|
||||
|
||||
const StyledFlowIcon = styled(TiFlowMerge)<{ rotate: number }>`
|
||||
@ -82,21 +93,14 @@ const StyledTopWrapper = styled.nav`
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
|
||||
& > div:nth-child(n + 1) {
|
||||
border-bottom: 1px solid ${({ theme }) => theme.BACKGROUND_MODIFIER_ACCENT};
|
||||
}
|
||||
|
||||
.mobile {
|
||||
display: none;
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 768px) {
|
||||
justify-content: space-evenly;
|
||||
flex-direction: row;
|
||||
|
||||
& > div:nth-child(n + 1) {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.mobile {
|
||||
display: initial;
|
||||
}
|
||||
@ -114,18 +118,19 @@ const StyledBottomWrapper = styled.nav`
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
|
||||
& > div,
|
||||
a:nth-child(0) {
|
||||
border-top: 1px solid ${({ theme }) => theme.BACKGROUND_MODIFIER_ACCENT};
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 768px) {
|
||||
display: none;
|
||||
}
|
||||
`;
|
||||
|
||||
const StyledLogo = styled.div`
|
||||
const StyledLogo = styled.a`
|
||||
color: ${({ theme }) => theme.FULL_WHITE};
|
||||
padding: 8px 4px;
|
||||
border-bottom: 1px solid ${({ theme }) => theme.BACKGROUND_MODIFIER_ACCENT};
|
||||
|
||||
@media only screen and (max-width: 768px) {
|
||||
border-bottom: 0;
|
||||
}
|
||||
`;
|
||||
|
||||
function rotateLayout(layout: "LEFT" | "RIGHT" | "DOWN" | "UP") {
|
||||
@ -142,6 +147,7 @@ export const Sidebar: React.FC = () => {
|
||||
const [uploadVisible, setUploadVisible] = React.useState(false);
|
||||
const [clearVisible, setClearVisible] = React.useState(false);
|
||||
const [shareVisible, setShareVisible] = React.useState(false);
|
||||
const [isDownloadVisible, setDownloadVisible] = React.useState(false);
|
||||
const { push } = useRouter();
|
||||
|
||||
const [expand, layout, hideEditor] = useConfig(
|
||||
@ -215,6 +221,11 @@ export const Sidebar: React.FC = () => {
|
||||
<AiOutlineSave />
|
||||
</StyledElement>
|
||||
</Tooltip>
|
||||
<Tooltip className="mobile" title="Download Image">
|
||||
<StyledElement onClick={() => setDownloadVisible(true)}>
|
||||
<FiDownload />
|
||||
</StyledElement>
|
||||
</Tooltip>
|
||||
<Tooltip title="Clear JSON">
|
||||
<StyledElement onClick={() => setClearVisible(true)}>
|
||||
<AiOutlineDelete />
|
||||
@ -252,6 +263,10 @@ export const Sidebar: React.FC = () => {
|
||||
<ImportModal visible={uploadVisible} setVisible={setUploadVisible} />
|
||||
<ClearModal visible={clearVisible} setVisible={setClearVisible} />
|
||||
<ShareModal visible={shareVisible} setVisible={setShareVisible} />
|
||||
<DownloadModal
|
||||
visible={isDownloadVisible}
|
||||
setVisible={setDownloadVisible}
|
||||
/>
|
||||
</StyledSidebar>
|
||||
);
|
||||
};
|
||||
|
@ -7,7 +7,7 @@ interface TooltipProps extends React.ComponentPropsWithoutRef<"div"> {
|
||||
|
||||
const StyledTooltipWrapper = styled.div`
|
||||
position: relative;
|
||||
width: 100%;
|
||||
width: fit-content;
|
||||
height: 100%;
|
||||
`;
|
||||
|
||||
@ -15,7 +15,7 @@ const StyledTooltip = styled.div<{ visible: boolean }>`
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
transform: translate(calc(100% + 15px), 10%);
|
||||
transform: translate(calc(100% + 15px), 25%);
|
||||
z-index: 5;
|
||||
background: ${({ theme }) => theme.BACKGROUND_PRIMARY};
|
||||
color: ${({ theme }) => theme.TEXT_NORMAL};
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Example taken from https://mdn.github.io/learning-area/javascript/oojs/json/superheroes.json
|
||||
export const defaultJson = {
|
||||
export const defaultJson = JSON.stringify({
|
||||
squadName: "Super hero squad",
|
||||
homeTown: "Metro City",
|
||||
formed: 2016,
|
||||
@ -35,4 +35,4 @@ export const defaultJson = {
|
||||
],
|
||||
},
|
||||
],
|
||||
};
|
||||
});
|
||||
|
@ -35,26 +35,14 @@ const GlobalStyle = createGlobalStyle`
|
||||
}
|
||||
|
||||
button {
|
||||
min-height: 32px;
|
||||
border: none;
|
||||
border-radius: 3px;
|
||||
outline: none;
|
||||
font-family: 'Catamaran', sans-serif;
|
||||
font-weight: 500;
|
||||
font-size: 14px;
|
||||
background-image: none;
|
||||
-webkit-tap-highlight-color: transparent;
|
||||
background: transparent;
|
||||
width: fit-content;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
cursor: pointer;
|
||||
|
||||
div {
|
||||
white-space: normal;
|
||||
margin: 0 auto;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background-image: linear-gradient(rgba(0, 0, 0, 0.1) 0 0);
|
||||
}
|
||||
}
|
||||
|
||||
#carbonads * {
|
||||
|
@ -24,6 +24,7 @@ export const darkTheme: DefaultTheme = {
|
||||
SILVER_DARK: "#4D4D4D",
|
||||
NODE_KEY: "#FAA81A",
|
||||
OBJECT_KEY: "#59b8ff",
|
||||
SIDEBAR_ICONS: "#8B8E90",
|
||||
|
||||
INTERACTIVE_NORMAL: "#b9bbbe",
|
||||
INTERACTIVE_HOVER: "#dcddde",
|
||||
@ -44,6 +45,7 @@ export const lightTheme: DefaultTheme = {
|
||||
SILVER_DARK: "#CCCCCC",
|
||||
NODE_KEY: "#DC3790",
|
||||
OBJECT_KEY: "#0260E8",
|
||||
SIDEBAR_ICONS: "#6D6E70",
|
||||
|
||||
INTERACTIVE_NORMAL: "#4f5660",
|
||||
INTERACTIVE_HOVER: "#2e3338",
|
||||
|
@ -1,8 +1,7 @@
|
||||
import React from "react";
|
||||
import styled from "styled-components";
|
||||
import Editor from "@monaco-editor/react";
|
||||
import parseJson from "parse-json";
|
||||
import { loader } from "@monaco-editor/react";
|
||||
import MonacoEditor, { loader } from "@monaco-editor/react";
|
||||
import { ErrorContainer } from "src/components/ErrorContainer/ErrorContainer";
|
||||
import useConfig from "src/hooks/store/useConfig";
|
||||
import { Loading } from "src/components/Loading";
|
||||
@ -76,7 +75,7 @@ export const JsonEditor: React.FC = () => {
|
||||
<StyledEditorWrapper>
|
||||
<ErrorContainer error={error} />
|
||||
<StyledWrapper>
|
||||
<Editor
|
||||
<MonacoEditor
|
||||
height="100%"
|
||||
defaultLanguage="json"
|
||||
value={value}
|
||||
|
@ -5,18 +5,16 @@ import {
|
||||
AiOutlinePlus,
|
||||
} from "react-icons/ai";
|
||||
import { FiDownload } from "react-icons/fi";
|
||||
import { HiOutlineSun, HiOutlineMoon } from "react-icons/hi";
|
||||
import { MdCenterFocusWeak } from "react-icons/md";
|
||||
import { SearchInput } from "src/components/SearchInput";
|
||||
import styled from "styled-components";
|
||||
import useConfig from "src/hooks/store/useConfig";
|
||||
import shallow from "zustand/shallow";
|
||||
import { DownloadModal } from "../Modals/DownloadModal";
|
||||
import useStored from "src/hooks/store/useStored";
|
||||
import { TbSettings } from "react-icons/tb";
|
||||
import { Settings } from "./Settings";
|
||||
import { SettingsModal } from "src/containers/Modals/SettingsModal";
|
||||
|
||||
export const StyledTools = styled.div`
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
@ -26,6 +24,7 @@ export const StyledTools = styled.div`
|
||||
background: ${({ theme }) => theme.BACKGROUND_PRIMARY};
|
||||
color: ${({ theme }) => theme.SILVER};
|
||||
box-shadow: 0 1px 0px ${({ theme }) => theme.BACKGROUND_TERTIARY};
|
||||
z-index: 36;
|
||||
|
||||
@media only screen and (max-width: 768px) {
|
||||
display: none;
|
||||
@ -38,6 +37,12 @@ const StyledToolElement = styled.button`
|
||||
font-size: 20px;
|
||||
background: none;
|
||||
color: ${({ theme }) => theme.INTERACTIVE_NORMAL};
|
||||
padding: 6px;
|
||||
border-radius: 3px;
|
||||
|
||||
&:hover {
|
||||
background-image: linear-gradient(rgba(0, 0, 0, 0.1) 0 0);
|
||||
}
|
||||
|
||||
&:hover {
|
||||
color: ${({ theme }) => theme.INTERACTIVE_HOVER};
|
||||
@ -49,8 +54,6 @@ const StyledToolElement = styled.button`
|
||||
export const Tools: React.FC = () => {
|
||||
const [settingsVisible, setSettingsVisible] = React.useState(false);
|
||||
const [isDownloadVisible, setDownloadVisible] = React.useState(false);
|
||||
const lightmode = useStored((state) => state.lightmode);
|
||||
const setLightTheme = useStored((state) => state.setLightTheme);
|
||||
|
||||
const hideEditor = useConfig((state) => state.hideEditor);
|
||||
const setConfig = useConfig((state) => state.setConfig);
|
||||
@ -59,7 +62,6 @@ export const Tools: React.FC = () => {
|
||||
const zoomOut = useConfig((state) => state.zoomOut);
|
||||
const centerView = useConfig((state) => state.centerView);
|
||||
const toggleEditor = () => setConfig("hideEditor", !hideEditor);
|
||||
const toggleTheme = () => setLightTheme(!lightmode);
|
||||
|
||||
return (
|
||||
<StyledTools>
|
||||
@ -72,9 +74,6 @@ export const Tools: React.FC = () => {
|
||||
>
|
||||
<TbSettings />
|
||||
</StyledToolElement>
|
||||
<StyledToolElement aria-label="switch theme" onClick={toggleTheme}>
|
||||
{lightmode ? <HiOutlineMoon /> : <HiOutlineSun />}
|
||||
</StyledToolElement>
|
||||
<SearchInput />
|
||||
<StyledToolElement
|
||||
aria-label="save"
|
||||
@ -95,7 +94,10 @@ export const Tools: React.FC = () => {
|
||||
visible={isDownloadVisible}
|
||||
setVisible={setDownloadVisible}
|
||||
/>
|
||||
<Settings visible={settingsVisible} setVisible={setSettingsVisible} />
|
||||
<SettingsModal
|
||||
visible={settingsVisible}
|
||||
setVisible={setSettingsVisible}
|
||||
/>
|
||||
</StyledTools>
|
||||
);
|
||||
};
|
||||
|
@ -53,6 +53,7 @@ export const NodeModal = ({
|
||||
},
|
||||
2
|
||||
)}
|
||||
readOnly
|
||||
/>
|
||||
</Modal.Content>
|
||||
<Modal.Controls setVisible={closeModal}>
|
||||
|
@ -16,10 +16,12 @@ const StyledModalWrapper = styled.div`
|
||||
gap: 20px;
|
||||
`;
|
||||
|
||||
export const Settings: React.FC<{
|
||||
export const SettingsModal: React.FC<{
|
||||
visible: boolean;
|
||||
setVisible: React.Dispatch<React.SetStateAction<boolean>>;
|
||||
}> = ({ visible, setVisible }) => {
|
||||
const lightmode = useStored((state) => state.lightmode);
|
||||
const setLightTheme = useStored((state) => state.setLightTheme);
|
||||
const [toggleHideCollapse, hideCollapse] = useStored(
|
||||
(state) => [state.toggleHideCollapse, state.hideCollapse],
|
||||
shallow
|
||||
@ -33,6 +35,12 @@ export const Settings: React.FC<{
|
||||
<StyledToggle onChange={toggleHideCollapse} checked={hideCollapse}>
|
||||
Hide Collapse/Expand Button
|
||||
</StyledToggle>
|
||||
<StyledToggle
|
||||
onChange={() => setLightTheme(!lightmode)}
|
||||
checked={lightmode}
|
||||
>
|
||||
Enable Light Theme
|
||||
</StyledToggle>
|
||||
</StyledModalWrapper>
|
||||
</Modal.Content>
|
||||
<Modal.Controls setVisible={setVisible} />
|
@ -22,7 +22,7 @@ export interface Config {
|
||||
}
|
||||
|
||||
const initialStates: Config = {
|
||||
json: JSON.stringify(defaultJson),
|
||||
json: defaultJson,
|
||||
cursorMode: "move",
|
||||
layout: "RIGHT",
|
||||
expand: true,
|
||||
|
@ -36,9 +36,9 @@ const useStored = create(
|
||||
users: [],
|
||||
nextDate: Date.now(),
|
||||
},
|
||||
setLightTheme: (enabled: boolean) =>
|
||||
setLightTheme: (value: boolean) =>
|
||||
set({
|
||||
lightmode: enabled,
|
||||
lightmode: value,
|
||||
}),
|
||||
setSponsors: (users) =>
|
||||
set({
|
||||
|
@ -8,6 +8,7 @@ import {
|
||||
import useConfig from "./store/useConfig";
|
||||
|
||||
export const useFocusNode = () => {
|
||||
const setConfig = useConfig((state) => state.setConfig);
|
||||
const zoomPanPinch = useConfig((state) => state.zoomPanPinch);
|
||||
const [selectedNode, setSelectedNode] = React.useState(0);
|
||||
const [content, setContent] = React.useState({
|
||||
@ -18,12 +19,14 @@ export const useFocusNode = () => {
|
||||
const skip = () => setSelectedNode((current) => current + 1);
|
||||
|
||||
React.useEffect(() => {
|
||||
setConfig("performanceMode", !content.value.length);
|
||||
|
||||
const debouncer = setTimeout(() => {
|
||||
setContent((val) => ({ ...val, debounced: content.value }));
|
||||
}, 1500);
|
||||
|
||||
return () => clearTimeout(debouncer);
|
||||
}, [content.value]);
|
||||
}, [content.value, setConfig]);
|
||||
|
||||
React.useEffect(() => {
|
||||
if (!zoomPanPinch) return;
|
||||
|
@ -43,7 +43,7 @@ const WidgetPage = () => {
|
||||
|
||||
React.useEffect(() => {
|
||||
if (!query.json) {
|
||||
setJson(JSON.stringify(defaultJson));
|
||||
setJson(defaultJson);
|
||||
} else {
|
||||
const jsonURI = decodeURIComponent(query.json as string);
|
||||
const isJsonValid = isValidJson(jsonURI);
|
||||
|
1
src/typings/styled.d.ts
vendored
1
src/typings/styled.d.ts
vendored
@ -20,6 +20,7 @@ declare module "styled-components" {
|
||||
PRIMARY: string;
|
||||
NODE_KEY: string;
|
||||
OBJECT_KEY: string;
|
||||
SIDEBAR_ICONS: string;
|
||||
|
||||
INTERACTIVE_NORMAL: string;
|
||||
INTERACTIVE_HOVER: string;
|
||||
|
Loading…
x
Reference in New Issue
Block a user