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
|
import { Tooltip } from '@reach/tooltip';
import cx from 'clsx';
import * as React from 'react';
import { Info } from 'react-feather';
import { useTranslation } from 'react-i18next';
import { FcAreaChart, FcDocument, FcGlobe, FcLink, FcRuler, FcSettings } from 'react-icons/fc';
import { useQuery } from 'react-query';
import { Link, useLocation } from 'react-router-dom';
import { fetchVersion } from '~/api/version';
import { ThemeSwitcher } from '~/components/shared/ThemeSwitcher';
import { connect } from '~/components/StateProvider';
import { getClashAPIConfig } from '~/store/app';
import { ClashAPIConfig } from '~/types';
import s from './SideBar.module.scss';
type Props = { apiConfig: ClashAPIConfig };
const icons = {
activity: FcAreaChart,
globe: FcGlobe,
command: FcRuler,
file: FcDocument,
settings: FcSettings,
link: FcLink,
};
const SideBarRow = React.memo(function SideBarRow({
isActive,
to,
iconId,
labelText,
}: SideBarRowProps) {
const Comp = icons[iconId];
const className = cx(s.row, isActive ? s.rowActive : null);
return (
<Link to={to} className={className}>
<Comp />
<div className={s.label}>{labelText}</div>
</Link>
);
});
interface SideBarRowProps {
isActive: boolean;
to: string;
iconId?: string;
labelText?: string;
}
const pages = [
{
to: '/',
iconId: 'activity',
labelText: 'Overview',
},
{
to: '/proxies',
iconId: 'globe',
labelText: 'Proxies',
},
{
to: '/rules',
iconId: 'command',
labelText: 'Rules',
},
{
to: '/connections',
iconId: 'link',
labelText: 'Conns',
},
{
to: '/configs',
iconId: 'settings',
labelText: 'Config',
},
{
to: '/logs',
iconId: 'file',
labelText: 'Logs',
},
];
const mapState = (s) => ({
apiConfig: getClashAPIConfig(s),
});
export default connect(mapState)(SideBar);
function SideBar(props: Props) {
const { t } = useTranslation();
const location = useLocation();
const { data: version } = useQuery(['/version', props.apiConfig], () =>
fetchVersion('/version', props.apiConfig)
);
return (
<div className={s.root}>
<div className={version.meta && version.premium ? s.logo_singbox : s.logo_meta} />
<div className={s.rows}>
{pages.map(({ to, iconId, labelText }) => (
<SideBarRow
key={to}
to={to}
isActive={location.pathname === to}
iconId={iconId}
labelText={t(labelText)}
/>
))}
</div>
<div className={s.footer}>
<ThemeSwitcher />
<Tooltip label={t('about')}>
<Link to="/about" className={s.iconWrapper}>
<Info size={20} />
</Link>
</Tooltip>
</div>
</div>
);
}
|