mirror of
https://github.com/AykutSarac/jsoncrack.com.git
synced 2025-01-20 05:12:54 +08:00
add light theme
This commit is contained in:
parent
89847c5f4f
commit
73e042b98b
@ -39,9 +39,13 @@ const StyledInput = styled.input`
|
||||
const StyledSearchButton = styled.button`
|
||||
display: grid;
|
||||
background: none;
|
||||
color: inherit;
|
||||
color: ${({ theme }) => theme.INTERACTIVE_NORMAL};
|
||||
padding: 0;
|
||||
min-height: unset;
|
||||
|
||||
&:hover {
|
||||
box-shadow: none;
|
||||
}
|
||||
`;
|
||||
|
||||
export const Input = () => {
|
||||
|
@ -36,7 +36,7 @@ const StyledSidebar = styled.div`
|
||||
width: 42px;
|
||||
background: ${({ theme }) => theme.BACKGROUND_TERTIARY};
|
||||
padding: 8px;
|
||||
border-right: 1px solid ${({ theme }) => theme.SILVER_DARK};
|
||||
border-right: 1px solid ${({ theme }) => theme.BACKGROUND_MODIFIER_ACCENT};
|
||||
`;
|
||||
|
||||
const StyledElement = styled.div`
|
||||
@ -61,7 +61,7 @@ const StyledElement = styled.div`
|
||||
|
||||
const StyledText = styled.span<{ secondary?: boolean }>`
|
||||
color: ${({ theme, secondary }) =>
|
||||
secondary ? theme.FULL_WHITE : theme.ORANGE};
|
||||
secondary ? theme.INTERACTIVE_NORMAL : theme.ORANGE};
|
||||
`;
|
||||
|
||||
const StyledTopWrapper = styled.nav`
|
||||
|
@ -17,7 +17,7 @@ const StyledTooltip = styled.div<{ visible: boolean }>`
|
||||
right: 0;
|
||||
transform: translate(calc(100% + 15px), 25%);
|
||||
z-index: 5;
|
||||
background: ${({ theme }) => theme.SILVER_DARK};
|
||||
background: ${({ theme }) => theme.BACKGROUND_PRIMARY};
|
||||
color: ${({ theme }) => theme.TEXT_NORMAL};
|
||||
border-radius: 5px;
|
||||
padding: 4px 8px;
|
||||
@ -27,6 +27,9 @@ const StyledTooltip = styled.div<{ visible: boolean }>`
|
||||
font-size: 16px;
|
||||
user-select: none;
|
||||
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``;
|
||||
|
@ -40,4 +40,5 @@ export const defaultConfig: StorageConfig = {
|
||||
hideEditor: false,
|
||||
searchNode: "",
|
||||
zoomPanPinch: null,
|
||||
lightmode: false
|
||||
};
|
||||
|
@ -20,11 +20,42 @@ export const darkTheme: DefaultTheme = {
|
||||
INTERACTIVE_NORMAL: "#b9bbbe",
|
||||
INTERACTIVE_HOVER: "#dcddde",
|
||||
INTERACTIVE_ACTIVE: "#fff",
|
||||
BACKGROUND_NODE: "#2B2C3E",
|
||||
BACKGROUND_TERTIARY: "#202225",
|
||||
BACKGROUND_SECONDARY: "#2f3136",
|
||||
BACKGROUND_PRIMARY: "#36393f",
|
||||
BACKGROUND_MODIFIER_ACCENT: "rgba(79,84,92,0.48)",
|
||||
TEXT_NORMAL: "#dcddde",
|
||||
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;
|
||||
|
@ -6,6 +6,7 @@ import {
|
||||
AiOutlineMinus,
|
||||
AiOutlinePlus,
|
||||
} from "react-icons/ai";
|
||||
import { HiOutlineSun, HiOutlineMoon } from "react-icons/hi";
|
||||
import { MdCenterFocusWeak } from "react-icons/md";
|
||||
import { Input } from "src/components/Input";
|
||||
import { useConfig } from "src/hocs/config";
|
||||
@ -19,9 +20,10 @@ export const StyledTools = styled.div`
|
||||
flex-direction: row-reverse;
|
||||
height: 28px;
|
||||
padding: 4px 16px;
|
||||
border-bottom: 1px solid #1f2124;
|
||||
background: ${({ theme }) => theme.BACKGROUND_PRIMARY};
|
||||
color: ${({ theme }) => theme.SILVER};
|
||||
|
||||
box-shadow: 0 1px 0px ${({ theme }) => theme.BACKGROUND_TERTIARY};
|
||||
`;
|
||||
|
||||
const StyledToolElement = styled.button`
|
||||
@ -53,11 +55,16 @@ export const Tools: React.FC = () => {
|
||||
|
||||
const toggleEditor = () => dispatch({ type: ConfigActionType.TOGGLE_DOCK });
|
||||
|
||||
const toggleTheme = () => dispatch({ type: ConfigActionType.TOGGLE_THEME });
|
||||
|
||||
return (
|
||||
<StyledTools>
|
||||
<StyledToolElement aria-label="fullscreen" onClick={toggleEditor}>
|
||||
<AiOutlineFullscreen />
|
||||
</StyledToolElement>
|
||||
<StyledToolElement aria-label="switch theme" onClick={toggleTheme}>
|
||||
{states.settings.lightmode ? <HiOutlineMoon /> : <HiOutlineSun />}
|
||||
</StyledToolElement>
|
||||
<Input />
|
||||
<StyledToolElement aria-label="save" onClick={handleSave}>
|
||||
<AiOutlineSave />
|
||||
|
@ -21,7 +21,7 @@ export const StyledEditor = styled(SplitPane)`
|
||||
background: ${({ theme }) => theme.BACKGROUND_SECONDARY};
|
||||
|
||||
.Resizer {
|
||||
background: ${({ theme }) => theme.BLACK};
|
||||
background: ${({ theme }) => theme.BACKGROUND_MODIFIER_ACCENT};
|
||||
box-sizing: border-box;
|
||||
background-clip: padding-box;
|
||||
z-index: 1;
|
||||
@ -50,12 +50,12 @@ export const StyledEditor = styled(SplitPane)`
|
||||
}
|
||||
|
||||
.Resizer.vertical {
|
||||
width: 16px;
|
||||
width: 14px;
|
||||
margin: 0 -5px;
|
||||
border-left: 5px solid rgba(255, 255, 255, 0);
|
||||
border-right: 5px solid rgba(255, 255, 255, 0);
|
||||
cursor: col-resize;
|
||||
z-index: 0 !important;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.Resizer.vertical:hover {
|
||||
|
@ -17,13 +17,16 @@ interface ErrorContainerProps {
|
||||
setError: React.Dispatch<React.SetStateAction<Error>>;
|
||||
}
|
||||
|
||||
const StyledErrorWrapper = styled.div``;
|
||||
const StyledErrorWrapper = styled.div`
|
||||
z-index: 5;
|
||||
`;
|
||||
|
||||
const StyledErrorHeader = styled.div`
|
||||
height: 28px;
|
||||
padding: 4px 16px;
|
||||
border-bottom: 1px solid #1f2124;
|
||||
background: ${({ theme }) => theme.BLACK_DARK};
|
||||
background: ${({ theme }) => theme.BACKGROUND_SECONDARY};
|
||||
|
||||
box-shadow: 0 1px 0px ${({ theme }) => theme.BACKGROUND_TERTIARY};
|
||||
`;
|
||||
|
||||
const StyledErrorExpand = styled.button<{ error: boolean }>`
|
||||
|
@ -2,11 +2,12 @@ import React from "react";
|
||||
import AceEditor from "react-ace";
|
||||
import parseJson from "parse-json";
|
||||
import styled from "styled-components";
|
||||
import { Error, ErrorContainer } from "./ErrorContainer";
|
||||
import { ErrorContainer } from "./ErrorContainer";
|
||||
import { ConfigActionType } from "src/reducer/reducer";
|
||||
import { useConfig } from "src/hocs/config";
|
||||
require("ace-builds/src-noconflict/mode-json");
|
||||
require("ace-builds/src-noconflict/theme-tomorrow_night");
|
||||
require("ace-builds/src-noconflict/theme-github");
|
||||
|
||||
const StyledEditorWrapper = styled.div`
|
||||
display: flex;
|
||||
@ -32,6 +33,11 @@ const JsonEditor: React.FC = () => {
|
||||
isExpanded: true,
|
||||
});
|
||||
|
||||
const editorTheme = React.useMemo(
|
||||
() => (settings.lightmode ? "github" : "tomorrow_night"),
|
||||
[settings.lightmode]
|
||||
);
|
||||
|
||||
React.useEffect(() => {
|
||||
const resizeObserver = new ResizeObserver((observed) => {
|
||||
const width = observed[0].contentRect.width;
|
||||
@ -83,7 +89,7 @@ const JsonEditor: React.FC = () => {
|
||||
value={value}
|
||||
onChange={setValue}
|
||||
mode="json"
|
||||
theme="tomorrow_night"
|
||||
theme={editorTheme}
|
||||
width={editorWidth}
|
||||
height="100%"
|
||||
fontSize={12}
|
||||
|
@ -18,19 +18,11 @@ const baseLabelStyle = {
|
||||
strokeWidth: 0,
|
||||
};
|
||||
|
||||
const basePortStyle = {
|
||||
fill: "black",
|
||||
};
|
||||
|
||||
export const CustomNode = (nodeProps: NodeProps) => {
|
||||
export const CustomNode = React.memo((nodeProps: NodeProps) => {
|
||||
const { properties: data } = nodeProps;
|
||||
|
||||
return (
|
||||
<Node
|
||||
{...nodeProps}
|
||||
label={<Label style={baseLabelStyle} />}
|
||||
port={<Port style={basePortStyle} rx={10} ry={10} />}
|
||||
>
|
||||
<Node {...nodeProps} label={<Label style={baseLabelStyle} />}>
|
||||
{(nodeProps: NodeProps) => {
|
||||
const { width, height } = nodeProps;
|
||||
|
||||
@ -60,4 +52,4 @@ export const CustomNode = (nodeProps: NodeProps) => {
|
||||
}}
|
||||
</Node>
|
||||
);
|
||||
};
|
||||
});
|
||||
|
@ -20,20 +20,9 @@ const StyledLiveEditor = styled.div`
|
||||
|
||||
const StyledEditorWrapper = styled.div`
|
||||
position: absolute;
|
||||
`;
|
||||
|
||||
const StyledControls = styled.div`
|
||||
position: fixed;
|
||||
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;
|
||||
rect {
|
||||
fill: ${({ theme }) => theme.BACKGROUND_NODE};
|
||||
}
|
||||
`;
|
||||
|
||||
@ -118,7 +107,7 @@ export const LiveEditor: React.FC = React.memo(function LiveEditor() {
|
||||
<TransformComponent>
|
||||
<Canvas
|
||||
nodes={data.nodes}
|
||||
node={CustomNode}
|
||||
node={(props) => <CustomNode {...props} />}
|
||||
edges={data.edges}
|
||||
maxWidth={20000}
|
||||
maxHeight={20000}
|
||||
@ -127,7 +116,7 @@ export const LiveEditor: React.FC = React.memo(function LiveEditor() {
|
||||
fit={true}
|
||||
direction={settings.layout}
|
||||
readonly
|
||||
key={settings.layout}
|
||||
key={settings.layout || settings.lightmode}
|
||||
onCanvasClick={onCanvasClick}
|
||||
/>
|
||||
</TransformComponent>
|
||||
|
@ -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 };
|
||||
|
@ -3,13 +3,18 @@ import type { AppProps } from "next/app";
|
||||
import { ThemeProvider } from "styled-components";
|
||||
|
||||
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 { useConfig, withConfig, WithConfig } from "src/hocs/config";
|
||||
|
||||
function JsonVisio({ Component, pageProps }: AppProps) {
|
||||
const {
|
||||
states: { settings },
|
||||
} = useConfig();
|
||||
|
||||
return (
|
||||
<>
|
||||
<ThemeProvider theme={darkTheme}>
|
||||
<ThemeProvider theme={settings.lightmode ? lightTheme : darkTheme}>
|
||||
<GlobalStyle />
|
||||
<Component {...pageProps} />
|
||||
<Toaster
|
||||
@ -26,4 +31,4 @@ function JsonVisio({ Component, pageProps }: AppProps) {
|
||||
);
|
||||
}
|
||||
|
||||
export default JsonVisio;
|
||||
export default withConfig(JsonVisio);
|
||||
|
@ -1,7 +1,6 @@
|
||||
import React from "react";
|
||||
import Head from "next/head";
|
||||
import { Editor } from "src/containers/Editor";
|
||||
import { WithConfig } from "src/hocs/config";
|
||||
|
||||
const EditorPage: React.FC = () => {
|
||||
return (
|
||||
@ -13,9 +12,7 @@ const EditorPage: React.FC = () => {
|
||||
content="View your JSON data in graphs instantly."
|
||||
/>
|
||||
</Head>
|
||||
<WithConfig>
|
||||
<Editor />
|
||||
</WithConfig>
|
||||
<Editor />
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
@ -8,6 +8,7 @@ export enum ConfigActionType {
|
||||
TOGGLE_EXPAND,
|
||||
TOGGLE_AUTOFORMAT,
|
||||
TOGGLE_DOCK,
|
||||
TOGGLE_THEME,
|
||||
ZOOM_IN,
|
||||
ZOOM_OUT,
|
||||
CENTER_VIEW,
|
||||
@ -29,6 +30,15 @@ export const useConfigReducer: React.Reducer<AppConfig, ReducerAction> = (
|
||||
case ConfigActionType.SET_CONFIG:
|
||||
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:
|
||||
return {
|
||||
...state,
|
||||
|
@ -8,4 +8,5 @@ export interface StorageConfig {
|
||||
hideEditor: boolean;
|
||||
searchNode: string;
|
||||
zoomPanPinch: ReactZoomPanPinchRef | null;
|
||||
lightmode: boolean;
|
||||
}
|
||||
|
1
src/typings/styled.d.ts
vendored
1
src/typings/styled.d.ts
vendored
@ -28,6 +28,7 @@ declare module "styled-components" {
|
||||
INTERACTIVE_NORMAL: string;
|
||||
INTERACTIVE_HOVER: string;
|
||||
INTERACTIVE_ACTIVE: string;
|
||||
BACKGROUND_NODE: string;
|
||||
BACKGROUND_TERTIARY: string;
|
||||
BACKGROUND_SECONDARY: string;
|
||||
BACKGROUND_PRIMARY: string;
|
||||
|
Loading…
x
Reference in New Issue
Block a user