summaryrefslogtreecommitdiff
path: root/src/components
diff options
context:
space:
mode:
authorHaishan <[email protected]>2018-12-04 23:39:26 +0800
committerHaishan <[email protected]>2018-12-07 00:19:49 +0800
commit3584ff617966af35ddd0fd45ef2df7cdfb8f5071 (patch)
tree83f4f535d1fd3ca1c85807a1c2b397cf9b6733c5 /src/components
parenta265c62020d4dd3a4e57e5ad0894794461dd8385 (diff)
feat: initial theming support
Diffstat (limited to 'src/components')
-rw-r--r--src/components/ContentHeader.module.scss1
-rw-r--r--src/components/Logs.js17
-rw-r--r--src/components/Root.js40
-rw-r--r--src/components/Root.module.scss5
-rw-r--r--src/components/SideBar.js11
-rw-r--r--src/components/SideBar.module.scss22
-rw-r--r--src/components/Theme.js17
-rw-r--r--src/components/Theme.module.scss11
-rw-r--r--src/components/TrafficChart.js52
-rw-r--r--src/components/TrafficNow.js26
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;
}