diff --git a/src/components/SwitchThemed.tsx b/src/components/SwitchThemed.tsx
index 7121acb..7289bd2 100644
--- a/src/components/SwitchThemed.tsx
+++ b/src/components/SwitchThemed.tsx
@@ -1,11 +1,14 @@
-import React from 'react';
-import S from 'react-switch';
+import * as React from 'react';
+import ReactSwitch from 'react-switch';
+
+import { State } from '$src/store/types';
import { getTheme } from '../store/app';
import { connect } from './StateProvider';
// workaround https://github.com/vitejs/vite/issues/2139#issuecomment-802981228
-const Switch = S.default ? S.default : S;
+// @ts-ignore
+const Switch = ReactSwitch.default ? ReactSwitch.default : ReactSwitch;
function SwitchThemed({ checked = false, onChange, theme, name }) {
const offColor = theme === 'dark' ? '#393939' : '#e9e9e9';
@@ -29,6 +32,4 @@ function SwitchThemed({ checked = false, onChange, theme, name }) {
);
}
-export default connect((s) => ({
- theme: getTheme(s),
-}))(SwitchThemed);
+export default connect((s: State) => ({ theme: getTheme(s) }))(SwitchThemed);
diff --git a/src/components/ToggleSwitch.tsx b/src/components/ToggleSwitch.tsx
index 0c84059..9eb1019 100644
--- a/src/components/ToggleSwitch.tsx
+++ b/src/components/ToggleSwitch.tsx
@@ -16,8 +16,7 @@ function ToggleSwitch({ options, value, name, onChange }: Props) {
);
const getPortionPercentage = useCallback(
- // @ts-expect-error ts-migrate(7030) FIXME: Not all code paths return a value.
- (idx) => {
+ (idx: number) => {
const w = Math.floor(100 / options.length);
if (idx === options.length - 1) {
return 100 - options.length * w + w;
diff --git a/src/components/TrafficChart.tsx b/src/components/TrafficChart.tsx
index 056cac6..367166a 100644
--- a/src/components/TrafficChart.tsx
+++ b/src/components/TrafficChart.tsx
@@ -1,6 +1,8 @@
import * as React from 'react';
import { useTranslation } from 'react-i18next';
+import { State } from '$src/store/types';
+
import { fetchData } from '../api/traffic';
import useLineChart from '../hooks/useLineChart';
import {
@@ -19,7 +21,7 @@ const chartWrapperStyle = {
maxWidth: 1000,
};
-const mapState = (s) => ({
+const mapState = (s: State) => ({
apiConfig: getClashAPIConfig(s),
selectedChartStyleIndex: getSelectedChartStyleIndex(s),
});
@@ -27,7 +29,7 @@ const mapState = (s) => ({
export default connect(mapState)(TrafficChart);
function TrafficChart({ apiConfig, selectedChartStyleIndex }) {
- const Chart = chartJSResource.read();
+ const ChartMod = chartJSResource.read();
const traffic = fetchData(apiConfig);
const { t } = useTranslation();
const data = useMemo(
@@ -48,10 +50,10 @@ function TrafficChart({ apiConfig, selectedChartStyleIndex }) {
},
],
}),
- [traffic, selectedChartStyleIndex, t]
+ [ traffic, selectedChartStyleIndex, t]
);
- useLineChart(Chart, 'trafficChart', data, traffic);
+ useLineChart(ChartMod.Chart, 'trafficChart', data, traffic);
return (
// @ts-expect-error ts-migrate(2322) FIXME: Type '{ position: string; maxWidth: number; }' is ... Remove this comment to see the full error message
diff --git a/src/components/TrafficChartSample.tsx b/src/components/TrafficChartSample.tsx
index fb9b2ee..3e0bba3 100644
--- a/src/components/TrafficChartSample.tsx
+++ b/src/components/TrafficChartSample.tsx
@@ -1,19 +1,17 @@
-import React, { useMemo } from 'react';
+import * as React from 'react';
import useLineChart from '../hooks/useLineChart';
-import {
- chartJSResource,
- chartStyles,
- commonDataSetProps,
-} from '../misc/chart';
+import { chartJSResource, chartStyles, commonDataSetProps } from '../misc/chart';
-const extraChartOptions = {
- legend: {
- display: false,
+const { useMemo } = React;
+
+const extraChartOptions: import('chart.js').ChartOptions<'line'> = {
+ plugins: {
+ legend: { display: false },
},
scales: {
- xAxes: [{ display: false }],
- yAxes: [{ display: false }],
+ x: { display: false, type: 'category' },
+ y: { display: false, type: 'linear' },
},
};
@@ -22,7 +20,7 @@ const data2 = [184e3, 183e3, 196e3, 182e3, 190e3, 186e3, 182e3, 189e3];
const labels = data1;
export default function TrafficChart({ id }) {
- const Chart = chartJSResource.read();
+ const ChartMod = chartJSResource.read();
const data = useMemo(
() => ({
@@ -44,7 +42,7 @@ export default function TrafficChart({ id }) {
);
const eleId = 'chart-' + id;
- useLineChart(Chart, eleId, data, null, extraChartOptions);
+ useLineChart(ChartMod.Chart, eleId, data, null, extraChartOptions);
return (
diff --git a/src/hooks/useLineChart.ts b/src/hooks/useLineChart.ts
index 2757ee1..a3205aa 100644
--- a/src/hooks/useLineChart.ts
+++ b/src/hooks/useLineChart.ts
@@ -1,28 +1,24 @@
+import type { ChartConfiguration } from 'chart.js';
import React from 'react';
import { commonChartOptions } from 'src/misc/chart';
const { useEffect } = React;
-const options = commonChartOptions;
export default function useLineChart(
- Chart,
- elementId,
- data,
- subscription,
+ chart: typeof import('chart.js').Chart,
+ elementId: string,
+ data: ChartConfiguration['data'],
+ subscription: any,
extraChartOptions = {}
) {
useEffect(() => {
- const ctx = document.getElementById(elementId).getContext('2d');
- const c = new Chart(ctx, {
- type: 'line',
- data,
- options: { ...options, ...extraChartOptions },
- });
- const unsubscribe =
- subscription && subscription.subscribe(() => c.update());
+ const ctx = (document.getElementById(elementId) as HTMLCanvasElement).getContext('2d');
+ const options = { ...commonChartOptions, ...extraChartOptions };
+ const c = new chart(ctx, { type: 'line', data, options });
+ const unsubscribe = subscription && subscription.subscribe(() => c.update());
return () => {
unsubscribe && unsubscribe();
c.destroy();
};
- }, [Chart, elementId, data, subscription, extraChartOptions]);
+ }, [chart, elementId, data, subscription, extraChartOptions]);
}
diff --git a/src/misc/chart-lib.ts b/src/misc/chart-lib.ts
new file mode 100644
index 0000000..9a2bf35
--- /dev/null
+++ b/src/misc/chart-lib.ts
@@ -0,0 +1,23 @@
+import {
+ CategoryScale,
+ Chart,
+ Filler,
+ Legend,
+ LinearScale,
+ LineController,
+ LineElement,
+ PointElement,
+} from 'chart.js';
+
+// see https://www.chartjs.org/docs/latest/getting-started/integration.html#bundlers-webpack-rollup-etc
+Chart.register(
+ LineElement,
+ PointElement,
+ LineController,
+ CategoryScale,
+ LinearScale,
+ Filler,
+ Legend
+);
+
+export { Chart };
diff --git a/src/misc/chart.ts b/src/misc/chart.ts
index 9e2c459..a6ee82e 100644
--- a/src/misc/chart.ts
+++ b/src/misc/chart.ts
@@ -1,71 +1,36 @@
import { unstable_createResource as createResource } from '@hsjs/react-cache';
import prettyBytes from './pretty-bytes';
-
export const chartJSResource = createResource(() => {
- return import(
- /* webpackChunkName: "chartjs" */
- /* webpackPrefetch: true */
- /* webpackPreload: true */
- 'chart.js/dist/Chart.min.js'
- ).then((c) => c.default);
+ return import('$src/misc/chart-lib');
});
-export const commonDataSetProps = {
- borderWidth: 1,
- lineTension: 0,
- pointRadius: 0,
-};
+export const commonDataSetProps = { borderWidth: 1, pointRadius: 0, tension: 0.2, fill: true };
-export const commonChartOptions = {
+export const commonChartOptions: import('chart.js').ChartOptions<'line'> = {
responsive: true,
maintainAspectRatio: true,
- title: {
- display: false,
- },
- legend: {
- display: true,
- position: 'top',
- labels: {
- fontColor: '#ccc',
- boxWidth: 20,
- },
- },
- tooltips: {
- enabled: false,
- mode: 'index',
- intersect: false,
- animationDuration: 100,
- },
- hover: {
- mode: 'nearest',
- intersect: true,
+ plugins: {
+ legend: { labels: { boxWidth: 20 } }
},
scales: {
- xAxes: [
- {
- display: false,
- gridLines: {
- display: false,
- },
- },
- ],
- yAxes: [
- {
+ x: { display: false, type: 'category' },
+ y: {
+ type: 'linear',
+ display: true,
+ grid: {
display: true,
- gridLines: {
- display: true,
- color: '#555',
- borderDash: [3, 6],
- drawBorder: false,
- },
- ticks: {
- callback(value) {
- return prettyBytes(value) + '/s ';
- },
+ color: '#555',
+ drawTicks: false,
+ borderDash: [3, 6],
+ drawBorder: false,
+ },
+ ticks: {
+ callback(value: number) {
+ return prettyBytes(value) + '/s ';
},
},
- ],
+ },
},
};
diff --git a/src/misc/constants.ts b/src/misc/constants.ts
deleted file mode 100644
index 5c66350..0000000
--- a/src/misc/constants.ts
+++ /dev/null
@@ -1 +0,0 @@
-// const ProxySortingOptions =
diff --git a/src/misc/sentry.ts b/src/misc/sentry.ts
deleted file mode 100644
index efedcb3..0000000
--- a/src/misc/sentry.ts
+++ /dev/null
@@ -1,10 +0,0 @@
-const dsn = 'https://7068a15928ae45cf884dd8398fe8649c@sentry.io/1359284';
-let Sentry;
-export async function getSentry() {
- if (Sentry) return Sentry;
- const s = await import('@sentry/browser');
- s.init({ dsn });
- // eslint-disable-next-line require-atomic-updates
- Sentry = s;
- return Sentry;
-}
diff --git a/src/store/app.ts b/src/store/app.ts
index 6680e6e..7262b32 100644
--- a/src/store/app.ts
+++ b/src/store/app.ts
@@ -22,7 +22,6 @@ export const getLogStreamingPaused = (s: State) => s.app.logStreamingPaused;
const saveStateDebounced = debounce(saveState, 600);
-// @ts-expect-error ts-migrate(7030) FIXME: Not all code paths return a value.
function findClashAPIConfigIndex(getState: GetStateFn, { baseURL, secret }) {
const arr = getClashAPIConfigs(getState());
for (let i = 0; i < arr.length; i++) {
diff --git a/src/store/types.ts b/src/store/types.ts
index b9141ac..d12adaa 100644
--- a/src/store/types.ts
+++ b/src/store/types.ts
@@ -108,10 +108,8 @@ export type State = {
export type GetStateFn = () => State;
export interface DispatchFn {
(msg: string, change: (s: State) => void): void;
- (
- action: (dispatch: DispatchFn, getState: GetStateFn) => Promise
- ): ReturnType;
- (action: (dispatch: DispatchFn, getState: GetStateFn) => void): ReturnType<
+ (action: (dispatch: DispatchFn, getState: GetStateFn) => Promise): ReturnType<
typeof action
>;
+ (action: (dispatch: DispatchFn, getState: GetStateFn) => void): ReturnType;
}
diff --git a/tsconfig.json b/tsconfig.json
index c5a74e9..9ecdbea 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -2,6 +2,10 @@
"$schema": "https://json.schemastore.org/tsconfig",
"compilerOptions": {
"baseUrl": ".",
+ "paths": {
+ "$src": ["src"],
+ "$src/*": ["src/*"]
+ },
"target": "ESNext",
"lib": ["DOM", "DOM.Iterable", "ESNext", "WebWorker"],
"skipLibCheck": true,
@@ -14,20 +18,7 @@
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true,
- "jsx": "react",
- "downlevelIteration": true,
- "importHelpers": true,
- "sourceMap": true,
- "checkJs": false,
- "experimentalDecorators": true,
- "noImplicitAny": false,
- "noUnusedParameters": false,
- "noImplicitReturns": true,
- "noImplicitThis": true,
- "noUnusedLocals": true,
- "strictNullChecks": false,
- "suppressImplicitAnyIndexErrors": true,
- "types": ["jest"]
+ "jsx": "react"
},
"include": ["./src"]
}
diff --git a/vite.config.ts b/vite.config.ts
index c3b00d6..e0f16f8 100644
--- a/vite.config.ts
+++ b/vite.config.ts
@@ -1,6 +1,6 @@
import { defineConfig } from 'vite';
import { VitePWA } from 'vite-plugin-pwa';
-import reactRefresh from '@vitejs/plugin-react-refresh';
+import react from '@vitejs/plugin-react'
import * as path from 'path';
import * as pkg from './package.json';
@@ -12,15 +12,22 @@ export default defineConfig(({ mode }) => ({
'process.env.PUBLIC_URL': JSON.stringify('./'),
},
base: './',
+ resolve: {
+ alias: {
+ $src: path.resolve(__dirname, './src'),
+ src: path.resolve(__dirname, './src'),
+ },
+ },
publicDir: 'assets',
build: {
+ // sourcemap: true,
// the default value is 'dist'
// which make more sense
// but change this may break other people's tools
outDir: 'public',
},
plugins: [
- reactRefresh(),
+ react(),
VitePWA({
srcDir: 'src',
outDir: 'public',
@@ -29,9 +36,4 @@ export default defineConfig(({ mode }) => ({
base: './',
}),
],
- resolve: {
- alias: {
- src: path.resolve(__dirname, './src'),
- },
- },
}));