add light theme

This commit is contained in:
AykutSarac 2022-04-15 22:36:51 +03:00
parent 89847c5f4f
commit 73e042b98b
17 changed files with 106 additions and 48 deletions

View File

@ -39,9 +39,13 @@ const StyledInput = styled.input`
const StyledSearchButton = styled.button` const StyledSearchButton = styled.button`
display: grid; display: grid;
background: none; background: none;
color: inherit; color: ${({ theme }) => theme.INTERACTIVE_NORMAL};
padding: 0; padding: 0;
min-height: unset; min-height: unset;
&:hover {
box-shadow: none;
}
`; `;
export const Input = () => { export const Input = () => {

View File

@ -36,7 +36,7 @@ const StyledSidebar = styled.div`
width: 42px; width: 42px;
background: ${({ theme }) => theme.BACKGROUND_TERTIARY}; background: ${({ theme }) => theme.BACKGROUND_TERTIARY};
padding: 8px; padding: 8px;
border-right: 1px solid ${({ theme }) => theme.SILVER_DARK}; border-right: 1px solid ${({ theme }) => theme.BACKGROUND_MODIFIER_ACCENT};
`; `;
const StyledElement = styled.div` const StyledElement = styled.div`
@ -61,7 +61,7 @@ const StyledElement = styled.div`
const StyledText = styled.span<{ secondary?: boolean }>` const StyledText = styled.span<{ secondary?: boolean }>`
color: ${({ theme, secondary }) => color: ${({ theme, secondary }) =>
secondary ? theme.FULL_WHITE : theme.ORANGE}; secondary ? theme.INTERACTIVE_NORMAL : theme.ORANGE};
`; `;
const StyledTopWrapper = styled.nav` const StyledTopWrapper = styled.nav`

View File

@ -17,7 +17,7 @@ const StyledTooltip = styled.div<{ visible: boolean }>`
right: 0; right: 0;
transform: translate(calc(100% + 15px), 25%); transform: translate(calc(100% + 15px), 25%);
z-index: 5; z-index: 5;
background: ${({ theme }) => theme.SILVER_DARK}; background: ${({ theme }) => theme.BACKGROUND_PRIMARY};
color: ${({ theme }) => theme.TEXT_NORMAL}; color: ${({ theme }) => theme.TEXT_NORMAL};
border-radius: 5px; border-radius: 5px;
padding: 4px 8px; padding: 4px 8px;
@ -27,6 +27,9 @@ const StyledTooltip = styled.div<{ visible: boolean }>`
font-size: 16px; font-size: 16px;
user-select: none; user-select: none;
font-weight: 600; font-weight: 600;
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.07), 0 2px 4px rgba(0, 0, 0, 0.07),
0 4px 8px rgba(0, 0, 0, 0.07), 0 8px 16px rgba(0, 0, 0, 0.07),
0 16px 32px rgba(0, 0, 0, 0.07), 0 32px 64px rgba(0, 0, 0, 0.07);
`; `;
const StyledChildren = styled.div``; const StyledChildren = styled.div``;

View File

@ -40,4 +40,5 @@ export const defaultConfig: StorageConfig = {
hideEditor: false, hideEditor: false,
searchNode: "", searchNode: "",
zoomPanPinch: null, zoomPanPinch: null,
lightmode: false
}; };

View File

@ -20,11 +20,42 @@ export const darkTheme: DefaultTheme = {
INTERACTIVE_NORMAL: "#b9bbbe", INTERACTIVE_NORMAL: "#b9bbbe",
INTERACTIVE_HOVER: "#dcddde", INTERACTIVE_HOVER: "#dcddde",
INTERACTIVE_ACTIVE: "#fff", INTERACTIVE_ACTIVE: "#fff",
BACKGROUND_NODE: "#2B2C3E",
BACKGROUND_TERTIARY: "#202225", BACKGROUND_TERTIARY: "#202225",
BACKGROUND_SECONDARY: "#2f3136", BACKGROUND_SECONDARY: "#2f3136",
BACKGROUND_PRIMARY: "#36393f", BACKGROUND_PRIMARY: "#36393f",
BACKGROUND_MODIFIER_ACCENT: "rgba(79,84,92,0.48)", BACKGROUND_MODIFIER_ACCENT: "rgba(79,84,92,0.48)",
TEXT_NORMAL: "#dcddde", TEXT_NORMAL: "#dcddde",
TEXT_POSITIVE: "hsl(139,calc(var(--saturation-factor, 1)*51.6%),52.2%)", TEXT_POSITIVE: "hsl(139,calc(var(--saturation-factor, 1)*51.6%),52.2%)",
TEXT_DANGER: "hsl(359,calc(var(--saturation-factor, 1)*82%),73.9%)" TEXT_DANGER: "hsl(359,calc(var(--saturation-factor, 1)*82%),73.9%)",
} as const;
export const lightTheme: DefaultTheme = {
BLURPLE: "#5865F2",
FULL_WHITE: "#FFFFFF",
BLACK: "#202225",
BLACK_DARK: "#2C2F33",
BLACK_LIGHT: "#2F3136",
BLACK_PRIMARY: "#36393f",
BLACK_SECONDARY: "#23272A",
CRIMSON: "#DC143C",
DARK_SALMON: "#E9967A",
DANGER: "#db662e",
LIGHTGREEN: "#90EE90",
SEAGREEN: "#3BA55D",
ORANGE: "#FAA81A",
SILVER: "#B9BBBE",
SILVER_DARK: "#4D4D4D",
INTERACTIVE_NORMAL: "#4f5660",
INTERACTIVE_HOVER: "#2e3338",
INTERACTIVE_ACTIVE: "#060607",
BACKGROUND_NODE: "#FFFFFF",
BACKGROUND_TERTIARY: "#e3e5e8",
BACKGROUND_SECONDARY: "#f2f3f5",
BACKGROUND_PRIMARY: "#FFFFFF",
BACKGROUND_MODIFIER_ACCENT: "rgba(106,116,128,0.24)",
TEXT_NORMAL: "#2e3338",
TEXT_POSITIVE: "hsl(139,calc(var(--saturation-factor, 1)*51.6%),52.2%)",
TEXT_DANGER: "hsl(359,calc(var(--saturation-factor, 1)*82%),73.9%)",
} as const; } as const;

View File

@ -6,6 +6,7 @@ import {
AiOutlineMinus, AiOutlineMinus,
AiOutlinePlus, AiOutlinePlus,
} from "react-icons/ai"; } from "react-icons/ai";
import { HiOutlineSun, HiOutlineMoon } from "react-icons/hi";
import { MdCenterFocusWeak } from "react-icons/md"; import { MdCenterFocusWeak } from "react-icons/md";
import { Input } from "src/components/Input"; import { Input } from "src/components/Input";
import { useConfig } from "src/hocs/config"; import { useConfig } from "src/hocs/config";
@ -19,9 +20,10 @@ export const StyledTools = styled.div`
flex-direction: row-reverse; flex-direction: row-reverse;
height: 28px; height: 28px;
padding: 4px 16px; padding: 4px 16px;
border-bottom: 1px solid #1f2124;
background: ${({ theme }) => theme.BACKGROUND_PRIMARY}; background: ${({ theme }) => theme.BACKGROUND_PRIMARY};
color: ${({ theme }) => theme.SILVER}; color: ${({ theme }) => theme.SILVER};
box-shadow: 0 1px 0px ${({ theme }) => theme.BACKGROUND_TERTIARY};
`; `;
const StyledToolElement = styled.button` const StyledToolElement = styled.button`
@ -53,11 +55,16 @@ export const Tools: React.FC = () => {
const toggleEditor = () => dispatch({ type: ConfigActionType.TOGGLE_DOCK }); const toggleEditor = () => dispatch({ type: ConfigActionType.TOGGLE_DOCK });
const toggleTheme = () => dispatch({ type: ConfigActionType.TOGGLE_THEME });
return ( return (
<StyledTools> <StyledTools>
<StyledToolElement aria-label="fullscreen" onClick={toggleEditor}> <StyledToolElement aria-label="fullscreen" onClick={toggleEditor}>
<AiOutlineFullscreen /> <AiOutlineFullscreen />
</StyledToolElement> </StyledToolElement>
<StyledToolElement aria-label="switch theme" onClick={toggleTheme}>
{states.settings.lightmode ? <HiOutlineMoon /> : <HiOutlineSun />}
</StyledToolElement>
<Input /> <Input />
<StyledToolElement aria-label="save" onClick={handleSave}> <StyledToolElement aria-label="save" onClick={handleSave}>
<AiOutlineSave /> <AiOutlineSave />

View File

@ -21,7 +21,7 @@ export const StyledEditor = styled(SplitPane)`
background: ${({ theme }) => theme.BACKGROUND_SECONDARY}; background: ${({ theme }) => theme.BACKGROUND_SECONDARY};
.Resizer { .Resizer {
background: ${({ theme }) => theme.BLACK}; background: ${({ theme }) => theme.BACKGROUND_MODIFIER_ACCENT};
box-sizing: border-box; box-sizing: border-box;
background-clip: padding-box; background-clip: padding-box;
z-index: 1; z-index: 1;
@ -50,12 +50,12 @@ export const StyledEditor = styled(SplitPane)`
} }
.Resizer.vertical { .Resizer.vertical {
width: 16px; width: 14px;
margin: 0 -5px; margin: 0 -5px;
border-left: 5px solid rgba(255, 255, 255, 0); border-left: 5px solid rgba(255, 255, 255, 0);
border-right: 5px solid rgba(255, 255, 255, 0); border-right: 5px solid rgba(255, 255, 255, 0);
cursor: col-resize; cursor: col-resize;
z-index: 0 !important; z-index: 1;
} }
.Resizer.vertical:hover { .Resizer.vertical:hover {

View File

@ -17,13 +17,16 @@ interface ErrorContainerProps {
setError: React.Dispatch<React.SetStateAction<Error>>; setError: React.Dispatch<React.SetStateAction<Error>>;
} }
const StyledErrorWrapper = styled.div``; const StyledErrorWrapper = styled.div`
z-index: 5;
`;
const StyledErrorHeader = styled.div` const StyledErrorHeader = styled.div`
height: 28px; height: 28px;
padding: 4px 16px; padding: 4px 16px;
border-bottom: 1px solid #1f2124; background: ${({ theme }) => theme.BACKGROUND_SECONDARY};
background: ${({ theme }) => theme.BLACK_DARK};
box-shadow: 0 1px 0px ${({ theme }) => theme.BACKGROUND_TERTIARY};
`; `;
const StyledErrorExpand = styled.button<{ error: boolean }>` const StyledErrorExpand = styled.button<{ error: boolean }>`

View File

@ -2,11 +2,12 @@ import React from "react";
import AceEditor from "react-ace"; import AceEditor from "react-ace";
import parseJson from "parse-json"; import parseJson from "parse-json";
import styled from "styled-components"; import styled from "styled-components";
import { Error, ErrorContainer } from "./ErrorContainer"; import { ErrorContainer } from "./ErrorContainer";
import { ConfigActionType } from "src/reducer/reducer"; import { ConfigActionType } from "src/reducer/reducer";
import { useConfig } from "src/hocs/config"; import { useConfig } from "src/hocs/config";
require("ace-builds/src-noconflict/mode-json"); require("ace-builds/src-noconflict/mode-json");
require("ace-builds/src-noconflict/theme-tomorrow_night"); require("ace-builds/src-noconflict/theme-tomorrow_night");
require("ace-builds/src-noconflict/theme-github");
const StyledEditorWrapper = styled.div` const StyledEditorWrapper = styled.div`
display: flex; display: flex;
@ -32,6 +33,11 @@ const JsonEditor: React.FC = () => {
isExpanded: true, isExpanded: true,
}); });
const editorTheme = React.useMemo(
() => (settings.lightmode ? "github" : "tomorrow_night"),
[settings.lightmode]
);
React.useEffect(() => { React.useEffect(() => {
const resizeObserver = new ResizeObserver((observed) => { const resizeObserver = new ResizeObserver((observed) => {
const width = observed[0].contentRect.width; const width = observed[0].contentRect.width;
@ -83,7 +89,7 @@ const JsonEditor: React.FC = () => {
value={value} value={value}
onChange={setValue} onChange={setValue}
mode="json" mode="json"
theme="tomorrow_night" theme={editorTheme}
width={editorWidth} width={editorWidth}
height="100%" height="100%"
fontSize={12} fontSize={12}

View File

@ -18,19 +18,11 @@ const baseLabelStyle = {
strokeWidth: 0, strokeWidth: 0,
}; };
const basePortStyle = { export const CustomNode = React.memo((nodeProps: NodeProps) => {
fill: "black",
};
export const CustomNode = (nodeProps: NodeProps) => {
const { properties: data } = nodeProps; const { properties: data } = nodeProps;
return ( return (
<Node <Node {...nodeProps} label={<Label style={baseLabelStyle} />}>
{...nodeProps}
label={<Label style={baseLabelStyle} />}
port={<Port style={basePortStyle} rx={10} ry={10} />}
>
{(nodeProps: NodeProps) => { {(nodeProps: NodeProps) => {
const { width, height } = nodeProps; const { width, height } = nodeProps;
@ -60,4 +52,4 @@ export const CustomNode = (nodeProps: NodeProps) => {
}} }}
</Node> </Node>
); );
}; });

View File

@ -20,20 +20,9 @@ const StyledLiveEditor = styled.div`
const StyledEditorWrapper = styled.div` const StyledEditorWrapper = styled.div`
position: absolute; position: absolute;
`;
const StyledControls = styled.div` rect {
position: fixed; fill: ${({ theme }) => theme.BACKGROUND_NODE};
display: grid;
grid-template-columns: 1fr 1fr;
grid-template-rows: 1fr 1fr;
gap: 8px;
bottom: 8px;
right: 8px;
opacity: 0.9;
button:hover {
opacity: 0.7;
} }
`; `;
@ -118,7 +107,7 @@ export const LiveEditor: React.FC = React.memo(function LiveEditor() {
<TransformComponent> <TransformComponent>
<Canvas <Canvas
nodes={data.nodes} nodes={data.nodes}
node={CustomNode} node={(props) => <CustomNode {...props} />}
edges={data.edges} edges={data.edges}
maxWidth={20000} maxWidth={20000}
maxHeight={20000} maxHeight={20000}
@ -127,7 +116,7 @@ export const LiveEditor: React.FC = React.memo(function LiveEditor() {
fit={true} fit={true}
direction={settings.layout} direction={settings.layout}
readonly readonly
key={settings.layout} key={settings.layout || settings.lightmode}
onCanvasClick={onCanvasClick} onCanvasClick={onCanvasClick}
/> />
</TransformComponent> </TransformComponent>

View File

@ -37,4 +37,12 @@ const WithConfig: React.FC = ({ children }) => {
); );
}; };
export { WithConfig, useConfig, ConfigContext }; const withConfig = (Component) => {
return (props) => (
<WithConfig>
<Component {...props} />
</WithConfig>
);
};
export { WithConfig, useConfig, ConfigContext, withConfig };

View File

@ -3,13 +3,18 @@ import type { AppProps } from "next/app";
import { ThemeProvider } from "styled-components"; import { ThemeProvider } from "styled-components";
import GlobalStyle from "src/constants/globalStyle"; import GlobalStyle from "src/constants/globalStyle";
import { darkTheme } from "src/constants/theme"; import { darkTheme, lightTheme } from "src/constants/theme";
import { Toaster } from "react-hot-toast"; import { Toaster } from "react-hot-toast";
import { useConfig, withConfig, WithConfig } from "src/hocs/config";
function JsonVisio({ Component, pageProps }: AppProps) { function JsonVisio({ Component, pageProps }: AppProps) {
const {
states: { settings },
} = useConfig();
return ( return (
<> <>
<ThemeProvider theme={darkTheme}> <ThemeProvider theme={settings.lightmode ? lightTheme : darkTheme}>
<GlobalStyle /> <GlobalStyle />
<Component {...pageProps} /> <Component {...pageProps} />
<Toaster <Toaster
@ -26,4 +31,4 @@ function JsonVisio({ Component, pageProps }: AppProps) {
); );
} }
export default JsonVisio; export default withConfig(JsonVisio);

View File

@ -1,7 +1,6 @@
import React from "react"; import React from "react";
import Head from "next/head"; import Head from "next/head";
import { Editor } from "src/containers/Editor"; import { Editor } from "src/containers/Editor";
import { WithConfig } from "src/hocs/config";
const EditorPage: React.FC = () => { const EditorPage: React.FC = () => {
return ( return (
@ -13,9 +12,7 @@ const EditorPage: React.FC = () => {
content="View your JSON data in graphs instantly." content="View your JSON data in graphs instantly."
/> />
</Head> </Head>
<WithConfig> <Editor />
<Editor />
</WithConfig>
</> </>
); );
}; };

View File

@ -8,6 +8,7 @@ export enum ConfigActionType {
TOGGLE_EXPAND, TOGGLE_EXPAND,
TOGGLE_AUTOFORMAT, TOGGLE_AUTOFORMAT,
TOGGLE_DOCK, TOGGLE_DOCK,
TOGGLE_THEME,
ZOOM_IN, ZOOM_IN,
ZOOM_OUT, ZOOM_OUT,
CENTER_VIEW, CENTER_VIEW,
@ -29,6 +30,15 @@ export const useConfigReducer: React.Reducer<AppConfig, ReducerAction> = (
case ConfigActionType.SET_CONFIG: case ConfigActionType.SET_CONFIG:
return { ...state, settings: action.payload }; return { ...state, settings: action.payload };
case ConfigActionType.TOGGLE_THEME:
return {
...state,
settings: {
...state.settings,
lightmode: !state.settings.lightmode,
},
};
case ConfigActionType.SET_ZOOM_PAN_PICNH_REF: case ConfigActionType.SET_ZOOM_PAN_PICNH_REF:
return { return {
...state, ...state,

View File

@ -8,4 +8,5 @@ export interface StorageConfig {
hideEditor: boolean; hideEditor: boolean;
searchNode: string; searchNode: string;
zoomPanPinch: ReactZoomPanPinchRef | null; zoomPanPinch: ReactZoomPanPinchRef | null;
lightmode: boolean;
} }

View File

@ -28,6 +28,7 @@ declare module "styled-components" {
INTERACTIVE_NORMAL: string; INTERACTIVE_NORMAL: string;
INTERACTIVE_HOVER: string; INTERACTIVE_HOVER: string;
INTERACTIVE_ACTIVE: string; INTERACTIVE_ACTIVE: string;
BACKGROUND_NODE: string;
BACKGROUND_TERTIARY: string; BACKGROUND_TERTIARY: string;
BACKGROUND_SECONDARY: string; BACKGROUND_SECONDARY: string;
BACKGROUND_PRIMARY: string; BACKGROUND_PRIMARY: string;