diff options
| author | Haishan <[email protected]> | 2018-12-04 23:39:26 +0800 |
|---|---|---|
| committer | Haishan <[email protected]> | 2018-12-07 00:19:49 +0800 |
| commit | 3584ff617966af35ddd0fd45ef2df7cdfb8f5071 (patch) | |
| tree | 83f4f535d1fd3ca1c85807a1c2b397cf9b6733c5 /src/components | |
| parent | a265c62020d4dd3a4e57e5ad0894794461dd8385 (diff) | |
feat: initial theming support
Diffstat (limited to 'src/components')
| -rw-r--r-- | src/components/ContentHeader.module.scss | 1 | ||||
| -rw-r--r-- | src/components/Logs.js | 17 | ||||
| -rw-r--r-- | src/components/Root.js | 40 | ||||
| -rw-r--r-- | src/components/Root.module.scss | 5 | ||||
| -rw-r--r-- | src/components/SideBar.js | 11 | ||||
| -rw-r--r-- | src/components/SideBar.module.scss | 22 | ||||
| -rw-r--r-- | src/components/Theme.js | 17 | ||||
| -rw-r--r-- | src/components/Theme.module.scss | 11 | ||||
| -rw-r--r-- | src/components/TrafficChart.js | 52 | ||||
| -rw-r--r-- | src/components/TrafficNow.js | 26 |
10 files changed, 143 insertions, 59 deletions
diff --git a/src/components/ContentHeader.module.scss b/src/components/ContentHeader.module.scss index caf572e..54e4c99 100644 --- a/src/components/ContentHeader.module.scss +++ b/src/components/ContentHeader.module.scss @@ -6,7 +6,6 @@ .h1 { padding: 0 40px; - color: #ddd; text-align: left; margin: 0; } diff --git a/src/components/Logs.js b/src/components/Logs.js index 235e7ba..08d634f 100644 --- a/src/components/Logs.js +++ b/src/components/Logs.js @@ -1,9 +1,12 @@ import React, { useState, useEffect } from 'react'; import PropTypes from 'prop-types'; import cx from 'classnames'; +import { useComponentState } from 'm/store'; +import { getClashAPIConfig } from 'd/app'; import Icon from 'c/Icon'; import ContentHeader from 'c/ContentHeader'; +// TODO move this into a redux action import { fetchLogs } from '../api/logs'; import yacd from 's/yacd.svg'; @@ -42,12 +45,16 @@ LogLine.propTypes = { export default function Logs() { const [logs, setLogs] = useState([]); + const { apiConfig } = useComponentState(getClashAPIConfig); - useEffect(() => { - const x = fetchLogs(); - setLogs(x.logs); - return x.subscribe(() => setLogs(x.logs)); - }, []); + useEffect( + () => { + const x = fetchLogs(apiConfig); + setLogs(x.logs); + return x.subscribe(() => setLogs(x.logs)); + }, + [apiConfig.hostname, apiConfig.port, apiConfig.secret] + ); return ( <div> diff --git a/src/components/Root.js b/src/components/Root.js index e9d9141..60b89f4 100644 --- a/src/components/Root.js +++ b/src/components/Root.js @@ -4,7 +4,7 @@ import { HashRouter as Router, Route } from 'react-router-dom'; // import { hot } from 'react-hot-loader'; // import createHistory from 'history/createHashHistory'; // import createHistory from 'history/createBrowserHistory'; - +import Theme from 'c/Theme'; import SideBar from 'c/SideBar'; import Home from 'c/Home'; import Logs from 'c/Logs'; @@ -23,23 +23,27 @@ import s0 from './Root.module.scss'; window.store = store; -const Root = () => ( - <Provider store={store}> - <Router> - <div className={s0.app}> - <APIDiscovery /> - <Route path="/" render={() => <SideBar />} /> - <div className={s0.content}> - <Route exact path="/" render={() => <Home />} /> - <Route exact path="/overview" render={() => <Home />} /> - <Route exact path="/configs" render={() => <Config />} /> - <Route exact path="/logs" render={() => <Logs />} /> - <Route exact path="/proxies" render={() => <Proxies />} /> - </div> - </div> - </Router> - </Provider> -); +const Root = () => { + return ( + <Provider store={store}> + <Theme> + <Router> + <div className={s0.app}> + <APIDiscovery /> + <Route path="/" render={() => <SideBar />} /> + <div className={s0.content}> + <Route exact path="/" render={() => <Home />} /> + <Route exact path="/overview" render={() => <Home />} /> + <Route exact path="/configs" render={() => <Config />} /> + <Route exact path="/logs" render={() => <Logs />} /> + <Route exact path="/proxies" render={() => <Proxies />} /> + </div> + </div> + </Router> + </Theme> + </Provider> + ); +}; // <Route exact path="/__0" component={StyleGuide} /> // <Route exact path="/__1" component={Loading} /> diff --git a/src/components/Root.module.scss b/src/components/Root.module.scss index e4a0e87..5ecd02e 100644 --- a/src/components/Root.module.scss +++ b/src/components/Root.module.scss @@ -1,8 +1,8 @@ .app { display: flex; - color: #ddd; - background: #202020; + background: var(--color-background); + color: var(--color-text); min-height: 300px; height: 100vh; } @@ -10,6 +10,7 @@ .content { flex-grow: 1; overflow: scroll; + // background: #202020; // $w: 7px; // &::-webkit-scrollbar { diff --git a/src/components/SideBar.js b/src/components/SideBar.js index cee0960..8a38a46 100644 --- a/src/components/SideBar.js +++ b/src/components/SideBar.js @@ -2,6 +2,9 @@ import React from 'react'; import PropTypes from 'prop-types'; import { NavLink } from 'react-router-dom'; +import { useActions } from 'm/store'; +import { switchTheme } from 'd/app'; + import Icon from 'c/Icon'; import activity from 's/activity.svg'; @@ -9,6 +12,7 @@ import settings from 's/settings.svg'; import globe from 's/globe.svg'; import file from 's/file.svg'; import yacd from 's/yacd.svg'; +import moon from 's/moon.svg'; import s from 'c/SideBar.module.scss'; @@ -27,7 +31,10 @@ SideBarRow.propTypes = { labelText: PropTypes.string }; +const actions = { switchTheme }; + function SideBar() { + const { switchTheme } = useActions(actions); return ( <div className={s.root}> <div className={s.logo}> @@ -40,6 +47,10 @@ function SideBar() { <SideBarRow to="/configs" iconId={settings.id} labelText="Config" /> <SideBarRow to="/logs" iconId={file.id} labelText="Logs" /> </div> + + <div className={s.themeSwitchContainer} onClick={switchTheme}> + <Icon id={moon.id} width={20} height={20} /> + </div> </div> ); } diff --git a/src/components/SideBar.module.scss b/src/components/SideBar.module.scss index 86260f4..a0ca07d 100644 --- a/src/components/SideBar.module.scss +++ b/src/components/SideBar.module.scss @@ -1,6 +1,6 @@ .root { - background: #2d2d30; - // width: 220px; + background: var(--color-bg-sidebar); + position: relative; } .logo { @@ -48,3 +48,21 @@ .label { padding-left: 14px; } + +.themeSwitchContainer { + $sz: 50px; + + position: absolute; + bottom: 0; + left: 50%; + transform: translateX(-50%); + width: $sz; + height: $sz; + padding: 20px 0; + display: flex; + justify-content: center; + align-items: center; + svg { + display: block; + } +} diff --git a/src/components/Theme.js b/src/components/Theme.js new file mode 100644 index 0000000..ed6952e --- /dev/null +++ b/src/components/Theme.js @@ -0,0 +1,17 @@ +import React, { memo, useEffect, useState } from 'react'; +import PropTypes from 'prop-types'; +import { useComponentState } from 'm/store'; + +import { getTheme } from 'd/app'; + +import s0 from './Theme.module.scss'; + +const mapStateToProps = s => ({ theme: getTheme(s) }); + +function Theme({ children }) { + const { theme } = useComponentState(mapStateToProps); + const className = theme === 'dark' ? s0.dark : s0.light; + return <div className={className}>{children}</div>; +} + +export default memo(Theme); diff --git a/src/components/Theme.module.scss b/src/components/Theme.module.scss new file mode 100644 index 0000000..754da63 --- /dev/null +++ b/src/components/Theme.module.scss @@ -0,0 +1,11 @@ +.dark { + --color-background: #202020; + --color-text: #ddd; + --color-bg-sidebar: #2d2d30; +} + +.light { + --color-background: #eee; + --color-text: #222; + --color-bg-sidebar: #2d2d30; +} diff --git a/src/components/TrafficChart.js b/src/components/TrafficChart.js index 4bfb4a7..5d54c59 100644 --- a/src/components/TrafficChart.js +++ b/src/components/TrafficChart.js @@ -2,6 +2,8 @@ import React, { useEffect } from 'react'; import prettyBytes from 'm/pretty-bytes'; import { fetchData } from '../api/traffic'; import { unstable_createResource as createResource } from 'react-cache'; +import { useComponentState } from 'm/store'; +import { getClashAPIConfig } from 'd/app'; // const delay = ms => new Promise(r => setTimeout(r, ms)); const chartJSResource = createResource(() => { @@ -119,29 +121,33 @@ const chartWrapperStyle = { export default function TrafficChart() { const Chart = chartJSResource.read(); - useEffect(() => { - const ctx = document.getElementById('trafficChart').getContext('2d'); - const traffic = fetchData(); - const data = { - labels: traffic.labels, - datasets: [ - { - ...upProps, - data: traffic.up - }, - { - ...downProps, - data: traffic.down - } - ] - }; - const c = new Chart(ctx, { - type: 'line', - data, - options - }); - return traffic.subscribe(() => c.update()); - }, []); + const { hostname, port, secret } = useComponentState(getClashAPIConfig); + useEffect( + () => { + const ctx = document.getElementById('trafficChart').getContext('2d'); + const traffic = fetchData({ hostname, port, secret }); + const data = { + labels: traffic.labels, + datasets: [ + { + ...upProps, + data: traffic.up + }, + { + ...downProps, + data: traffic.down + } + ] + }; + const c = new Chart(ctx, { + type: 'line', + data, + options + }); + return traffic.subscribe(() => c.update()); + }, + [hostname, port, secret] + ); return ( <div style={chartWrapperStyle}> diff --git a/src/components/TrafficNow.js b/src/components/TrafficNow.js index 43236a7..09fa43f 100644 --- a/src/components/TrafficNow.js +++ b/src/components/TrafficNow.js @@ -1,6 +1,8 @@ import React, { useState, useEffect } from 'react'; import prettyBytes from 'm/pretty-bytes'; +import { useComponentState } from 'm/store'; +import { getClashAPIConfig } from 'd/app'; import { fetchData } from '../api/traffic'; import s0 from 'c/TrafficNow.module.scss'; @@ -23,13 +25,21 @@ export default function TrafficNow() { function useSpeed() { const [speed, setSpeed] = useState({ upStr: '0 B/s', downStr: '0 B/s' }); - useEffect(() => { - return fetchData().subscribe(o => - setSpeed({ - upStr: prettyBytes(o.up) + '/s', - downStr: prettyBytes(o.down) + '/s' - }) - ); - }); + const { hostname, port, secret } = useComponentState(getClashAPIConfig); + useEffect( + () => { + return fetchData({ + hostname, + port, + secret + }).subscribe(o => + setSpeed({ + upStr: prettyBytes(o.up) + '/s', + downStr: prettyBytes(o.down) + '/s' + }) + ); + }, + [hostname, port, secret] + ); return speed; } |
