From f6531f080ef15c0a55387057cdbc4be71371818c Mon Sep 17 00:00:00 2001
From: Olivi <225673551+Olivi-9@users.noreply.github.com>
Date: Mon, 13 Apr 2026 23:10:10 +0800
Subject: chore: remove unnecessary hover effects and adjust styles & adjust
layout Overview
---
src/components/TrafficNow.module.scss | 25 +++++++++++++++++++++----
1 file changed, 21 insertions(+), 4 deletions(-)
(limited to 'src/components/TrafficNow.module.scss')
diff --git a/src/components/TrafficNow.module.scss b/src/components/TrafficNow.module.scss
index e0e3271..85281e2 100644
--- a/src/components/TrafficNow.module.scss
+++ b/src/components/TrafficNow.module.scss
@@ -1,10 +1,28 @@
.TrafficNow {
color: var(--color-text);
- display: grid;
- grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
- grid-gap: 20px;
+ display: flex;
+ flex-direction: column; grid-gap: 20px;
+ gap: 20px;
padding: 10px 0;
+.overview {
+ display: grid;
+ grid-template-columns: 1fr 1fr;
+ gap: 20px;
+
+ & > div:nth-child(3) {
+ grid-column: 1 / -1;
+ }
+
+ @media (min-width: 768px) {
+ grid-template-columns: 1fr 1fr 1fr;
+
+ & > div:nth-child(3) {
+ grid-column: auto;
+ }
+ }
+ }
+
.sec {
padding: 20px;
background-color: var(--color-bg-card);
@@ -17,7 +35,6 @@
min-height: 140px;
&:hover {
- transform: translateY(-2px);
box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05);
}
--
cgit v1.3.1
From 56758999537ca0790837f446984379eebca3a44d Mon Sep 17 00:00:00 2001
From: Larvan2 <78135608+Larvan2@users.noreply.github.com>
Date: Sat, 18 Apr 2026 14:07:20 +0800
Subject: chore: modify chart
---
src/components/Collapsible.tsx | 23 +++--
src/components/Sparkline.tsx | 24 +++--
src/components/TrafficNow.module.scss | 32 +++++--
src/components/TrafficNow.tsx | 82 +++++++++--------
src/components/proxies/ProxyProvider.tsx | 28 +++---
src/components/shared/FeatherIcons.ts | 91 ++++++++-----------
src/components/shared/ThemeSwitcher.tsx | 150 +++++++++++++++----------------
7 files changed, 226 insertions(+), 204 deletions(-)
(limited to 'src/components/TrafficNow.module.scss')
diff --git a/src/components/Collapsible.tsx b/src/components/Collapsible.tsx
index f43dbd6..6948cef 100644
--- a/src/components/Collapsible.tsx
+++ b/src/components/Collapsible.tsx
@@ -1,7 +1,6 @@
+import { LazyMotion, domAnimation, m } from 'framer-motion';
import React from 'react';
-import { framerMotionResouce } from '../misc/motion';
-
const { memo } = React;
const variantsCollpapsibleWrap = {
@@ -27,17 +26,17 @@ const variantsCollpapsibleWrap = {
};
const Collapsible = memo(({ children, isOpen }: { children: React.ReactNode; isOpen: boolean }) => {
- const module = framerMotionResouce.read();
- const motion = module.motion;
return (
-
- {children}
-
+
+
+ {children}
+
+
);
});
diff --git a/src/components/Sparkline.tsx b/src/components/Sparkline.tsx
index b7f35a9..79f8bf5 100644
--- a/src/components/Sparkline.tsx
+++ b/src/components/Sparkline.tsx
@@ -63,9 +63,19 @@ const extraChartOptions: any = {
export default function Sparkline({ data: dataArray, labels, type, styleIndex = 0 }) {
chartJSResource.read();
+ const isMemory = type === 'inuse';
+
const options = useMemo(() => {
return {
...extraChartOptions,
+ scales: {
+ ...extraChartOptions.scales,
+ y: {
+ display: false,
+ // 内存值稳定,不从零开始,让 Y 轴自动适应数据范围以显示波动
+ beginAtZero: !isMemory,
+ },
+ },
plugins: {
...extraChartOptions.plugins,
tooltip: {
@@ -75,9 +85,9 @@ export default function Sparkline({ data: dataArray, labels, type, styleIndex =
title: () => '',
label(context) {
if (context.parsed.y !== null) {
- const suffix = type === 'inuse' ? '' : '/s';
- // 还原 log1p 变换后的真实值
- return prettyBytes(Math.expm1(context.parsed.y)) + suffix;
+ const suffix = isMemory ? '' : '/s';
+ const raw = isMemory ? context.parsed.y : Math.expm1(context.parsed.y);
+ return prettyBytes(raw) + suffix;
}
return '';
},
@@ -85,7 +95,7 @@ export default function Sparkline({ data: dataArray, labels, type, styleIndex =
},
},
};
- }, [type]);
+ }, [type, isMemory]);
const data = useMemo(
() => ({
@@ -93,13 +103,13 @@ export default function Sparkline({ data: dataArray, labels, type, styleIndex =
{
...commonDataSetProps,
...chartStyles[styleIndex][type],
- // log1p 变换:压缩大尖刺,让小流量也可见;log1p(0)=0 不会出现 -Infinity
- data: dataArray.map((v, i) => ({ x: labels[i], y: Math.log1p(v) })),
+ // 内存用原始值(变化幅度小,不需要压缩);流量用 log1p 压缩尖刺
+ data: dataArray.map((v, i) => ({ x: labels[i], y: isMemory ? v : Math.log1p(v) })),
fill: true,
},
],
}),
- [dataArray, labels, type, styleIndex]
+ [dataArray, labels, type, styleIndex, isMemory],
);
return (
diff --git a/src/components/TrafficNow.module.scss b/src/components/TrafficNow.module.scss
index 85281e2..2b0bcdf 100644
--- a/src/components/TrafficNow.module.scss
+++ b/src/components/TrafficNow.module.scss
@@ -1,11 +1,12 @@
.TrafficNow {
color: var(--color-text);
display: flex;
- flex-direction: column; grid-gap: 20px;
+ flex-direction: column;
+ grid-gap: 20px;
gap: 20px;
padding: 10px 0;
-.overview {
+ .overview {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 20px;
@@ -23,19 +24,40 @@
}
}
+ .chartsRow {
+ display: flex;
+ flex-direction: column;
+ gap: 20px;
+
+ @media (min-width: 768px) {
+ flex-direction: row;
+
+ & > .sec {
+ flex: 1;
+ min-width: 0;
+ }
+ }
+ }
+
.sec {
padding: 20px;
background-color: var(--color-bg-card);
border-radius: 12px;
- box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
- transition: transform 0.2s ease, box-shadow 0.2s ease;
+ box-shadow:
+ 0 4px 6px -1px rgba(0, 0, 0, 0.1),
+ 0 2px 4px -1px rgba(0, 0, 0, 0.06);
+ transition:
+ transform 0.2s ease,
+ box-shadow 0.2s ease;
display: flex;
flex-direction: column;
justify-content: space-between;
min-height: 140px;
&:hover {
- box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05);
+ box-shadow:
+ 0 10px 15px -3px rgba(0, 0, 0, 0.1),
+ 0 4px 6px -2px rgba(0, 0, 0, 0.05);
}
.header {
diff --git a/src/components/TrafficNow.tsx b/src/components/TrafficNow.tsx
index e1b0f6d..5dc601b 100644
--- a/src/components/TrafficNow.tsx
+++ b/src/components/TrafficNow.tsx
@@ -1,5 +1,12 @@
import * as React from 'react';
-import { Download, ArrowDown, ArrowUp, Cpu, Link as LinkIcon, Upload } from '~/components/shared/FeatherIcons';
+import {
+ Download,
+ ArrowDown,
+ ArrowUp,
+ Cpu,
+ Link as LinkIcon,
+ Upload,
+} from '~/components/shared/FeatherIcons';
import { useTranslation } from 'react-i18next';
import useMemory from '../hooks/useMemory';
@@ -51,45 +58,46 @@ export default function TrafficNow({ apiConfig, selectedChartStyleIndex }: Props
-
-
-
-
{t('Download')}
+
-
-
-
-
{t('Upload')}
+
-
{upStr}
-
-
-
-
-
-
-
{t('Memory Usage')}
+
+
+
+ {t('Memory Usage')}
+
+
{mUsage}
+
-
{mUsage}
-
{' '}
);
diff --git a/src/components/proxies/ProxyProvider.tsx b/src/components/proxies/ProxyProvider.tsx
index bd2b4fa..47ccb8b 100644
--- a/src/components/proxies/ProxyProvider.tsx
+++ b/src/components/proxies/ProxyProvider.tsx
@@ -8,7 +8,7 @@ import Collapsible from '~/components/Collapsible';
import CollapsibleSectionHeader from '~/components/CollapsibleSectionHeader';
import s0 from '~/components/proxies/ProxyGroup.module.scss';
import { useStoreActions } from '~/components/StateProvider';
-import { framerMotionResouce } from '~/misc/motion';
+import { LazyMotion, domAnimation, m } from 'framer-motion';
import { useFilteredAndSorted, useUpdateProviderItem } from '~/modules/proxies/hooks';
import { healthcheckProviderByName } from '~/store/proxies';
import { DelayMapping, DispatchFn, ProxiesMapping, SubscriptionInfo } from '~/store/types';
@@ -190,19 +190,19 @@ function formatBytes(bytes, decimals = 2) {
return `${parseFloat((bytes / Math.pow(k, i)).toFixed(dm))} ${sizes[i]}`;
}
function Refresh() {
- const module = framerMotionResouce.read();
- const motion = module.motion;
return (
-
-
-
-
-
+
+
+
+
+
+
+
);
}
diff --git a/src/components/shared/FeatherIcons.ts b/src/components/shared/FeatherIcons.ts
index 745baa1..ee1f410 100644
--- a/src/components/shared/FeatherIcons.ts
+++ b/src/components/shared/FeatherIcons.ts
@@ -1,53 +1,38 @@
-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
;
-
-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');
+export {
+ Activity,
+ ArrowDown,
+ ArrowDownCircle,
+ ArrowUp,
+ ChevronDown,
+ ChevronUp,
+ Cpu,
+ Database,
+ Download,
+ DownloadCloud,
+ Eye,
+ EyeOff,
+ FileText,
+ GitHub,
+ Globe,
+ Hash,
+ Info,
+ Link,
+ LogOut,
+ Menu,
+ Monitor,
+ Pause,
+ Play,
+ RefreshCcw,
+ RefreshCw,
+ RotateCw,
+ Settings,
+ Shield,
+ Sliders,
+ Tag,
+ Tool,
+ Trash2,
+ Upload,
+ X,
+ XCircle,
+ Zap,
+} from 'react-feather';
diff --git a/src/components/shared/ThemeSwitcher.tsx b/src/components/shared/ThemeSwitcher.tsx
index 363d422..dfe248d 100644
--- a/src/components/shared/ThemeSwitcher.tsx
+++ b/src/components/shared/ThemeSwitcher.tsx
@@ -3,7 +3,7 @@ import * as React from 'react';
import { useTranslation } from 'react-i18next';
import { connect } from '~/components/StateProvider';
-import { framerMotionResouce } from '~/misc/motion';
+import { LazyMotion, domAnimation, m } from 'framer-motion';
import { getTheme, switchTheme } from '~/store/app';
import { State } from '~/store/types';
@@ -28,7 +28,7 @@ export function ThemeSwitcherImpl({ theme, dispatch }) {
const onChange = React.useCallback(
(e: React.ChangeEvent) => dispatch(switchTheme(e.target.value)),
- [dispatch]
+ [dispatch],
);
return (
@@ -46,91 +46,89 @@ export function ThemeSwitcherImpl({ theme, dispatch }) {
}
function MoonA() {
- const module = framerMotionResouce.read();
- const motion = module.motion;
return (
-
+
+
+
);
}
function Sun() {
- const module = framerMotionResouce.read();
- const motion = module.motion;
-
return (
-
+
+
+
);
}
function Auto() {
- const module = framerMotionResouce.read();
- const motion = module.motion;
-
return (
-
+
+
+
);
}
--
cgit v1.3.1