From fd86c0dba42c177a3517c89b1a53798fcb6515eb Mon Sep 17 00:00:00 2001 From: pompurin404 Date: Wed, 7 Aug 2024 21:21:04 +0800 Subject: [PATCH] support local profile --- src/main/config/profile.ts | 2 +- src/main/utils/ipc.ts | 4 +- .../src/components/base/base-page.tsx | 14 ++-- .../components/profiles/edit-info-modal.tsx | 25 +++---- .../src/components/profiles/profile-item.tsx | 65 ++++++++++++------- .../src/components/sider/profile-card.tsx | 65 ++++++++++++------- .../components/sider/sysproxy-switcher.tsx | 2 +- src/renderer/src/pages/profiles.tsx | 50 +++++++++++++- 8 files changed, 157 insertions(+), 70 deletions(-) diff --git a/src/main/config/profile.ts b/src/main/config/profile.ts index 7055f53..1df3271 100644 --- a/src/main/config/profile.ts +++ b/src/main/config/profile.ts @@ -105,7 +105,7 @@ export async function createProfile(item: Partial): Promise { try { execSync(removeCommand, { shell: 'powershell' }) } catch { - console.log('Remove-NetFirewallRule Failed') + console.error('Remove-NetFirewallRule Failed') } try { execSync(createCommand, { shell: 'powershell' }) } catch (e) { dialog.showErrorBox('防火墙设置失败', `${e}`) reject(e) - console.log('New-NetFirewallRule Failed') + console.error('New-NetFirewallRule Failed') } } resolve() diff --git a/src/renderer/src/components/base/base-page.tsx b/src/renderer/src/components/base/base-page.tsx index f726076..9aa49ba 100644 --- a/src/renderer/src/components/base/base-page.tsx +++ b/src/renderer/src/components/base/base-page.tsx @@ -1,5 +1,5 @@ import { Divider } from '@nextui-org/react' -import React from 'react' +import React, { forwardRef, useImperativeHandle, useRef } from 'react' interface Props { title?: React.ReactNode header?: React.ReactNode @@ -7,9 +7,14 @@ interface Props { contentClassName?: string } -const BasePage: React.FC = (props) => { +const BasePage = forwardRef((props, ref) => { + const contentRef = useRef(null) + useImperativeHandle(ref, () => { + return contentRef.current as HTMLDivElement + }) + return ( -
+
{props.title}
@@ -20,6 +25,7 @@ const BasePage: React.FC = (props) => {
{props.children}
) -} +}) +BasePage.displayName = 'BasePage' export default BasePage diff --git a/src/renderer/src/components/profiles/edit-info-modal.tsx b/src/renderer/src/components/profiles/edit-info-modal.tsx index c9e1f72..f61c97d 100644 --- a/src/renderer/src/components/profiles/edit-info-modal.tsx +++ b/src/renderer/src/components/profiles/edit-info-modal.tsx @@ -50,18 +50,19 @@ const EditInfoModal: React.FC = (props) => { /> )} - - - { - setValues({ ...values, interval: parseInt(v) }) - }} - /> - + {values.type === 'remote' && ( + + { + setValues({ ...values, interval: parseInt(v) }) + }} + /> + + )} + disabled={updating} + onPress={() => { + setUpdating(true) + addProfileItem(info).finally(() => { + setUpdating(false) + }) + }} + > + + + )} +
-
- {extra ? `${calcTraffic(usage)}/${calcTraffic(total)}` : undefined} - {dayjs(info.updated).fromNow()} -
+ {info.type === 'remote' && ( +
+ {extra ? `${calcTraffic(usage)}/${calcTraffic(total)}` : undefined} + {dayjs(info.updated).fromNow()} +
+ )} + {info.type === 'local' && ( +
+ + 本地 + +
+ )} {extra && ( diff --git a/src/renderer/src/components/sider/profile-card.tsx b/src/renderer/src/components/sider/profile-card.tsx index d05e233..e5bc7f7 100644 --- a/src/renderer/src/components/sider/profile-card.tsx +++ b/src/renderer/src/components/sider/profile-card.tsx @@ -1,4 +1,4 @@ -import { Button, Card, CardBody, CardFooter, Progress } from '@nextui-org/react' +import { Button, Card, CardBody, CardFooter, Chip, Progress } from '@nextui-org/react' import { useProfileConfig } from '@renderer/hooks/use-profile-config' import { useLocation, useNavigate } from 'react-router-dom' import { calcTraffic, calcPercent } from '@renderer/utils/calc' @@ -42,30 +42,47 @@ const ProfileCard: React.FC = () => { > {info?.name} - + )} +
+ {info.type === 'remote' && ( +
- - -
-
- {extra ? `${calcTraffic(usage)}/${calcTraffic(total)}` : undefined} - {dayjs(info.updated).fromNow()} -
+ {extra ? `${calcTraffic(usage)}/${calcTraffic(total)}` : undefined} + {dayjs(info.updated).fromNow()} + + )} + {info.type === 'local' && ( +
+ + 本地 + +
+ )} {extra && ( diff --git a/src/renderer/src/components/sider/sysproxy-switcher.tsx b/src/renderer/src/components/sider/sysproxy-switcher.tsx index faca5ac..989ce3c 100644 --- a/src/renderer/src/components/sider/sysproxy-switcher.tsx +++ b/src/renderer/src/components/sider/sysproxy-switcher.tsx @@ -19,7 +19,7 @@ const SysproxySwitcher: React.FC = () => { await triggerSysProxy(enable) await patchAppConfig({ sysProxy: { enable } }) } catch (e) { - console.log(e) + console.error(e) } } diff --git a/src/renderer/src/pages/profiles.tsx b/src/renderer/src/pages/profiles.tsx index 82a7f0d..c7ff404 100644 --- a/src/renderer/src/pages/profiles.tsx +++ b/src/renderer/src/pages/profiles.tsx @@ -2,7 +2,7 @@ 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-config' -import { useState } from 'react' +import { useEffect, useRef, useState } from 'react' import { MdContentPaste } from 'react-icons/md' const Profiles: React.FC = () => { @@ -16,6 +16,7 @@ const Profiles: React.FC = () => { } = useProfileConfig() const { current, items } = profileConfig || {} const [importing, setImporting] = useState(false) + const [fileOver, setFileOver] = useState(false) const [url, setUrl] = useState('') const handleImport = async (): Promise => { @@ -26,9 +27,50 @@ const Profiles: React.FC = () => { setImporting(false) } } + const pageRef = useRef(null) + + useEffect(() => { + pageRef.current?.addEventListener('dragover', (e) => { + e.preventDefault() + e.stopPropagation() + setFileOver(true) + }) + pageRef.current?.addEventListener('dragleave', (e) => { + e.preventDefault() + e.stopPropagation() + setFileOver(false) + }) + pageRef.current?.addEventListener('drop', (event) => { + event.preventDefault() + event.stopPropagation() + if (event.dataTransfer?.files) { + const file = event.dataTransfer.files[0] + if (file.name.endsWith('.yml') || file.name.endsWith('.yaml')) { + const reader = new FileReader() + reader.onload = async (e): Promise => { + const content = e.target?.result as string + try { + await addProfileItem({ name: file.name, type: 'local', file: content }) + } finally { + setFileOver(false) + } + } + reader.readAsText(file) + } else { + alert('不支持的文件类型') + } + } + setFileOver(false) + }) + return (): void => { + pageRef.current?.removeEventListener('dragover', () => {}) + pageRef.current?.removeEventListener('dragleave', () => {}) + pageRef.current?.removeEventListener('drop', () => {}) + } + }, []) return ( - +
{ 导入
-
+
{items?.map((item) => (