mirror of
https://gh.catmak.name/https://github.com/mihomo-party-org/mihomo-party
synced 2025-12-27 13:10:30 +08:00
profile page
This commit is contained in:
parent
27f2f70f1b
commit
eb90aa2819
@ -44,7 +44,7 @@ const App: React.FC = () => {
|
||||
return (
|
||||
<div className="w-full h-[100vh] flex">
|
||||
<div className="side w-[250px] h-full overflow-y-auto no-scrollbar">
|
||||
<div className="sticky top-0 z-40 backdrop-blur h-[48px]">
|
||||
<div className="sticky top-0 z-40 backdrop-blur bg-background/70 h-[48px]">
|
||||
<div className="flex justify-between p-2">
|
||||
<h3 className="select-none text-lg font-bold leading-[32px]">Mihomo Party</h3>
|
||||
<Button
|
||||
|
||||
@ -10,7 +10,7 @@ interface Props {
|
||||
const BasePage: React.FC<Props> = (props) => {
|
||||
return (
|
||||
<div className="w-full h-full overflow-y-auto custom-scrollbar">
|
||||
<div className="sticky top-0 z-40 h-[48px] w-full backdrop-blur">
|
||||
<div className="sticky top-0 z-40 h-[48px] w-full backdrop-blur bg-background/70">
|
||||
<div className="p-2 flex justify-between">
|
||||
<div className="select-none title h-full text-lg leading-[32px]">{props.title}</div>
|
||||
<div className="header h-full">{props.header}</div>
|
||||
|
||||
41
src/renderer/src/components/profiles/profile-item.tsx
Normal file
41
src/renderer/src/components/profiles/profile-item.tsx
Normal file
@ -0,0 +1,41 @@
|
||||
import { Button, Card, CardBody, CardFooter, Progress } from '@nextui-org/react'
|
||||
import { calcPercent, calcTraffic } from '@renderer/utils/calc'
|
||||
import React from 'react'
|
||||
import { IoMdRefresh } from 'react-icons/io'
|
||||
|
||||
interface Props {
|
||||
info: IProfileItem
|
||||
isCurrent: boolean
|
||||
onClick: () => void
|
||||
}
|
||||
|
||||
const ProfileItem: React.FC<Props> = (props) => {
|
||||
const { info, onClick, isCurrent } = props
|
||||
const extra = info?.extra
|
||||
const usage = (extra?.upload ?? 0) + (extra?.download ?? 0)
|
||||
const total = extra?.total ?? 0
|
||||
return (
|
||||
<Card fullWidth isPressable onPress={onClick} className={isCurrent ? 'bg-primary' : ''}>
|
||||
<CardBody>
|
||||
<div className="flex justify-between h-[32px]">
|
||||
<h3 className="select-none text-ellipsis whitespace-nowrap overflow-hidden text-md font-bold leading-[32px]">
|
||||
{info?.name}
|
||||
</h3>
|
||||
<Button isIconOnly size="sm" variant="light" color="default">
|
||||
<IoMdRefresh color="default" className="text-[24px]" />
|
||||
</Button>
|
||||
</div>
|
||||
</CardBody>
|
||||
<CardFooter className="pt-1">
|
||||
<Progress
|
||||
classNames={{ indicator: 'bg-foreground', label: 'select-none' }}
|
||||
label={extra ? `${calcTraffic(usage)}/${calcTraffic(total)}` : undefined}
|
||||
value={calcPercent(extra?.upload, extra?.download, extra?.total)}
|
||||
className="max-w-md"
|
||||
/>
|
||||
</CardFooter>
|
||||
</Card>
|
||||
)
|
||||
}
|
||||
|
||||
export default ProfileItem
|
||||
@ -1,7 +1,7 @@
|
||||
import { Button, Card, CardBody, CardFooter, Progress } from '@nextui-org/react'
|
||||
import { useProfileConfig } from '@renderer/hooks/use-profile'
|
||||
import { useLocation, useNavigate } from 'react-router-dom'
|
||||
import { calcTraffic } from '@renderer/utils/calc'
|
||||
import { calcTraffic, calcPercent } from '@renderer/utils/calc'
|
||||
import { IoMdRefresh } from 'react-icons/io'
|
||||
|
||||
const ProfileCard: React.FC = () => {
|
||||
@ -50,14 +50,3 @@ const ProfileCard: React.FC = () => {
|
||||
}
|
||||
|
||||
export default ProfileCard
|
||||
|
||||
function calcPercent(
|
||||
upload: number | undefined,
|
||||
download: number | undefined,
|
||||
total: number | undefined
|
||||
): number {
|
||||
if (upload === undefined || download === undefined || total === undefined) {
|
||||
return 100
|
||||
}
|
||||
return Math.round(((upload + download) / total) * 100)
|
||||
}
|
||||
|
||||
@ -1,11 +1,13 @@
|
||||
import { Button, Input } from '@nextui-org/react'
|
||||
import BasePage from '@renderer/components/base/base-page'
|
||||
import ProfileItem from '@renderer/components/profiles/profile-item'
|
||||
import { useProfileConfig } from '@renderer/hooks/use-profile'
|
||||
import { useState } from 'react'
|
||||
import { MdContentPaste } from 'react-icons/md'
|
||||
|
||||
const Profiles: React.FC = () => {
|
||||
const { profileConfig, addProfileItem } = useProfileConfig()
|
||||
const { current, items } = profileConfig || {}
|
||||
const [importing, setImporting] = useState(false)
|
||||
const [url, setUrl] = useState('')
|
||||
|
||||
@ -22,7 +24,7 @@ const Profiles: React.FC = () => {
|
||||
|
||||
return (
|
||||
<BasePage title="订阅">
|
||||
<div className="flex m-2">
|
||||
<div className="sticky top-[48px] z-40 backdrop-blur bg-background/70 flex p-2">
|
||||
<Input
|
||||
variant="bordered"
|
||||
className="mr-2"
|
||||
@ -48,7 +50,16 @@ const Profiles: React.FC = () => {
|
||||
导入
|
||||
</Button>
|
||||
</div>
|
||||
{JSON.stringify(profileConfig)}
|
||||
<div className="grid sm:grid-cols-2 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-2 mx-2">
|
||||
{items?.map((item) => (
|
||||
<ProfileItem
|
||||
key={item.id}
|
||||
isCurrent={item.id === current}
|
||||
info={item}
|
||||
onClick={() => {}}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
</BasePage>
|
||||
)
|
||||
}
|
||||
|
||||
@ -17,3 +17,14 @@ export function calcTraffic(bit: number): string {
|
||||
bit /= 1024
|
||||
return `${bit.toFixed(2)} YB`
|
||||
}
|
||||
|
||||
export function calcPercent(
|
||||
upload: number | undefined,
|
||||
download: number | undefined,
|
||||
total: number | undefined
|
||||
): number {
|
||||
if (upload === undefined || download === undefined || total === undefined) {
|
||||
return 100
|
||||
}
|
||||
return Math.round(((upload + download) / total) * 100)
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user