mirror of
https://gh.catmak.name/https://github.com/mihomo-party-org/mihomo-party
synced 2025-12-28 05:30:29 +08:00
Compare commits
2 Commits
e3cc4d4970
...
a81f970baa
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a81f970baa | ||
|
|
bc54d87389 |
107
package.json
107
package.json
@ -23,75 +23,76 @@
|
||||
"build:linux": "electron-vite build && electron-builder --publish never --linux"
|
||||
},
|
||||
"dependencies": {
|
||||
"@electron-toolkit/preload": "^3.0.1",
|
||||
"@electron-toolkit/utils": "^3.0.0",
|
||||
"@heroui/react": "^2.6.14",
|
||||
"@mihomo-party/sysproxy": "^2.0.7",
|
||||
"@mihomo-party/sysproxy-darwin-arm64": "^2.0.7",
|
||||
"@electron-toolkit/preload": "^3.0.2",
|
||||
"@electron-toolkit/utils": "^4.0.0",
|
||||
"@heroui/react": "^2.8.2",
|
||||
"@mihomo-party/sysproxy": "^2.0.8",
|
||||
"@mihomo-party/sysproxy-darwin-arm64": "^2.0.8",
|
||||
"@types/crypto-js": "^4.2.2",
|
||||
"adm-zip": "^0.5.16",
|
||||
"axios": "^1.7.7",
|
||||
"chokidar": "^4.0.1",
|
||||
"axios": "^1.11.0",
|
||||
"chart.js": "^4.5.0",
|
||||
"chokidar": "^4.0.3",
|
||||
"crypto-js": "^4.2.0",
|
||||
"dayjs": "^1.11.13",
|
||||
"express": "^5.0.1",
|
||||
"i18next": "^24.2.2",
|
||||
"express": "^5.1.0",
|
||||
"i18next": "^25.3.2",
|
||||
"iconv-lite": "^0.6.3",
|
||||
"react-i18next": "^15.4.0",
|
||||
"webdav": "^5.7.1",
|
||||
"ws": "^8.18.0",
|
||||
"yaml": "^2.6.0"
|
||||
"react-chartjs-2": "^5.3.0",
|
||||
"react-i18next": "^15.6.1",
|
||||
"webdav": "^5.8.0",
|
||||
"ws": "^8.18.3",
|
||||
"yaml": "^2.8.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@dnd-kit/core": "^6.1.0",
|
||||
"@dnd-kit/core": "^6.3.1",
|
||||
"@dnd-kit/sortable": "^10.0.0",
|
||||
"@dnd-kit/utilities": "^3.2.2",
|
||||
"@electron-toolkit/eslint-config-prettier": "^2.0.0",
|
||||
"@electron-toolkit/eslint-config-ts": "^2.0.0",
|
||||
"@electron-toolkit/eslint-config-prettier": "^3.0.0",
|
||||
"@electron-toolkit/eslint-config-ts": "^3.1.0",
|
||||
"@electron-toolkit/tsconfig": "^1.0.1",
|
||||
"@types/adm-zip": "^0.5.6",
|
||||
"@types/express": "^5.0.0",
|
||||
"@types/node": "^22.13.1",
|
||||
"@types/adm-zip": "^0.5.7",
|
||||
"@types/express": "^5.0.3",
|
||||
"@types/node": "^24.1.0",
|
||||
"@types/pubsub-js": "^1.8.6",
|
||||
"@types/react": "^19.0.4",
|
||||
"@types/react-dom": "^19.0.2",
|
||||
"@types/ws": "^8.5.13",
|
||||
"@vitejs/plugin-react": "^4.3.3",
|
||||
"autoprefixer": "^10.4.20",
|
||||
"cron-validator": "^1.3.1",
|
||||
"driver.js": "^1.3.5",
|
||||
"electron": "^34.0.2",
|
||||
"electron-builder": "25.1.8",
|
||||
"electron-vite": "^2.3.0",
|
||||
"@types/react": "^19.1.9",
|
||||
"@types/react-dom": "^19.1.7",
|
||||
"@types/ws": "^8.18.1",
|
||||
"@vitejs/plugin-react": "^4.7.0",
|
||||
"autoprefixer": "^10.4.21",
|
||||
"cron-validator": "^1.4.0",
|
||||
"driver.js": "^1.3.6",
|
||||
"electron": "^37.2.5",
|
||||
"electron-builder": "26.0.12",
|
||||
"electron-vite": "^4.0.0",
|
||||
"electron-window-state": "^5.0.3",
|
||||
"eslint": "8.57.1",
|
||||
"eslint-plugin-react": "^7.37.2",
|
||||
"form-data": "^4.0.1",
|
||||
"framer-motion": "12.0.11",
|
||||
"eslint": "9.32.0",
|
||||
"eslint-plugin-react": "^7.37.5",
|
||||
"form-data": "^4.0.4",
|
||||
"framer-motion": "12.23.12",
|
||||
"lodash": "^4.17.21",
|
||||
"meta-json-schema": "^1.18.9",
|
||||
"monaco-yaml": "^5.2.3",
|
||||
"nanoid": "^5.0.8",
|
||||
"next-themes": "^0.4.3",
|
||||
"postcss": "^8.4.47",
|
||||
"prettier": "^3.3.3",
|
||||
"meta-json-schema": "^1.19.12",
|
||||
"monaco-yaml": "^5.4.0",
|
||||
"nanoid": "^5.1.5",
|
||||
"next-themes": "^0.4.6",
|
||||
"postcss": "^8.5.6",
|
||||
"prettier": "^3.6.2",
|
||||
"pubsub-js": "^1.9.5",
|
||||
"react": "^19.0.0",
|
||||
"react-dom": "^19.0.0",
|
||||
"react-error-boundary": "^5.0.0",
|
||||
"react-icons": "^5.3.0",
|
||||
"react-markdown": "^9.0.1",
|
||||
"react-monaco-editor": "^0.58.0",
|
||||
"react-router-dom": "^7.1.5",
|
||||
"react-virtuoso": "^4.12.0",
|
||||
"recharts": "^2.13.3",
|
||||
"swr": "^2.2.5",
|
||||
"tailwindcss": "^3.4.17",
|
||||
"react": "^19.1.1",
|
||||
"react-dom": "^19.1.1",
|
||||
"react-error-boundary": "^6.0.0",
|
||||
"react-icons": "^5.5.0",
|
||||
"react-markdown": "^10.1.0",
|
||||
"react-monaco-editor": "^0.59.0",
|
||||
"react-router-dom": "^7.7.1",
|
||||
"react-virtuoso": "^4.13.0",
|
||||
"swr": "^2.3.4",
|
||||
"tailwindcss": "^4.1.11",
|
||||
"tar": "^7.4.3",
|
||||
"tsx": "^4.19.2",
|
||||
"tsx": "^4.20.3",
|
||||
"types-pac": "^1.0.3",
|
||||
"typescript": "^5.6.3",
|
||||
"vite": "^6.0.7",
|
||||
"typescript": "^5.9.2",
|
||||
"vite": "^7.0.6",
|
||||
"vite-plugin-monaco-editor": "^1.1.0"
|
||||
},
|
||||
"packageManager": "pnpm@9.15.0+sha512.76e2379760a4328ec4415815bcd6628dee727af3779aaa4c914e3944156c4299921a89f976381ee107d41f12cfa4b66681ca9c718f0668fa0831ed4c6d8ba56c"
|
||||
|
||||
9139
pnpm-lock.yaml
generated
9139
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
@ -373,13 +373,13 @@ const App: React.FC = () => {
|
||||
setSiderWidthValue(e.clientX)
|
||||
}
|
||||
}}
|
||||
className={`w-full h-[100vh] flex ${resizing ? 'cursor-ew-resize' : ''}`}
|
||||
className={`w-full h-screen flex ${resizing ? 'cursor-ew-resize' : ''}`}
|
||||
>
|
||||
{siderWidthValue === narrowWidth ? (
|
||||
<div style={{ width: `${narrowWidth}px` }} className="side h-full">
|
||||
<div className="app-drag flex justify-center items-center z-40 bg-transparent h-[49px]">
|
||||
{platform !== 'darwin' && (
|
||||
<MihomoIcon className="h-[32px] leading-[32px] text-lg mx-[1px]" />
|
||||
<MihomoIcon className="h-[32px] leading-[32px] text-lg mx-px" />
|
||||
)}
|
||||
<UpdaterButton iconOnly={true} />
|
||||
</div>
|
||||
@ -417,7 +417,7 @@ const App: React.FC = () => {
|
||||
className={`flex justify-between p-2 ${!useWindowFrame && platform === 'darwin' ? 'ml-[60px]' : ''}`}
|
||||
>
|
||||
<div className="flex ml-1">
|
||||
<MihomoIcon className="h-[32px] leading-[32px] text-lg mx-[1px]" />
|
||||
<MihomoIcon className="h-[32px] leading-[32px] text-lg mx-px" />
|
||||
<h3 className="text-lg font-bold leading-[32px]">ihomo Party</h3>
|
||||
</div>
|
||||
<UpdaterButton />
|
||||
|
||||
@ -59,9 +59,9 @@ const FloatingApp: React.FC = () => {
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<div className="app-drag h-[100vh] w-[100vw] overflow-hidden">
|
||||
<div className="app-drag h-screen w-screen overflow-hidden">
|
||||
<div className="floating-bg border-1 border-divider flex rounded-full bg-content1 h-[calc(100%-2px)] w-[calc(100%-2px)]">
|
||||
<div className="flex justify-center items-center h-[100%] aspect-square">
|
||||
<div className="flex justify-center items-center h-full aspect-square">
|
||||
<div
|
||||
onContextMenu={(e) => {
|
||||
e.preventDefault()
|
||||
|
||||
@ -1,6 +1,4 @@
|
||||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
@import 'tailwindcss';
|
||||
|
||||
.floating-text {
|
||||
font-family:
|
||||
|
||||
@ -1,6 +1,4 @@
|
||||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
@import 'tailwindcss';
|
||||
|
||||
@font-face {
|
||||
font-family: 'Noto Color Emoji';
|
||||
|
||||
@ -1,5 +1,7 @@
|
||||
.border-switch {
|
||||
input[type='checkbox'] {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.border-switch input[type='checkbox'] {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
@ -2,16 +2,29 @@ import { Button, Card, CardBody, CardFooter, Tooltip } from '@heroui/react'
|
||||
import { FaCircleArrowDown, FaCircleArrowUp } from 'react-icons/fa6'
|
||||
import { useLocation, useNavigate } from 'react-router-dom'
|
||||
import { calcTraffic } from '@renderer/utils/calc'
|
||||
import React, { useEffect, useState } from 'react'
|
||||
import React, { useEffect, useState, useMemo } from 'react'
|
||||
import { useSortable } from '@dnd-kit/sortable'
|
||||
import { CSS } from '@dnd-kit/utilities'
|
||||
import { IoLink } from 'react-icons/io5'
|
||||
import { useTheme } from 'next-themes'
|
||||
|
||||
import { useAppConfig } from '@renderer/hooks/use-app-config'
|
||||
import { platform } from '@renderer/utils/init'
|
||||
import { Area, AreaChart, ResponsiveContainer } from 'recharts'
|
||||
import { Line } from 'react-chartjs-2'
|
||||
import {
|
||||
Chart as ChartJS,
|
||||
CategoryScale,
|
||||
LinearScale,
|
||||
PointElement,
|
||||
LineElement,
|
||||
Filler,
|
||||
ChartOptions,
|
||||
ScriptableContext
|
||||
} from 'chart.js'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
|
||||
// 注册 Chart.js 组件
|
||||
ChartJS.register(CategoryScale, LinearScale, PointElement, LineElement, Filler)
|
||||
|
||||
let currentUpload: number | undefined = undefined
|
||||
let currentDownload: number | undefined = undefined
|
||||
let hasShowTraffic = false
|
||||
@ -21,10 +34,9 @@ interface Props {
|
||||
iconOnly?: boolean
|
||||
}
|
||||
const ConnCard: React.FC<Props> = (props) => {
|
||||
const { theme = 'system', systemTheme = 'dark' } = useTheme()
|
||||
const { iconOnly } = props
|
||||
const { appConfig } = useAppConfig()
|
||||
const { showTraffic = false, connectionCardStatus = 'col-span-2', customTheme } = appConfig || {}
|
||||
const { showTraffic = false, connectionCardStatus = 'col-span-2' } = appConfig || {}
|
||||
const location = useLocation()
|
||||
const navigate = useNavigate()
|
||||
const match = location.pathname.includes('/connections')
|
||||
@ -43,25 +55,69 @@ const ConnCard: React.FC<Props> = (props) => {
|
||||
id: 'connection'
|
||||
})
|
||||
const [series, setSeries] = useState(Array(10).fill(0))
|
||||
const [chartColor, setChartColor] = useState('rgba(255,255,255)')
|
||||
|
||||
useEffect(() => {
|
||||
setChartColor(
|
||||
match
|
||||
? `hsla(${getComputedStyle(document.documentElement).getPropertyValue('--heroui-primary-foreground')})`
|
||||
: `hsla(${getComputedStyle(document.documentElement).getPropertyValue('--heroui-foreground')})`
|
||||
)
|
||||
}, [theme, systemTheme, match])
|
||||
// Chart.js 配置
|
||||
const chartData = useMemo(() => {
|
||||
return {
|
||||
labels: Array(10).fill(''),
|
||||
datasets: [
|
||||
{
|
||||
data: series,
|
||||
fill: true,
|
||||
backgroundColor: (context: ScriptableContext<'line'>) => {
|
||||
const chart = context.chart
|
||||
const { ctx, chartArea } = chart
|
||||
if (!chartArea) {
|
||||
return 'transparent'
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
setTimeout(() => {
|
||||
setChartColor(
|
||||
match
|
||||
? `hsla(${getComputedStyle(document.documentElement).getPropertyValue('--heroui-primary-foreground')})`
|
||||
: `hsla(${getComputedStyle(document.documentElement).getPropertyValue('--heroui-foreground')})`
|
||||
)
|
||||
}, 200)
|
||||
}, [customTheme])
|
||||
const gradient = ctx.createLinearGradient(0, chartArea.top, 0, chartArea.bottom)
|
||||
|
||||
// 颜色处理
|
||||
const isMatch = location.pathname.includes('/connections')
|
||||
const baseColor = isMatch ? '6, 182, 212' : '161, 161, 170' // primary vs foreground 的近似 RGB 值
|
||||
|
||||
gradient.addColorStop(0, `rgba(${baseColor}, 0.8)`)
|
||||
gradient.addColorStop(1, `rgba(${baseColor}, 0)`)
|
||||
return gradient
|
||||
},
|
||||
borderColor: 'transparent',
|
||||
pointRadius: 0,
|
||||
pointHoverRadius: 0,
|
||||
tension: 0.4
|
||||
}
|
||||
]
|
||||
}
|
||||
}, [series, location.pathname])
|
||||
|
||||
const chartOptions: ChartOptions<'line'> = {
|
||||
responsive: true,
|
||||
maintainAspectRatio: false,
|
||||
plugins: {
|
||||
legend: {
|
||||
display: false
|
||||
}
|
||||
},
|
||||
scales: {
|
||||
x: {
|
||||
display: false
|
||||
},
|
||||
y: {
|
||||
display: false
|
||||
}
|
||||
},
|
||||
elements: {
|
||||
line: {
|
||||
borderWidth: 0
|
||||
}
|
||||
},
|
||||
interaction: {
|
||||
intersect: false
|
||||
},
|
||||
animation: {
|
||||
duration: 0
|
||||
}
|
||||
}
|
||||
|
||||
const transform = tf ? { x: tf.x, y: tf.y, scaleX: 1, scaleY: 1 } : null
|
||||
useEffect(() => {
|
||||
@ -168,30 +224,9 @@ const ConnCard: React.FC<Props> = (props) => {
|
||||
</h3>
|
||||
</CardFooter>
|
||||
</Card>
|
||||
<ResponsiveContainer
|
||||
height="100%"
|
||||
width="100%"
|
||||
className="w-full h-full absolute top-0 left-0 pointer-events-none overflow-hidden rounded-[14px]"
|
||||
>
|
||||
<AreaChart
|
||||
data={series.map((v) => ({ traffic: v }))}
|
||||
margin={{ top: 50, right: 0, left: 0, bottom: 0 }}
|
||||
>
|
||||
<defs>
|
||||
<linearGradient id="gradient" x1="0" y1="0" x2="0" y2="1">
|
||||
<stop offset="0%" stopColor={chartColor} stopOpacity={0.8} />
|
||||
<stop offset="100%" stopColor={chartColor} stopOpacity={0} />
|
||||
</linearGradient>
|
||||
</defs>
|
||||
<Area
|
||||
isAnimationActive={false}
|
||||
type="monotone"
|
||||
dataKey="traffic"
|
||||
stroke="none"
|
||||
fill="url(#gradient)"
|
||||
/>
|
||||
</AreaChart>
|
||||
</ResponsiveContainer>
|
||||
<div className="w-full h-full absolute top-0 left-0 pointer-events-none overflow-hidden rounded-[14px]">
|
||||
<Line data={chartData} options={chartOptions} />
|
||||
</div>
|
||||
</>
|
||||
) : (
|
||||
<Card
|
||||
|
||||
@ -273,7 +273,7 @@ const Connections: React.FC = () => {
|
||||
</div>
|
||||
<Divider />
|
||||
</div>
|
||||
<div className="h-[calc(100vh-100px)] mt-[1px]">
|
||||
<div className="h-[calc(100vh-100px)] mt-px">
|
||||
<Virtuoso
|
||||
data={filteredConnections}
|
||||
itemContent={(i, connection) => (
|
||||
|
||||
@ -264,7 +264,7 @@ const DNS: React.FC = () => {
|
||||
{[...values.nameserverPolicy, { domain: '', value: '' }].map(
|
||||
({ domain, value }, index) => (
|
||||
<div key={index} className="flex mb-2">
|
||||
<div className="flex-[4]">
|
||||
<div className="flex-4">
|
||||
<Input
|
||||
size="sm"
|
||||
fullWidth
|
||||
@ -281,7 +281,7 @@ const DNS: React.FC = () => {
|
||||
/>
|
||||
</div>
|
||||
<span className="mx-2">:</span>
|
||||
<div className="flex-[6] flex">
|
||||
<div className="flex-6 flex">
|
||||
<Input
|
||||
size="sm"
|
||||
fullWidth
|
||||
@ -332,7 +332,7 @@ const DNS: React.FC = () => {
|
||||
<h3 className="mb-2">{t('dns.customHosts.list')}</h3>
|
||||
{[...values.hosts, { domain: '', value: '' }].map(({ domain, value }, index) => (
|
||||
<div key={index} className="flex mb-2">
|
||||
<div className="flex-[4]">
|
||||
<div className="flex-4">
|
||||
<Input
|
||||
size="sm"
|
||||
fullWidth
|
||||
@ -349,7 +349,7 @@ const DNS: React.FC = () => {
|
||||
/>
|
||||
</div>
|
||||
<span className="mx-2">:</span>
|
||||
<div className="flex-[6] flex">
|
||||
<div className="flex-6 flex">
|
||||
<Input
|
||||
size="sm"
|
||||
fullWidth
|
||||
|
||||
@ -109,7 +109,7 @@ const Logs: React.FC = () => {
|
||||
</div>
|
||||
<Divider />
|
||||
</div>
|
||||
<div className="h-[calc(100vh-100px)] mt-[1px]">
|
||||
<div className="h-[calc(100vh-100px)] mt-px">
|
||||
<Virtuoso
|
||||
ref={virtuosoRef}
|
||||
data={filteredLogs}
|
||||
|
||||
@ -652,7 +652,7 @@ const Mihomo: React.FC = () => {
|
||||
const [user, pass] = auth.split(':')
|
||||
return (
|
||||
<div key={index} className="flex mb-2">
|
||||
<div className="flex-[4]">
|
||||
<div className="flex-4">
|
||||
<Input
|
||||
size="sm"
|
||||
fullWidth
|
||||
@ -672,7 +672,7 @@ const Mihomo: React.FC = () => {
|
||||
/>
|
||||
</div>
|
||||
<span className="mx-2">:</span>
|
||||
<div className="flex-[6] flex">
|
||||
<div className="flex-6 flex">
|
||||
<Input
|
||||
size="sm"
|
||||
fullWidth
|
||||
|
||||
@ -38,7 +38,7 @@ const Rules: React.FC = () => {
|
||||
</div>
|
||||
<Divider />
|
||||
</div>
|
||||
<div className="h-[calc(100vh-100px)] mt-[1px]">
|
||||
<div className="h-[calc(100vh-100px)] mt-px">
|
||||
<Virtuoso
|
||||
data={filteredRules}
|
||||
itemContent={(i, rule) => (
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user