1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
|
import { loadState, saveState, clearState } from '../misc/storage';
import { fetchConfigs } from './configs';
import { closeModal } from './modals';
const UpdateClashAPIConfig = 'app/UpdateClashAPIConfig';
const SwitchTheme = 'app/SwitchTheme';
const SELECT_CHART_STYLE_INDEX = 'app/SELECT_CHART_STYLE_INDEX';
export const getClashAPIConfig = s => s.app.clashAPIConfig;
export const getTheme = s => s.app.theme;
export const getSelectedChartStyleIndex = s => s.app.selectedChartStyleIndex;
export function updateClashAPIConfig({ hostname: iHostname, port, secret }) {
return async (dispatch, getState) => {
const hostname = iHostname.trim().replace(/^http(s):\/\//, '');
dispatch({
type: UpdateClashAPIConfig,
payload: { hostname, port, secret }
});
// side effect
saveState(getState().app);
dispatch(closeModal('apiConfig'));
dispatch(fetchConfigs());
};
}
const bodyElement = document.body;
function setTheme(theme = 'dark') {
if (theme === 'dark') {
bodyElement.classList.remove('light');
bodyElement.classList.add('dark');
} else {
bodyElement.classList.remove('dark');
bodyElement.classList.add('light');
}
}
export function switchTheme() {
return (dispatch, getState) => {
const currentTheme = getTheme(getState());
const theme = currentTheme === 'light' ? 'dark' : 'light';
// side effect
setTheme(theme);
dispatch({ type: SwitchTheme, payload: { theme } });
// side effect
saveState(getState().app);
};
}
export function clearStorage() {
clearState();
try {
window.location.reload();
} catch (err) {
// ignore
}
}
export function selectChartStyleIndex(selectedChartStyleIndex) {
return (dispatch, getState) => {
dispatch({
type: SELECT_CHART_STYLE_INDEX,
payload: {
selectedChartStyleIndex
}
});
// side effect
saveState(getState().app);
};
}
// type Theme = 'light' | 'dark';
const defaultState = {
clashAPIConfig: {
hostname: '127.0.0.1',
port: '7892',
secret: ''
},
selectedChartStyleIndex: 0,
theme: 'dark'
};
function parseConfigQueryString() {
const { search } = window.location;
const collector = {};
if (typeof search !== 'string' || search === '') return collector;
const qs = search.replace(/^\?/, '').split('&');
for (let i = 0; i < qs.length; i++) {
const [k, v] = qs[i].split('=');
collector[k] = encodeURIComponent(v);
}
return collector;
}
function getInitialState() {
let s = loadState();
s = { ...defaultState, ...s };
// TODO flat clashAPIConfig?
const configQuery = parseConfigQueryString();
if (configQuery.port) {
s.clashAPIConfig.port = configQuery.port;
}
if (configQuery.secret) {
s.clashAPIConfig.secret = configQuery.secret;
}
// set initial theme
setTheme(s.theme);
return s;
}
export default function reducer(state = getInitialState(), { type, payload }) {
switch (type) {
case UpdateClashAPIConfig: {
return { ...state, clashAPIConfig: { ...payload } };
}
case SwitchTheme: {
return { ...state, ...payload };
}
case SELECT_CHART_STYLE_INDEX: {
return { ...state, ...payload };
}
default:
return state;
}
}
|