mirror of
https://gh.catmak.name/https://github.com/mihomo-party-org/mihomo-party
synced 2025-12-27 21:20:29 +08:00
adjust styles
This commit is contained in:
parent
5815076ee3
commit
1882a38aa2
@ -101,6 +101,7 @@ async function checkProfile(): Promise<void> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export async function autoGrantCorePermition(corePath: string): Promise<void> {
|
export async function autoGrantCorePermition(corePath: string): Promise<void> {
|
||||||
|
if (process.platform === 'win32') return
|
||||||
const { encryptedPassword } = await getAppConfig()
|
const { encryptedPassword } = await getAppConfig()
|
||||||
const execPromise = promisify(exec)
|
const execPromise = promisify(exec)
|
||||||
if (encryptedPassword && isEncryptionAvailable()) {
|
if (encryptedPassword && isEncryptionAvailable()) {
|
||||||
|
|||||||
@ -15,8 +15,8 @@ const BasePage = forwardRef<HTMLDivElement, Props>((props, ref) => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div ref={contentRef} className="w-full h-full overflow-y-auto custom-scrollbar">
|
<div ref={contentRef} className="w-full h-full overflow-y-auto custom-scrollbar">
|
||||||
<div className="sticky top-0 z-40 h-[48px] w-full backdrop-blur bg-background/40">
|
<div className="sticky top-0 z-40 h-[49px] w-full backdrop-blur bg-background/40">
|
||||||
<div className="p-2 flex justify-between">
|
<div className="p-2 flex justify-between h-[48px]">
|
||||||
<div className="title h-full text-lg leading-[32px]">{props.title}</div>
|
<div className="title h-full text-lg leading-[32px]">{props.title}</div>
|
||||||
<div className="header h-full">{props.header}</div>
|
<div className="header h-full">{props.header}</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -7,18 +7,20 @@ const colorMap = {
|
|||||||
info: 'primary',
|
info: 'primary',
|
||||||
debug: 'default'
|
debug: 'default'
|
||||||
}
|
}
|
||||||
const LogItem: React.FC<IMihomoLogInfo> = (props) => {
|
const LogItem: React.FC<IMihomoLogInfo & { index: number }> = (props) => {
|
||||||
const { type, payload, time } = props
|
const { type, payload, time, index } = props
|
||||||
return (
|
return (
|
||||||
<Card className="m-2">
|
<div className={`px-2 pb-2 ${index === 0 ? 'pt-2' : ''}`}>
|
||||||
<CardHeader className="pb-0 pt-1">
|
<Card>
|
||||||
<div className={`mr-2 text-lg font-bold text-${colorMap[type]}`}>
|
<CardHeader className="pb-0 pt-1">
|
||||||
{props.type.toUpperCase()}
|
<div className={`mr-2 text-lg font-bold text-${colorMap[type]}`}>
|
||||||
</div>
|
{props.type.toUpperCase()}
|
||||||
<small className="text-default-500">{time}</small>
|
</div>
|
||||||
</CardHeader>
|
<small className="text-default-500">{time}</small>
|
||||||
<CardBody className="pt-0 text-sm">{payload}</CardBody>
|
</CardHeader>
|
||||||
</Card>
|
<CardBody className="pt-0 text-sm">{payload}</CardBody>
|
||||||
|
</Card>
|
||||||
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,18 +1,20 @@
|
|||||||
import { Card, CardBody } from '@nextui-org/react'
|
import { Card, CardBody } from '@nextui-org/react'
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
|
|
||||||
const RuleItem: React.FC<IMihomoRulesDetail> = (props) => {
|
const RuleItem: React.FC<IMihomoRulesDetail & { index: number }> = (props) => {
|
||||||
const { type, payload, proxy } = props
|
const { type, payload, proxy, index } = props
|
||||||
return (
|
return (
|
||||||
<Card className="mb-2 mx-2">
|
<div className={`w-full px-2 pb-2 ${index === 0 ? 'pt-2' : ''}`}>
|
||||||
<CardBody className="w-full">
|
<Card>
|
||||||
<div className="text-ellipsis whitespace-nowrap overflow-hidden">{payload}</div>
|
<CardBody className="w-full">
|
||||||
<div className="flex justify-start text-default-500">
|
<div className="text-ellipsis whitespace-nowrap overflow-hidden">{payload}</div>
|
||||||
<div>{type}</div>
|
<div className="flex justify-start text-default-500">
|
||||||
<div className="ml-2">{proxy}</div>
|
<div>{type}</div>
|
||||||
</div>
|
<div className="ml-2">{proxy}</div>
|
||||||
</CardBody>
|
</div>
|
||||||
</Card>
|
</CardBody>
|
||||||
|
</Card>
|
||||||
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -6,7 +6,7 @@ import {
|
|||||||
stopMihomoConnections
|
stopMihomoConnections
|
||||||
} from '@renderer/utils/ipc'
|
} from '@renderer/utils/ipc'
|
||||||
import { Key, useEffect, useMemo, useState } from 'react'
|
import { Key, useEffect, useMemo, useState } from 'react'
|
||||||
import { Button, Input } from '@nextui-org/react'
|
import { Button, Divider, Input } from '@nextui-org/react'
|
||||||
import { IoCloseCircle } from 'react-icons/io5'
|
import { IoCloseCircle } from 'react-icons/io5'
|
||||||
import { calcTraffic } from '@renderer/utils/calc'
|
import { calcTraffic } from '@renderer/utils/calc'
|
||||||
import { Table, TableHeader, TableColumn, TableBody, TableRow, TableCell } from '@nextui-org/react'
|
import { Table, TableHeader, TableColumn, TableBody, TableRow, TableCell } from '@nextui-org/react'
|
||||||
@ -83,14 +83,17 @@ const Connections: React.FC = () => {
|
|||||||
connection={selectedConnection}
|
connection={selectedConnection}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
<div className="overflow-x-auto sticky top-[49px] z-40 backdrop-blur bg-background/40 flex p-2">
|
<div className="overflow-x-auto sticky top-[49px] z-40">
|
||||||
<Input
|
<div className="flex p-2">
|
||||||
variant="bordered"
|
<Input
|
||||||
size="sm"
|
variant="bordered"
|
||||||
value={filter}
|
size="sm"
|
||||||
placeholder="筛选过滤"
|
value={filter}
|
||||||
onValueChange={setFilter}
|
placeholder="筛选过滤"
|
||||||
/>
|
onValueChange={setFilter}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<Divider />
|
||||||
</div>
|
</div>
|
||||||
<Table
|
<Table
|
||||||
onRowAction={(id: Key) => {
|
onRowAction={(id: Key) => {
|
||||||
|
|||||||
@ -2,7 +2,7 @@ import BasePage from '@renderer/components/base/base-page'
|
|||||||
import { startMihomoLogs, stopMihomoLogs } from '@renderer/utils/ipc'
|
import { startMihomoLogs, stopMihomoLogs } from '@renderer/utils/ipc'
|
||||||
import LogItem from '@renderer/components/logs/log-item'
|
import LogItem from '@renderer/components/logs/log-item'
|
||||||
import { useEffect, useMemo, useRef, useState } from 'react'
|
import { useEffect, useMemo, useRef, useState } from 'react'
|
||||||
import { Button, Input } from '@nextui-org/react'
|
import { Button, Divider, Input } from '@nextui-org/react'
|
||||||
import { Virtuoso, VirtuosoHandle } from 'react-virtuoso'
|
import { Virtuoso, VirtuosoHandle } from 'react-virtuoso'
|
||||||
|
|
||||||
const Logs: React.FC = () => {
|
const Logs: React.FC = () => {
|
||||||
@ -45,8 +45,8 @@ const Logs: React.FC = () => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<BasePage title="实时日志">
|
<BasePage title="实时日志">
|
||||||
<div className="sticky top-[49px] z-40 backdrop-blur bg-background/40 flex p-2">
|
<div className="sticky top-[49px] z-40">
|
||||||
<div className="w-full flex">
|
<div className="w-full flex p-2">
|
||||||
<Input
|
<Input
|
||||||
variant="bordered"
|
variant="bordered"
|
||||||
size="sm"
|
size="sm"
|
||||||
@ -66,17 +66,19 @@ const Logs: React.FC = () => {
|
|||||||
追踪
|
追踪
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
|
<Divider />
|
||||||
</div>
|
</div>
|
||||||
<Virtuoso
|
<Virtuoso
|
||||||
autoFocus
|
autoFocus
|
||||||
ref={virtuosoRef}
|
ref={virtuosoRef}
|
||||||
style={{ height: 'calc(100vh - 100px)' }}
|
style={{ height: 'calc(100vh - 100px)' }}
|
||||||
|
data={filteredLogs}
|
||||||
totalCount={filteredLogs.length}
|
totalCount={filteredLogs.length}
|
||||||
itemContent={(index) => {
|
itemContent={(i, log) => {
|
||||||
const log = filteredLogs[index]
|
|
||||||
return (
|
return (
|
||||||
<LogItem
|
<LogItem
|
||||||
key={log.payload + index}
|
index={i}
|
||||||
|
key={log.payload + i}
|
||||||
time={log.time}
|
time={log.time}
|
||||||
type={log.type}
|
type={log.type}
|
||||||
payload={log.payload}
|
payload={log.payload}
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import { Button, Input } from '@nextui-org/react'
|
import { Button, Divider, Input } from '@nextui-org/react'
|
||||||
import BasePage from '@renderer/components/base/base-page'
|
import BasePage from '@renderer/components/base/base-page'
|
||||||
import { getFilePath, readTextFile } from '@renderer/utils/ipc'
|
import { getFilePath, readTextFile } from '@renderer/utils/ipc'
|
||||||
import { useEffect, useRef, useState } from 'react'
|
import { useEffect, useRef, useState } from 'react'
|
||||||
@ -133,62 +133,65 @@ const Override: React.FC = () => {
|
|||||||
</>
|
</>
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<div className="sticky top-[48px] z-40 backdrop-blur bg-background/40 flex p-2">
|
<div className="sticky top-[49px] z-40 backdrop-blur bg-background/40">
|
||||||
<Input
|
<div className="flex p-2">
|
||||||
variant="bordered"
|
<Input
|
||||||
size="sm"
|
variant="bordered"
|
||||||
value={url}
|
size="sm"
|
||||||
onValueChange={setUrl}
|
value={url}
|
||||||
endContent={
|
onValueChange={setUrl}
|
||||||
<Button
|
endContent={
|
||||||
size="sm"
|
<Button
|
||||||
isIconOnly
|
size="sm"
|
||||||
variant="light"
|
isIconOnly
|
||||||
onPress={() => {
|
variant="light"
|
||||||
navigator.clipboard.readText().then((text) => {
|
onPress={() => {
|
||||||
setUrl(text)
|
navigator.clipboard.readText().then((text) => {
|
||||||
})
|
setUrl(text)
|
||||||
}}
|
})
|
||||||
>
|
}}
|
||||||
<MdContentPaste className="text-lg" />
|
>
|
||||||
</Button>
|
<MdContentPaste className="text-lg" />
|
||||||
}
|
</Button>
|
||||||
/>
|
}
|
||||||
<Button
|
/>
|
||||||
size="sm"
|
<Button
|
||||||
color="primary"
|
size="sm"
|
||||||
className="ml-2"
|
color="primary"
|
||||||
isDisabled={url === ''}
|
className="ml-2"
|
||||||
isLoading={importing}
|
isDisabled={url === ''}
|
||||||
onPress={handleImport}
|
isLoading={importing}
|
||||||
>
|
onPress={handleImport}
|
||||||
导入
|
>
|
||||||
</Button>
|
导入
|
||||||
<Button
|
</Button>
|
||||||
size="sm"
|
<Button
|
||||||
color="primary"
|
size="sm"
|
||||||
className="ml-2"
|
color="primary"
|
||||||
onPress={() => {
|
className="ml-2"
|
||||||
getFilePath(['js', 'yaml']).then(async (files) => {
|
onPress={() => {
|
||||||
if (files?.length) {
|
getFilePath(['js', 'yaml']).then(async (files) => {
|
||||||
const content = await readTextFile(files[0])
|
if (files?.length) {
|
||||||
const fileName = files[0].split('/').pop()?.split('\\').pop()
|
const content = await readTextFile(files[0])
|
||||||
await addOverrideItem({
|
const fileName = files[0].split('/').pop()?.split('\\').pop()
|
||||||
name: fileName,
|
await addOverrideItem({
|
||||||
type: 'local',
|
name: fileName,
|
||||||
file: content,
|
type: 'local',
|
||||||
ext: fileName?.endsWith('.js') ? 'js' : 'yaml'
|
file: content,
|
||||||
})
|
ext: fileName?.endsWith('.js') ? 'js' : 'yaml'
|
||||||
}
|
})
|
||||||
})
|
}
|
||||||
}}
|
})
|
||||||
>
|
}}
|
||||||
打开
|
>
|
||||||
</Button>
|
打开
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
<Divider />
|
||||||
</div>
|
</div>
|
||||||
<DndContext sensors={sensors} collisionDetection={closestCenter} onDragEnd={onDragEnd}>
|
<DndContext sensors={sensors} collisionDetection={closestCenter} onDragEnd={onDragEnd}>
|
||||||
<div
|
<div
|
||||||
className={`${fileOver ? 'blur-sm' : ''} grid sm:grid-cols-2 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-2 mx-2`}
|
className={`${fileOver ? 'blur-sm' : ''} grid sm:grid-cols-2 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-2 m-2`}
|
||||||
>
|
>
|
||||||
<SortableContext
|
<SortableContext
|
||||||
items={sortedItems.map((item) => {
|
items={sortedItems.map((item) => {
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import { Button, Checkbox, Input } from '@nextui-org/react'
|
import { Button, Checkbox, Divider, Input } from '@nextui-org/react'
|
||||||
import BasePage from '@renderer/components/base/base-page'
|
import BasePage from '@renderer/components/base/base-page'
|
||||||
import ProfileItem from '@renderer/components/profiles/profile-item'
|
import ProfileItem from '@renderer/components/profiles/profile-item'
|
||||||
import { useProfileConfig } from '@renderer/hooks/use-profile-config'
|
import { useProfileConfig } from '@renderer/hooks/use-profile-config'
|
||||||
@ -122,70 +122,73 @@ const Profiles: React.FC = () => {
|
|||||||
</Button>
|
</Button>
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<div className="sticky top-[48px] z-40 backdrop-blur bg-background/40 flex p-2">
|
<div className="sticky top-[49px] z-40 backdrop-blur bg-background/40">
|
||||||
<Input
|
<div className="flex p-2">
|
||||||
variant="bordered"
|
<Input
|
||||||
size="sm"
|
variant="bordered"
|
||||||
value={url}
|
size="sm"
|
||||||
onValueChange={setUrl}
|
value={url}
|
||||||
endContent={
|
onValueChange={setUrl}
|
||||||
<>
|
endContent={
|
||||||
<Button
|
<>
|
||||||
size="sm"
|
<Button
|
||||||
isIconOnly
|
size="sm"
|
||||||
variant="light"
|
isIconOnly
|
||||||
onPress={() => {
|
variant="light"
|
||||||
navigator.clipboard.readText().then((text) => {
|
onPress={() => {
|
||||||
setUrl(text)
|
navigator.clipboard.readText().then((text) => {
|
||||||
})
|
setUrl(text)
|
||||||
}}
|
})
|
||||||
>
|
}}
|
||||||
<MdContentPaste className="text-lg" />
|
>
|
||||||
</Button>
|
<MdContentPaste className="text-lg" />
|
||||||
<Checkbox
|
</Button>
|
||||||
className="whitespace-nowrap"
|
<Checkbox
|
||||||
checked={useProxy}
|
className="whitespace-nowrap"
|
||||||
onValueChange={setUseProxy}
|
checked={useProxy}
|
||||||
>
|
onValueChange={setUseProxy}
|
||||||
代理
|
>
|
||||||
</Checkbox>
|
代理
|
||||||
</>
|
</Checkbox>
|
||||||
}
|
</>
|
||||||
/>
|
|
||||||
|
|
||||||
<Button
|
|
||||||
size="sm"
|
|
||||||
color="primary"
|
|
||||||
className="ml-2"
|
|
||||||
isDisabled={url === ''}
|
|
||||||
isLoading={importing}
|
|
||||||
onPress={handleImport}
|
|
||||||
>
|
|
||||||
导入
|
|
||||||
</Button>
|
|
||||||
<Button
|
|
||||||
size="sm"
|
|
||||||
color="primary"
|
|
||||||
className="ml-2"
|
|
||||||
onPress={async () => {
|
|
||||||
try {
|
|
||||||
const files = await getFilePath(['yml', 'yaml'])
|
|
||||||
if (files?.length) {
|
|
||||||
const content = await readTextFile(files[0])
|
|
||||||
const fileName = files[0].split('/').pop()?.split('\\').pop()
|
|
||||||
await addProfileItem({ name: fileName, type: 'local', file: content })
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
alert(e)
|
|
||||||
}
|
}
|
||||||
}}
|
/>
|
||||||
>
|
|
||||||
打开
|
<Button
|
||||||
</Button>
|
size="sm"
|
||||||
|
color="primary"
|
||||||
|
className="ml-2"
|
||||||
|
isDisabled={url === ''}
|
||||||
|
isLoading={importing}
|
||||||
|
onPress={handleImport}
|
||||||
|
>
|
||||||
|
导入
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
size="sm"
|
||||||
|
color="primary"
|
||||||
|
className="ml-2"
|
||||||
|
onPress={async () => {
|
||||||
|
try {
|
||||||
|
const files = await getFilePath(['yml', 'yaml'])
|
||||||
|
if (files?.length) {
|
||||||
|
const content = await readTextFile(files[0])
|
||||||
|
const fileName = files[0].split('/').pop()?.split('\\').pop()
|
||||||
|
await addProfileItem({ name: fileName, type: 'local', file: content })
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
alert(e)
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
打开
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
<Divider />
|
||||||
</div>
|
</div>
|
||||||
<DndContext sensors={sensors} collisionDetection={closestCenter} onDragEnd={onDragEnd}>
|
<DndContext sensors={sensors} collisionDetection={closestCenter} onDragEnd={onDragEnd}>
|
||||||
<div
|
<div
|
||||||
className={`${fileOver ? 'blur-sm' : ''} grid sm:grid-cols-2 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-2 mx-2`}
|
className={`${fileOver ? 'blur-sm' : ''} grid sm:grid-cols-2 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-2 m-2`}
|
||||||
>
|
>
|
||||||
<SortableContext
|
<SortableContext
|
||||||
items={sortedItems.map((item) => {
|
items={sortedItems.map((item) => {
|
||||||
|
|||||||
@ -2,14 +2,12 @@ import BasePage from '@renderer/components/base/base-page'
|
|||||||
import RuleItem from '@renderer/components/rules/rule-item'
|
import RuleItem from '@renderer/components/rules/rule-item'
|
||||||
import { Virtuoso } from 'react-virtuoso'
|
import { Virtuoso } from 'react-virtuoso'
|
||||||
import { useMemo, useState } from 'react'
|
import { useMemo, useState } from 'react'
|
||||||
import { Input } from '@nextui-org/react'
|
import { Divider, Input } from '@nextui-org/react'
|
||||||
import useSWR from 'swr'
|
import useSWR from 'swr'
|
||||||
import { mihomoRules } from '@renderer/utils/ipc'
|
import { mihomoRules } from '@renderer/utils/ipc'
|
||||||
|
|
||||||
const Rules: React.FC = () => {
|
const Rules: React.FC = () => {
|
||||||
const { data: rules } = useSWR<IMihomoRulesInfo>('mihomoRules', mihomoRules, {
|
const { data: rules } = useSWR<IMihomoRulesInfo>('mihomoRules', mihomoRules)
|
||||||
refreshInterval: 5000
|
|
||||||
})
|
|
||||||
const [filter, setFilter] = useState('')
|
const [filter, setFilter] = useState('')
|
||||||
|
|
||||||
const filteredRules = useMemo(() => {
|
const filteredRules = useMemo(() => {
|
||||||
@ -24,20 +22,29 @@ const Rules: React.FC = () => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<BasePage title="分流规则">
|
<BasePage title="分流规则">
|
||||||
<div className="sticky top-[49px] z-40 backdrop-blur bg-background/40 flex p-2">
|
<div className="sticky top-[50px] z-40">
|
||||||
<Input
|
<div className="flex p-2">
|
||||||
variant="bordered"
|
<Input
|
||||||
size="sm"
|
variant="bordered"
|
||||||
value={filter}
|
size="sm"
|
||||||
placeholder="筛选过滤"
|
value={filter}
|
||||||
onValueChange={setFilter}
|
placeholder="筛选过滤"
|
||||||
/>
|
onValueChange={setFilter}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<Divider />
|
||||||
</div>
|
</div>
|
||||||
<Virtuoso
|
<Virtuoso
|
||||||
style={{ height: 'calc(100vh - 100px)' }}
|
style={{ height: 'calc(100vh - 100px)', marginTop: '1px' }}
|
||||||
data={filteredRules}
|
data={filteredRules}
|
||||||
itemContent={(_, rule) => (
|
itemContent={(i, rule) => (
|
||||||
<RuleItem type={rule.type} payload={rule.payload} proxy={rule.proxy} size={rule.size} />
|
<RuleItem
|
||||||
|
index={i}
|
||||||
|
type={rule.type}
|
||||||
|
payload={rule.payload}
|
||||||
|
proxy={rule.proxy}
|
||||||
|
size={rule.size}
|
||||||
|
/>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
</BasePage>
|
</BasePage>
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user