summaryrefslogtreecommitdiff
path: root/src/components
diff options
context:
space:
mode:
authorOlivi <[email protected]>2026-04-15 19:26:24 +0800
committerOlivi <[email protected]>2026-04-15 19:26:24 +0800
commitedf6c5cb65cbf103fb1848760595f5c381dac723 (patch)
treec7e2d98570fb82fd4789e4379f2e889fb9633770 /src/components
parente48240ddf861466cb380fd7b6d6c29807234d8b2 (diff)
build(deps)!: update depends
Diffstat (limited to 'src/components')
-rw-r--r--src/components/BackendList.tsx2
-rw-r--r--src/components/Button.module.scss2
-rw-r--r--src/components/Config.module.scss2
-rw-r--r--src/components/Config.tsx2
-rw-r--r--src/components/ConnectionCard.tsx2
-rw-r--r--src/components/ConnectionTable.tsx68
-rw-r--r--src/components/Connections.tsx4
-rw-r--r--src/components/ContentHeader.module.scss2
-rw-r--r--src/components/Home.module.scss2
-rw-r--r--src/components/Logs.tsx2
-rw-r--r--src/components/Modal.tsx32
-rw-r--r--src/components/ModalCloseAllConnections.tsx18
-rw-r--r--src/components/ModalConnectionDetails.tsx3
-rw-r--r--src/components/ModalManageConnectionColumns.tsx2
-rw-r--r--src/components/Rule.module.scss2
-rw-r--r--src/components/Rule.tsx2
-rw-r--r--src/components/Rules.module.scss2
-rw-r--r--src/components/Rules.tsx32
-rw-r--r--src/components/SideBar.module.scss2
-rw-r--r--src/components/SideBar.tsx2
-rw-r--r--src/components/StateProvider.tsx12
-rw-r--r--src/components/StyleGuide.tsx2
-rw-r--r--src/components/TrafficNow.tsx2
-rw-r--r--src/components/about/About.module.scss2
-rw-r--r--src/components/about/About.tsx4
-rw-r--r--src/components/proxies/Proxies.module.scss2
-rw-r--r--src/components/proxies/Proxy.module.scss2
-rw-r--r--src/components/proxies/ProxyGroup.tsx2
-rw-r--r--src/components/proxies/ProxyLatency.module.scss2
-rw-r--r--src/components/proxies/ProxyList.module.scss2
-rw-r--r--src/components/proxies/ProxyPageFab.tsx2
-rw-r--r--src/components/proxies/ProxyProvider.module.scss2
-rw-r--r--src/components/proxies/ProxyProvider.tsx2
-rw-r--r--src/components/rules/RuleProviderItem.tsx2
-rw-r--r--src/components/shared/BaseModal.tsx11
-rw-r--r--src/components/shared/Basic.module.scss2
-rw-r--r--src/components/shared/Fab.tsx13
-rw-r--r--src/components/shared/FeatherIcons.ts53
-rw-r--r--src/components/shared/RotateIcon.tsx2
39 files changed, 189 insertions, 117 deletions
diff --git a/src/components/BackendList.tsx b/src/components/BackendList.tsx
index 2246dd6..bb9ae53 100644
--- a/src/components/BackendList.tsx
+++ b/src/components/BackendList.tsx
@@ -1,6 +1,6 @@
import cx from 'clsx';
import * as React from 'react';
-import { Eye, EyeOff, X as Close } from 'react-feather';
+import { Eye, EyeOff, X as Close } from '~/components/shared/FeatherIcons';
import { useToggle } from '~/hooks/basic';
import type { ClashAPIConfigWithAddedAt } from '~/store/types';
diff --git a/src/components/Button.module.scss b/src/components/Button.module.scss
index 5dd6733..4f89d4c 100644
--- a/src/components/Button.module.scss
+++ b/src/components/Button.module.scss
@@ -1,4 +1,4 @@
-@import '~/styles/utils/custom-media';
+@use '~/styles/utils/custom-media' as *;
.btn {
-webkit-appearance: none;
diff --git a/src/components/Config.module.scss b/src/components/Config.module.scss
index 9bc3f08..1c178b4 100644
--- a/src/components/Config.module.scss
+++ b/src/components/Config.module.scss
@@ -1,4 +1,4 @@
-@import '~/styles/utils/custom-media';
+@use '~/styles/utils/custom-media' as *;
.root {
max-width: 1000px;
diff --git a/src/components/Config.tsx b/src/components/Config.tsx
index 670555f..2d3f08b 100644
--- a/src/components/Config.tsx
+++ b/src/components/Config.tsx
@@ -8,7 +8,7 @@ import {
Settings,
Tool,
Trash2,
-} from 'react-feather';
+} from '~/components/shared/FeatherIcons';
import { useTranslation } from 'react-i18next';
import Select from '~/components/shared/Select';
diff --git a/src/components/ConnectionCard.tsx b/src/components/ConnectionCard.tsx
index 8a3a88a..bf16eb6 100644
--- a/src/components/ConnectionCard.tsx
+++ b/src/components/ConnectionCard.tsx
@@ -1,7 +1,7 @@
import { formatDistance, Locale } from 'date-fns';
import { enUS, zhCN, zhTW } from 'date-fns/locale';
import React from 'react';
-import { ArrowDown, ArrowDownCircle, ArrowUp, X } from 'react-feather';
+import { ArrowDown, ArrowDownCircle, ArrowUp, X } from '~/components/shared/FeatherIcons';
import { useTranslation } from 'react-i18next';
import { FormattedConn } from '~/store/connections';
diff --git a/src/components/ConnectionTable.tsx b/src/components/ConnectionTable.tsx
index 8a2f0a6..e296706 100644
--- a/src/components/ConnectionTable.tsx
+++ b/src/components/ConnectionTable.tsx
@@ -4,10 +4,10 @@ import cx from 'clsx';
import { formatDistance, Locale } from 'date-fns';
import { enUS, zhCN, zhTW } from 'date-fns/locale';
import React, { useCallback, useEffect, useMemo, useState } from 'react';
-import { ArrowDown, ArrowUp, ChevronDown, Sliders, XCircle } from 'react-feather';
+import { ArrowDown, ArrowUp, ChevronDown, Sliders, XCircle } from '~/components/shared/FeatherIcons';
import { useTranslation } from 'react-i18next';
import { useSortBy, useTable } from 'react-table';
-import { FixedSizeList as List } from 'react-window';
+import { List as VirtualList, RowComponentProps } from 'react-window';
import { FormattedConn } from '~/store/connections';
@@ -40,19 +40,6 @@ const COLUMN_WIDTHS = {
const TOTAL_WIDTH = Object.values(COLUMN_WIDTHS).reduce((a, b) => a + b, 0);
-const InnerElement = React.forwardRef<HTMLDivElement, React.HTMLProps<HTMLDivElement>>(
- ({ style, ...rest }, ref) => (
- <div
- ref={ref}
- style={{
- ...style,
- width: TOTAL_WIDTH,
- }}
- {...rest}
- />
- )
-);
-
const getColumnStyle = (columnId: string) => {
const width = COLUMN_WIDTHS[columnId] || 100;
const style: React.CSSProperties = {
@@ -82,19 +69,6 @@ function Table({ data, columns, hiddenColumns, apiConfig, height }) {
const [isMobile, setIsMobile] = useState(false);
const headerRef = React.useRef<HTMLDivElement>(null);
- const outerRef = React.useRef<HTMLDivElement>(null);
-
- useEffect(() => {
- const outer = outerRef.current;
- if (!outer) return;
- const handleScroll = () => {
- if (headerRef.current) {
- headerRef.current.scrollLeft = outer.scrollLeft;
- }
- };
- outer.addEventListener('scroll', handleScroll);
- return () => outer.removeEventListener('scroll', handleScroll);
- }, []);
useEffect(() => {
const mql = window.matchMedia('(max-width: 768px)');
@@ -193,7 +167,7 @@ function Table({ data, columns, hiddenColumns, apiConfig, height }) {
}, [state.sortBy]);
const MobileRow = useCallback(
- ({ index, style }) => {
+ ({ index, style }: RowComponentProps) => {
const row = rows[index];
const conn = row.original as FormattedConn;
return (
@@ -211,7 +185,7 @@ function Table({ data, columns, hiddenColumns, apiConfig, height }) {
);
const DesktopRow = useCallback(
- ({ index, style }) => {
+ ({ index, style }: RowComponentProps) => {
const row = rows[index];
prepareRow(row);
return (
@@ -259,6 +233,12 @@ function Table({ data, columns, hiddenColumns, apiConfig, height }) {
[prepareRow, rows, renderCell, locale]
);
+ const handleDesktopListScroll = useCallback((e: React.UIEvent<HTMLDivElement>) => {
+ if (headerRef.current) {
+ headerRef.current.scrollLeft = e.currentTarget.scrollLeft;
+ }
+ }, []);
+
return (
<div className={s.tableWrapper} style={{ height, overflow: 'hidden' }}>
{isMobile ? (
@@ -290,9 +270,13 @@ function Table({ data, columns, hiddenColumns, apiConfig, height }) {
{currentSort.desc ? <ArrowDown size={18} /> : <ArrowUp size={18} />}
</button>
</div>
- <List height={height - 50} itemCount={rows.length} itemSize={120} width="100%">
- {MobileRow}
- </List>
+ <VirtualList
+ style={{ height: height - 50, width: '100%' }}
+ rowCount={rows.length}
+ rowHeight={120}
+ rowComponent={MobileRow}
+ rowProps={{}}
+ />
</div>
) : (
<div
@@ -347,16 +331,14 @@ function Table({ data, columns, hiddenColumns, apiConfig, height }) {
))}
</div>
</div>
- <List
- height={height - 50}
- itemCount={rows.length}
- itemSize={44}
- width="100%"
- outerRef={outerRef}
- innerElementType={InnerElement}
- >
- {DesktopRow}
- </List>
+ <VirtualList
+ style={{ height: height - 50, width: '100%' }}
+ onScroll={handleDesktopListScroll}
+ rowCount={rows.length}
+ rowHeight={44}
+ rowComponent={DesktopRow}
+ rowProps={{}}
+ />
</div>
)}
<MOdalCloseConnection
diff --git a/src/components/Connections.tsx b/src/components/Connections.tsx
index 38da7b8..64a5998 100644
--- a/src/components/Connections.tsx
+++ b/src/components/Connections.tsx
@@ -1,7 +1,7 @@
import './Connections.css';
import React from 'react';
-import { Pause, Play, RefreshCcw, Settings, Tag, X as IconClose } from 'react-feather';
+import { Pause, Play, RefreshCcw, Settings, Tag, X as IconClose } from '~/components/shared/FeatherIcons';
import { useTranslation } from 'react-i18next';
import { Tab, TabList, TabPanel, Tabs } from 'react-tabs';
@@ -114,14 +114,12 @@ export default function Connections({ apiConfig }: Props) {
<Tab>
<span>{t('Active')}</span>
<span className={s.connQty}>
- {/* @ts-expect-error ts-migrate(2786) FIXME: 'ConnQty' cannot be used as a JSX component. */}
<ConnQty qty={filteredConns.length} />
</span>
</Tab>
<Tab>
<span>{t('Closed')}</span>
<span className={s.connQty}>
- {/* @ts-expect-error ts-migrate(2786) FIXME: 'ConnQty' cannot be used as a JSX component. */}
<ConnQty qty={filteredClosedConns.length} />
</span>
</Tab>
diff --git a/src/components/ContentHeader.module.scss b/src/components/ContentHeader.module.scss
index 37a7b86..be1697b 100644
--- a/src/components/ContentHeader.module.scss
+++ b/src/components/ContentHeader.module.scss
@@ -1,4 +1,4 @@
-@import '~/styles/utils/custom-media';
+@use '~/styles/utils/custom-media' as *;
.root {
height: 60px;
diff --git a/src/components/Home.module.scss b/src/components/Home.module.scss
index 8da1d49..7fa6ada 100644
--- a/src/components/Home.module.scss
+++ b/src/components/Home.module.scss
@@ -1,4 +1,4 @@
-@import '~/styles/utils/custom-media';
+@use '~/styles/utils/custom-media' as *;
.root {
padding: 6px 15px;
diff --git a/src/components/Logs.tsx b/src/components/Logs.tsx
index 0dbb8f0..59abced 100644
--- a/src/components/Logs.tsx
+++ b/src/components/Logs.tsx
@@ -1,5 +1,5 @@
import * as React from 'react';
-import { ArrowDown, Pause, Play, Trash2 } from 'react-feather';
+import { ArrowDown, Pause, Play, Trash2 } from '~/components/shared/FeatherIcons';
import { useTranslation } from 'react-i18next';
import ContentHeader from '~/components/ContentHeader';
diff --git a/src/components/Modal.tsx b/src/components/Modal.tsx
index e91523c..dfb9683 100644
--- a/src/components/Modal.tsx
+++ b/src/components/Modal.tsx
@@ -1,6 +1,6 @@
import cx from 'clsx';
import * as React from 'react';
-import Modal, { Props as ReactModalProps } from 'react-modal';
+import ReactModalBase, { Props as ReactModalProps } from 'react-modal';
import s0 from './Modal.module.scss';
@@ -8,10 +8,28 @@ type Props = ReactModalProps & {
isOpen: boolean;
onRequestClose: (...args: any[]) => any;
children: React.ReactNode;
- className?: string;
- overlayClassName?: string;
};
+const ReactModal = ReactModalBase as unknown as React.ComponentType<ReactModalProps>;
+
+function withBaseClass(
+ className: ReactModalProps['className'],
+ baseClassName: string
+): ReactModalProps['className'] {
+ if (!className) {
+ return baseClassName;
+ }
+
+ if (typeof className === 'string') {
+ return cx(className, baseClassName);
+ }
+
+ return {
+ ...className,
+ base: cx(className.base, baseClassName),
+ };
+}
+
function ModalAPIConfig({
isOpen,
onRequestClose,
@@ -20,10 +38,10 @@ function ModalAPIConfig({
children,
...otherProps
}: Props) {
- const contentCls = cx(className, s0.content);
- const overlayCls = cx(overlayClassName, s0.overlay);
+ const contentCls = withBaseClass(className, s0.content);
+ const overlayCls = withBaseClass(overlayClassName, s0.overlay);
return (
- <Modal
+ <ReactModal
isOpen={isOpen}
onRequestClose={onRequestClose}
className={contentCls}
@@ -31,7 +49,7 @@ function ModalAPIConfig({
{...otherProps}
>
{children}
- </Modal>
+ </ReactModal>
);
}
diff --git a/src/components/ModalCloseAllConnections.tsx b/src/components/ModalCloseAllConnections.tsx
index 77bcb59..72efc7c 100644
--- a/src/components/ModalCloseAllConnections.tsx
+++ b/src/components/ModalCloseAllConnections.tsx
@@ -1,7 +1,8 @@
import cx from 'clsx';
import React from 'react';
import { useTranslation } from 'react-i18next';
-import Modal from 'react-modal';
+
+import Modal from './Modal';
import Button from './Button';
import modalStyle from './Modal.module.scss';
@@ -9,16 +10,25 @@ import s from './ModalCloseAllConnections.module.scss';
const { useRef, useCallback, useMemo } = React;
+type Props = {
+ confirm?: string;
+ isOpen: boolean;
+ onRequestClose: () => void;
+ primaryButtonOnTap: (e: React.MouseEvent<HTMLButtonElement>) => unknown;
+};
+
export default function Comp({
confirm = 'close_all_confirm',
isOpen,
onRequestClose,
primaryButtonOnTap,
-}) {
+}: Props) {
const { t } = useTranslation();
- const primaryButtonRef = useRef(null);
+ const primaryButtonRef = useRef<HTMLButtonElement | null>(null);
const onAfterOpen = useCallback(() => {
- primaryButtonRef.current.focus();
+ if (primaryButtonRef.current) {
+ primaryButtonRef.current.focus();
+ }
}, []);
const className = useMemo(
() => ({
diff --git a/src/components/ModalConnectionDetails.tsx b/src/components/ModalConnectionDetails.tsx
index 3274b4e..4fb4c0c 100644
--- a/src/components/ModalConnectionDetails.tsx
+++ b/src/components/ModalConnectionDetails.tsx
@@ -3,7 +3,8 @@ import { formatDistance } from 'date-fns';
import { enUS, zhCN, zhTW } from 'date-fns/locale';
import React from 'react';
import { useTranslation } from 'react-i18next';
-import Modal from 'react-modal';
+
+import Modal from './Modal';
import { FormattedConn } from '~/store/connections';
diff --git a/src/components/ModalManageConnectionColumns.tsx b/src/components/ModalManageConnectionColumns.tsx
index 463f76b..6c687c4 100644
--- a/src/components/ModalManageConnectionColumns.tsx
+++ b/src/components/ModalManageConnectionColumns.tsx
@@ -1,6 +1,6 @@
import { DragDropContext, Draggable, Droppable } from '@hello-pangea/dnd';
import React from 'react';
-import { ChevronDown, ChevronUp, Menu } from 'react-feather';
+import { ChevronDown, ChevronUp, Menu } from '~/components/shared/FeatherIcons';
import { useTranslation } from 'react-i18next';
import BaseModal from '~/components/shared/BaseModal';
diff --git a/src/components/Rule.module.scss b/src/components/Rule.module.scss
index 845fa5e..48a22e7 100644
--- a/src/components/Rule.module.scss
+++ b/src/components/Rule.module.scss
@@ -1,4 +1,4 @@
-@import '~/styles/utils/custom-media';
+@use '~/styles/utils/custom-media' as *;
.rule {
display: flex;
diff --git a/src/components/Rule.tsx b/src/components/Rule.tsx
index 24e2e57..ee3a7ab 100644
--- a/src/components/Rule.tsx
+++ b/src/components/Rule.tsx
@@ -1,5 +1,5 @@
import React from 'react';
-import { FileText, Globe, Hash, Link, Shield, Zap } from 'react-feather';
+import { FileText, Globe, Hash, Link, Shield, Zap } from '~/components/shared/FeatherIcons';
import s0 from './Rule.module.scss';
diff --git a/src/components/Rules.module.scss b/src/components/Rules.module.scss
index c2a4f39..f764d09 100644
--- a/src/components/Rules.module.scss
+++ b/src/components/Rules.module.scss
@@ -1,4 +1,4 @@
-@import '~/styles/utils/custom-media';
+@use '~/styles/utils/custom-media' as *;
.container {
display: flex;
diff --git a/src/components/Rules.tsx b/src/components/Rules.tsx
index c4ecd90..fb63028 100644
--- a/src/components/Rules.tsx
+++ b/src/components/Rules.tsx
@@ -1,14 +1,14 @@
import cx from 'clsx';
import React from 'react';
import { useTranslation } from 'react-i18next';
-import { areEqual, VariableSizeList } from 'react-window';
+import { List as VirtualList, RowComponentProps } from 'react-window';
import ContentHeader from '~/components/ContentHeader';
import { RuleProviderItem } from '~/components/rules/RuleProviderItem';
import { RulesPageFab } from '~/components/rules/RulesPageFab';
import { TextFilter } from '~/components/shared/TextFitler';
import { useRulesPage } from '~/modules/rules/hooks';
-import { formatQty, getItemSizeFactory, itemKey, RulesListItemData } from '~/modules/rules/utils';
+import { formatQty, getItemSizeFactory, RulesListItemData } from '~/modules/rules/utils';
import { ruleFilterText } from '~/store/rules';
import { ClashAPIConfig } from '~/types';
@@ -17,10 +17,11 @@ import useRemainingViewPortHeight from '../hooks/useRemainingViewPortHeight';
import Rule from './Rule';
import s from './Rules.module.scss';
-const { memo } = React;
+type RulesRowProps = {
+ data: RulesListItemData;
+};
-// @ts-expect-error ts-migrate(2339) FIXME: Property 'index' does not exist on type '{ childre... Remove this comment to see the full error message
-const Row = memo(({ index, style, data }) => {
+function Row({ index, style, data }: RowComponentProps<RulesRowProps>) {
const { rules, provider, apiConfig } = data;
if (!rules) {
@@ -39,7 +40,7 @@ const Row = memo(({ index, style, data }) => {
<Rule {...r} />
</div>
);
-}, areEqual);
+}
type RulesProps = {
apiConfig: ClashAPIConfig;
@@ -86,16 +87,15 @@ export default function Rules({ apiConfig }: RulesProps) {
</div>
</ContentHeader>
<div ref={refRulesContainer} className={s.listWrapper}>
- <VariableSizeList
- height={containerHeight}
- width="100%"
- itemCount={isRulesTab ? rules.length : provider.names.length}
- itemSize={getItemSize}
- itemData={{ rules: isRulesTab ? rules : null, provider, apiConfig } as RulesListItemData}
- itemKey={itemKey}
- >
- {Row}
- </VariableSizeList>
+ <VirtualList
+ style={{ height: containerHeight, width: '100%' }}
+ rowCount={isRulesTab ? rules.length : provider.names.length}
+ rowHeight={getItemSize}
+ rowComponent={Row}
+ rowProps={{
+ data: { rules: isRulesTab ? rules : null, provider, apiConfig } as RulesListItemData,
+ }}
+ />
</div>
{provider && provider.names && provider.names.length > 0 ? (
<RulesPageFab apiConfig={apiConfig} />
diff --git a/src/components/SideBar.module.scss b/src/components/SideBar.module.scss
index aab6324..74f7087 100644
--- a/src/components/SideBar.module.scss
+++ b/src/components/SideBar.module.scss
@@ -1,4 +1,4 @@
-@import '~/styles/utils/custom-media';
+@use '~/styles/utils/custom-media' as *;
.root {
background: var(--color-bg-sidebar);
diff --git a/src/components/SideBar.tsx b/src/components/SideBar.tsx
index 307a362..a117533 100644
--- a/src/components/SideBar.tsx
+++ b/src/components/SideBar.tsx
@@ -1,7 +1,7 @@
import { Tooltip } from '@reach/tooltip';
import cx from 'clsx';
import * as React from 'react';
-import { Info } from 'react-feather';
+import { Info } from '~/components/shared/FeatherIcons';
import { useTranslation } from 'react-i18next';
import { FcAreaChart, FcDocument, FcGlobe, FcLink, FcRuler, FcSettings } from 'react-icons/fc';
import { useQuery } from 'react-query';
diff --git a/src/components/StateProvider.tsx b/src/components/StateProvider.tsx
index 1ef48d7..4b074ef 100644
--- a/src/components/StateProvider.tsx
+++ b/src/components/StateProvider.tsx
@@ -1,15 +1,15 @@
-import produce, * as immer from 'immer';
+import { produce, setAutoFreeze } from 'immer';
import React from 'react';
// in logs store we update logs in place
// outside of immer produce
// this is just workaround
-immer.setAutoFreeze(false);
+setAutoFreeze(false);
const { createContext, memo, useMemo, useRef, useEffect, useCallback, useContext, useState } =
React;
-export { immer };
+export const immer = { produce, setAutoFreeze };
const StateContext = createContext(null);
const DispatchContext = createContext(null);
@@ -33,7 +33,7 @@ export default function Provider({ initialState, actions = {}, children }) {
const [state, setState] = useState(initialState);
const getState = useCallback(() => stateRef.current, []);
useEffect(() => {
- if (process.env.NODE_ENV === 'development') {
+ if (import.meta.env.DEV) {
(window as any).getState2 = getState;
}
}, [getState]);
@@ -43,7 +43,7 @@ export default function Provider({ initialState, actions = {}, children }) {
const stateNext = produce(getState(), fn);
if (stateNext !== stateRef.current) {
- if (process.env.NODE_ENV === 'development') {
+ if (import.meta.env.DEV) {
// eslint-disable-next-line no-console
console.log(actionId, stateNext);
}
@@ -81,7 +81,7 @@ export function connect(mapStateToProps: any) {
// steal from https://github.com/reduxjs/redux/blob/master/src/bindActionCreators.ts
function bindAction(action: any, dispatch: any) {
return function (...args: any[]) {
- return dispatch(action.apply(this, args));
+ return dispatch(action(...args));
};
}
diff --git a/src/components/StyleGuide.tsx b/src/components/StyleGuide.tsx
index 0e5d2a5..f743f89 100644
--- a/src/components/StyleGuide.tsx
+++ b/src/components/StyleGuide.tsx
@@ -1,5 +1,5 @@
import React from 'react';
-import { Zap } from 'react-feather';
+import { Zap } from '~/components/shared/FeatherIcons';
import Loading from '~/components/Loading';
diff --git a/src/components/TrafficNow.tsx b/src/components/TrafficNow.tsx
index 300ecf8..e1b0f6d 100644
--- a/src/components/TrafficNow.tsx
+++ b/src/components/TrafficNow.tsx
@@ -1,5 +1,5 @@
import * as React from 'react';
-import { Download, ArrowDown, ArrowUp, Cpu, Link as LinkIcon, Upload } from 'react-feather';
+import { Download, ArrowDown, ArrowUp, Cpu, Link as LinkIcon, Upload } from '~/components/shared/FeatherIcons';
import { useTranslation } from 'react-i18next';
import useMemory from '../hooks/useMemory';
diff --git a/src/components/about/About.module.scss b/src/components/about/About.module.scss
index 7ed1aa5..de20013 100644
--- a/src/components/about/About.module.scss
+++ b/src/components/about/About.module.scss
@@ -1,4 +1,4 @@
-@import '~/styles/utils/custom-media';
+@use '~/styles/utils/custom-media' as *;
.root {
padding: 6px 15px;
diff --git a/src/components/about/About.tsx b/src/components/about/About.tsx
index 8fa3129..cb08218 100644
--- a/src/components/about/About.tsx
+++ b/src/components/about/About.tsx
@@ -1,5 +1,5 @@
import * as React from 'react';
-import { GitHub } from 'react-feather';
+import { GitHub } from '~/components/shared/FeatherIcons';
import ContentHeader from '~/components/ContentHeader';
import { useAboutVersionQuery } from '~/modules/about/hooks';
@@ -34,7 +34,7 @@ export function About({ apiConfig }: Props) {
return (
<>
- <ContentHeader title="About" />
+ <ContentHeader>About</ContentHeader>
{coreVersionMeta && version?.version ? (
<Version
name={coreVersionMeta.name}
diff --git a/src/components/proxies/Proxies.module.scss b/src/components/proxies/Proxies.module.scss
index 8990688..af961cf 100644
--- a/src/components/proxies/Proxies.module.scss
+++ b/src/components/proxies/Proxies.module.scss
@@ -1,4 +1,4 @@
-@import '~/styles/utils/custom-media';
+@use '~/styles/utils/custom-media' as *;
.topBar {
position: sticky;
diff --git a/src/components/proxies/Proxy.module.scss b/src/components/proxies/Proxy.module.scss
index 7bc37dd..066026f 100644
--- a/src/components/proxies/Proxy.module.scss
+++ b/src/components/proxies/Proxy.module.scss
@@ -1,4 +1,4 @@
-@import '~/styles/utils/custom-media';
+@use '~/styles/utils/custom-media' as *;
.proxy {
padding: 5px;
diff --git a/src/components/proxies/ProxyGroup.tsx b/src/components/proxies/ProxyGroup.tsx
index 69f2551..7b751fb 100644
--- a/src/components/proxies/ProxyGroup.tsx
+++ b/src/components/proxies/ProxyGroup.tsx
@@ -1,6 +1,6 @@
import cx from 'clsx';
import * as React from 'react';
-import { ChevronDown, Zap } from 'react-feather';
+import { ChevronDown, Zap } from '~/components/shared/FeatherIcons';
import { useQuery } from 'react-query';
import * as proxiesAPI from '~/api/proxies';
diff --git a/src/components/proxies/ProxyLatency.module.scss b/src/components/proxies/ProxyLatency.module.scss
index fce0a2e..ac39100 100644
--- a/src/components/proxies/ProxyLatency.module.scss
+++ b/src/components/proxies/ProxyLatency.module.scss
@@ -1,4 +1,4 @@
-@import '~/styles/utils/custom-media';
+@use '~/styles/utils/custom-media' as *;
.proxyLatency {
display: inline-flex;
diff --git a/src/components/proxies/ProxyList.module.scss b/src/components/proxies/ProxyList.module.scss
index a7e1956..f4c8d87 100644
--- a/src/components/proxies/ProxyList.module.scss
+++ b/src/components/proxies/ProxyList.module.scss
@@ -1,4 +1,4 @@
-@import '~/styles/utils/custom-media';
+@use '~/styles/utils/custom-media' as *;
.list {
margin: 8px 0;
diff --git a/src/components/proxies/ProxyPageFab.tsx b/src/components/proxies/ProxyPageFab.tsx
index ec78650..a8536e0 100644
--- a/src/components/proxies/ProxyPageFab.tsx
+++ b/src/components/proxies/ProxyPageFab.tsx
@@ -1,5 +1,5 @@
import * as React from 'react';
-import { Zap } from 'react-feather';
+import { Zap } from '~/components/shared/FeatherIcons';
import { useTranslation } from 'react-i18next';
import { Action, Fab, IsFetching, position as fabPosition } from '~/components/shared/Fab';
diff --git a/src/components/proxies/ProxyProvider.module.scss b/src/components/proxies/ProxyProvider.module.scss
index d222bc5..d22e50b 100644
--- a/src/components/proxies/ProxyProvider.module.scss
+++ b/src/components/proxies/ProxyProvider.module.scss
@@ -1,4 +1,4 @@
-@import '~/styles/utils/custom-media';
+@use '~/styles/utils/custom-media' as *;
.updatedAt {
margin-bottom: 12px;
diff --git a/src/components/proxies/ProxyProvider.tsx b/src/components/proxies/ProxyProvider.tsx
index d1f257a..bd2b4fa 100644
--- a/src/components/proxies/ProxyProvider.tsx
+++ b/src/components/proxies/ProxyProvider.tsx
@@ -1,7 +1,7 @@
import cx from 'clsx';
import { formatDistance } from 'date-fns';
import * as React from 'react';
-import { ChevronDown, RotateCw, Zap } from 'react-feather';
+import { ChevronDown, RotateCw, Zap } from '~/components/shared/FeatherIcons';
import Button from '~/components/Button';
import Collapsible from '~/components/Collapsible';
diff --git a/src/components/rules/RuleProviderItem.tsx b/src/components/rules/RuleProviderItem.tsx
index 7077ed1..5100f3d 100644
--- a/src/components/rules/RuleProviderItem.tsx
+++ b/src/components/rules/RuleProviderItem.tsx
@@ -1,6 +1,6 @@
import { formatDistance } from 'date-fns';
import * as React from 'react';
-import { Activity, Database, RefreshCw } from 'react-feather';
+import { Activity, Database, RefreshCw } from '~/components/shared/FeatherIcons';
import Button from '~/components/Button';
import { useUpdateRuleProviderItem } from '~/modules/rules/hooks';
diff --git a/src/components/shared/BaseModal.tsx b/src/components/shared/BaseModal.tsx
index 72dcba4..f7841f8 100644
--- a/src/components/shared/BaseModal.tsx
+++ b/src/components/shared/BaseModal.tsx
@@ -1,6 +1,7 @@
import cx from 'clsx';
import * as React from 'react';
-import Modal from 'react-modal';
+
+import Modal from '../Modal';
import modalStyle from '../Modal.module.scss';
@@ -8,7 +9,13 @@ import s from './BaseModal.module.scss';
const { useMemo } = React;
-export default function BaseModal({ isOpen, onRequestClose, children }) {
+type BaseModalProps = {
+ isOpen: boolean;
+ onRequestClose: (...args: any[]) => unknown;
+ children: React.ReactNode;
+};
+
+export default function BaseModal({ isOpen, onRequestClose, children }: BaseModalProps) {
const className = useMemo(
() => ({
base: cx(modalStyle.content, s.cnt),
diff --git a/src/components/shared/Basic.module.scss b/src/components/shared/Basic.module.scss
index 79b8a16..df412e5 100644
--- a/src/components/shared/Basic.module.scss
+++ b/src/components/shared/Basic.module.scss
@@ -1,4 +1,4 @@
-@import '~/styles/utils/custom-media';
+@use '~/styles/utils/custom-media' as *;
h2.sectionNameType {
margin: 0;
diff --git a/src/components/shared/Fab.tsx b/src/components/shared/Fab.tsx
index 8e72432..49c9a89 100644
--- a/src/components/shared/Fab.tsx
+++ b/src/components/shared/Fab.tsx
@@ -18,7 +18,7 @@ export const position = {
interface ABProps extends React.HTMLAttributes<HTMLButtonElement> {
text?: string;
- onClick?: (e: React.FormEvent) => void;
+ onClick?: (e: React.MouseEvent<HTMLButtonElement>) => unknown;
'data-testid'?: string;
}
@@ -46,7 +46,7 @@ interface FabProps {
alwaysShowTitle?: boolean;
icon?: React.ReactNode;
mainButtonStyles?: React.CSSProperties;
- onClick?: (e: React.FormEvent) => void;
+ onClick?: (e: React.MouseEvent<HTMLButtonElement>) => unknown;
text?: string;
children?: React.ReactNode;
}
@@ -68,7 +68,7 @@ const Fab: React.FC<FabProps> = ({
const close = () => setIsOpen(false);
const enter = () => event === 'hover' && open();
const leave = () => event === 'hover' && close();
- const toggle = (e: React.FormEvent) => {
+ const toggle = (e: React.MouseEvent<HTMLButtonElement>) => {
if (onClick) {
return onClick(e);
}
@@ -76,7 +76,10 @@ const Fab: React.FC<FabProps> = ({
return event === 'click' ? (isOpen ? close() : open()) : null;
};
- const actionOnClick = (e: React.FormEvent, userFunc: (e: React.FormEvent) => void) => {
+ const actionOnClick = (
+ e: React.MouseEvent<HTMLButtonElement>,
+ userFunc: (e: React.MouseEvent<HTMLButtonElement>) => unknown
+ ) => {
e.persist();
setIsOpen(false);
setTimeout(() => {
@@ -95,7 +98,7 @@ const Fab: React.FC<FabProps> = ({
'aria-hidden': ariaHidden,
tabIndex: isOpen ? 0 : -1,
...ch.props,
- onClick: (e: React.FormEvent) => {
+ onClick: (e: React.MouseEvent<HTMLButtonElement>) => {
if (ch.props.onClick) actionOnClick(e, ch.props.onClick);
},
})}
diff --git a/src/components/shared/FeatherIcons.ts b/src/components/shared/FeatherIcons.ts
new file mode 100644
index 0000000..745baa1
--- /dev/null
+++ b/src/components/shared/FeatherIcons.ts
@@ -0,0 +1,53 @@
+import * as React from 'react';
+import * as Feather from 'react-feather';
+
+type FeatherCompatProps = {
+ color?: string;
+ size?: string | number;
+ className?: string;
+ style?: React.CSSProperties;
+ [key: string]: unknown;
+};
+
+type IconComponent = React.ComponentType<FeatherCompatProps>;
+
+function asIcon(name: keyof typeof Feather): IconComponent {
+ return Feather[name] as unknown as IconComponent;
+}
+
+export const Activity = asIcon('Activity');
+export const ArrowDown = asIcon('ArrowDown');
+export const ArrowDownCircle = asIcon('ArrowDownCircle');
+export const ArrowUp = asIcon('ArrowUp');
+export const ChevronDown = asIcon('ChevronDown');
+export const ChevronUp = asIcon('ChevronUp');
+export const Cpu = asIcon('Cpu');
+export const Database = asIcon('Database');
+export const Download = asIcon('Download');
+export const DownloadCloud = asIcon('DownloadCloud');
+export const Eye = asIcon('Eye');
+export const EyeOff = asIcon('EyeOff');
+export const FileText = asIcon('FileText');
+export const GitHub = asIcon('GitHub');
+export const Globe = asIcon('Globe');
+export const Hash = asIcon('Hash');
+export const Info = asIcon('Info');
+export const Link = asIcon('Link');
+export const LogOut = asIcon('LogOut');
+export const Menu = asIcon('Menu');
+export const Monitor = asIcon('Monitor');
+export const Pause = asIcon('Pause');
+export const Play = asIcon('Play');
+export const RefreshCcw = asIcon('RefreshCcw');
+export const RefreshCw = asIcon('RefreshCw');
+export const RotateCw = asIcon('RotateCw');
+export const Settings = asIcon('Settings');
+export const Shield = asIcon('Shield');
+export const Sliders = asIcon('Sliders');
+export const Tag = asIcon('Tag');
+export const Tool = asIcon('Tool');
+export const Trash2 = asIcon('Trash2');
+export const Upload = asIcon('Upload');
+export const X = asIcon('X');
+export const XCircle = asIcon('XCircle');
+export const Zap = asIcon('Zap');
diff --git a/src/components/shared/RotateIcon.tsx b/src/components/shared/RotateIcon.tsx
index 7e3ceae..0a5a018 100644
--- a/src/components/shared/RotateIcon.tsx
+++ b/src/components/shared/RotateIcon.tsx
@@ -1,6 +1,6 @@
import cx from 'clsx';
import * as React from 'react';
-import { RotateCw } from 'react-feather';
+import { RotateCw } from '~/components/shared/FeatherIcons';
import s from './RotateIcon.module.scss';