diff --git a/src/main/utils/init.ts b/src/main/utils/init.ts index d621123..379649e 100644 --- a/src/main/utils/init.ts +++ b/src/main/utils/init.ts @@ -26,7 +26,7 @@ import { existsSync } from 'fs' import path from 'path' import { startPacServer, startSubStoreServer } from '../resolve/server' import { triggerSysProxy } from '../sys/sysproxy' -import { getAppConfig } from '../config' +import { getAppConfig, patchAppConfig } from '../config' import { app } from 'electron' async function initDirs(): Promise { @@ -119,6 +119,31 @@ async function cleanup(): Promise { } } +async function migration(): Promise { + const { + siderOrder = [ + 'sysproxy', + 'tun', + 'profile', + 'proxy', + 'mihomo', + 'connection', + 'dns', + 'sniff', + 'log', + 'rule', + 'resource', + 'override', + 'substore' + ], + useSubStore = true + } = await getAppConfig() + // add substore sider card + if (useSubStore && !siderOrder.includes('substore')) { + await patchAppConfig({ siderOrder: [...siderOrder, 'substore'] }) + } +} + function initDeeplink(): void { if (process.defaultApp) { if (process.argv.length >= 2) { @@ -134,6 +159,7 @@ function initDeeplink(): void { export async function init(): Promise { await initDirs() await initConfig() + await migration() await initFiles() await cleanup() await startPacServer() diff --git a/src/main/utils/template.ts b/src/main/utils/template.ts index 4857511..cc8c3a7 100644 --- a/src/main/utils/template.ts +++ b/src/main/utils/template.ts @@ -30,7 +30,8 @@ export const defaultConfig: IAppConfig = { 'log', 'rule', 'resource', - 'override' + 'override', + 'substore' ], sysProxy: { enable: false, mode: 'manual' } } diff --git a/src/renderer/index.html b/src/renderer/index.html index e4145fb..f315d9b 100644 --- a/src/renderer/index.html +++ b/src/renderer/index.html @@ -6,7 +6,7 @@ diff --git a/src/renderer/src/App.tsx b/src/renderer/src/App.tsx index 645aa12..fac976e 100644 --- a/src/renderer/src/App.tsx +++ b/src/renderer/src/App.tsx @@ -27,10 +27,11 @@ import LogCard from '@renderer/components/sider/log-card' import MihomoCoreCard from '@renderer/components/sider/mihomo-core-card' import ResourceCard from '@renderer/components/sider/resource-card' import UpdaterButton from '@renderer/components/updater/updater-button' -import { useAppConfig } from './hooks/use-app-config' -import { setNativeTheme, setTitleBarOverlay } from './utils/ipc' -import { platform } from './utils/init' +import { useAppConfig } from '@renderer/hooks/use-app-config' +import { setNativeTheme, setTitleBarOverlay } from '@renderer/utils/ipc' +import { platform } from '@renderer/utils/init' import { TitleBarOverlayOptions } from 'electron' +import SubStoreCard from '@renderer/components/sider/substore-card' const App: React.FC = () => { const { appConfig, patchAppConfig } = useAppConfig() @@ -38,6 +39,7 @@ const App: React.FC = () => { appTheme = 'system', controlDns = true, controlSniff = true, + useSubStore = true, useWindowFrame = false, siderOrder = [ 'sysproxy', @@ -51,7 +53,8 @@ const App: React.FC = () => { 'log', 'rule', 'resource', - 'override' + 'override', + 'substore' ] } = appConfig || {} const [order, setOrder] = useState(siderOrder) @@ -127,7 +130,8 @@ const App: React.FC = () => { log: , rule: , resource: , - override: + override: , + substore: } return ( @@ -167,6 +171,7 @@ const App: React.FC = () => { {order.map((key: string) => { if (key === 'dns' && controlDns === false) return null if (key === 'sniff' && controlSniff === false) return null + if (key === 'substore' && useSubStore === false) return null return componentMap[key] })} diff --git a/src/renderer/src/components/base/substore-icon.tsx b/src/renderer/src/components/base/substore-icon.tsx index 776512c..987eabd 100644 --- a/src/renderer/src/components/base/substore-icon.tsx +++ b/src/renderer/src/components/base/substore-icon.tsx @@ -1,83 +1,88 @@ -import React from 'react' - -const SubStoreIcon: React.FC = (props) => ( - - - - - - - - - - - - - - - - - - - - -) +import { GenIcon } from 'react-icons' +function SubStoreIcon(props): JSX.Element { + return GenIcon({ + tag: 'svg', + attr: { viewBox: '0 0 192 192' }, + child: [ + { + tag: 'path', + attr: { + d: 'M 68.39 29.61 L 66.04 44.57 Q 58.35 38.29 49.10 42.15 Q 50.32 34.82 49.38 27.02 Q 59.70 24.72 68.39 29.61 Z' + }, + child: [] + }, + { + tag: 'path', + attr: { + d: 'M 139.00 26.36 L 139.01 40.67 Q 129.55 40.19 122.90 47.18 Q 118.96 51.31 117.05 53.18 Q 116.67 53.55 116.30 53.17 L 107.39 44.27 A 0.43 0.43 0.0 0 1 107.39 43.67 Q 110.90 40.03 114.45 36.45 C 121.01 29.80 129.51 25.72 139.00 26.36 Z' + }, + child: [] + }, + { + tag: 'path', + attr: { + d: 'M 139.00 26.36 C 149.79 27.49 158.88 35.13 163.59 44.55 C 168.66 54.70 165.55 66.43 158.45 74.97 Q 155.25 78.82 149.02 85.23 Q 148.70 85.57 148.37 85.24 L 139.73 76.60 Q 139.30 76.16 139.71 75.70 Q 142.64 72.41 146.67 67.43 Q 149.30 64.19 150.73 59.99 C 153.81 50.98 148.48 42.41 139.01 40.67 L 139.00 26.36 Z' + }, + child: [] + }, + { + tag: 'path', + attr: { + d: 'M 49.38 27.02 Q 50.32 34.82 49.10 42.15 Q 40.00 46.95 40.92 56.52 C 41.75 65.26 47.53 69.89 53.42 75.42 A 0.48 0.47 -46.3 0 1 53.43 76.10 L 44.44 85.08 Q 44.18 85.35 43.90 85.09 C 36.16 77.74 27.62 70.06 26.59 58.80 Q 25.43 46.09 34.03 36.28 Q 40.19 29.26 49.38 27.02 Z' + }, + child: [] + }, + { + tag: 'path', + attr: { + d: 'M 66.04 44.57 L 68.39 29.61 Q 75.36 34.19 80.49 39.03 Q 90.49 48.44 105.30 63.79 Q 105.67 64.17 105.29 64.55 L 96.67 73.17 Q 96.31 73.53 95.95 73.17 Q 82.37 59.67 71.05 48.70 Q 69.90 47.58 66.04 44.57 Z' + }, + child: [] + }, + { + tag: 'path', + attr: { + d: 'M74.45 96.86 86.25 108.66Q86.65 109.06 86.25 109.47L77.35 118.37Q77.11 118.61 76.86 118.37L55.28 96.78Q54.82 96.33 55.27 95.87 67.38 83.29 76.25 75.52 77.32 74.58 78.33 75.59L86.23 83.48Q86.55 83.81 86.23 84.14L74.45 95.91Q73.98 96.39 74.45 96.86ZM117.92 96.06 106.07 84.21Q105.67 83.81 106.07 83.4L113.56 75.91Q114.99 74.49 116.47 75.85 127.14 85.6 137.26 96.16 137.42 96.32 137.26 96.48L115.35 118.39Q115.13 118.61 114.91 118.39L106.11 109.59Q105.58 109.06 106.11 108.53L117.92 96.72A.47.47 0 0 0 117.92 96.06Z' + }, + child: [] + }, + { + tag: 'path', + attr: { + d: 'M 56.72 151.84 L 56.05 166.25 C 43.95 166.03 33.55 157.74 28.69 147.07 C 23.99 136.75 27.53 125.24 34.82 116.79 Q 38.65 112.35 43.53 107.39 Q 43.98 106.93 44.43 107.38 L 53.06 116.01 Q 53.37 116.32 53.08 116.64 C 47.94 122.46 42.28 128.07 41.22 135.90 C 39.98 145.11 47.70 152.27 56.72 151.84 Z' + }, + child: [] + }, + { + tag: 'path', + attr: { + d: 'M 139.28 166.07 L 138.77 151.74 Q 148.28 149.97 150.90 141.99 C 152.98 135.69 150.90 128.82 146.49 124.19 Q 144.17 121.74 139.51 117.31 Q 138.89 116.72 139.50 116.10 L 148.09 107.52 Q 148.46 107.14 148.85 107.50 C 154.93 113.23 158.56 116.62 162.48 122.95 C 166.31 129.12 167.21 137.50 165.26 144.01 Q 160.45 160.01 144.46 165.22 Q 142.72 165.78 139.28 166.07 Z' + }, + child: [] + }, + { + tag: 'path', + attr: { + d: 'M 121.23 143.44 L 119.51 159.49 Q 113.86 155.23 108.76 150.22 Q 97.69 139.36 87.37 128.74 Q 86.96 128.32 87.38 127.91 L 96.15 119.13 A 0.30 0.29 44.3 0 1 96.56 119.13 L 121.23 143.44 Z' + }, + child: [] + }, + { + tag: 'path', + attr: { + d: 'M 56.05 166.25 L 56.72 151.84 Q 62.78 151.21 66.28 148.29 Q 71.06 144.32 75.45 139.32 A 0.62 0.62 0.0 0 1 76.35 139.29 L 85.16 148.10 Q 85.45 148.40 85.18 148.71 Q 79.76 155.07 74.12 159.60 Q 66.32 165.87 56.05 166.25 Z' + }, + child: [] + }, + { + tag: 'path', + attr: { + d: 'M 121.23 143.44 C 126.74 148.19 130.95 152.38 138.77 151.74 L 139.28 166.07 Q 128.14 166.99 119.51 159.49 L 121.23 143.44 Z' + }, + child: [] + } + ] + })(props) +} export default SubStoreIcon diff --git a/src/renderer/src/components/settings/general-config.tsx b/src/renderer/src/components/settings/general-config.tsx index 3e2ace4..0122e22 100644 --- a/src/renderer/src/components/settings/general-config.tsx +++ b/src/renderer/src/components/settings/general-config.tsx @@ -163,7 +163,7 @@ const GeneralConfig: React.FC = () => { )} - + { /> {useSubStore && ( - + { )} {useCustomSubStore && ( - + { + const navigate = useNavigate() + const location = useLocation() + const match = location.pathname.includes('/substore') + const { + attributes, + listeners, + setNodeRef, + transform: tf, + transition, + isDragging + } = useSortable({ + id: 'substore' + }) + const transform = tf ? { x: tf.x, y: tf.y, scaleX: 1, scaleY: 1 } : null + return ( +
+ navigate('/substore')} + > + +
+ +
+
+ +

+ Sub-Store +

+
+
+
+ ) +} + +export default SubStoreCard diff --git a/src/renderer/src/pages/profiles.tsx b/src/renderer/src/pages/profiles.tsx index 7733760..83affd8 100644 --- a/src/renderer/src/pages/profiles.tsx +++ b/src/renderer/src/pages/profiles.tsx @@ -34,6 +34,7 @@ import { FaPlus } from 'react-icons/fa6' import { IoMdRefresh } from 'react-icons/io' import SubStoreIcon from '@renderer/components/base/substore-icon' import useSWR from 'swr' +import { useNavigate } from 'react-router-dom' const Profiles: React.FC = () => { const { @@ -48,6 +49,7 @@ const Profiles: React.FC = () => { const { appConfig } = useAppConfig() const { useSubStore = true, useCustomSubStore = false, customSubStoreUrl = '' } = appConfig || {} const { current, items = [] } = profileConfig || {} + const navigate = useNavigate() const [sortedItems, setSortedItems] = useState(items) const [useProxy, setUseProxy] = useState(false) const [subStoreImporting, setSubStoreImporting] = useState(false) @@ -65,11 +67,10 @@ const Profiles: React.FC = () => { useSubStore ? subStoreCollections : (): undefined => {} ) const subStoreMenuItems = useMemo(() => { - console.log(subs, collections) const items: { icon?: ReactNode; key: string; name: string; divider: boolean }[] = [ { key: 'open-substore', - name: '访问 SubStore', + name: '访问 Sub-Store', icon: , divider: (Boolean(subs) && subs.length > 0) || (Boolean(collections) && collections.length > 0) @@ -258,18 +259,13 @@ const Profiles: React.FC = () => { isIconOnly color="primary" > - + { if (key === 'open-substore') { - const port = await subStorePort() - if (useCustomSubStore) { - open(`https://sub-store.vercel.app/subs?api=${customSubStoreUrl}`) - } else { - open(`https://sub-store.vercel.app/subs?api=http://127.0.0.1:${port}`) - } + navigate('/substore') } else if (key.toString().startsWith('sub-')) { setSubStoreImporting(true) try { diff --git a/src/renderer/src/pages/substore.tsx b/src/renderer/src/pages/substore.tsx new file mode 100644 index 0000000..e89b0f7 --- /dev/null +++ b/src/renderer/src/pages/substore.tsx @@ -0,0 +1,52 @@ +import { Button } from '@nextui-org/react' +import BasePage from '@renderer/components/base/base-page' +import { useAppConfig } from '@renderer/hooks/use-app-config' +import { subStorePort } from '@renderer/utils/ipc' +import React, { useEffect, useState } from 'react' +import { HiExternalLink } from 'react-icons/hi' + +const SubStore: React.FC = () => { + const { appConfig } = useAppConfig() + const { useCustomSubStore, customSubStoreUrl } = appConfig || {} + const [port, setPort] = useState() + + const getPort = async (): Promise => { + setPort(await subStorePort()) + } + useEffect(() => { + if (!useCustomSubStore) { + getPort() + } + }, [useCustomSubStore]) + if (!useCustomSubStore && !port) return null + return ( + <> + { + open( + `https://sub-store.vercel.app/subs?api=${useCustomSubStore ? customSubStoreUrl : `http://127.0.0.1:${port}`}` + ) + }} + > + + + } + > +