adjust styles

This commit is contained in:
pompurin404 2024-08-27 09:36:49 +08:00
parent 5815076ee3
commit 1882a38aa2
No known key found for this signature in database
9 changed files with 192 additions and 169 deletions

View File

@ -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()) {

View File

@ -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>

View File

@ -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>
) )
} }

View File

@ -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>
) )
} }

View File

@ -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) => {

View File

@ -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}

View File

@ -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) => {

View File

@ -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) => {

View File

@ -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>