mirror of
https://gh.catmak.name/https://github.com/mihomo-party-org/mihomo-party
synced 2025-12-27 13:10:30 +08:00
support edit theme
This commit is contained in:
parent
6592a7a278
commit
71f3f786b9
@ -1,4 +1,4 @@
|
|||||||
import { copyFile, readdir, readFile } from 'fs/promises'
|
import { copyFile, readdir, readFile, writeFile } from 'fs/promises'
|
||||||
import { themesDir } from '../utils/dirs'
|
import { themesDir } from '../utils/dirs'
|
||||||
import path from 'path'
|
import path from 'path'
|
||||||
import axios from 'axios'
|
import axios from 'axios'
|
||||||
@ -56,9 +56,17 @@ export async function importThemes(files: string[]): Promise<void> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function readTheme(theme: string): Promise<string> {
|
||||||
|
if (!existsSync(path.join(themesDir(), theme))) return ''
|
||||||
|
return await readFile(path.join(themesDir(), theme), 'utf-8')
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function writeTheme(theme: string, css: string): Promise<void> {
|
||||||
|
await writeFile(path.join(themesDir(), theme), css)
|
||||||
|
}
|
||||||
|
|
||||||
export async function applyTheme(theme: string): Promise<void> {
|
export async function applyTheme(theme: string): Promise<void> {
|
||||||
if (!existsSync(path.join(themesDir(), theme))) return
|
const css = await readTheme(theme)
|
||||||
const css = await readFile(path.join(themesDir(), theme), 'utf-8')
|
|
||||||
await mainWindow?.webContents.removeInsertedCSS(insertedCSSKey || '')
|
await mainWindow?.webContents.removeInsertedCSS(insertedCSSKey || '')
|
||||||
insertedCSSKey = await mainWindow?.webContents.insertCSS(css)
|
insertedCSSKey = await mainWindow?.webContents.insertCSS(css)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -65,7 +65,14 @@ import { getInterfaces } from '../sys/interface'
|
|||||||
import { copyEnv } from '../resolve/tray'
|
import { copyEnv } from '../resolve/tray'
|
||||||
import { registerShortcut } from '../resolve/shortcut'
|
import { registerShortcut } from '../resolve/shortcut'
|
||||||
import { mainWindow } from '..'
|
import { mainWindow } from '..'
|
||||||
import { applyTheme, fetchThemes, importThemes, resolveThemes } from '../resolve/theme'
|
import {
|
||||||
|
applyTheme,
|
||||||
|
fetchThemes,
|
||||||
|
importThemes,
|
||||||
|
readTheme,
|
||||||
|
resolveThemes,
|
||||||
|
writeTheme
|
||||||
|
} from '../resolve/theme'
|
||||||
import { subStoreCollections, subStoreSubs } from '../core/subStoreApi'
|
import { subStoreCollections, subStoreSubs } from '../core/subStoreApi'
|
||||||
import { logDir } from './dirs'
|
import { logDir } from './dirs'
|
||||||
import path from 'path'
|
import path from 'path'
|
||||||
@ -205,6 +212,8 @@ export function registerIpcMainHandlers(): void {
|
|||||||
ipcMain.handle('resolveThemes', () => ipcErrorWrapper(resolveThemes)())
|
ipcMain.handle('resolveThemes', () => ipcErrorWrapper(resolveThemes)())
|
||||||
ipcMain.handle('fetchThemes', () => ipcErrorWrapper(fetchThemes)())
|
ipcMain.handle('fetchThemes', () => ipcErrorWrapper(fetchThemes)())
|
||||||
ipcMain.handle('importThemes', (_e, file) => ipcErrorWrapper(importThemes)(file))
|
ipcMain.handle('importThemes', (_e, file) => ipcErrorWrapper(importThemes)(file))
|
||||||
|
ipcMain.handle('readTheme', (_e, theme) => ipcErrorWrapper(readTheme)(theme))
|
||||||
|
ipcMain.handle('writeTheme', (_e, theme, css) => ipcErrorWrapper(writeTheme)(theme, css))
|
||||||
ipcMain.handle('applyTheme', (_e, theme) => ipcErrorWrapper(applyTheme)(theme))
|
ipcMain.handle('applyTheme', (_e, theme) => ipcErrorWrapper(applyTheme)(theme))
|
||||||
ipcMain.handle('copyEnv', (_e, type) => ipcErrorWrapper(copyEnv)(type))
|
ipcMain.handle('copyEnv', (_e, type) => ipcErrorWrapper(copyEnv)(type))
|
||||||
ipcMain.handle('alert', (_e, msg) => {
|
ipcMain.handle('alert', (_e, msg) => {
|
||||||
|
|||||||
54
src/renderer/src/components/settings/css-editor-modal.tsx
Normal file
54
src/renderer/src/components/settings/css-editor-modal.tsx
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
import { Modal, ModalContent, ModalHeader, ModalBody, ModalFooter, Button } from '@nextui-org/react'
|
||||||
|
import { BaseEditor } from '@renderer/components/base/base-editor'
|
||||||
|
import { readTheme } from '@renderer/utils/ipc'
|
||||||
|
import React, { useEffect, useState } from 'react'
|
||||||
|
interface Props {
|
||||||
|
theme: string
|
||||||
|
onCancel: () => void
|
||||||
|
onConfirm: (script: string) => void
|
||||||
|
}
|
||||||
|
const CSSEditorModal: React.FC<Props> = (props) => {
|
||||||
|
const { theme, onCancel, onConfirm } = props
|
||||||
|
const [currData, setCurrData] = useState('')
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (theme) {
|
||||||
|
readTheme(theme).then((css) => {
|
||||||
|
setCurrData(css)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}, [theme])
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Modal
|
||||||
|
backdrop="blur"
|
||||||
|
classNames={{ backdrop: 'top-[48px]' }}
|
||||||
|
size="5xl"
|
||||||
|
hideCloseButton
|
||||||
|
isOpen={true}
|
||||||
|
onOpenChange={onCancel}
|
||||||
|
scrollBehavior="inside"
|
||||||
|
>
|
||||||
|
<ModalContent className="h-full w-[calc(100%-100px)]">
|
||||||
|
<ModalHeader className="flex pb-0">编辑主题</ModalHeader>
|
||||||
|
<ModalBody className="h-full">
|
||||||
|
<BaseEditor
|
||||||
|
language="css"
|
||||||
|
value={currData}
|
||||||
|
onChange={(value) => setCurrData(value || '')}
|
||||||
|
/>
|
||||||
|
</ModalBody>
|
||||||
|
<ModalFooter className="pt-0">
|
||||||
|
<Button size="sm" variant="light" onPress={onCancel}>
|
||||||
|
取消
|
||||||
|
</Button>
|
||||||
|
<Button size="sm" color="primary" onPress={() => onConfirm(currData)}>
|
||||||
|
确认
|
||||||
|
</Button>
|
||||||
|
</ModalFooter>
|
||||||
|
</ModalContent>
|
||||||
|
</Modal>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default CSSEditorModal
|
||||||
@ -5,6 +5,7 @@ import { Button, Input, Select, SelectItem, Switch, Tab, Tabs, Tooltip } from '@
|
|||||||
import { BiCopy, BiSolidFileImport } from 'react-icons/bi'
|
import { BiCopy, BiSolidFileImport } from 'react-icons/bi'
|
||||||
import useSWR from 'swr'
|
import useSWR from 'swr'
|
||||||
import {
|
import {
|
||||||
|
applyTheme,
|
||||||
checkAutoRun,
|
checkAutoRun,
|
||||||
copyEnv,
|
copyEnv,
|
||||||
disableAutoRun,
|
disableAutoRun,
|
||||||
@ -14,17 +15,21 @@ import {
|
|||||||
importThemes,
|
importThemes,
|
||||||
relaunchApp,
|
relaunchApp,
|
||||||
resolveThemes,
|
resolveThemes,
|
||||||
restartCore
|
restartCore,
|
||||||
|
writeTheme
|
||||||
} from '@renderer/utils/ipc'
|
} from '@renderer/utils/ipc'
|
||||||
import { useAppConfig } from '@renderer/hooks/use-app-config'
|
import { useAppConfig } from '@renderer/hooks/use-app-config'
|
||||||
import { platform } from '@renderer/utils/init'
|
import { platform } from '@renderer/utils/init'
|
||||||
import { useTheme } from 'next-themes'
|
import { useTheme } from 'next-themes'
|
||||||
import { IoIosHelpCircle, IoMdCloudDownload } from 'react-icons/io'
|
import { IoIosHelpCircle, IoMdCloudDownload } from 'react-icons/io'
|
||||||
|
import { MdEditDocument } from 'react-icons/md'
|
||||||
|
import CSSEditorModal from './css-editor-modal'
|
||||||
|
|
||||||
const GeneralConfig: React.FC = () => {
|
const GeneralConfig: React.FC = () => {
|
||||||
const { data: enable, mutate: mutateEnable } = useSWR('checkAutoRun', checkAutoRun)
|
const { data: enable, mutate: mutateEnable } = useSWR('checkAutoRun', checkAutoRun)
|
||||||
const { appConfig, patchAppConfig } = useAppConfig()
|
const { appConfig, patchAppConfig } = useAppConfig()
|
||||||
const [customThemes, setCustomThemes] = useState<{ key: string; label: string }[]>()
|
const [customThemes, setCustomThemes] = useState<{ key: string; label: string }[]>()
|
||||||
|
const [openCSSEditor, setOpenCSSEditor] = useState(false)
|
||||||
const [fetching, setFetching] = useState(false)
|
const [fetching, setFetching] = useState(false)
|
||||||
const { setTheme } = useTheme()
|
const { setTheme } = useTheme()
|
||||||
const {
|
const {
|
||||||
@ -49,6 +54,17 @@ const GeneralConfig: React.FC = () => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
{openCSSEditor && (
|
||||||
|
<CSSEditorModal
|
||||||
|
theme={customTheme}
|
||||||
|
onCancel={() => setOpenCSSEditor(false)}
|
||||||
|
onConfirm={async (css: string) => {
|
||||||
|
await writeTheme(customTheme, css)
|
||||||
|
await applyTheme(customTheme)
|
||||||
|
setOpenCSSEditor(false)
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
<SettingCard>
|
<SettingCard>
|
||||||
<SettingItem title="开机自启" divider>
|
<SettingItem title="开机自启" divider>
|
||||||
<Switch
|
<Switch
|
||||||
@ -261,6 +277,17 @@ const GeneralConfig: React.FC = () => {
|
|||||||
>
|
>
|
||||||
<BiSolidFileImport className="text-lg" />
|
<BiSolidFileImport className="text-lg" />
|
||||||
</Button>
|
</Button>
|
||||||
|
<Button
|
||||||
|
size="sm"
|
||||||
|
isIconOnly
|
||||||
|
title="编辑主题"
|
||||||
|
variant="light"
|
||||||
|
onPress={async () => {
|
||||||
|
setOpenCSSEditor(true)
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<MdEditDocument className="text-lg" />
|
||||||
|
</Button>
|
||||||
</>
|
</>
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
|
|||||||
@ -343,6 +343,14 @@ export async function importThemes(files: string[]): Promise<void> {
|
|||||||
return ipcErrorWrapper(await window.electron.ipcRenderer.invoke('importThemes', files))
|
return ipcErrorWrapper(await window.electron.ipcRenderer.invoke('importThemes', files))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function readTheme(theme: string): Promise<string> {
|
||||||
|
return ipcErrorWrapper(await window.electron.ipcRenderer.invoke('readTheme', theme))
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function writeTheme(theme: string, css: string): Promise<void> {
|
||||||
|
return ipcErrorWrapper(await window.electron.ipcRenderer.invoke('writeTheme', theme, css))
|
||||||
|
}
|
||||||
|
|
||||||
let applyThemeRunning = false
|
let applyThemeRunning = false
|
||||||
const waitList: string[] = []
|
const waitList: string[] = []
|
||||||
export async function applyTheme(theme: string): Promise<void> {
|
export async function applyTheme(theme: string): Promise<void> {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user