summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorHaishan <[email protected]>2021-06-13 15:20:12 +0800
committerHaishan <[email protected]>2021-06-13 18:26:30 +0800
commitc78dbcf8f89072dc9c2fa8ba81e2cf5a80218cd7 (patch)
tree1801b2954623c3b6710ba769836e5c25a68cf65a /src
parentaad1d2681e4415add1ab440159bf1253b5b34d8e (diff)
Support switch theme on backend config page
Diffstat (limited to 'src')
-rw-r--r--src/components/APIConfig.module.scss7
-rw-r--r--src/components/APIConfig.tsx10
-rw-r--r--src/components/APIDiscovery.module.scss9
-rw-r--r--src/components/APIDiscovery.tsx19
-rw-r--r--src/components/BackendList.module.scss3
-rw-r--r--src/components/Field.module.scss3
-rw-r--r--src/components/Field.tsx10
-rw-r--r--src/components/Modal.module.scss4
-rw-r--r--src/components/Modal.tsx6
-rw-r--r--src/components/Root.scss20
-rw-r--r--src/components/SideBar.module.scss7
-rw-r--r--src/components/SideBar.tsx88
-rw-r--r--src/components/SvgYacd.tsx17
-rw-r--r--src/components/shared/ThemeSwitcher.module.css28
-rw-r--r--src/components/shared/ThemeSwitcher.tsx97
-rw-r--r--src/store/app.ts11
-rw-r--r--src/store/modals.ts10
-rw-r--r--src/store/types.ts7
18 files changed, 216 insertions, 140 deletions
diff --git a/src/components/APIConfig.module.scss b/src/components/APIConfig.module.scss
index afc2d53..6581d46 100644
--- a/src/components/APIConfig.module.scss
+++ b/src/components/APIConfig.module.scss
@@ -10,11 +10,12 @@
align-items: center;
.icon {
- color: #2d2d30;
- opacity: 0.4;
+ --stroke: #f3f3f3;
+ color: #20497e;
+ opacity: 0.7;
transition: opacity 400ms;
&:hover {
- opacity: 0.7;
+ opacity: 1;
}
}
}
diff --git a/src/components/APIConfig.tsx b/src/components/APIConfig.tsx
index 9b2e7e9..9bf255f 100644
--- a/src/components/APIConfig.tsx
+++ b/src/components/APIConfig.tsx
@@ -1,9 +1,10 @@
import * as React from 'react';
import { fetchConfigs } from 'src/api/configs';
import { BackendList } from 'src/components/BackendList';
+import { addClashAPIConfig, getClashAPIConfig } from 'src/store/app';
+import { State } from 'src/store/types';
import { ClashAPIConfig } from 'src/types';
-import { addClashAPIConfig, getClashAPIConfig } from '../store/app';
import s0 from './APIConfig.module.scss';
import Button from './Button';
import Field from './Field';
@@ -13,7 +14,7 @@ import SvgYacd from './SvgYacd';
const { useState, useRef, useCallback } = React;
const Ok = 0;
-const mapState = (s) => ({
+const mapState = (s: State) => ({
apiConfig: getClashAPIConfig(s),
});
@@ -73,23 +74,22 @@ function APIConfig({ dispatch }) {
<div className={s0.root} ref={contentEl} onKeyDown={handleContentOnKeyDown}>
<div className={s0.header}>
<div className={s0.icon}>
- <SvgYacd width={160} height={160} />
+ <SvgYacd width={160} height={160} stroke="var(--stroke)" />
</div>
</div>
<div className={s0.body}>
<div className={s0.hostnamePort}>
<Field
id="baseURL"
- // @ts-expect-error ts-migrate(2322) FIXME: Type '{ id: string; name: string; label: string; t... Remove this comment to see the full error message
name="baseURL"
label="API Base URL"
type="text"
+ placeholder="http://127.0.0.1:9090"
value={baseURL}
onChange={handleInputOnChange}
/>
<Field
id="secret"
- // @ts-expect-error ts-migrate(2322) FIXME: Type '{ id: string; name: string; label: string; v... Remove this comment to see the full error message
name="secret"
label="Secret(optional)"
value={secret}
diff --git a/src/components/APIDiscovery.module.scss b/src/components/APIDiscovery.module.scss
index 6c1295a..e2161f8 100644
--- a/src/components/APIDiscovery.module.scss
+++ b/src/components/APIDiscovery.module.scss
@@ -22,5 +22,12 @@
}
.overlay.overlay {
- background: #222;
+ background-color: var(--color-background);
+}
+
+.fixed {
+ position: fixed;
+ padding: 16px;
+ bottom: 0;
+ right: 0;
}
diff --git a/src/components/APIDiscovery.tsx b/src/components/APIDiscovery.tsx
index 82ffbbf..f34c886 100644
--- a/src/components/APIDiscovery.tsx
+++ b/src/components/APIDiscovery.tsx
@@ -1,9 +1,11 @@
-import React from 'react';
+import * as React from 'react';
+import { ThemeSwitcher } from 'src/components/shared/ThemeSwitcher';
+import { DOES_NOT_SUPPORT_FETCH, errors } from 'src/misc/errors';
+import { getClashAPIConfig } from 'src/store/app';
+import { fetchConfigs } from 'src/store/configs';
+import { closeModal } from 'src/store/modals';
+import { State } from 'src/store/types';
-import { DOES_NOT_SUPPORT_FETCH, errors } from '../misc/errors';
-import { getClashAPIConfig } from '../store/app';
-import { fetchConfigs } from '../store/configs';
-import { closeModal } from '../store/modals';
import APIConfig from './APIConfig';
import s0 from './APIDiscovery.module.scss';
import Modal from './Modal';
@@ -32,7 +34,6 @@ function APIDiscovery({ dispatch, apiConfig, modals }) {
isOpen={modals.apiConfig}
className={s0.content}
overlayClassName={s0.overlay}
- // @ts-expect-error ts-migrate(2322) FIXME: Type '{ children: Element; isOpen: any; className:... Remove this comment to see the full error message
shouldCloseOnOverlayClick={false}
shouldCloseOnEsc={false}
onRequestClose={closeApiConfigModal}
@@ -40,11 +41,15 @@ function APIDiscovery({ dispatch, apiConfig, modals }) {
<div className={s0.container}>
<APIConfig />
</div>
+
+ <div className={s0.fixed}>
+ <ThemeSwitcher />
+ </div>
</Modal>
);
}
-const mapState = (s) => ({
+const mapState = (s: State) => ({
modals: s.modals,
apiConfig: getClashAPIConfig(s),
});
diff --git a/src/components/BackendList.module.scss b/src/components/BackendList.module.scss
index 1de1972..6872d3a 100644
--- a/src/components/BackendList.module.scss
+++ b/src/components/BackendList.module.scss
@@ -19,6 +19,7 @@
grid-template-rows: 30px;
grid-template-areas: 'close url .';
column-gap: 10px;
+ border: 1px solid var(--bg-near-transparent);
}
.li:hover {
@@ -29,6 +30,7 @@
opacity: 0;
grid-area: close;
place-self: center;
+ cursor: pointer;
}
.li:hover .close,
@@ -83,6 +85,7 @@
}
.btn:hover:enabled {
background-color: var(--color-focus-blue);
+ color: white;
}
.btn:active:enabled {
transform: scale(0.97);
diff --git a/src/components/Field.module.scss b/src/components/Field.module.scss
index 9a5f1e4..72a5149 100644
--- a/src/components/Field.module.scss
+++ b/src/components/Field.module.scss
@@ -9,13 +9,12 @@
border-radius: 0;
border-bottom: 1px solid var(--color-input-border);
box-sizing: border-box;
- color: #c1c1c1;
+ color: inherit;
display: inline-block;
font-size: inherit;
height: 40px;
outline: none;
padding: 0 4px;
- transition: border-color 0.2s cubic-bezier(0.645, 0.045, 0.355, 1);
width: 100%;
&:focus {
border-color: var(--color-focus-blue);
diff --git a/src/components/Field.tsx b/src/components/Field.tsx
index 4134d3e..a0d43cf 100644
--- a/src/components/Field.tsx
+++ b/src/components/Field.tsx
@@ -1,27 +1,25 @@
-import cx from 'clsx';
-import React from 'react';
+import * as React from 'react';
import s from './Field.module.scss';
const { useCallback } = React;
type Props = {
+ name: string;
value?: string | number;
type?: 'text' | 'number';
onChange?: (...args: any[]) => any;
id?: string;
label?: string;
+ placeholder?: string;
};
export default function Field({ id, label, value, onChange, ...props }: Props) {
const valueOnChange = useCallback((e) => onChange(e), [onChange]);
- const labelClassName = cx({
- [s.floatAbove]: typeof value === 'string' && value !== '',
- });
return (
<div className={s.root}>
<input id={id} value={value} onChange={valueOnChange} {...props} />
- <label htmlFor={id} className={labelClassName}>
+ <label htmlFor={id} className={s.floatAbove}>
{label}
</label>
</div>
diff --git a/src/components/Modal.module.scss b/src/components/Modal.module.scss
index 6192a1f..8f9807c 100644
--- a/src/components/Modal.module.scss
+++ b/src/components/Modal.module.scss
@@ -11,11 +11,11 @@
.content {
outline: none;
position: relative;
- color: #ddd;
+ color: var(--color-text);
+ background: #444;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
- background: #444;
padding: 20px;
border-radius: 10px;
}
diff --git a/src/components/Modal.tsx b/src/components/Modal.tsx
index fda3263..e91523c 100644
--- a/src/components/Modal.tsx
+++ b/src/components/Modal.tsx
@@ -1,10 +1,10 @@
import cx from 'clsx';
-import React from 'react';
-import Modal from 'react-modal';
+import * as React from 'react';
+import Modal, { Props as ReactModalProps } from 'react-modal';
import s0 from './Modal.module.scss';
-type Props = {
+type Props = ReactModalProps & {
isOpen: boolean;
onRequestClose: (...args: any[]) => any;
children: React.ReactNode;
diff --git a/src/components/Root.scss b/src/components/Root.scss
index 83d4171..55198ab 100644
--- a/src/components/Root.scss
+++ b/src/components/Root.scss
@@ -68,12 +68,12 @@ body {
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
-webkit-text-size-adjust: 100%;
-webkit-font-smoothing: antialiased;
+ -moz-osx-font-smoothing: grayscale;
margin: 0;
padding: 0;
}
-body,
-body.dark {
+@mixin dark {
--color-background: #202020;
--color-background2: rgba(32, 32, 32, 0.3);
--color-bg-card: #2d2d2d;
@@ -100,8 +100,7 @@ body.dark {
--select-border-color: #040404;
--select-bg-hover: url(data:image/svg+xml,%0A%20%20%20%20%3Csvg%20width%3D%228%22%20height%3D%2224%22%20viewBox%3D%220%200%208%2024%22%20fill%3D%22none%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%20%20%20%20%3Cpath%20d%3D%22M4%207L7%2011H1L4%207Z%22%20fill%3D%22%23ffffff%22%20%2F%3E%0A%20%20%20%20%20%20%3Cpath%20d%3D%22M4%2017L1%2013L7%2013L4%2017Z%22%20fill%3D%22%23ffffff%22%20%2F%3E%0A%20%20%20%20%3C%2Fsvg%3E%0A%20%20);
}
-
-body.light {
+@mixin light {
--color-background: #eee;
--color-background2: rgba(240, 240, 240, 0.3);
--color-bg-card: #fafafa;
@@ -129,6 +128,19 @@ body.light {
--select-bg-hover: url(data:image/svg+xml,%0A%20%20%20%20%3Csvg%20width%3D%228%22%20height%3D%2224%22%20viewBox%3D%220%200%208%2024%22%20fill%3D%22none%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%20%20%20%20%3Cpath%20d%3D%22M4%207L7%2011H1L4%207Z%22%20fill%3D%22%23222222%22%20%2F%3E%0A%20%20%20%20%20%20%3Cpath%20d%3D%22M4%2017L1%2013L7%2013L4%2017Z%22%20fill%3D%22%23222222%22%20%2F%3E%0A%20%20%20%20%3C%2Fsvg%3E%0A%20%20);
}
+// we don't have a "system" or "auto" mode now
+// it's just not make sense to have these yet
+// @media (prefers-color-scheme: dark) {}
+// @media (prefers-color-scheme: light) {}
+
+:root[data-theme='dark'] {
+ @include dark;
+}
+
+:root[data-theme='light'] {
+ @include light;
+}
+
.flexCenter {
display: flex;
align-items: center;
diff --git a/src/components/SideBar.module.scss b/src/components/SideBar.module.scss
index 744d29d..4a06377 100644
--- a/src/components/SideBar.module.scss
+++ b/src/components/SideBar.module.scss
@@ -103,10 +103,3 @@
.iconWrapper:focus {
border-color: var(--color-focus-blue);
}
-
-.themeSwitchContainer {
- appearance: none;
- user-select: none;
- background: none;
- cursor: pointer;
-}
diff --git a/src/components/SideBar.tsx b/src/components/SideBar.tsx
index 8a6429a..dbe7f0d 100644
--- a/src/components/SideBar.tsx
+++ b/src/components/SideBar.tsx
@@ -12,13 +12,9 @@ import {
FcSettings,
} from 'react-icons/fc';
import { Link, useLocation } from 'react-router-dom';
+import { ThemeSwitcher } from 'src/components/shared/ThemeSwitcher';
-import { framerMotionResouce } from '../misc/motion';
-import { getTheme, switchTheme } from '../store/app';
import s from './SideBar.module.scss';
-import { connect } from './StateProvider';
-
-const { useCallback } = React;
const icons = {
activity: FcAreaChart,
@@ -85,12 +81,9 @@ const pages = [
},
];
-function SideBar({ dispatch, theme }) {
+export default function SideBar() {
const { t } = useTranslation();
const location = useLocation();
- const switchThemeHooked = useCallback(() => {
- dispatch(switchTheme());
- }, [dispatch]);
return (
<div className={s.root}>
<div className={s.logoPlaceholder} />
@@ -106,19 +99,7 @@ function SideBar({ dispatch, theme }) {
))}
</div>
<div className={s.footer}>
- <Tooltip
- label={t('theme')}
- aria-label={
- 'switch to ' + (theme === 'light' ? 'dark' : 'light') + ' theme'
- }
- >
- <button
- className={cx(s.iconWrapper, s.themeSwitchContainer)}
- onClick={switchThemeHooked}
- >
- {theme === 'light' ? <MoonA /> : <Sun />}
- </button>
- </Tooltip>
+ <ThemeSwitcher />
<Tooltip label={t('about')}>
<Link to="/about" className={s.iconWrapper}>
<Info size={20} />
@@ -128,66 +109,3 @@ function SideBar({ dispatch, theme }) {
</div>
);
}
-
-function MoonA() {
- const module = framerMotionResouce.read();
- const motion = module.motion;
- return (
- <svg
- xmlns="http://www.w3.org/2000/svg"
- width="20"
- height="20"
- viewBox="0 0 24 24"
- fill="none"
- stroke="currentColor"
- strokeWidth="2"
- strokeLinecap="round"
- strokeLinejoin="round"
- >
- <motion.path
- d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z"
- initial={{ rotate: -30 }}
- animate={{ rotate: 0 }}
- transition={{ duration: 0.7 }}
- />
- </svg>
- );
-}
-
-function Sun() {
- const module = framerMotionResouce.read();
- const motion = module.motion;
-
- return (
- <svg
- xmlns="http://www.w3.org/2000/svg"
- width="20"
- height="20"
- viewBox="0 0 24 24"
- fill="none"
- stroke="currentColor"
- strokeWidth="2"
- strokeLinecap="round"
- strokeLinejoin="round"
- >
- <circle cx="12" cy="12" r="5"></circle>
- <motion.g
- initial={{ scale: 0.8 }}
- animate={{ scale: 1 }}
- transition={{ duration: 0.7 }}
- >
- <line x1="12" y1="1" x2="12" y2="3"></line>
- <line x1="12" y1="21" x2="12" y2="23"></line>
- <line x1="4.22" y1="4.22" x2="5.64" y2="5.64"></line>
- <line x1="18.36" y1="18.36" x2="19.78" y2="19.78"></line>
- <line x1="1" y1="12" x2="3" y2="12"></line>
- <line x1="21" y1="12" x2="23" y2="12"></line>
- <line x1="4.22" y1="19.78" x2="5.64" y2="18.36"></line>
- <line x1="18.36" y1="5.64" x2="19.78" y2="4.22"></line>
- </motion.g>
- </svg>
- );
-}
-
-const mapState = (s) => ({ theme: getTheme(s) });
-export default connect(mapState)(SideBar);
diff --git a/src/components/SvgYacd.tsx b/src/components/SvgYacd.tsx
index 90ad7e2..63c0bd5 100644
--- a/src/components/SvgYacd.tsx
+++ b/src/components/SvgYacd.tsx
@@ -1,5 +1,5 @@
import cx from 'clsx';
-import React from 'react';
+import * as React from 'react';
import s from './SvgYacd.module.scss';
@@ -9,6 +9,9 @@ type Props = {
animate?: boolean;
c0?: string;
c1?: string;
+ stroke?: string;
+ eye?: string;
+ mouth?: string;
};
function SvgYacd({
@@ -16,7 +19,9 @@ function SvgYacd({
height = 320,
animate = false,
c0 = 'currentColor',
- c1 = '#eee',
+ stroke = '#eee',
+ eye = '#eee',
+ mouth = '#eee',
}: Props) {
const faceClasName = cx({ [s.path]: animate });
return (
@@ -30,16 +35,16 @@ function SvgYacd({
{/* face */}
<path
d="M71.689 53.055c9.23-1.487 25.684 27.263 41.411 56.663 18.572-8.017 71.708-7.717 93.775 0 4.714-15.612 31.96-57.405 41.626-56.663 3.992.088 13.07 31.705 23.309 94.96 2.743 16.949 7.537 47.492 14.38 91.63-42.339 17.834-84.37 26.751-126.095 26.751-41.724 0-83.756-8.917-126.095-26.751C52.973 116.244 65.536 54.047 71.689 53.055z"
- stroke={c1}
+ stroke={stroke}
strokeWidth="4"
strokeLinecap="round"
fill={c0}
className={faceClasName}
/>
- <circle fill={c1} cx="216.5" cy="181.5" r="14.5" />
- <circle fill={c1} cx="104.5" cy="181.5" r="14.5" />
+ <circle fill={eye} cx="216.5" cy="181.5" r="14.5" />
+ <circle fill={eye} cx="104.5" cy="181.5" r="14.5" />
{/* mouth */}
- <g stroke={c1} strokeLinecap="round" strokeWidth="4">
+ <g stroke={mouth} strokeLinecap="round" strokeWidth="4">
<path d="M175.568 218.694c-2.494 1.582-5.534 2.207-8.563 1.508-3.029-.7-5.487-2.594-7.035-5.11M143.981 218.694c2.494 1.582 5.534 2.207 8.563 1.508 3.03-.7 5.488-2.594 7.036-5.11" />
</g>
</g>
diff --git a/src/components/shared/ThemeSwitcher.module.css b/src/components/shared/ThemeSwitcher.module.css
new file mode 100644
index 0000000..919c86c
--- /dev/null
+++ b/src/components/shared/ThemeSwitcher.module.css
@@ -0,0 +1,28 @@
+.iconWrapper {
+ --sz: 40px;
+
+ width: var(--sz);
+ height: var(--sz);
+ display: flex;
+ justify-content: center;
+ align-items: center;
+
+ outline: none;
+ padding: 5px;
+ color: var(--color-text);
+ border-radius: 100%;
+ border: 1px solid transparent;
+}
+.iconWrapper:hover {
+ opacity: 0.6;
+}
+.iconWrapper:focus {
+ border-color: var(--color-focus-blue);
+}
+
+.themeSwitchContainer {
+ appearance: none;
+ user-select: none;
+ background: none;
+ cursor: pointer;
+}
diff --git a/src/components/shared/ThemeSwitcher.tsx b/src/components/shared/ThemeSwitcher.tsx
new file mode 100644
index 0000000..fba5b0b
--- /dev/null
+++ b/src/components/shared/ThemeSwitcher.tsx
@@ -0,0 +1,97 @@
+import Tooltip from '@reach/tooltip';
+import cx from 'clsx';
+import * as React from 'react';
+import { useTranslation } from 'react-i18next';
+import { connect } from 'src/components/StateProvider';
+import { framerMotionResouce } from 'src/misc/motion';
+import { getTheme, switchTheme } from 'src/store/app';
+import { State } from 'src/store/types';
+
+import s from './ThemeSwitcher.module.css';
+
+export function ThemeSwitcherImpl({ theme, dispatch }) {
+ const { t } = useTranslation();
+
+ const switchThemeHooked = React.useCallback(() => {
+ dispatch(switchTheme());
+ }, [dispatch]);
+
+ return (
+ <Tooltip
+ label={t('theme')}
+ aria-label={
+ 'switch to ' + (theme === 'light' ? 'dark' : 'light') + ' theme'
+ }
+ >
+ <button
+ className={cx(s.iconWrapper, s.themeSwitchContainer)}
+ onClick={switchThemeHooked}
+ >
+ {theme === 'light' ? <MoonA /> : <Sun />}
+ </button>
+ </Tooltip>
+ );
+}
+
+function MoonA() {
+ const module = framerMotionResouce.read();
+ const motion = module.motion;
+ return (
+ <svg
+ xmlns="http://www.w3.org/2000/svg"
+ width="20"
+ height="20"
+ viewBox="0 0 24 24"
+ fill="none"
+ stroke="currentColor"
+ strokeWidth="2"
+ strokeLinecap="round"
+ strokeLinejoin="round"
+ >
+ <motion.path
+ d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z"
+ initial={{ rotate: -30 }}
+ animate={{ rotate: 0 }}
+ transition={{ duration: 0.7 }}
+ />
+ </svg>
+ );
+}
+
+function Sun() {
+ const module = framerMotionResouce.read();
+ const motion = module.motion;
+
+ return (
+ <svg
+ xmlns="http://www.w3.org/2000/svg"
+ width="20"
+ height="20"
+ viewBox="0 0 24 24"
+ fill="none"
+ stroke="currentColor"
+ strokeWidth="2"
+ strokeLinecap="round"
+ strokeLinejoin="round"
+ >
+ <circle cx="12" cy="12" r="5"></circle>
+ <motion.g
+ initial={{ scale: 0.8 }}
+ animate={{ scale: 1 }}
+ transition={{ duration: 0.7 }}
+ >
+ <line x1="12" y1="1" x2="12" y2="3"></line>
+ <line x1="12" y1="21" x2="12" y2="23"></line>
+ <line x1="4.22" y1="4.22" x2="5.64" y2="5.64"></line>
+ <line x1="18.36" y1="18.36" x2="19.78" y2="19.78"></line>
+ <line x1="1" y1="12" x2="3" y2="12"></line>
+ <line x1="21" y1="12" x2="23" y2="12"></line>
+ <line x1="4.22" y1="19.78" x2="5.64" y2="18.36"></line>
+ <line x1="18.36" y1="5.64" x2="19.78" y2="4.22"></line>
+ </motion.g>
+ </svg>
+ );
+}
+
+const mapState = (s: State) => ({ theme: getTheme(s) });
+export const ThemeSwitcher = connect(mapState)(ThemeSwitcherImpl);
diff --git a/src/store/app.ts b/src/store/app.ts
index ccdae1a..c6a455e 100644
--- a/src/store/app.ts
+++ b/src/store/app.ts
@@ -95,14 +95,15 @@ export function updateClashAPIConfig({ baseURL, secret }) {
};
}
-const bodyElement = document.body;
+const rootEl = document.querySelector('html');
+const themeColorMeta = document.querySelector('meta[name="theme-color"]');
function setTheme(theme = 'dark') {
if (theme === 'dark') {
- bodyElement.classList.remove('light');
- bodyElement.classList.add('dark');
+ rootEl.setAttribute('data-theme', 'dark');
+ themeColorMeta.setAttribute('content', '#202020');
} else {
- bodyElement.classList.remove('dark');
- bodyElement.classList.add('light');
+ rootEl.setAttribute('data-theme', 'light');
+ themeColorMeta.setAttribute('content', '#eeeeee');
}
}
diff --git a/src/store/modals.ts b/src/store/modals.ts
index 3b8b488..0b27ce9 100644
--- a/src/store/modals.ts
+++ b/src/store/modals.ts
@@ -1,13 +1,15 @@
-export function openModal(modalName) {
- return (dispatch) => {
+import { DispatchFn } from './types';
+
+export function openModal(modalName: string) {
+ return (dispatch: DispatchFn) => {
dispatch(`openModal:${modalName}`, (s) => {
s.modals[modalName] = true;
});
};
}
-export function closeModal(modalName) {
- return (dispatch) => {
+export function closeModal(modalName: string) {
+ return (dispatch: DispatchFn) => {
dispatch(`closeModal:${modalName}`, (s) => {
s.modals[modalName] = false;
});
diff --git a/src/store/types.ts b/src/store/types.ts
index c358ae3..7e6a39d 100644
--- a/src/store/types.ts
+++ b/src/store/types.ts
@@ -88,6 +88,12 @@ export type StateConfigs = {
haveFetchedConfig: boolean;
};
+///// store.modals
+
+export type StateModals = {
+ apiConfig: boolean;
+};
+
//////
export type State = {
@@ -95,6 +101,7 @@ export type State = {
configs: StateConfigs;
proxies: StateProxies;
logs: StateLogs;
+ modals: StateModals;
};
export type GetStateFn = () => State;