From 8d7ae19274da9f198513546165c2be11939e316e Mon Sep 17 00:00:00 2001 From: pompurin404 Date: Mon, 5 Aug 2024 14:04:40 +0800 Subject: [PATCH] Initialization constant --- src/main/config/profile.ts | 7 +- src/renderer/index.html | 2 +- .../src/components/profiles/profile-item.tsx | 122 +++++++++++++++--- .../src/components/sider/profile-card.tsx | 28 ++-- .../src/components/sider/tun-switcher.tsx | 10 +- src/renderer/src/main.tsx | 26 ++-- src/renderer/src/pages/profiles.tsx | 10 +- src/renderer/src/utils/init.ts | 8 ++ src/renderer/src/utils/ipc.ts | 2 +- 9 files changed, 169 insertions(+), 46 deletions(-) diff --git a/src/main/config/profile.ts b/src/main/config/profile.ts index 48c6a8b9..a6f3b81b 100644 --- a/src/main/config/profile.ts +++ b/src/main/config/profile.ts @@ -51,9 +51,14 @@ export async function addProfileItem(item: Partial): Promise export function removeProfileItem(id: string): void { profileConfig.items = profileConfig.items?.filter((item) => item.id !== id) if (profileConfig.current === id) { - profileConfig.current = profileConfig.items[0]?.id + if (profileConfig.items.length > 0) { + profileConfig.current = profileConfig.items[0]?.id + } else { + profileConfig.current = undefined + } } fs.writeFileSync(profileConfigPath(), yaml.stringify(profileConfig)) + fs.rmSync(profilePath(id)) window?.webContents.send('profileConfigUpdated') } diff --git a/src/renderer/index.html b/src/renderer/index.html index a48de92b..59278255 100644 --- a/src/renderer/index.html +++ b/src/renderer/index.html @@ -1,7 +1,7 @@ - + Mihomo Party Promise + mutateProfileConfig: () => void onClick: () => Promise } +interface MenuItem { + key: string + label: string + showDivider: boolean + color: 'default' | 'danger' + className: string +} const ProfileItem: React.FC = (props) => { - const { info, onClick, isCurrent } = props + const { info, removeProfileItem, mutateProfileConfig, onClick, isCurrent } = props const extra = info?.extra const usage = (extra?.upload ?? 0) + (extra?.download ?? 0) const total = extra?.total ?? 0 + const menuItems: MenuItem[] = useMemo(() => { + const list = [ + { + key: 'edit', + label: '编辑文件', + showDivider: true, + color: 'default', + className: '' + } as MenuItem, + { + key: 'delete', + label: '删除', + showDivider: false, + color: 'danger', + className: 'text-danger' + } as MenuItem + ] + if (info.home) { + list.unshift({ + key: 'home', + label: '主页', + showDivider: false, + color: 'default', + className: '' + } as MenuItem) + } + return list + }, [info]) + + const onMenuAction = (key: Key): void => { + switch (key) { + case 'edit': + break + case 'delete': { + removeProfileItem(info.id) + mutateProfileConfig() + break + } + + case 'home': { + open(info.home) + break + } + } + } + return ( - +

{info?.name}

- +
+ + + + + + + {menuItems.map((item) => ( + + {item.label} + + ))} + + +
+
+
+ {extra ? `${calcTraffic(usage)}/${calcTraffic(total)}` : undefined} + {dayjs(info.updated).fromNow()}
- - + + {extra && ( + + )}
) diff --git a/src/renderer/src/components/sider/profile-card.tsx b/src/renderer/src/components/sider/profile-card.tsx index 9c2bf5f5..6c528b35 100644 --- a/src/renderer/src/components/sider/profile-card.tsx +++ b/src/renderer/src/components/sider/profile-card.tsx @@ -3,6 +3,12 @@ import { useProfileConfig } from '@renderer/hooks/use-profile-config' import { useLocation, useNavigate } from 'react-router-dom' import { calcTraffic, calcPercent } from '@renderer/utils/calc' import { IoMdRefresh } from 'react-icons/io' +import relativeTime from 'dayjs/plugin/relativeTime' +import 'dayjs/locale/zh-cn' +import dayjs from 'dayjs' + +dayjs.extend(relativeTime) +dayjs.locale('zh-cn') const ProfileCard: React.FC = () => { const navigate = useNavigate() @@ -16,6 +22,7 @@ const ProfileCard: React.FC = () => { type: 'local', name: '空白订阅' } + const extra = info?.extra const usage = (extra?.upload ?? 0) + (extra?.download ?? 0) const total = extra?.total ?? 0 @@ -27,7 +34,7 @@ const ProfileCard: React.FC = () => { isPressable onPress={() => navigate('/profiles')} > - +

{info?.name} @@ -36,14 +43,19 @@ const ProfileCard: React.FC = () => {

+
+ {extra ? `${calcTraffic(usage)}/${calcTraffic(total)}` : undefined} + {dayjs(info.updated).fromNow()} +
- - + + {extra && ( + + )} ) diff --git a/src/renderer/src/components/sider/tun-switcher.tsx b/src/renderer/src/components/sider/tun-switcher.tsx index c73c9c20..e008990b 100644 --- a/src/renderer/src/components/sider/tun-switcher.tsx +++ b/src/renderer/src/components/sider/tun-switcher.tsx @@ -3,12 +3,8 @@ import { useControledMihomoConfig } from '@renderer/hooks/use-controled-mihomo-c import BorderSwitch from '@renderer/components/base/border-swtich' import { TbDeviceIpadHorizontalBolt } from 'react-icons/tb' import { useLocation, useNavigate } from 'react-router-dom' -import { - platform, - encryptString, - patchMihomoConfig, - isEncryptionAvailable -} from '@renderer/utils/ipc' +import { encryptString, patchMihomoConfig, isEncryptionAvailable } from '@renderer/utils/ipc' +import { platform } from '@renderer/utils/init' import React, { useState } from 'react' import { useAppConfig } from '@renderer/hooks/use-app-config' import BasePasswordModal from '../base/base-password-modal' @@ -24,7 +20,7 @@ const TunSwitcher: React.FC = () => { const { enable } = tun || {} const onChange = async (enable: boolean): Promise => { - if (enable && (await platform()) !== 'win32') { + if (enable && platform !== 'win32') { const encryptionAvailable = await isEncryptionAvailable() if (!appConfig?.encryptedPassword && encryptionAvailable) { setOpenPasswordModal(true) diff --git a/src/renderer/src/main.tsx b/src/renderer/src/main.tsx index 6b74a391..5f67e3f6 100644 --- a/src/renderer/src/main.tsx +++ b/src/renderer/src/main.tsx @@ -3,18 +3,20 @@ import ReactDOM from 'react-dom/client' import { HashRouter } from 'react-router-dom' import { ThemeProvider as NextThemesProvider } from 'next-themes' import { NextUIProvider } from '@nextui-org/react' -import '@renderer/utils/init' +import { init } from '@renderer/utils/init' import '@renderer/assets/main.css' import App from '@renderer/App' -ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render( - - - - - - - - - -) +init().then(() => { + ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render( + + + + + + + + + + ) +}) diff --git a/src/renderer/src/pages/profiles.tsx b/src/renderer/src/pages/profiles.tsx index 67c0127d..750057cc 100644 --- a/src/renderer/src/pages/profiles.tsx +++ b/src/renderer/src/pages/profiles.tsx @@ -6,7 +6,13 @@ import { useState } from 'react' import { MdContentPaste } from 'react-icons/md' const Profiles: React.FC = () => { - const { profileConfig, addProfileItem, changeCurrentProfile } = useProfileConfig() + const { + profileConfig, + addProfileItem, + removeProfileItem, + changeCurrentProfile, + mutateProfileConfig + } = useProfileConfig() const { current, items } = profileConfig || {} const [importing, setImporting] = useState(false) const [url, setUrl] = useState('') @@ -55,6 +61,8 @@ const Profiles: React.FC = () => { { await changeCurrentProfile(item.id) diff --git a/src/renderer/src/utils/init.ts b/src/renderer/src/utils/init.ts index 63ed9d3d..91f21440 100644 --- a/src/renderer/src/utils/init.ts +++ b/src/renderer/src/utils/init.ts @@ -1,4 +1,6 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ + +import { getPlatform } from './ipc' const originError = console.error const originWarn = console.warn console.error = function (...args: any[]): void { @@ -13,3 +15,9 @@ console.warn = function (...args): void { } originWarn.call(console, args) } + +export let platform: NodeJS.Platform + +export async function init(): Promise { + platform = await getPlatform() +} diff --git a/src/renderer/src/utils/ipc.ts b/src/renderer/src/utils/ipc.ts index d8b0eea4..3e027bb1 100644 --- a/src/renderer/src/utils/ipc.ts +++ b/src/renderer/src/utils/ipc.ts @@ -115,7 +115,7 @@ export async function encryptString(str: string): Promise { return await window.electron.ipcRenderer.invoke('encryptString', str) } -export async function platform(): Promise { +export async function getPlatform(): Promise { return await window.electron.ipcRenderer.invoke('platform') }