From 84318acb18ef21ee4fd4094044a64a2e4e819b3f Mon Sep 17 00:00:00 2001 From: bietiaop <1527109126@qq.com> Date: Sat, 8 Feb 2025 21:01:29 +0800 Subject: [PATCH 01/10] feat(webui): theme --- napcat.webui/src/controllers/qq_manager.ts | 13 + napcat.webui/src/controllers/webui_manager.ts | 14 + napcat.webui/src/types/server.d.ts | 133 +++++++ src/webui/index.ts | 4 +- src/webui/src/api/BaseInfo.ts | 13 +- src/webui/src/api/File.ts | 6 +- src/webui/src/api/Log.ts | 6 +- src/webui/src/api/QQLogin.ts | 18 +- src/webui/src/helper/config.ts | 343 +++++++++++++++++- src/webui/src/router/Base.ts | 5 +- src/webui/src/router/QQLogin.ts | 6 + 11 files changed, 532 insertions(+), 29 deletions(-) diff --git a/napcat.webui/src/controllers/qq_manager.ts b/napcat.webui/src/controllers/qq_manager.ts index 9375afc2..040eefb4 100644 --- a/napcat.webui/src/controllers/qq_manager.ts +++ b/napcat.webui/src/controllers/qq_manager.ts @@ -73,4 +73,17 @@ export default class QQManager { ) return data.data.data } + + public static async getQuickLoginQQ() { + const { data } = await serverRequest.post>( + '/QQLogin/GetQuickLoginQQ' + ) + return data.data + } + + public static async setQuickLoginQQ(uin: string) { + await serverRequest.post>('/QQLogin/SetQuickLoginQQ', { + uin + }) + } } diff --git a/napcat.webui/src/controllers/webui_manager.ts b/napcat.webui/src/controllers/webui_manager.ts index 35cb4ed4..ac472126 100644 --- a/napcat.webui/src/controllers/webui_manager.ts +++ b/napcat.webui/src/controllers/webui_manager.ts @@ -59,6 +59,20 @@ export default class WebUIManager { return data.data } + public static async getThemeConfig() { + const { data } = + await serverRequest.get>('/base/Theme') + return data.data + } + + public static async setThemeConfig(theme: ThemeConfig) { + const { data } = await serverRequest.post>( + '/base/SetTheme', + { theme } + ) + return data.data + } + public static async getLogList() { const { data } = await serverRequest.get>('/Log/GetLogList') diff --git a/napcat.webui/src/types/server.d.ts b/napcat.webui/src/types/server.d.ts index 28096eba..59005c22 100644 --- a/napcat.webui/src/types/server.d.ts +++ b/napcat.webui/src/types/server.d.ts @@ -48,3 +48,136 @@ interface SystemStatus { } arch: string } + +interface ThemeConfigItem { + '--heroui-background': string + '--heroui-foreground-50': string + '--heroui-foreground-100': string + '--heroui-foreground-200': string + '--heroui-foreground-300': string + '--heroui-foreground-400': string + '--heroui-foreground-500': string + '--heroui-foreground-600': string + '--heroui-foreground-700': string + '--heroui-foreground-800': string + '--heroui-foreground-900': string + '--heroui-foreground': string + '--heroui-focus': string + '--heroui-overlay': string + '--heroui-divider': string + '--heroui-divider-opacity': string + '--heroui-content1': string + '--heroui-content1-foreground': string + '--heroui-content2': string + '--heroui-content2-foreground': string + '--heroui-content3': string + '--heroui-content3-foreground': string + '--heroui-content4': string + '--heroui-content4-foreground': string + '--heroui-default-50': string + '--heroui-default-100': string + '--heroui-default-200': string + '--heroui-default-300': string + '--heroui-default-400': string + '--heroui-default-500': string + '--heroui-default-600': string + '--heroui-default-700': string + '--heroui-default-800': string + '--heroui-default-900': string + '--heroui-default-foreground': string + '--heroui-default': string + // 新增 danger + '--heroui-danger-50': string + '--heroui-danger-100': string + '--heroui-danger-200': string + '--heroui-danger-300': string + '--heroui-danger-400': string + '--heroui-danger-500': string + '--heroui-danger-600': string + '--heroui-danger-700': string + '--heroui-danger-800': string + '--heroui-danger-900': string + '--heroui-danger-foreground': string + '--heroui-danger': string + // 新增 primary + '--heroui-primary-50': string + '--heroui-primary-100': string + '--heroui-primary-200': string + '--heroui-primary-300': string + '--heroui-primary-400': string + '--heroui-primary-500': string + '--heroui-primary-600': string + '--heroui-primary-700': string + '--heroui-primary-800': string + '--heroui-primary-900': string + '--heroui-primary-foreground': string + '--heroui-primary': string + // 新增 secondary + '--heroui-secondary-50': string + '--heroui-secondary-100': string + '--heroui-secondary-200': string + '--heroui-secondary-300': string + '--heroui-secondary-400': string + '--heroui-secondary-500': string + '--heroui-secondary-600': string + '--heroui-secondary-700': string + '--heroui-secondary-800': string + '--heroui-secondary-900': string + '--heroui-secondary-foreground': string + '--heroui-secondary': string + // 新增 success + '--heroui-success-50': string + '--heroui-success-100': string + '--heroui-success-200': string + '--heroui-success-300': string + '--heroui-success-400': string + '--heroui-success-500': string + '--heroui-success-600': string + '--heroui-success-700': string + '--heroui-success-800': string + '--heroui-success-900': string + '--heroui-success-foreground': string + '--heroui-success': string + // 新增 warning + '--heroui-warning-50': string + '--heroui-warning-100': string + '--heroui-warning-200': string + '--heroui-warning-300': string + '--heroui-warning-400': string + '--heroui-warning-500': string + '--heroui-warning-600': string + '--heroui-warning-700': string + '--heroui-warning-800': string + '--heroui-warning-900': string + '--heroui-warning-foreground': string + '--heroui-warning': string + // 其它配置 + '--heroui-code-background': string + '--heroui-strong': string + '--heroui-code-mdx': string + '--heroui-divider-weight': string + '--heroui-disabled-opacity': string + '--heroui-font-size-tiny': string + '--heroui-font-size-small': string + '--heroui-font-size-medium': string + '--heroui-font-size-large': string + '--heroui-line-height-tiny': string + '--heroui-line-height-small': string + '--heroui-line-height-medium': string + '--heroui-line-height-large': string + '--heroui-radius-small': string + '--heroui-radius-medium': string + '--heroui-radius-large': string + '--heroui-border-width-small': string + '--heroui-border-width-medium': string + '--heroui-border-width-large': string + '--heroui-box-shadow-small': string + '--heroui-box-shadow-medium': string + '--heroui-box-shadow-large': string + '--heroui-hover-opacity': string +} + +interface ThemeConfig { + dark: ThemeConfigItem + light: ThemeConfigItem +} diff --git a/src/webui/index.ts b/src/webui/index.ts index 5bde50e1..bb4d8949 100644 --- a/src/webui/index.ts +++ b/src/webui/index.ts @@ -73,9 +73,9 @@ export async function InitWebUi(logger: LogWrapper, pathWrapper: NapCatPathWrapp // 如果是webui字体文件,挂载字体文件 app.use('/webui/fonts/AaCute.woff', async (_req, res, next) => { - const isFontExist = await WebUiConfigWrapper.CheckWebUIFontExist(); + const isFontExist = await WebUiConfig.CheckWebUIFontExist(); if (isFontExist) { - res.sendFile(WebUiConfigWrapper.GetWebUIFontPath()); + res.sendFile(WebUiConfig.GetWebUIFontPath()); } else { next(); } diff --git a/src/webui/src/api/BaseInfo.ts b/src/webui/src/api/BaseInfo.ts index 12a5fd1f..43df485b 100644 --- a/src/webui/src/api/BaseInfo.ts +++ b/src/webui/src/api/BaseInfo.ts @@ -2,14 +2,25 @@ import { RequestHandler } from 'express'; import { WebUiDataRuntime } from '@webapi/helper/Data'; import { sendSuccess } from '@webapi/utils/response'; +import { WebUiConfig } from '@/webui'; export const PackageInfoHandler: RequestHandler = (_, res) => { const data = WebUiDataRuntime.getPackageJson(); sendSuccess(res, data); }; - export const QQVersionHandler: RequestHandler = (_, res) => { const data = WebUiDataRuntime.getQQVersion(); sendSuccess(res, data); }; + +export const GetThemeConfigHandler: RequestHandler = (_, res) => { + const data = WebUiConfig.GetTheme(); + sendSuccess(res, data); +}; + +export const SetThemeConfigHandler: RequestHandler = (req, res) => { + const { theme } = req.body; + const data = WebUiConfig.UpdateTheme(theme); + sendSuccess(res, data); +}; diff --git a/src/webui/src/api/File.ts b/src/webui/src/api/File.ts index 1bf5cf8c..db5e27b4 100644 --- a/src/webui/src/api/File.ts +++ b/src/webui/src/api/File.ts @@ -7,9 +7,9 @@ import os from 'os'; import compressing from 'compressing'; import { PassThrough } from 'stream'; import multer from 'multer'; -import { WebUiConfigWrapper } from '../helper/config'; import webUIFontUploader from '../uploader/webui_font'; import diskUploader from '../uploader/disk'; +import { WebUiConfig } from '@/webui'; const isWindows = os.platform() === 'win32'; @@ -384,8 +384,8 @@ export const UploadWebUIFontHandler: RequestHandler = async (req, res) => { // 删除WebUI字体文件处理方法 export const DeleteWebUIFontHandler: RequestHandler = async (_req, res) => { try { - const fontPath = WebUiConfigWrapper.GetWebUIFontPath(); - const exists = await WebUiConfigWrapper.CheckWebUIFontExist(); + const fontPath = WebUiConfig.GetWebUIFontPath(); + const exists = await WebUiConfig.CheckWebUIFontExist(); if (!exists) { return sendSuccess(res, true); diff --git a/src/webui/src/api/Log.ts b/src/webui/src/api/Log.ts index a531d275..4e66ee3e 100644 --- a/src/webui/src/api/Log.ts +++ b/src/webui/src/api/Log.ts @@ -1,8 +1,8 @@ import type { RequestHandler } from 'express'; import { sendError, sendSuccess } from '../utils/response'; -import { WebUiConfigWrapper } from '../helper/config'; import { logSubscription } from '@/common/log'; import { terminalManager } from '../terminal/terminal_manager'; +import { WebUiConfig } from '@/webui'; // 判断是否是 macos const isMacOS = process.platform === 'darwin'; // 日志记录 @@ -15,13 +15,13 @@ export const LogHandler: RequestHandler = async (req, res) => { if (filename.includes('..')) { return sendError(res, 'ID不合法'); } - const logContent = await WebUiConfigWrapper.GetLogContent(filename); + const logContent = await WebUiConfig.GetLogContent(filename); return sendSuccess(res, logContent); }; // 日志列表 export const LogListHandler: RequestHandler = async (_, res) => { - const logList = await WebUiConfigWrapper.GetLogsList(); + const logList = await WebUiConfig.GetLogsList(); return sendSuccess(res, logList); }; diff --git a/src/webui/src/api/QQLogin.ts b/src/webui/src/api/QQLogin.ts index 4f324d22..7da2000e 100644 --- a/src/webui/src/api/QQLogin.ts +++ b/src/webui/src/api/QQLogin.ts @@ -3,9 +3,10 @@ import { RequestHandler } from 'express'; import { WebUiDataRuntime } from '@webapi/helper/Data'; import { isEmpty } from '@webapi/utils/check'; import { sendError, sendSuccess } from '@webapi/utils/response'; +import { WebUiConfig } from '@/webui'; // 获取QQ登录二维码 -export const QQGetQRcodeHandler: RequestHandler = async (req, res) => { +export const QQGetQRcodeHandler: RequestHandler = async (_, res) => { // 判断是否已经登录 if (WebUiDataRuntime.getQQLoginStatus()) { // 已经登录 @@ -25,7 +26,7 @@ export const QQGetQRcodeHandler: RequestHandler = async (req, res) => { }; // 获取QQ登录状态 -export const QQCheckLoginStatusHandler: RequestHandler = async (req, res) => { +export const QQCheckLoginStatusHandler: RequestHandler = async (_, res) => { const data = { isLogin: WebUiDataRuntime.getQQLoginStatus(), qrcodeurl: WebUiDataRuntime.getQQLoginQrcodeURL(), @@ -74,3 +75,16 @@ export const getQQLoginInfoHandler: RequestHandler = async (_, res) => { const data = WebUiDataRuntime.getQQLoginInfo(); return sendSuccess(res, data); }; + +// 获取自动登录QQ账号 +export const getAutoLoginAccountHandler: RequestHandler = async (_, res) => { + const data = WebUiConfig.getAutoLoginAccount(); + return sendSuccess(res, data); +}; + +// 设置自动登录QQ账号 +export const setAutoLoginAccountHandler: RequestHandler = async (req, res) => { + const { uin } = req.body; + await WebUiConfig.UpdateAutoLoginAccount(uin); + return sendSuccess(res, null); +}; diff --git a/src/webui/src/helper/config.ts b/src/webui/src/helper/config.ts index b9ef685e..5e4e982e 100644 --- a/src/webui/src/helper/config.ts +++ b/src/webui/src/helper/config.ts @@ -14,11 +14,280 @@ const WebUiConfigSchema = Type.Object({ token: Type.String({ default: 'napcat' }), loginRate: Type.Number({ default: 10 }), autoLoginAccount: Type.String({ default: '' }), + theme: Type.Object({ + dark: Type.Object({ + '--heroui-background': Type.String({ default: '0 0% 0%' }), + '--heroui-foreground-50': Type.String({ default: '240 5.88% 10%' }), + '--heroui-foreground-100': Type.String({ default: '240 3.7% 15.88%' }), + '--heroui-foreground-200': Type.String({ default: '240 5.26% 26.08%' }), + '--heroui-foreground-300': Type.String({ default: '240 5.2% 33.92%' }), + '--heroui-foreground-400': Type.String({ default: '240 3.83% 46.08%' }), + '--heroui-foreground-500': Type.String({ default: '240 5.03% 64.9%' }), + '--heroui-foreground-600': Type.String({ default: '240 4.88% 83.92%' }), + '--heroui-foreground-700': Type.String({ default: '240 5.88% 90%' }), + '--heroui-foreground-800': Type.String({ default: '240 4.76% 95.88%' }), + '--heroui-foreground-900': Type.String({ default: '0 0% 98.04%' }), + '--heroui-foreground': Type.String({ default: '210 5.56% 92.94%' }), + '--heroui-focus': Type.String({ default: '212.01999999999998 100% 46.67%' }), + '--heroui-overlay': Type.String({ default: '0 0% 0%' }), + '--heroui-divider': Type.String({ default: '0 0% 100%' }), + '--heroui-divider-opacity': Type.String({ default: '0.15' }), + '--heroui-content1': Type.String({ default: '240 5.88% 10%' }), + '--heroui-content1-foreground': Type.String({ default: '0 0% 98.04%' }), + '--heroui-content2': Type.String({ default: '240 3.7% 15.88%' }), + '--heroui-content2-foreground': Type.String({ default: '240 4.76% 95.88%' }), + '--heroui-content3': Type.String({ default: '240 5.26% 26.08%' }), + '--heroui-content3-foreground': Type.String({ default: '240 5.88% 90%' }), + '--heroui-content4': Type.String({ default: '240 5.2% 33.92%' }), + '--heroui-content4-foreground': Type.String({ default: '240 4.88% 83.92%' }), + '--heroui-default-50': Type.String({ default: '240 5.88% 10%' }), + '--heroui-default-100': Type.String({ default: '240 3.7% 15.88%' }), + '--heroui-default-200': Type.String({ default: '240 5.26% 26.08%' }), + '--heroui-default-300': Type.String({ default: '240 5.2% 33.92%' }), + '--heroui-default-400': Type.String({ default: '240 3.83% 46.08%' }), + '--heroui-default-500': Type.String({ default: '240 5.03% 64.9%' }), + '--heroui-default-600': Type.String({ default: '240 4.88% 83.92%' }), + '--heroui-default-700': Type.String({ default: '240 5.88% 90%' }), + '--heroui-default-800': Type.String({ default: '240 4.76% 95.88%' }), + '--heroui-default-900': Type.String({ default: '0 0% 98.04%' }), + '--heroui-default-foreground': Type.String({ default: '0 0% 100%' }), + '--heroui-default': Type.String({ default: '240 5.26% 26.08%' }), + '--heroui-danger-50': Type.String({ default: '301.89 82.61% 22.55%' }), + '--heroui-danger-100': Type.String({ default: '308.18 76.39% 28.24%' }), + '--heroui-danger-200': Type.String({ default: '313.85 70.65% 36.08%' }), + '--heroui-danger-300': Type.String({ default: '319.73 65.64% 44.51%' }), + '--heroui-danger-400': Type.String({ default: '325.82 69.62% 53.53%' }), + '--heroui-danger-500': Type.String({ default: '331.82 75% 65.49%' }), + '--heroui-danger-600': Type.String({ default: '337.84 83.46% 73.92%' }), + '--heroui-danger-700': Type.String({ default: '343.42 90.48% 83.53%' }), + '--heroui-danger-800': Type.String({ default: '350.53 90.48% 91.76%' }), + '--heroui-danger-900': Type.String({ default: '324 90.91% 95.69%' }), + '--heroui-danger-foreground': Type.String({ default: '0 0% 100%' }), + '--heroui-danger': Type.String({ default: '325.82 69.62% 53.53%' }), + '--heroui-primary-50': Type.String({ default: '340 84.91% 10.39%' }), + '--heroui-primary-100': Type.String({ default: '339.33 86.54% 20.39%' }), + '--heroui-primary-200': Type.String({ default: '339.11 85.99% 30.78%' }), + '--heroui-primary-300': Type.String({ default: '339 86.54% 40.78%' }), + '--heroui-primary-400': Type.String({ default: '339.2 90.36% 51.18%' }), + '--heroui-primary-500': Type.String({ default: '339 90% 60.78%' }), + '--heroui-primary-600': Type.String({ default: '339.11 90.6% 70.78%' }), + '--heroui-primary-700': Type.String({ default: '339.33 90% 80.39%' }), + '--heroui-primary-800': Type.String({ default: '340 91.84% 90.39%' }), + '--heroui-primary-900': Type.String({ default: '339.13 92% 95.1%' }), + '--heroui-primary-foreground': Type.String({ default: '0 0% 100%' }), + '--heroui-primary': Type.String({ default: '339.2 90.36% 51.18%' }), + // 新增 secondary + '--heroui-secondary-50': Type.String({ default: '270 66.67% 9.41%' }), + '--heroui-secondary-100': Type.String({ default: '270 66.67% 18.82%' }), + '--heroui-secondary-200': Type.String({ default: '270 66.67% 28.24%' }), + '--heroui-secondary-300': Type.String({ default: '270 66.67% 37.65%' }), + '--heroui-secondary-400': Type.String({ default: '270 66.67% 47.06%' }), + '--heroui-secondary-500': Type.String({ default: '270 59.26% 57.65%' }), + '--heroui-secondary-600': Type.String({ default: '270 59.26% 68.24%' }), + '--heroui-secondary-700': Type.String({ default: '270 59.26% 78.82%' }), + '--heroui-secondary-800': Type.String({ default: '270 59.26% 89.41%' }), + '--heroui-secondary-900': Type.String({ default: '270 61.54% 94.9%' }), + '--heroui-secondary-foreground': Type.String({ default: '0 0% 100%' }), + '--heroui-secondary': Type.String({ default: '270 59.26% 57.65%' }), + // 新增 success + '--heroui-success-50': Type.String({ default: '145.71 77.78% 8.82%' }), + '--heroui-success-100': Type.String({ default: '146.2 79.78% 17.45%' }), + '--heroui-success-200': Type.String({ default: '145.79 79.26% 26.47%' }), + '--heroui-success-300': Type.String({ default: '146.01 79.89% 35.1%' }), + '--heroui-success-400': Type.String({ default: '145.96 79.46% 43.92%' }), + '--heroui-success-500': Type.String({ default: '146.01 62.45% 55.1%' }), + '--heroui-success-600': Type.String({ default: '145.79 62.57% 66.47%' }), + '--heroui-success-700': Type.String({ default: '146.2 61.74% 77.45%' }), + '--heroui-success-800': Type.String({ default: '145.71 61.4% 88.82%' }), + '--heroui-success-900': Type.String({ default: '146.67 64.29% 94.51%' }), + '--heroui-success-foreground': Type.String({ default: '0 0% 0%' }), + '--heroui-success': Type.String({ default: '145.96 79.46% 43.92%' }), + // 新增 warning + '--heroui-warning-50': Type.String({ default: '37.14 75% 10.98%' }), + '--heroui-warning-100': Type.String({ default: '37.14 75% 21.96%' }), + '--heroui-warning-200': Type.String({ default: '36.96 73.96% 33.14%' }), + '--heroui-warning-300': Type.String({ default: '37.01 74.22% 44.12%' }), + '--heroui-warning-400': Type.String({ default: '37.03 91.27% 55.1%' }), + '--heroui-warning-500': Type.String({ default: '37.01 91.26% 64.12%' }), + '--heroui-warning-600': Type.String({ default: '36.96 91.24% 73.14%' }), + '--heroui-warning-700': Type.String({ default: '37.14 91.3% 81.96%' }), + '--heroui-warning-800': Type.String({ default: '37.14 91.3% 90.98%' }), + '--heroui-warning-900': Type.String({ default: '54.55 91.67% 95.29%' }), + '--heroui-warning-foreground': Type.String({ default: '0 0% 0%' }), + '--heroui-warning': Type.String({ default: '37.03 91.27% 55.1%' }), + // 其它配置 + '--heroui-code-background': Type.String({ default: '240 5.56% 7.06%' }), + '--heroui-strong': Type.String({ default: '190.14 94.67% 44.12%' }), + '--heroui-code-mdx': Type.String({ default: '190.14 94.67% 44.12%' }), + '--heroui-divider-weight': Type.String({ default: '1px' }), + '--heroui-disabled-opacity': Type.String({ default: '.5' }), + '--heroui-font-size-tiny': Type.String({ default: '0.75rem' }), + '--heroui-font-size-small': Type.String({ default: '0.875rem' }), + '--heroui-font-size-medium': Type.String({ default: '1rem' }), + '--heroui-font-size-large': Type.String({ default: '1.125rem' }), + '--heroui-line-height-tiny': Type.String({ default: '1rem' }), + '--heroui-line-height-small': Type.String({ default: '1.25rem' }), + '--heroui-line-height-medium': Type.String({ default: '1.5rem' }), + '--heroui-line-height-large': Type.String({ default: '1.75rem' }), + '--heroui-radius-small': Type.String({ default: '8px' }), + '--heroui-radius-medium': Type.String({ default: '12px' }), + '--heroui-radius-large': Type.String({ default: '14px' }), + '--heroui-border-width-small': Type.String({ default: '1px' }), + '--heroui-border-width-medium': Type.String({ default: '2px' }), + '--heroui-border-width-large': Type.String({ default: '3px' }), + '--heroui-box-shadow-small': Type.String({ + default: + '0px 0px 5px 0px rgba(0, 0, 0, .05), 0px 2px 10px 0px rgba(0, 0, 0, .2), inset 0px 0px 1px 0px hsla(0, 0%, 100%, .15)', + }), + '--heroui-box-shadow-medium': Type.String({ + default: + '0px 0px 15px 0px rgba(0, 0, 0, .06), 0px 2px 30px 0px rgba(0, 0, 0, .22), inset 0px 0px 1px 0px hsla(0, 0%, 100%, .15)', + }), + '--heroui-box-shadow-large': Type.String({ + default: + '0px 0px 30px 0px rgba(0, 0, 0, .07), 0px 30px 60px 0px rgba(0, 0, 0, .26), inset 0px 0px 1px 0px hsla(0, 0%, 100%, .15)', + }), + '--heroui-hover-opacity': Type.String({ default: '.9' }), + }), + light: Type.Object({ + '--heroui-background': Type.String({ default: '0 0% 100%' }), + '--heroui-foreground-50': Type.String({ default: '240 5.88% 95%' }), + '--heroui-foreground-100': Type.String({ default: '240 3.7% 90%' }), + '--heroui-foreground-200': Type.String({ default: '240 5.26% 80%' }), + '--heroui-foreground-300': Type.String({ default: '240 5.2% 70%' }), + '--heroui-foreground-400': Type.String({ default: '240 3.83% 60%' }), + '--heroui-foreground-500': Type.String({ default: '240 5.03% 50%' }), + '--heroui-foreground-600': Type.String({ default: '240 4.88% 40%' }), + '--heroui-foreground-700': Type.String({ default: '240 5.88% 30%' }), + '--heroui-foreground-800': Type.String({ default: '240 4.76% 20%' }), + '--heroui-foreground-900': Type.String({ default: '0 0% 10%' }), + '--heroui-foreground': Type.String({ default: '210 5.56% 7.06%' }), + '--heroui-focus': Type.String({ default: '212.01999999999998 100% 53.33%' }), + '--heroui-overlay': Type.String({ default: '0 0% 100%' }), + '--heroui-divider': Type.String({ default: '0 0% 0%' }), + '--heroui-divider-opacity': Type.String({ default: '0.85' }), + '--heroui-content1': Type.String({ default: '240 5.88% 95%' }), + '--heroui-content1-foreground': Type.String({ default: '0 0% 10%' }), + '--heroui-content2': Type.String({ default: '240 3.7% 90%' }), + '--heroui-content2-foreground': Type.String({ default: '240 4.76% 20%' }), + '--heroui-content3': Type.String({ default: '240 5.26% 80%' }), + '--heroui-content3-foreground': Type.String({ default: '240 5.88% 30%' }), + '--heroui-content4': Type.String({ default: '240 5.2% 70%' }), + '--heroui-content4-foreground': Type.String({ default: '240 4.88% 40%' }), + '--heroui-default-50': Type.String({ default: '240 5.88% 95%' }), + '--heroui-default-100': Type.String({ default: '240 3.7% 90%' }), + '--heroui-default-200': Type.String({ default: '240 5.26% 80%' }), + '--heroui-default-300': Type.String({ default: '240 5.2% 70%' }), + '--heroui-default-400': Type.String({ default: '240 3.83% 60%' }), + '--heroui-default-500': Type.String({ default: '240 5.03% 50%' }), + '--heroui-default-600': Type.String({ default: '240 4.88% 40%' }), + '--heroui-default-700': Type.String({ default: '240 5.88% 30%' }), + '--heroui-default-800': Type.String({ default: '240 4.76% 20%' }), + '--heroui-default-900': Type.String({ default: '0 0% 10%' }), + '--heroui-default-foreground': Type.String({ default: '0 0% 0%' }), + '--heroui-default': Type.String({ default: '240 5.26% 80%' }), + '--heroui-danger-50': Type.String({ default: '324 90.91% 95.69%' }), + '--heroui-danger-100': Type.String({ default: '350.53 90.48% 91.76%' }), + '--heroui-danger-200': Type.String({ default: '343.42 90.48% 83.53%' }), + '--heroui-danger-300': Type.String({ default: '337.84 83.46% 73.92%' }), + '--heroui-danger-400': Type.String({ default: '331.82 75% 65.49%' }), + '--heroui-danger-500': Type.String({ default: '325.82 69.62% 53.53%' }), + '--heroui-danger-600': Type.String({ default: '319.73 65.64% 44.51%' }), + '--heroui-danger-700': Type.String({ default: '313.85 70.65% 36.08%' }), + '--heroui-danger-800': Type.String({ default: '308.18 76.39% 28.24%' }), + '--heroui-danger-900': Type.String({ default: '301.89 82.61% 22.55%' }), + '--heroui-danger-foreground': Type.String({ default: '0 0% 100%' }), + '--heroui-danger': Type.String({ default: '325.82 69.62% 53.53%' }), + '--heroui-primary-50': Type.String({ default: '339.13 92% 95.1%' }), + '--heroui-primary-100': Type.String({ default: '340 91.84% 90.39%' }), + '--heroui-primary-200': Type.String({ default: '339.33 90% 80.39%' }), + '--heroui-primary-300': Type.String({ default: '339.11 90.6% 70.78%' }), + '--heroui-primary-400': Type.String({ default: '339 90% 60.78%' }), + '--heroui-primary-500': Type.String({ default: '339.2 90.36% 51.18%' }), + '--heroui-primary-600': Type.String({ default: '339 86.54% 40.78%' }), + '--heroui-primary-700': Type.String({ default: '339.11 85.99% 30.78%' }), + '--heroui-primary-800': Type.String({ default: '339.33 86.54% 20.39%' }), + '--heroui-primary-900': Type.String({ default: '340 84.91% 10.39%' }), + '--heroui-primary-foreground': Type.String({ default: '0 0% 100%' }), + '--heroui-primary': Type.String({ default: '339.2 90.36% 51.18%' }), + // 新增 secondary + '--heroui-secondary-50': Type.String({ default: '270 61.54% 94.9%' }), + '--heroui-secondary-100': Type.String({ default: '270 59.26% 89.41%' }), + '--heroui-secondary-200': Type.String({ default: '270 59.26% 78.82%' }), + '--heroui-secondary-300': Type.String({ default: '270 59.26% 68.24%' }), + '--heroui-secondary-400': Type.String({ default: '270 59.26% 57.65%' }), + '--heroui-secondary-500': Type.String({ default: '270 66.67% 47.06%' }), + '--heroui-secondary-600': Type.String({ default: '270 66.67% 37.65%' }), + '--heroui-secondary-700': Type.String({ default: '270 66.67% 28.24%' }), + '--heroui-secondary-800': Type.String({ default: '270 66.67% 18.82%' }), + '--heroui-secondary-900': Type.String({ default: '270 66.67% 9.41%' }), + '--heroui-secondary-foreground': Type.String({ default: '0 0% 100%' }), + '--heroui-secondary': Type.String({ default: '270 66.67% 47.06%' }), + // 新增 success + '--heroui-success-50': Type.String({ default: '146.67 64.29% 94.51%' }), + '--heroui-success-100': Type.String({ default: '145.71 61.4% 88.82%' }), + '--heroui-success-200': Type.String({ default: '146.2 61.74% 77.45%' }), + '--heroui-success-300': Type.String({ default: '145.79 62.57% 66.47%' }), + '--heroui-success-400': Type.String({ default: '146.01 62.45% 55.1%' }), + '--heroui-success-500': Type.String({ default: '145.96 79.46% 43.92%' }), + '--heroui-success-600': Type.String({ default: '146.01 79.89% 35.1%' }), + '--heroui-success-700': Type.String({ default: '145.79 79.26% 26.47%' }), + '--heroui-success-800': Type.String({ default: '146.2 79.78% 17.45%' }), + '--heroui-success-900': Type.String({ default: '145.71 77.78% 8.82%' }), + '--heroui-success-foreground': Type.String({ default: '0 0% 0%' }), + '--heroui-success': Type.String({ default: '145.96 79.46% 43.92%' }), + // 新增 warning + '--heroui-warning-50': Type.String({ default: '54.55 91.67% 95.29%' }), + '--heroui-warning-100': Type.String({ default: '37.14 91.3% 90.98%' }), + '--heroui-warning-200': Type.String({ default: '37.14 91.3% 81.96%' }), + '--heroui-warning-300': Type.String({ default: '36.96 91.24% 73.14%' }), + '--heroui-warning-400': Type.String({ default: '37.01 91.26% 64.12%' }), + '--heroui-warning-500': Type.String({ default: '37.03 91.27% 55.1%' }), + '--heroui-warning-600': Type.String({ default: '37.01 74.22% 44.12%' }), + '--heroui-warning-700': Type.String({ default: '36.96 73.96% 33.14%' }), + '--heroui-warning-800': Type.String({ default: '37.14 75% 21.96%' }), + '--heroui-warning-900': Type.String({ default: '37.14 75% 10.98%' }), + '--heroui-warning-foreground': Type.String({ default: '0 0% 0%' }), + '--heroui-warning': Type.String({ default: '37.03 91.27% 55.1%' }), + // 其它配置 + '--heroui-code-background': Type.String({ default: '221.25 17.39% 18.04%' }), + '--heroui-strong': Type.String({ default: '316.95 100% 65.29%' }), + '--heroui-code-mdx': Type.String({ default: '316.95 100% 65.29%' }), + '--heroui-divider-weight': Type.String({ default: '1px' }), + '--heroui-disabled-opacity': Type.String({ default: '.5' }), + '--heroui-font-size-tiny': Type.String({ default: '0.75rem' }), + '--heroui-font-size-small': Type.String({ default: '0.875rem' }), + '--heroui-font-size-medium': Type.String({ default: '1rem' }), + '--heroui-font-size-large': Type.String({ default: '1.125rem' }), + '--heroui-line-height-tiny': Type.String({ default: '1rem' }), + '--heroui-line-height-small': Type.String({ default: '1.25rem' }), + '--heroui-line-height-medium': Type.String({ default: '1.5rem' }), + '--heroui-line-height-large': Type.String({ default: '1.75rem' }), + '--heroui-radius-small': Type.String({ default: '8px' }), + '--heroui-radius-medium': Type.String({ default: '12px' }), + '--heroui-radius-large': Type.String({ default: '14px' }), + '--heroui-border-width-small': Type.String({ default: '1px' }), + '--heroui-border-width-medium': Type.String({ default: '2px' }), + '--heroui-border-width-large': Type.String({ default: '3px' }), + '--heroui-box-shadow-small': Type.String({ + default: + '0px 0px 5px 0px rgba(0, 0, 0, .02), 0px 2px 10px 0px rgba(0, 0, 0, .06), 0px 0px 1px 0px rgba(0, 0, 0, .3)', + }), + '--heroui-box-shadow-medium': Type.String({ + default: + '0px 0px 15px 0px rgba(0, 0, 0, .03), 0px 2px 30px 0px rgba(0, 0, 0, .08), 0px 0px 1px 0px rgba(0, 0, 0, .3)', + }), + '--heroui-box-shadow-large': Type.String({ + default: + '0px 0px 30px 0px rgba(0, 0, 0, .04), 0px 30px 60px 0px rgba(0, 0, 0, .12), 0px 0px 1px 0px rgba(0, 0, 0, .3)', + }), + '--heroui-hover-opacity': Type.String({ default: '.8' }), + }), + }), }); export type WebUiConfigType = Static; - // 读取当前目录下名为 webui.json 的配置文件,如果不存在则创建初始化配置文件 export class WebUiConfigWrapper { WebUiConfigData: WebUiConfigType | undefined = undefined; @@ -29,7 +298,10 @@ export class WebUiConfigWrapper { } private async ensureConfigFileExists(configPath: string): Promise { - const configExists = await fs.access(configPath, constants.F_OK).then(() => true).catch(() => false); + const configExists = await fs + .access(configPath, constants.F_OK) + .then(() => true) + .catch(() => false); if (!configExists) { await fs.writeFile(configPath, JSON.stringify(this.validateAndApplyDefaults({}), null, 4)); } @@ -41,7 +313,10 @@ export class WebUiConfigWrapper { } private async writeConfig(configPath: string, config: WebUiConfigType): Promise { - const hasWritePermission = await fs.access(configPath, constants.W_OK).then(() => true).catch(() => false); + const hasWritePermission = await fs + .access(configPath, constants.W_OK) + .then(() => true) + .catch(() => false); if (hasWritePermission) { await fs.writeFile(configPath, JSON.stringify(config, null, 4)); } else { @@ -82,24 +357,32 @@ export class WebUiConfigWrapper { } // 获取日志文件夹路径 - public static async GetLogsPath(): Promise { + async GetLogsPath(): Promise { return resolve(webUiPathWrapper.logsPath); } // 获取日志列表 - public static async GetLogsList(): Promise { + async GetLogsList(): Promise { const logsPath = resolve(webUiPathWrapper.logsPath); - const logsExist = await fs.access(logsPath, constants.F_OK).then(() => true).catch(() => false); + const logsExist = await fs + .access(logsPath, constants.F_OK) + .then(() => true) + .catch(() => false); if (logsExist) { - return (await fs.readdir(logsPath)).filter(file => file.endsWith('.log')).map(file => file.replace('.log', '')); + return (await fs.readdir(logsPath)) + .filter((file) => file.endsWith('.log')) + .map((file) => file.replace('.log', '')); } return []; } // 获取指定日志文件内容 - public static async GetLogContent(filename: string): Promise { + async GetLogContent(filename: string): Promise { const logPath = resolve(webUiPathWrapper.logsPath, `${filename}.log`); - const logExists = await fs.access(logPath, constants.R_OK).then(() => true).catch(() => false); + const logExists = await fs + .access(logPath, constants.R_OK) + .then(() => true) + .catch(() => false); if (logExists) { return await fs.readFile(logPath, 'utf-8'); } @@ -107,27 +390,53 @@ export class WebUiConfigWrapper { } // 获取字体文件夹内的字体列表 - public static async GetFontList(): Promise { + async GetFontList(): Promise { const fontsPath = resolve(webUiPathWrapper.configPath, './fonts'); - const fontsExist = await fs.access(fontsPath, constants.F_OK).then(() => true).catch(() => false); + const fontsExist = await fs + .access(fontsPath, constants.F_OK) + .then(() => true) + .catch(() => false); if (fontsExist) { - return (await fs.readdir(fontsPath)).filter(file => file.endsWith('.ttf')); + return (await fs.readdir(fontsPath)).filter((file) => file.endsWith('.ttf')); } return []; } // 判断字体是否存在(webui.woff) - public static async CheckWebUIFontExist(): Promise { + async CheckWebUIFontExist(): Promise { const fontsPath = resolve(webUiPathWrapper.configPath, './fonts'); - return await fs.access(resolve(fontsPath, './webui.woff'), constants.F_OK).then(() => true).catch(() => false); + return await fs + .access(resolve(fontsPath, './webui.woff'), constants.F_OK) + .then(() => true) + .catch(() => false); } // 获取webui字体文件路径 - public static GetWebUIFontPath(): string { + GetWebUIFontPath(): string { return resolve(webUiPathWrapper.configPath, './fonts/webui.woff'); } - public getAutoLoginAccount(): string | undefined { + getAutoLoginAccount(): string | undefined { return this.WebUiConfigData?.autoLoginAccount; } -} \ No newline at end of file + + // 获取自动登录账号 + async GetAutoLoginAccount(): Promise { + return (await this.GetWebUIConfig()).autoLoginAccount; + } + + // 更新自动登录账号 + async UpdateAutoLoginAccount(uin: string): Promise { + await this.UpdateWebUIConfig({ autoLoginAccount: uin }); + } + + // 获取主题内容 + async GetTheme(): Promise { + return (await this.GetWebUIConfig()).theme; + } + + // 更新主题内容 + async UpdateTheme(theme: WebUiConfigType['theme']): Promise { + await this.UpdateWebUIConfig({ theme: theme }); + } +} diff --git a/src/webui/src/router/Base.ts b/src/webui/src/router/Base.ts index 0ec78532..f79975cf 100644 --- a/src/webui/src/router/Base.ts +++ b/src/webui/src/router/Base.ts @@ -1,5 +1,5 @@ import { Router } from 'express'; -import { PackageInfoHandler, QQVersionHandler } from '../api/BaseInfo'; +import { GetThemeConfigHandler, PackageInfoHandler, QQVersionHandler, SetThemeConfigHandler } from '../api/BaseInfo'; import { StatusRealTimeHandler } from '@webapi/api/Status'; import { GetProxyHandler } from '../api/Proxy'; @@ -9,4 +9,7 @@ router.get('/QQVersion', QQVersionHandler); router.get('/PackageInfo', PackageInfoHandler); router.get('/GetSysStatusRealTime', StatusRealTimeHandler); router.get('/proxy', GetProxyHandler); +router.get('/Theme', GetThemeConfigHandler); +router.post('/SetTheme', SetThemeConfigHandler); + export { router as BaseRouter }; diff --git a/src/webui/src/router/QQLogin.ts b/src/webui/src/router/QQLogin.ts index 5fd4ef18..aecb5b44 100644 --- a/src/webui/src/router/QQLogin.ts +++ b/src/webui/src/router/QQLogin.ts @@ -7,6 +7,8 @@ import { QQSetQuickLoginHandler, QQGetLoginListNewHandler, getQQLoginInfoHandler, + getAutoLoginAccountHandler, + setAutoLoginAccountHandler, } from '@webapi/api/QQLogin'; const router = Router(); @@ -22,5 +24,9 @@ router.post('/GetQQLoginQrcode', QQGetQRcodeHandler); router.post('/SetQuickLogin', QQSetQuickLoginHandler); // router:获取QQ登录信息 router.post('/GetQQLoginInfo', getQQLoginInfoHandler); +// router:获取快速登录QQ账号 +router.post('/GetQuickLoginQQ', getAutoLoginAccountHandler); +// router:设置自动登录QQ账号 +router.post('/SetQuickLoginQQ', setAutoLoginAccountHandler); export { router as QQLoginRouter }; From b54870cb60b20915c5fcec3eea84534a4a961c1f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=89=8B=E7=93=9C=E4=B8=80=E5=8D=81=E9=9B=AA?= Date: Sat, 8 Feb 2025 21:03:59 +0800 Subject: [PATCH 02/10] fix --- src/webui/src/helper/config.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/webui/src/helper/config.ts b/src/webui/src/helper/config.ts index 5e4e982e..42204faf 100644 --- a/src/webui/src/helper/config.ts +++ b/src/webui/src/helper/config.ts @@ -148,7 +148,7 @@ const WebUiConfigSchema = Type.Object({ '0px 0px 30px 0px rgba(0, 0, 0, .07), 0px 30px 60px 0px rgba(0, 0, 0, .26), inset 0px 0px 1px 0px hsla(0, 0%, 100%, .15)', }), '--heroui-hover-opacity': Type.String({ default: '.9' }), - }), + }, { default: {} }), light: Type.Object({ '--heroui-background': Type.String({ default: '0 0% 100%' }), '--heroui-foreground-50': Type.String({ default: '240 5.88% 95%' }), @@ -282,8 +282,8 @@ const WebUiConfigSchema = Type.Object({ '0px 0px 30px 0px rgba(0, 0, 0, .04), 0px 30px 60px 0px rgba(0, 0, 0, .12), 0px 0px 1px 0px rgba(0, 0, 0, .3)', }), '--heroui-hover-opacity': Type.String({ default: '.8' }), - }), - }), + }, { default: {} }), + }, { default: {} }), }); export type WebUiConfigType = Static; From f8c396b1fed3e894c7f55b12339a9b6af51396da Mon Sep 17 00:00:00 2001 From: bietiaop <1527109126@qq.com> Date: Sat, 8 Feb 2025 21:16:49 +0800 Subject: [PATCH 03/10] =?UTF-8?q?feat(webui):=20=E5=BF=AB=E9=80=9F?= =?UTF-8?q?=E7=99=BB=E5=BD=95config?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/pages/dashboard/config/index.tsx | 6 ++ .../src/pages/dashboard/config/login.tsx | 100 ++++++++++++++++++ 2 files changed, 106 insertions(+) create mode 100644 napcat.webui/src/pages/dashboard/config/login.tsx diff --git a/napcat.webui/src/pages/dashboard/config/index.tsx b/napcat.webui/src/pages/dashboard/config/index.tsx index b90558d3..980a55fa 100644 --- a/napcat.webui/src/pages/dashboard/config/index.tsx +++ b/napcat.webui/src/pages/dashboard/config/index.tsx @@ -4,6 +4,7 @@ import { useMediaQuery } from 'react-responsive' import { useNavigate, useSearchParams } from 'react-router-dom' import ChangePasswordCard from './change_password' +import LoginConfigCard from './login' import OneBotConfigCard from './onebot' import WebUIConfigCard from './webui' @@ -58,6 +59,11 @@ export default function ConfigPage() { + + + + + diff --git a/napcat.webui/src/pages/dashboard/config/login.tsx b/napcat.webui/src/pages/dashboard/config/login.tsx new file mode 100644 index 00000000..9abbb7d3 --- /dev/null +++ b/napcat.webui/src/pages/dashboard/config/login.tsx @@ -0,0 +1,100 @@ +import { Input } from '@heroui/input' +import { useRequest } from 'ahooks' +import { useEffect, useState } from 'react' +import { Controller, useForm } from 'react-hook-form' +import toast from 'react-hot-toast' + +import SaveButtons from '@/components/button/save_buttons' +import PageLoading from '@/components/page_loading' + +import QQManager from '@/controllers/qq_manager' + +const LoginConfigCard = () => { + const { + data: quickLoginData, + loading: quickLoginLoading, + error: quickLoginError, + refreshAsync: refreshQuickLogin + } = useRequest(QQManager.getQuickLoginQQ) + const [loading, setLoading] = useState(false) + const { + control, + handleSubmit: handleOnebotSubmit, + formState: { isSubmitting }, + setValue: setOnebotValue + } = useForm<{ + quickLoginQQ: string + }>({ + defaultValues: { + quickLoginQQ: '' + } + }) + + const reset = () => { + setOnebotValue('quickLoginQQ', quickLoginData ?? '') + } + + const onSubmit = handleOnebotSubmit((data) => { + try { + setLoading(true) + QQManager.setQuickLoginQQ(data.quickLoginQQ) + toast.success('保存成功') + } catch (error) { + const msg = (error as Error).message + toast.error(`保存失败: ${msg}`) + } finally { + setLoading(false) + } + }) + + const onRefresh = async (shotTip = true) => { + try { + setLoading(true) + await refreshQuickLogin() + if (shotTip) toast.success('刷新成功') + } catch (error) { + const msg = (error as Error).message + toast.error(`刷新失败: ${msg}`) + } finally { + setLoading(false) + } + } + + useEffect(() => { + reset() + }, [quickLoginData]) + + useEffect(() => { + onRefresh(false) + }, []) + + if (loading) return + + return ( + <> + OneBot配置 - NapCat WebUI +
快速登录QQ
+ ( + + )} + /> + + + ) +} + +export default LoginConfigCard From 2e013ed4f512cec86e698c16ac2fbe995594c39d Mon Sep 17 00:00:00 2001 From: bietiaop <1527109126@qq.com> Date: Sat, 8 Feb 2025 22:43:53 +0800 Subject: [PATCH 04/10] fix --- napcat.webui/package.json | 1 + napcat.webui/src/components/ColorPicker.tsx | 40 ++ .../src/pages/dashboard/config/index.tsx | 8 +- .../src/pages/dashboard/config/login.tsx | 8 +- .../src/pages/dashboard/config/theme.tsx | 106 ++++ package.json | 1 + src/webui/src/helper/config.ts | 558 +++++++++--------- 7 files changed, 444 insertions(+), 278 deletions(-) create mode 100644 napcat.webui/src/components/ColorPicker.tsx create mode 100644 napcat.webui/src/pages/dashboard/config/theme.tsx diff --git a/napcat.webui/package.json b/napcat.webui/package.json index bdef9b0d..9a73049a 100644 --- a/napcat.webui/package.json +++ b/napcat.webui/package.json @@ -64,6 +64,7 @@ "qrcode.react": "^4.2.0", "quill": "^2.0.3", "react": "^19.0.0", + "react-color": "^2.19.3", "react-dom": "^19.0.0", "react-dropzone": "^14.3.5", "react-error-boundary": "^5.0.0", diff --git a/napcat.webui/src/components/ColorPicker.tsx b/napcat.webui/src/components/ColorPicker.tsx new file mode 100644 index 00000000..856ecc11 --- /dev/null +++ b/napcat.webui/src/components/ColorPicker.tsx @@ -0,0 +1,40 @@ +import { Popover, PopoverContent, PopoverTrigger } from '@heroui/popover' +import React from 'react' +import { ColorResult, SketchPicker } from 'react-color' + +// 假定 heroui 提供的 Popover组件 + +interface ColorPickerProps { + color: string + onChange: (color: string) => void +} + +const ColorPicker: React.FC = ({ color, onChange }) => { + const handleChange = (colorResult: ColorResult) => { + const hsl = colorResult.hsl + const color = `${hsl.h} ${hsl.s}% ${hsl.l}%` + onChange(color) + } + + return ( + + +
+ + + + + + ) +} + +export default ColorPicker diff --git a/napcat.webui/src/pages/dashboard/config/index.tsx b/napcat.webui/src/pages/dashboard/config/index.tsx index 980a55fa..f61748ff 100644 --- a/napcat.webui/src/pages/dashboard/config/index.tsx +++ b/napcat.webui/src/pages/dashboard/config/index.tsx @@ -6,6 +6,7 @@ import { useNavigate, useSearchParams } from 'react-router-dom' import ChangePasswordCard from './change_password' import LoginConfigCard from './login' import OneBotConfigCard from './onebot' +import ThemeConfigCard from './theme' import WebUIConfigCard from './webui' export interface ConfigPageProps { @@ -58,7 +59,6 @@ export default function ConfigPage() { - @@ -69,6 +69,12 @@ export default function ConfigPage() { + + + + + + ) diff --git a/napcat.webui/src/pages/dashboard/config/login.tsx b/napcat.webui/src/pages/dashboard/config/login.tsx index 9abbb7d3..155170f5 100644 --- a/napcat.webui/src/pages/dashboard/config/login.tsx +++ b/napcat.webui/src/pages/dashboard/config/login.tsx @@ -47,11 +47,11 @@ const LoginConfigCard = () => { } }) - const onRefresh = async (shotTip = true) => { + const onRefresh = async () => { try { setLoading(true) await refreshQuickLogin() - if (shotTip) toast.success('刷新成功') + toast.success('刷新成功') } catch (error) { const msg = (error as Error).message toast.error(`刷新失败: ${msg}`) @@ -64,10 +64,6 @@ const LoginConfigCard = () => { reset() }, [quickLoginData]) - useEffect(() => { - onRefresh(false) - }, []) - if (loading) return return ( diff --git a/napcat.webui/src/pages/dashboard/config/theme.tsx b/napcat.webui/src/pages/dashboard/config/theme.tsx new file mode 100644 index 00000000..e62582f2 --- /dev/null +++ b/napcat.webui/src/pages/dashboard/config/theme.tsx @@ -0,0 +1,106 @@ +import { useRequest } from 'ahooks' +import { useEffect } from 'react' +import { Controller, useForm } from 'react-hook-form' +import toast from 'react-hot-toast' + +import ColorPicker from '@/components/ColorPicker' +import SaveButtons from '@/components/button/save_buttons' +import PageLoading from '@/components/page_loading' + +import WebUIManager from '@/controllers/webui_manager' + +const ThemeConfigCard = () => { + const { data, loading, error, refreshAsync } = useRequest( + WebUIManager.getThemeConfig + ) + const { + control, + handleSubmit: handleOnebotSubmit, + formState: { isSubmitting }, + setValue: setOnebotValue + } = useForm<{ + theme: ThemeConfig + }>({ + defaultValues: { + theme: { + dark: {}, + light: {} + } + } + }) + + const reset = () => { + if (data) setOnebotValue('theme', data) + } + + const onSubmit = handleOnebotSubmit((data) => { + try { + WebUIManager.setThemeConfig(data.theme) + toast.success('保存成功') + } catch (error) { + const msg = (error as Error).message + toast.error(`保存失败: ${msg}`) + } + }) + + const onRefresh = async () => { + try { + await refreshAsync() + toast.success('刷新成功') + } catch (error) { + const msg = (error as Error).message + toast.error(`刷新失败: ${msg}`) + } + } + + if (loading) return + + if (error) + return ( +
{error.message}
+ ) + + const colorKeys = [ + '--heroui-background', + '--heroui-primary', + '--heroui-danger' + ] as const + + return ( + <> + 主题配置 - NapCat WebUI +
主题配置
+ {(['dark', 'light'] as const).map((mode) => ( +
+

{mode === 'dark' ? '暗色主题' : '亮色主题'}

+ {colorKeys.map((key) => ( +
+ + { + console.log(value) + const hslArray = value?.split(' ') ?? [0, 0, 0] + const color = `hsl(${hslArray[0]}, ${hslArray[1]}, ${hslArray[2]})` + return + }} + /> +
+ ))} +
+ ))} + + + ) +} + +export default ThemeConfigCard diff --git a/package.json b/package.json index 8473f8b7..09f6b7cb 100644 --- a/package.json +++ b/package.json @@ -33,6 +33,7 @@ "@types/multer": "^1.4.12", "@types/node": "^22.0.1", "@types/qrcode-terminal": "^0.12.2", + "@types/react-color": "^3.0.13", "@types/ws": "^8.5.12", "@typescript-eslint/eslint-plugin": "^8.3.0", "@typescript-eslint/parser": "^8.3.0", diff --git a/src/webui/src/helper/config.ts b/src/webui/src/helper/config.ts index 42204faf..4cb9c6b9 100644 --- a/src/webui/src/helper/config.ts +++ b/src/webui/src/helper/config.ts @@ -14,276 +14,285 @@ const WebUiConfigSchema = Type.Object({ token: Type.String({ default: 'napcat' }), loginRate: Type.Number({ default: 10 }), autoLoginAccount: Type.String({ default: '' }), - theme: Type.Object({ - dark: Type.Object({ - '--heroui-background': Type.String({ default: '0 0% 0%' }), - '--heroui-foreground-50': Type.String({ default: '240 5.88% 10%' }), - '--heroui-foreground-100': Type.String({ default: '240 3.7% 15.88%' }), - '--heroui-foreground-200': Type.String({ default: '240 5.26% 26.08%' }), - '--heroui-foreground-300': Type.String({ default: '240 5.2% 33.92%' }), - '--heroui-foreground-400': Type.String({ default: '240 3.83% 46.08%' }), - '--heroui-foreground-500': Type.String({ default: '240 5.03% 64.9%' }), - '--heroui-foreground-600': Type.String({ default: '240 4.88% 83.92%' }), - '--heroui-foreground-700': Type.String({ default: '240 5.88% 90%' }), - '--heroui-foreground-800': Type.String({ default: '240 4.76% 95.88%' }), - '--heroui-foreground-900': Type.String({ default: '0 0% 98.04%' }), - '--heroui-foreground': Type.String({ default: '210 5.56% 92.94%' }), - '--heroui-focus': Type.String({ default: '212.01999999999998 100% 46.67%' }), - '--heroui-overlay': Type.String({ default: '0 0% 0%' }), - '--heroui-divider': Type.String({ default: '0 0% 100%' }), - '--heroui-divider-opacity': Type.String({ default: '0.15' }), - '--heroui-content1': Type.String({ default: '240 5.88% 10%' }), - '--heroui-content1-foreground': Type.String({ default: '0 0% 98.04%' }), - '--heroui-content2': Type.String({ default: '240 3.7% 15.88%' }), - '--heroui-content2-foreground': Type.String({ default: '240 4.76% 95.88%' }), - '--heroui-content3': Type.String({ default: '240 5.26% 26.08%' }), - '--heroui-content3-foreground': Type.String({ default: '240 5.88% 90%' }), - '--heroui-content4': Type.String({ default: '240 5.2% 33.92%' }), - '--heroui-content4-foreground': Type.String({ default: '240 4.88% 83.92%' }), - '--heroui-default-50': Type.String({ default: '240 5.88% 10%' }), - '--heroui-default-100': Type.String({ default: '240 3.7% 15.88%' }), - '--heroui-default-200': Type.String({ default: '240 5.26% 26.08%' }), - '--heroui-default-300': Type.String({ default: '240 5.2% 33.92%' }), - '--heroui-default-400': Type.String({ default: '240 3.83% 46.08%' }), - '--heroui-default-500': Type.String({ default: '240 5.03% 64.9%' }), - '--heroui-default-600': Type.String({ default: '240 4.88% 83.92%' }), - '--heroui-default-700': Type.String({ default: '240 5.88% 90%' }), - '--heroui-default-800': Type.String({ default: '240 4.76% 95.88%' }), - '--heroui-default-900': Type.String({ default: '0 0% 98.04%' }), - '--heroui-default-foreground': Type.String({ default: '0 0% 100%' }), - '--heroui-default': Type.String({ default: '240 5.26% 26.08%' }), - '--heroui-danger-50': Type.String({ default: '301.89 82.61% 22.55%' }), - '--heroui-danger-100': Type.String({ default: '308.18 76.39% 28.24%' }), - '--heroui-danger-200': Type.String({ default: '313.85 70.65% 36.08%' }), - '--heroui-danger-300': Type.String({ default: '319.73 65.64% 44.51%' }), - '--heroui-danger-400': Type.String({ default: '325.82 69.62% 53.53%' }), - '--heroui-danger-500': Type.String({ default: '331.82 75% 65.49%' }), - '--heroui-danger-600': Type.String({ default: '337.84 83.46% 73.92%' }), - '--heroui-danger-700': Type.String({ default: '343.42 90.48% 83.53%' }), - '--heroui-danger-800': Type.String({ default: '350.53 90.48% 91.76%' }), - '--heroui-danger-900': Type.String({ default: '324 90.91% 95.69%' }), - '--heroui-danger-foreground': Type.String({ default: '0 0% 100%' }), - '--heroui-danger': Type.String({ default: '325.82 69.62% 53.53%' }), - '--heroui-primary-50': Type.String({ default: '340 84.91% 10.39%' }), - '--heroui-primary-100': Type.String({ default: '339.33 86.54% 20.39%' }), - '--heroui-primary-200': Type.String({ default: '339.11 85.99% 30.78%' }), - '--heroui-primary-300': Type.String({ default: '339 86.54% 40.78%' }), - '--heroui-primary-400': Type.String({ default: '339.2 90.36% 51.18%' }), - '--heroui-primary-500': Type.String({ default: '339 90% 60.78%' }), - '--heroui-primary-600': Type.String({ default: '339.11 90.6% 70.78%' }), - '--heroui-primary-700': Type.String({ default: '339.33 90% 80.39%' }), - '--heroui-primary-800': Type.String({ default: '340 91.84% 90.39%' }), - '--heroui-primary-900': Type.String({ default: '339.13 92% 95.1%' }), - '--heroui-primary-foreground': Type.String({ default: '0 0% 100%' }), - '--heroui-primary': Type.String({ default: '339.2 90.36% 51.18%' }), - // 新增 secondary - '--heroui-secondary-50': Type.String({ default: '270 66.67% 9.41%' }), - '--heroui-secondary-100': Type.String({ default: '270 66.67% 18.82%' }), - '--heroui-secondary-200': Type.String({ default: '270 66.67% 28.24%' }), - '--heroui-secondary-300': Type.String({ default: '270 66.67% 37.65%' }), - '--heroui-secondary-400': Type.String({ default: '270 66.67% 47.06%' }), - '--heroui-secondary-500': Type.String({ default: '270 59.26% 57.65%' }), - '--heroui-secondary-600': Type.String({ default: '270 59.26% 68.24%' }), - '--heroui-secondary-700': Type.String({ default: '270 59.26% 78.82%' }), - '--heroui-secondary-800': Type.String({ default: '270 59.26% 89.41%' }), - '--heroui-secondary-900': Type.String({ default: '270 61.54% 94.9%' }), - '--heroui-secondary-foreground': Type.String({ default: '0 0% 100%' }), - '--heroui-secondary': Type.String({ default: '270 59.26% 57.65%' }), - // 新增 success - '--heroui-success-50': Type.String({ default: '145.71 77.78% 8.82%' }), - '--heroui-success-100': Type.String({ default: '146.2 79.78% 17.45%' }), - '--heroui-success-200': Type.String({ default: '145.79 79.26% 26.47%' }), - '--heroui-success-300': Type.String({ default: '146.01 79.89% 35.1%' }), - '--heroui-success-400': Type.String({ default: '145.96 79.46% 43.92%' }), - '--heroui-success-500': Type.String({ default: '146.01 62.45% 55.1%' }), - '--heroui-success-600': Type.String({ default: '145.79 62.57% 66.47%' }), - '--heroui-success-700': Type.String({ default: '146.2 61.74% 77.45%' }), - '--heroui-success-800': Type.String({ default: '145.71 61.4% 88.82%' }), - '--heroui-success-900': Type.String({ default: '146.67 64.29% 94.51%' }), - '--heroui-success-foreground': Type.String({ default: '0 0% 0%' }), - '--heroui-success': Type.String({ default: '145.96 79.46% 43.92%' }), - // 新增 warning - '--heroui-warning-50': Type.String({ default: '37.14 75% 10.98%' }), - '--heroui-warning-100': Type.String({ default: '37.14 75% 21.96%' }), - '--heroui-warning-200': Type.String({ default: '36.96 73.96% 33.14%' }), - '--heroui-warning-300': Type.String({ default: '37.01 74.22% 44.12%' }), - '--heroui-warning-400': Type.String({ default: '37.03 91.27% 55.1%' }), - '--heroui-warning-500': Type.String({ default: '37.01 91.26% 64.12%' }), - '--heroui-warning-600': Type.String({ default: '36.96 91.24% 73.14%' }), - '--heroui-warning-700': Type.String({ default: '37.14 91.3% 81.96%' }), - '--heroui-warning-800': Type.String({ default: '37.14 91.3% 90.98%' }), - '--heroui-warning-900': Type.String({ default: '54.55 91.67% 95.29%' }), - '--heroui-warning-foreground': Type.String({ default: '0 0% 0%' }), - '--heroui-warning': Type.String({ default: '37.03 91.27% 55.1%' }), - // 其它配置 - '--heroui-code-background': Type.String({ default: '240 5.56% 7.06%' }), - '--heroui-strong': Type.String({ default: '190.14 94.67% 44.12%' }), - '--heroui-code-mdx': Type.String({ default: '190.14 94.67% 44.12%' }), - '--heroui-divider-weight': Type.String({ default: '1px' }), - '--heroui-disabled-opacity': Type.String({ default: '.5' }), - '--heroui-font-size-tiny': Type.String({ default: '0.75rem' }), - '--heroui-font-size-small': Type.String({ default: '0.875rem' }), - '--heroui-font-size-medium': Type.String({ default: '1rem' }), - '--heroui-font-size-large': Type.String({ default: '1.125rem' }), - '--heroui-line-height-tiny': Type.String({ default: '1rem' }), - '--heroui-line-height-small': Type.String({ default: '1.25rem' }), - '--heroui-line-height-medium': Type.String({ default: '1.5rem' }), - '--heroui-line-height-large': Type.String({ default: '1.75rem' }), - '--heroui-radius-small': Type.String({ default: '8px' }), - '--heroui-radius-medium': Type.String({ default: '12px' }), - '--heroui-radius-large': Type.String({ default: '14px' }), - '--heroui-border-width-small': Type.String({ default: '1px' }), - '--heroui-border-width-medium': Type.String({ default: '2px' }), - '--heroui-border-width-large': Type.String({ default: '3px' }), - '--heroui-box-shadow-small': Type.String({ - default: - '0px 0px 5px 0px rgba(0, 0, 0, .05), 0px 2px 10px 0px rgba(0, 0, 0, .2), inset 0px 0px 1px 0px hsla(0, 0%, 100%, .15)', - }), - '--heroui-box-shadow-medium': Type.String({ - default: - '0px 0px 15px 0px rgba(0, 0, 0, .06), 0px 2px 30px 0px rgba(0, 0, 0, .22), inset 0px 0px 1px 0px hsla(0, 0%, 100%, .15)', - }), - '--heroui-box-shadow-large': Type.String({ - default: - '0px 0px 30px 0px rgba(0, 0, 0, .07), 0px 30px 60px 0px rgba(0, 0, 0, .26), inset 0px 0px 1px 0px hsla(0, 0%, 100%, .15)', - }), - '--heroui-hover-opacity': Type.String({ default: '.9' }), - }, { default: {} }), - light: Type.Object({ - '--heroui-background': Type.String({ default: '0 0% 100%' }), - '--heroui-foreground-50': Type.String({ default: '240 5.88% 95%' }), - '--heroui-foreground-100': Type.String({ default: '240 3.7% 90%' }), - '--heroui-foreground-200': Type.String({ default: '240 5.26% 80%' }), - '--heroui-foreground-300': Type.String({ default: '240 5.2% 70%' }), - '--heroui-foreground-400': Type.String({ default: '240 3.83% 60%' }), - '--heroui-foreground-500': Type.String({ default: '240 5.03% 50%' }), - '--heroui-foreground-600': Type.String({ default: '240 4.88% 40%' }), - '--heroui-foreground-700': Type.String({ default: '240 5.88% 30%' }), - '--heroui-foreground-800': Type.String({ default: '240 4.76% 20%' }), - '--heroui-foreground-900': Type.String({ default: '0 0% 10%' }), - '--heroui-foreground': Type.String({ default: '210 5.56% 7.06%' }), - '--heroui-focus': Type.String({ default: '212.01999999999998 100% 53.33%' }), - '--heroui-overlay': Type.String({ default: '0 0% 100%' }), - '--heroui-divider': Type.String({ default: '0 0% 0%' }), - '--heroui-divider-opacity': Type.String({ default: '0.85' }), - '--heroui-content1': Type.String({ default: '240 5.88% 95%' }), - '--heroui-content1-foreground': Type.String({ default: '0 0% 10%' }), - '--heroui-content2': Type.String({ default: '240 3.7% 90%' }), - '--heroui-content2-foreground': Type.String({ default: '240 4.76% 20%' }), - '--heroui-content3': Type.String({ default: '240 5.26% 80%' }), - '--heroui-content3-foreground': Type.String({ default: '240 5.88% 30%' }), - '--heroui-content4': Type.String({ default: '240 5.2% 70%' }), - '--heroui-content4-foreground': Type.String({ default: '240 4.88% 40%' }), - '--heroui-default-50': Type.String({ default: '240 5.88% 95%' }), - '--heroui-default-100': Type.String({ default: '240 3.7% 90%' }), - '--heroui-default-200': Type.String({ default: '240 5.26% 80%' }), - '--heroui-default-300': Type.String({ default: '240 5.2% 70%' }), - '--heroui-default-400': Type.String({ default: '240 3.83% 60%' }), - '--heroui-default-500': Type.String({ default: '240 5.03% 50%' }), - '--heroui-default-600': Type.String({ default: '240 4.88% 40%' }), - '--heroui-default-700': Type.String({ default: '240 5.88% 30%' }), - '--heroui-default-800': Type.String({ default: '240 4.76% 20%' }), - '--heroui-default-900': Type.String({ default: '0 0% 10%' }), - '--heroui-default-foreground': Type.String({ default: '0 0% 0%' }), - '--heroui-default': Type.String({ default: '240 5.26% 80%' }), - '--heroui-danger-50': Type.String({ default: '324 90.91% 95.69%' }), - '--heroui-danger-100': Type.String({ default: '350.53 90.48% 91.76%' }), - '--heroui-danger-200': Type.String({ default: '343.42 90.48% 83.53%' }), - '--heroui-danger-300': Type.String({ default: '337.84 83.46% 73.92%' }), - '--heroui-danger-400': Type.String({ default: '331.82 75% 65.49%' }), - '--heroui-danger-500': Type.String({ default: '325.82 69.62% 53.53%' }), - '--heroui-danger-600': Type.String({ default: '319.73 65.64% 44.51%' }), - '--heroui-danger-700': Type.String({ default: '313.85 70.65% 36.08%' }), - '--heroui-danger-800': Type.String({ default: '308.18 76.39% 28.24%' }), - '--heroui-danger-900': Type.String({ default: '301.89 82.61% 22.55%' }), - '--heroui-danger-foreground': Type.String({ default: '0 0% 100%' }), - '--heroui-danger': Type.String({ default: '325.82 69.62% 53.53%' }), - '--heroui-primary-50': Type.String({ default: '339.13 92% 95.1%' }), - '--heroui-primary-100': Type.String({ default: '340 91.84% 90.39%' }), - '--heroui-primary-200': Type.String({ default: '339.33 90% 80.39%' }), - '--heroui-primary-300': Type.String({ default: '339.11 90.6% 70.78%' }), - '--heroui-primary-400': Type.String({ default: '339 90% 60.78%' }), - '--heroui-primary-500': Type.String({ default: '339.2 90.36% 51.18%' }), - '--heroui-primary-600': Type.String({ default: '339 86.54% 40.78%' }), - '--heroui-primary-700': Type.String({ default: '339.11 85.99% 30.78%' }), - '--heroui-primary-800': Type.String({ default: '339.33 86.54% 20.39%' }), - '--heroui-primary-900': Type.String({ default: '340 84.91% 10.39%' }), - '--heroui-primary-foreground': Type.String({ default: '0 0% 100%' }), - '--heroui-primary': Type.String({ default: '339.2 90.36% 51.18%' }), - // 新增 secondary - '--heroui-secondary-50': Type.String({ default: '270 61.54% 94.9%' }), - '--heroui-secondary-100': Type.String({ default: '270 59.26% 89.41%' }), - '--heroui-secondary-200': Type.String({ default: '270 59.26% 78.82%' }), - '--heroui-secondary-300': Type.String({ default: '270 59.26% 68.24%' }), - '--heroui-secondary-400': Type.String({ default: '270 59.26% 57.65%' }), - '--heroui-secondary-500': Type.String({ default: '270 66.67% 47.06%' }), - '--heroui-secondary-600': Type.String({ default: '270 66.67% 37.65%' }), - '--heroui-secondary-700': Type.String({ default: '270 66.67% 28.24%' }), - '--heroui-secondary-800': Type.String({ default: '270 66.67% 18.82%' }), - '--heroui-secondary-900': Type.String({ default: '270 66.67% 9.41%' }), - '--heroui-secondary-foreground': Type.String({ default: '0 0% 100%' }), - '--heroui-secondary': Type.String({ default: '270 66.67% 47.06%' }), - // 新增 success - '--heroui-success-50': Type.String({ default: '146.67 64.29% 94.51%' }), - '--heroui-success-100': Type.String({ default: '145.71 61.4% 88.82%' }), - '--heroui-success-200': Type.String({ default: '146.2 61.74% 77.45%' }), - '--heroui-success-300': Type.String({ default: '145.79 62.57% 66.47%' }), - '--heroui-success-400': Type.String({ default: '146.01 62.45% 55.1%' }), - '--heroui-success-500': Type.String({ default: '145.96 79.46% 43.92%' }), - '--heroui-success-600': Type.String({ default: '146.01 79.89% 35.1%' }), - '--heroui-success-700': Type.String({ default: '145.79 79.26% 26.47%' }), - '--heroui-success-800': Type.String({ default: '146.2 79.78% 17.45%' }), - '--heroui-success-900': Type.String({ default: '145.71 77.78% 8.82%' }), - '--heroui-success-foreground': Type.String({ default: '0 0% 0%' }), - '--heroui-success': Type.String({ default: '145.96 79.46% 43.92%' }), - // 新增 warning - '--heroui-warning-50': Type.String({ default: '54.55 91.67% 95.29%' }), - '--heroui-warning-100': Type.String({ default: '37.14 91.3% 90.98%' }), - '--heroui-warning-200': Type.String({ default: '37.14 91.3% 81.96%' }), - '--heroui-warning-300': Type.String({ default: '36.96 91.24% 73.14%' }), - '--heroui-warning-400': Type.String({ default: '37.01 91.26% 64.12%' }), - '--heroui-warning-500': Type.String({ default: '37.03 91.27% 55.1%' }), - '--heroui-warning-600': Type.String({ default: '37.01 74.22% 44.12%' }), - '--heroui-warning-700': Type.String({ default: '36.96 73.96% 33.14%' }), - '--heroui-warning-800': Type.String({ default: '37.14 75% 21.96%' }), - '--heroui-warning-900': Type.String({ default: '37.14 75% 10.98%' }), - '--heroui-warning-foreground': Type.String({ default: '0 0% 0%' }), - '--heroui-warning': Type.String({ default: '37.03 91.27% 55.1%' }), - // 其它配置 - '--heroui-code-background': Type.String({ default: '221.25 17.39% 18.04%' }), - '--heroui-strong': Type.String({ default: '316.95 100% 65.29%' }), - '--heroui-code-mdx': Type.String({ default: '316.95 100% 65.29%' }), - '--heroui-divider-weight': Type.String({ default: '1px' }), - '--heroui-disabled-opacity': Type.String({ default: '.5' }), - '--heroui-font-size-tiny': Type.String({ default: '0.75rem' }), - '--heroui-font-size-small': Type.String({ default: '0.875rem' }), - '--heroui-font-size-medium': Type.String({ default: '1rem' }), - '--heroui-font-size-large': Type.String({ default: '1.125rem' }), - '--heroui-line-height-tiny': Type.String({ default: '1rem' }), - '--heroui-line-height-small': Type.String({ default: '1.25rem' }), - '--heroui-line-height-medium': Type.String({ default: '1.5rem' }), - '--heroui-line-height-large': Type.String({ default: '1.75rem' }), - '--heroui-radius-small': Type.String({ default: '8px' }), - '--heroui-radius-medium': Type.String({ default: '12px' }), - '--heroui-radius-large': Type.String({ default: '14px' }), - '--heroui-border-width-small': Type.String({ default: '1px' }), - '--heroui-border-width-medium': Type.String({ default: '2px' }), - '--heroui-border-width-large': Type.String({ default: '3px' }), - '--heroui-box-shadow-small': Type.String({ - default: - '0px 0px 5px 0px rgba(0, 0, 0, .02), 0px 2px 10px 0px rgba(0, 0, 0, .06), 0px 0px 1px 0px rgba(0, 0, 0, .3)', - }), - '--heroui-box-shadow-medium': Type.String({ - default: - '0px 0px 15px 0px rgba(0, 0, 0, .03), 0px 2px 30px 0px rgba(0, 0, 0, .08), 0px 0px 1px 0px rgba(0, 0, 0, .3)', - }), - '--heroui-box-shadow-large': Type.String({ - default: - '0px 0px 30px 0px rgba(0, 0, 0, .04), 0px 30px 60px 0px rgba(0, 0, 0, .12), 0px 0px 1px 0px rgba(0, 0, 0, .3)', - }), - '--heroui-hover-opacity': Type.String({ default: '.8' }), - }, { default: {} }), - }, { default: {} }), + theme: Type.Object( + { + dark: Type.Object( + { + '--heroui-background': Type.String({ default: '0 0% 0%' }), + '--heroui-foreground-50': Type.String({ default: '240 5.88% 10%' }), + '--heroui-foreground-100': Type.String({ default: '240 3.7% 15.88%' }), + '--heroui-foreground-200': Type.String({ default: '240 5.26% 26.08%' }), + '--heroui-foreground-300': Type.String({ default: '240 5.2% 33.92%' }), + '--heroui-foreground-400': Type.String({ default: '240 3.83% 46.08%' }), + '--heroui-foreground-500': Type.String({ default: '240 5.03% 64.9%' }), + '--heroui-foreground-600': Type.String({ default: '240 4.88% 83.92%' }), + '--heroui-foreground-700': Type.String({ default: '240 5.88% 90%' }), + '--heroui-foreground-800': Type.String({ default: '240 4.76% 95.88%' }), + '--heroui-foreground-900': Type.String({ default: '0 0% 98.04%' }), + '--heroui-foreground': Type.String({ default: '210 5.56% 92.94%' }), + '--heroui-focus': Type.String({ default: '212.01999999999998 100% 46.67%' }), + '--heroui-overlay': Type.String({ default: '0 0% 0%' }), + '--heroui-divider': Type.String({ default: '0 0% 100%' }), + '--heroui-divider-opacity': Type.String({ default: '0.15' }), + '--heroui-content1': Type.String({ default: '240 5.88% 10%' }), + '--heroui-content1-foreground': Type.String({ default: '0 0% 98.04%' }), + '--heroui-content2': Type.String({ default: '240 3.7% 15.88%' }), + '--heroui-content2-foreground': Type.String({ default: '240 4.76% 95.88%' }), + '--heroui-content3': Type.String({ default: '240 5.26% 26.08%' }), + '--heroui-content3-foreground': Type.String({ default: '240 5.88% 90%' }), + '--heroui-content4': Type.String({ default: '240 5.2% 33.92%' }), + '--heroui-content4-foreground': Type.String({ default: '240 4.88% 83.92%' }), + '--heroui-default-50': Type.String({ default: '240 5.88% 10%' }), + '--heroui-default-100': Type.String({ default: '240 3.7% 15.88%' }), + '--heroui-default-200': Type.String({ default: '240 5.26% 26.08%' }), + '--heroui-default-300': Type.String({ default: '240 5.2% 33.92%' }), + '--heroui-default-400': Type.String({ default: '240 3.83% 46.08%' }), + '--heroui-default-500': Type.String({ default: '240 5.03% 64.9%' }), + '--heroui-default-600': Type.String({ default: '240 4.88% 83.92%' }), + '--heroui-default-700': Type.String({ default: '240 5.88% 90%' }), + '--heroui-default-800': Type.String({ default: '240 4.76% 95.88%' }), + '--heroui-default-900': Type.String({ default: '0 0% 98.04%' }), + '--heroui-default-foreground': Type.String({ default: '0 0% 100%' }), + '--heroui-default': Type.String({ default: '240 5.26% 26.08%' }), + '--heroui-danger-50': Type.String({ default: '301.89 82.61% 22.55%' }), + '--heroui-danger-100': Type.String({ default: '308.18 76.39% 28.24%' }), + '--heroui-danger-200': Type.String({ default: '313.85 70.65% 36.08%' }), + '--heroui-danger-300': Type.String({ default: '319.73 65.64% 44.51%' }), + '--heroui-danger-400': Type.String({ default: '325.82 69.62% 53.53%' }), + '--heroui-danger-500': Type.String({ default: '331.82 75% 65.49%' }), + '--heroui-danger-600': Type.String({ default: '337.84 83.46% 73.92%' }), + '--heroui-danger-700': Type.String({ default: '343.42 90.48% 83.53%' }), + '--heroui-danger-800': Type.String({ default: '350.53 90.48% 91.76%' }), + '--heroui-danger-900': Type.String({ default: '324 90.91% 95.69%' }), + '--heroui-danger-foreground': Type.String({ default: '0 0% 100%' }), + '--heroui-danger': Type.String({ default: '325.82 69.62% 53.53%' }), + '--heroui-primary-50': Type.String({ default: '340 84.91% 10.39%' }), + '--heroui-primary-100': Type.String({ default: '339.33 86.54% 20.39%' }), + '--heroui-primary-200': Type.String({ default: '339.11 85.99% 30.78%' }), + '--heroui-primary-300': Type.String({ default: '339 86.54% 40.78%' }), + '--heroui-primary-400': Type.String({ default: '339.2 90.36% 51.18%' }), + '--heroui-primary-500': Type.String({ default: '339 90% 60.78%' }), + '--heroui-primary-600': Type.String({ default: '339.11 90.6% 70.78%' }), + '--heroui-primary-700': Type.String({ default: '339.33 90% 80.39%' }), + '--heroui-primary-800': Type.String({ default: '340 91.84% 90.39%' }), + '--heroui-primary-900': Type.String({ default: '339.13 92% 95.1%' }), + '--heroui-primary-foreground': Type.String({ default: '0 0% 100%' }), + '--heroui-primary': Type.String({ default: '339.2 90.36% 51.18%' }), + // 新增 secondary + '--heroui-secondary-50': Type.String({ default: '270 66.67% 9.41%' }), + '--heroui-secondary-100': Type.String({ default: '270 66.67% 18.82%' }), + '--heroui-secondary-200': Type.String({ default: '270 66.67% 28.24%' }), + '--heroui-secondary-300': Type.String({ default: '270 66.67% 37.65%' }), + '--heroui-secondary-400': Type.String({ default: '270 66.67% 47.06%' }), + '--heroui-secondary-500': Type.String({ default: '270 59.26% 57.65%' }), + '--heroui-secondary-600': Type.String({ default: '270 59.26% 68.24%' }), + '--heroui-secondary-700': Type.String({ default: '270 59.26% 78.82%' }), + '--heroui-secondary-800': Type.String({ default: '270 59.26% 89.41%' }), + '--heroui-secondary-900': Type.String({ default: '270 61.54% 94.9%' }), + '--heroui-secondary-foreground': Type.String({ default: '0 0% 100%' }), + '--heroui-secondary': Type.String({ default: '270 59.26% 57.65%' }), + // 新增 success + '--heroui-success-50': Type.String({ default: '145.71 77.78% 8.82%' }), + '--heroui-success-100': Type.String({ default: '146.2 79.78% 17.45%' }), + '--heroui-success-200': Type.String({ default: '145.79 79.26% 26.47%' }), + '--heroui-success-300': Type.String({ default: '146.01 79.89% 35.1%' }), + '--heroui-success-400': Type.String({ default: '145.96 79.46% 43.92%' }), + '--heroui-success-500': Type.String({ default: '146.01 62.45% 55.1%' }), + '--heroui-success-600': Type.String({ default: '145.79 62.57% 66.47%' }), + '--heroui-success-700': Type.String({ default: '146.2 61.74% 77.45%' }), + '--heroui-success-800': Type.String({ default: '145.71 61.4% 88.82%' }), + '--heroui-success-900': Type.String({ default: '146.67 64.29% 94.51%' }), + '--heroui-success-foreground': Type.String({ default: '0 0% 0%' }), + '--heroui-success': Type.String({ default: '145.96 79.46% 43.92%' }), + // 新增 warning + '--heroui-warning-50': Type.String({ default: '37.14 75% 10.98%' }), + '--heroui-warning-100': Type.String({ default: '37.14 75% 21.96%' }), + '--heroui-warning-200': Type.String({ default: '36.96 73.96% 33.14%' }), + '--heroui-warning-300': Type.String({ default: '37.01 74.22% 44.12%' }), + '--heroui-warning-400': Type.String({ default: '37.03 91.27% 55.1%' }), + '--heroui-warning-500': Type.String({ default: '37.01 91.26% 64.12%' }), + '--heroui-warning-600': Type.String({ default: '36.96 91.24% 73.14%' }), + '--heroui-warning-700': Type.String({ default: '37.14 91.3% 81.96%' }), + '--heroui-warning-800': Type.String({ default: '37.14 91.3% 90.98%' }), + '--heroui-warning-900': Type.String({ default: '54.55 91.67% 95.29%' }), + '--heroui-warning-foreground': Type.String({ default: '0 0% 0%' }), + '--heroui-warning': Type.String({ default: '37.03 91.27% 55.1%' }), + // 其它配置 + '--heroui-code-background': Type.String({ default: '240 5.56% 7.06%' }), + '--heroui-strong': Type.String({ default: '190.14 94.67% 44.12%' }), + '--heroui-code-mdx': Type.String({ default: '190.14 94.67% 44.12%' }), + '--heroui-divider-weight': Type.String({ default: '1px' }), + '--heroui-disabled-opacity': Type.String({ default: '.5' }), + '--heroui-font-size-tiny': Type.String({ default: '0.75rem' }), + '--heroui-font-size-small': Type.String({ default: '0.875rem' }), + '--heroui-font-size-medium': Type.String({ default: '1rem' }), + '--heroui-font-size-large': Type.String({ default: '1.125rem' }), + '--heroui-line-height-tiny': Type.String({ default: '1rem' }), + '--heroui-line-height-small': Type.String({ default: '1.25rem' }), + '--heroui-line-height-medium': Type.String({ default: '1.5rem' }), + '--heroui-line-height-large': Type.String({ default: '1.75rem' }), + '--heroui-radius-small': Type.String({ default: '8px' }), + '--heroui-radius-medium': Type.String({ default: '12px' }), + '--heroui-radius-large': Type.String({ default: '14px' }), + '--heroui-border-width-small': Type.String({ default: '1px' }), + '--heroui-border-width-medium': Type.String({ default: '2px' }), + '--heroui-border-width-large': Type.String({ default: '3px' }), + '--heroui-box-shadow-small': Type.String({ + default: + '0px 0px 5px 0px rgba(0, 0, 0, .05), 0px 2px 10px 0px rgba(0, 0, 0, .2), inset 0px 0px 1px 0px hsla(0, 0%, 100%, .15)', + }), + '--heroui-box-shadow-medium': Type.String({ + default: + '0px 0px 15px 0px rgba(0, 0, 0, .06), 0px 2px 30px 0px rgba(0, 0, 0, .22), inset 0px 0px 1px 0px hsla(0, 0%, 100%, .15)', + }), + '--heroui-box-shadow-large': Type.String({ + default: + '0px 0px 30px 0px rgba(0, 0, 0, .07), 0px 30px 60px 0px rgba(0, 0, 0, .26), inset 0px 0px 1px 0px hsla(0, 0%, 100%, .15)', + }), + '--heroui-hover-opacity': Type.String({ default: '.9' }), + }, + { default: {} } + ), + light: Type.Object( + { + '--heroui-background': Type.String({ default: '0 0% 100%' }), + '--heroui-foreground-50': Type.String({ default: '240 5.88% 95%' }), + '--heroui-foreground-100': Type.String({ default: '240 3.7% 90%' }), + '--heroui-foreground-200': Type.String({ default: '240 5.26% 80%' }), + '--heroui-foreground-300': Type.String({ default: '240 5.2% 70%' }), + '--heroui-foreground-400': Type.String({ default: '240 3.83% 60%' }), + '--heroui-foreground-500': Type.String({ default: '240 5.03% 50%' }), + '--heroui-foreground-600': Type.String({ default: '240 4.88% 40%' }), + '--heroui-foreground-700': Type.String({ default: '240 5.88% 30%' }), + '--heroui-foreground-800': Type.String({ default: '240 4.76% 20%' }), + '--heroui-foreground-900': Type.String({ default: '0 0% 10%' }), + '--heroui-foreground': Type.String({ default: '210 5.56% 7.06%' }), + '--heroui-focus': Type.String({ default: '212.01999999999998 100% 53.33%' }), + '--heroui-overlay': Type.String({ default: '0 0% 100%' }), + '--heroui-divider': Type.String({ default: '0 0% 0%' }), + '--heroui-divider-opacity': Type.String({ default: '0.85' }), + '--heroui-content1': Type.String({ default: '240 5.88% 95%' }), + '--heroui-content1-foreground': Type.String({ default: '0 0% 10%' }), + '--heroui-content2': Type.String({ default: '240 3.7% 90%' }), + '--heroui-content2-foreground': Type.String({ default: '240 4.76% 20%' }), + '--heroui-content3': Type.String({ default: '240 5.26% 80%' }), + '--heroui-content3-foreground': Type.String({ default: '240 5.88% 30%' }), + '--heroui-content4': Type.String({ default: '240 5.2% 70%' }), + '--heroui-content4-foreground': Type.String({ default: '240 4.88% 40%' }), + '--heroui-default-50': Type.String({ default: '240 5.88% 95%' }), + '--heroui-default-100': Type.String({ default: '240 3.7% 90%' }), + '--heroui-default-200': Type.String({ default: '240 5.26% 80%' }), + '--heroui-default-300': Type.String({ default: '240 5.2% 70%' }), + '--heroui-default-400': Type.String({ default: '240 3.83% 60%' }), + '--heroui-default-500': Type.String({ default: '240 5.03% 50%' }), + '--heroui-default-600': Type.String({ default: '240 4.88% 40%' }), + '--heroui-default-700': Type.String({ default: '240 5.88% 30%' }), + '--heroui-default-800': Type.String({ default: '240 4.76% 20%' }), + '--heroui-default-900': Type.String({ default: '0 0% 10%' }), + '--heroui-default-foreground': Type.String({ default: '0 0% 0%' }), + '--heroui-default': Type.String({ default: '240 5.26% 80%' }), + '--heroui-danger-50': Type.String({ default: '324 90.91% 95.69%' }), + '--heroui-danger-100': Type.String({ default: '350.53 90.48% 91.76%' }), + '--heroui-danger-200': Type.String({ default: '343.42 90.48% 83.53%' }), + '--heroui-danger-300': Type.String({ default: '337.84 83.46% 73.92%' }), + '--heroui-danger-400': Type.String({ default: '331.82 75% 65.49%' }), + '--heroui-danger-500': Type.String({ default: '325.82 69.62% 53.53%' }), + '--heroui-danger-600': Type.String({ default: '319.73 65.64% 44.51%' }), + '--heroui-danger-700': Type.String({ default: '313.85 70.65% 36.08%' }), + '--heroui-danger-800': Type.String({ default: '308.18 76.39% 28.24%' }), + '--heroui-danger-900': Type.String({ default: '301.89 82.61% 22.55%' }), + '--heroui-danger-foreground': Type.String({ default: '0 0% 100%' }), + '--heroui-danger': Type.String({ default: '325.82 69.62% 53.53%' }), + '--heroui-primary-50': Type.String({ default: '339.13 92% 95.1%' }), + '--heroui-primary-100': Type.String({ default: '340 91.84% 90.39%' }), + '--heroui-primary-200': Type.String({ default: '339.33 90% 80.39%' }), + '--heroui-primary-300': Type.String({ default: '339.11 90.6% 70.78%' }), + '--heroui-primary-400': Type.String({ default: '339 90% 60.78%' }), + '--heroui-primary-500': Type.String({ default: '339.2 90.36% 51.18%' }), + '--heroui-primary-600': Type.String({ default: '339 86.54% 40.78%' }), + '--heroui-primary-700': Type.String({ default: '339.11 85.99% 30.78%' }), + '--heroui-primary-800': Type.String({ default: '339.33 86.54% 20.39%' }), + '--heroui-primary-900': Type.String({ default: '340 84.91% 10.39%' }), + '--heroui-primary-foreground': Type.String({ default: '0 0% 100%' }), + '--heroui-primary': Type.String({ default: '339.2 90.36% 51.18%' }), + // 新增 secondary + '--heroui-secondary-50': Type.String({ default: '270 61.54% 94.9%' }), + '--heroui-secondary-100': Type.String({ default: '270 59.26% 89.41%' }), + '--heroui-secondary-200': Type.String({ default: '270 59.26% 78.82%' }), + '--heroui-secondary-300': Type.String({ default: '270 59.26% 68.24%' }), + '--heroui-secondary-400': Type.String({ default: '270 59.26% 57.65%' }), + '--heroui-secondary-500': Type.String({ default: '270 66.67% 47.06%' }), + '--heroui-secondary-600': Type.String({ default: '270 66.67% 37.65%' }), + '--heroui-secondary-700': Type.String({ default: '270 66.67% 28.24%' }), + '--heroui-secondary-800': Type.String({ default: '270 66.67% 18.82%' }), + '--heroui-secondary-900': Type.String({ default: '270 66.67% 9.41%' }), + '--heroui-secondary-foreground': Type.String({ default: '0 0% 100%' }), + '--heroui-secondary': Type.String({ default: '270 66.67% 47.06%' }), + // 新增 success + '--heroui-success-50': Type.String({ default: '146.67 64.29% 94.51%' }), + '--heroui-success-100': Type.String({ default: '145.71 61.4% 88.82%' }), + '--heroui-success-200': Type.String({ default: '146.2 61.74% 77.45%' }), + '--heroui-success-300': Type.String({ default: '145.79 62.57% 66.47%' }), + '--heroui-success-400': Type.String({ default: '146.01 62.45% 55.1%' }), + '--heroui-success-500': Type.String({ default: '145.96 79.46% 43.92%' }), + '--heroui-success-600': Type.String({ default: '146.01 79.89% 35.1%' }), + '--heroui-success-700': Type.String({ default: '145.79 79.26% 26.47%' }), + '--heroui-success-800': Type.String({ default: '146.2 79.78% 17.45%' }), + '--heroui-success-900': Type.String({ default: '145.71 77.78% 8.82%' }), + '--heroui-success-foreground': Type.String({ default: '0 0% 0%' }), + '--heroui-success': Type.String({ default: '145.96 79.46% 43.92%' }), + // 新增 warning + '--heroui-warning-50': Type.String({ default: '54.55 91.67% 95.29%' }), + '--heroui-warning-100': Type.String({ default: '37.14 91.3% 90.98%' }), + '--heroui-warning-200': Type.String({ default: '37.14 91.3% 81.96%' }), + '--heroui-warning-300': Type.String({ default: '36.96 91.24% 73.14%' }), + '--heroui-warning-400': Type.String({ default: '37.01 91.26% 64.12%' }), + '--heroui-warning-500': Type.String({ default: '37.03 91.27% 55.1%' }), + '--heroui-warning-600': Type.String({ default: '37.01 74.22% 44.12%' }), + '--heroui-warning-700': Type.String({ default: '36.96 73.96% 33.14%' }), + '--heroui-warning-800': Type.String({ default: '37.14 75% 21.96%' }), + '--heroui-warning-900': Type.String({ default: '37.14 75% 10.98%' }), + '--heroui-warning-foreground': Type.String({ default: '0 0% 0%' }), + '--heroui-warning': Type.String({ default: '37.03 91.27% 55.1%' }), + // 其它配置 + '--heroui-code-background': Type.String({ default: '221.25 17.39% 18.04%' }), + '--heroui-strong': Type.String({ default: '316.95 100% 65.29%' }), + '--heroui-code-mdx': Type.String({ default: '316.95 100% 65.29%' }), + '--heroui-divider-weight': Type.String({ default: '1px' }), + '--heroui-disabled-opacity': Type.String({ default: '.5' }), + '--heroui-font-size-tiny': Type.String({ default: '0.75rem' }), + '--heroui-font-size-small': Type.String({ default: '0.875rem' }), + '--heroui-font-size-medium': Type.String({ default: '1rem' }), + '--heroui-font-size-large': Type.String({ default: '1.125rem' }), + '--heroui-line-height-tiny': Type.String({ default: '1rem' }), + '--heroui-line-height-small': Type.String({ default: '1.25rem' }), + '--heroui-line-height-medium': Type.String({ default: '1.5rem' }), + '--heroui-line-height-large': Type.String({ default: '1.75rem' }), + '--heroui-radius-small': Type.String({ default: '8px' }), + '--heroui-radius-medium': Type.String({ default: '12px' }), + '--heroui-radius-large': Type.String({ default: '14px' }), + '--heroui-border-width-small': Type.String({ default: '1px' }), + '--heroui-border-width-medium': Type.String({ default: '2px' }), + '--heroui-border-width-large': Type.String({ default: '3px' }), + '--heroui-box-shadow-small': Type.String({ + default: + '0px 0px 5px 0px rgba(0, 0, 0, .02), 0px 2px 10px 0px rgba(0, 0, 0, .06), 0px 0px 1px 0px rgba(0, 0, 0, .3)', + }), + '--heroui-box-shadow-medium': Type.String({ + default: + '0px 0px 15px 0px rgba(0, 0, 0, .03), 0px 2px 30px 0px rgba(0, 0, 0, .08), 0px 0px 1px 0px rgba(0, 0, 0, .3)', + }), + '--heroui-box-shadow-large': Type.String({ + default: + '0px 0px 30px 0px rgba(0, 0, 0, .04), 0px 30px 60px 0px rgba(0, 0, 0, .12), 0px 0px 1px 0px rgba(0, 0, 0, .3)', + }), + '--heroui-hover-opacity': Type.String({ default: '.8' }), + }, + { default: {} } + ), + }, + { default: {} } + ), }); export type WebUiConfigType = Static; @@ -432,7 +441,14 @@ export class WebUiConfigWrapper { // 获取主题内容 async GetTheme(): Promise { - return (await this.GetWebUIConfig()).theme; + const config = await this.GetWebUIConfig(); + if (!config.theme || Object.keys(config.theme).length === 0) { + const defaultConfig = this.validateAndApplyDefaults({}); + config.theme = defaultConfig.theme; + // 更新配置文件中的 theme 字段 + await this.UpdateWebUIConfig({ theme: config.theme }); + } + return config.theme; } // 更新主题内容 From 970a49e2a5e42b14d9fafe33955da6aa8cd6f879 Mon Sep 17 00:00:00 2001 From: bietiaop <1527109126@qq.com> Date: Sat, 8 Feb 2025 23:05:48 +0800 Subject: [PATCH 05/10] =?UTF-8?q?fix:=20=E7=8C=AA=E5=92=AA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/webui/src/api/BaseInfo.ts | 10 +- src/webui/src/helper/config.ts | 293 +-------------------------------- src/webui/src/types/theme.ts | 260 +++++++++++++++++++++++++++++ src/webui/src/utils/object.ts | 22 +++ 4 files changed, 294 insertions(+), 291 deletions(-) create mode 100644 src/webui/src/types/theme.ts create mode 100644 src/webui/src/utils/object.ts diff --git a/src/webui/src/api/BaseInfo.ts b/src/webui/src/api/BaseInfo.ts index 43df485b..a7d3c514 100644 --- a/src/webui/src/api/BaseInfo.ts +++ b/src/webui/src/api/BaseInfo.ts @@ -14,13 +14,13 @@ export const QQVersionHandler: RequestHandler = (_, res) => { sendSuccess(res, data); }; -export const GetThemeConfigHandler: RequestHandler = (_, res) => { - const data = WebUiConfig.GetTheme(); +export const GetThemeConfigHandler: RequestHandler = async (_, res) => { + const data = await WebUiConfig.GetTheme(); sendSuccess(res, data); }; -export const SetThemeConfigHandler: RequestHandler = (req, res) => { +export const SetThemeConfigHandler: RequestHandler = async (req, res) => { const { theme } = req.body; - const data = WebUiConfig.UpdateTheme(theme); - sendSuccess(res, data); + await WebUiConfig.UpdateTheme(theme); + sendSuccess(res, { message: '更新成功' }); }; diff --git a/src/webui/src/helper/config.ts b/src/webui/src/helper/config.ts index 4cb9c6b9..a21b3639 100644 --- a/src/webui/src/helper/config.ts +++ b/src/webui/src/helper/config.ts @@ -5,6 +5,9 @@ import fs, { constants } from 'node:fs/promises'; import { resolve } from 'node:path'; +import { deepMerge } from '../utils/object'; +import { themeType } from '../types/theme'; + // 限制尝试端口的次数,避免死循环 // 定义配置的类型 @@ -14,285 +17,7 @@ const WebUiConfigSchema = Type.Object({ token: Type.String({ default: 'napcat' }), loginRate: Type.Number({ default: 10 }), autoLoginAccount: Type.String({ default: '' }), - theme: Type.Object( - { - dark: Type.Object( - { - '--heroui-background': Type.String({ default: '0 0% 0%' }), - '--heroui-foreground-50': Type.String({ default: '240 5.88% 10%' }), - '--heroui-foreground-100': Type.String({ default: '240 3.7% 15.88%' }), - '--heroui-foreground-200': Type.String({ default: '240 5.26% 26.08%' }), - '--heroui-foreground-300': Type.String({ default: '240 5.2% 33.92%' }), - '--heroui-foreground-400': Type.String({ default: '240 3.83% 46.08%' }), - '--heroui-foreground-500': Type.String({ default: '240 5.03% 64.9%' }), - '--heroui-foreground-600': Type.String({ default: '240 4.88% 83.92%' }), - '--heroui-foreground-700': Type.String({ default: '240 5.88% 90%' }), - '--heroui-foreground-800': Type.String({ default: '240 4.76% 95.88%' }), - '--heroui-foreground-900': Type.String({ default: '0 0% 98.04%' }), - '--heroui-foreground': Type.String({ default: '210 5.56% 92.94%' }), - '--heroui-focus': Type.String({ default: '212.01999999999998 100% 46.67%' }), - '--heroui-overlay': Type.String({ default: '0 0% 0%' }), - '--heroui-divider': Type.String({ default: '0 0% 100%' }), - '--heroui-divider-opacity': Type.String({ default: '0.15' }), - '--heroui-content1': Type.String({ default: '240 5.88% 10%' }), - '--heroui-content1-foreground': Type.String({ default: '0 0% 98.04%' }), - '--heroui-content2': Type.String({ default: '240 3.7% 15.88%' }), - '--heroui-content2-foreground': Type.String({ default: '240 4.76% 95.88%' }), - '--heroui-content3': Type.String({ default: '240 5.26% 26.08%' }), - '--heroui-content3-foreground': Type.String({ default: '240 5.88% 90%' }), - '--heroui-content4': Type.String({ default: '240 5.2% 33.92%' }), - '--heroui-content4-foreground': Type.String({ default: '240 4.88% 83.92%' }), - '--heroui-default-50': Type.String({ default: '240 5.88% 10%' }), - '--heroui-default-100': Type.String({ default: '240 3.7% 15.88%' }), - '--heroui-default-200': Type.String({ default: '240 5.26% 26.08%' }), - '--heroui-default-300': Type.String({ default: '240 5.2% 33.92%' }), - '--heroui-default-400': Type.String({ default: '240 3.83% 46.08%' }), - '--heroui-default-500': Type.String({ default: '240 5.03% 64.9%' }), - '--heroui-default-600': Type.String({ default: '240 4.88% 83.92%' }), - '--heroui-default-700': Type.String({ default: '240 5.88% 90%' }), - '--heroui-default-800': Type.String({ default: '240 4.76% 95.88%' }), - '--heroui-default-900': Type.String({ default: '0 0% 98.04%' }), - '--heroui-default-foreground': Type.String({ default: '0 0% 100%' }), - '--heroui-default': Type.String({ default: '240 5.26% 26.08%' }), - '--heroui-danger-50': Type.String({ default: '301.89 82.61% 22.55%' }), - '--heroui-danger-100': Type.String({ default: '308.18 76.39% 28.24%' }), - '--heroui-danger-200': Type.String({ default: '313.85 70.65% 36.08%' }), - '--heroui-danger-300': Type.String({ default: '319.73 65.64% 44.51%' }), - '--heroui-danger-400': Type.String({ default: '325.82 69.62% 53.53%' }), - '--heroui-danger-500': Type.String({ default: '331.82 75% 65.49%' }), - '--heroui-danger-600': Type.String({ default: '337.84 83.46% 73.92%' }), - '--heroui-danger-700': Type.String({ default: '343.42 90.48% 83.53%' }), - '--heroui-danger-800': Type.String({ default: '350.53 90.48% 91.76%' }), - '--heroui-danger-900': Type.String({ default: '324 90.91% 95.69%' }), - '--heroui-danger-foreground': Type.String({ default: '0 0% 100%' }), - '--heroui-danger': Type.String({ default: '325.82 69.62% 53.53%' }), - '--heroui-primary-50': Type.String({ default: '340 84.91% 10.39%' }), - '--heroui-primary-100': Type.String({ default: '339.33 86.54% 20.39%' }), - '--heroui-primary-200': Type.String({ default: '339.11 85.99% 30.78%' }), - '--heroui-primary-300': Type.String({ default: '339 86.54% 40.78%' }), - '--heroui-primary-400': Type.String({ default: '339.2 90.36% 51.18%' }), - '--heroui-primary-500': Type.String({ default: '339 90% 60.78%' }), - '--heroui-primary-600': Type.String({ default: '339.11 90.6% 70.78%' }), - '--heroui-primary-700': Type.String({ default: '339.33 90% 80.39%' }), - '--heroui-primary-800': Type.String({ default: '340 91.84% 90.39%' }), - '--heroui-primary-900': Type.String({ default: '339.13 92% 95.1%' }), - '--heroui-primary-foreground': Type.String({ default: '0 0% 100%' }), - '--heroui-primary': Type.String({ default: '339.2 90.36% 51.18%' }), - // 新增 secondary - '--heroui-secondary-50': Type.String({ default: '270 66.67% 9.41%' }), - '--heroui-secondary-100': Type.String({ default: '270 66.67% 18.82%' }), - '--heroui-secondary-200': Type.String({ default: '270 66.67% 28.24%' }), - '--heroui-secondary-300': Type.String({ default: '270 66.67% 37.65%' }), - '--heroui-secondary-400': Type.String({ default: '270 66.67% 47.06%' }), - '--heroui-secondary-500': Type.String({ default: '270 59.26% 57.65%' }), - '--heroui-secondary-600': Type.String({ default: '270 59.26% 68.24%' }), - '--heroui-secondary-700': Type.String({ default: '270 59.26% 78.82%' }), - '--heroui-secondary-800': Type.String({ default: '270 59.26% 89.41%' }), - '--heroui-secondary-900': Type.String({ default: '270 61.54% 94.9%' }), - '--heroui-secondary-foreground': Type.String({ default: '0 0% 100%' }), - '--heroui-secondary': Type.String({ default: '270 59.26% 57.65%' }), - // 新增 success - '--heroui-success-50': Type.String({ default: '145.71 77.78% 8.82%' }), - '--heroui-success-100': Type.String({ default: '146.2 79.78% 17.45%' }), - '--heroui-success-200': Type.String({ default: '145.79 79.26% 26.47%' }), - '--heroui-success-300': Type.String({ default: '146.01 79.89% 35.1%' }), - '--heroui-success-400': Type.String({ default: '145.96 79.46% 43.92%' }), - '--heroui-success-500': Type.String({ default: '146.01 62.45% 55.1%' }), - '--heroui-success-600': Type.String({ default: '145.79 62.57% 66.47%' }), - '--heroui-success-700': Type.String({ default: '146.2 61.74% 77.45%' }), - '--heroui-success-800': Type.String({ default: '145.71 61.4% 88.82%' }), - '--heroui-success-900': Type.String({ default: '146.67 64.29% 94.51%' }), - '--heroui-success-foreground': Type.String({ default: '0 0% 0%' }), - '--heroui-success': Type.String({ default: '145.96 79.46% 43.92%' }), - // 新增 warning - '--heroui-warning-50': Type.String({ default: '37.14 75% 10.98%' }), - '--heroui-warning-100': Type.String({ default: '37.14 75% 21.96%' }), - '--heroui-warning-200': Type.String({ default: '36.96 73.96% 33.14%' }), - '--heroui-warning-300': Type.String({ default: '37.01 74.22% 44.12%' }), - '--heroui-warning-400': Type.String({ default: '37.03 91.27% 55.1%' }), - '--heroui-warning-500': Type.String({ default: '37.01 91.26% 64.12%' }), - '--heroui-warning-600': Type.String({ default: '36.96 91.24% 73.14%' }), - '--heroui-warning-700': Type.String({ default: '37.14 91.3% 81.96%' }), - '--heroui-warning-800': Type.String({ default: '37.14 91.3% 90.98%' }), - '--heroui-warning-900': Type.String({ default: '54.55 91.67% 95.29%' }), - '--heroui-warning-foreground': Type.String({ default: '0 0% 0%' }), - '--heroui-warning': Type.String({ default: '37.03 91.27% 55.1%' }), - // 其它配置 - '--heroui-code-background': Type.String({ default: '240 5.56% 7.06%' }), - '--heroui-strong': Type.String({ default: '190.14 94.67% 44.12%' }), - '--heroui-code-mdx': Type.String({ default: '190.14 94.67% 44.12%' }), - '--heroui-divider-weight': Type.String({ default: '1px' }), - '--heroui-disabled-opacity': Type.String({ default: '.5' }), - '--heroui-font-size-tiny': Type.String({ default: '0.75rem' }), - '--heroui-font-size-small': Type.String({ default: '0.875rem' }), - '--heroui-font-size-medium': Type.String({ default: '1rem' }), - '--heroui-font-size-large': Type.String({ default: '1.125rem' }), - '--heroui-line-height-tiny': Type.String({ default: '1rem' }), - '--heroui-line-height-small': Type.String({ default: '1.25rem' }), - '--heroui-line-height-medium': Type.String({ default: '1.5rem' }), - '--heroui-line-height-large': Type.String({ default: '1.75rem' }), - '--heroui-radius-small': Type.String({ default: '8px' }), - '--heroui-radius-medium': Type.String({ default: '12px' }), - '--heroui-radius-large': Type.String({ default: '14px' }), - '--heroui-border-width-small': Type.String({ default: '1px' }), - '--heroui-border-width-medium': Type.String({ default: '2px' }), - '--heroui-border-width-large': Type.String({ default: '3px' }), - '--heroui-box-shadow-small': Type.String({ - default: - '0px 0px 5px 0px rgba(0, 0, 0, .05), 0px 2px 10px 0px rgba(0, 0, 0, .2), inset 0px 0px 1px 0px hsla(0, 0%, 100%, .15)', - }), - '--heroui-box-shadow-medium': Type.String({ - default: - '0px 0px 15px 0px rgba(0, 0, 0, .06), 0px 2px 30px 0px rgba(0, 0, 0, .22), inset 0px 0px 1px 0px hsla(0, 0%, 100%, .15)', - }), - '--heroui-box-shadow-large': Type.String({ - default: - '0px 0px 30px 0px rgba(0, 0, 0, .07), 0px 30px 60px 0px rgba(0, 0, 0, .26), inset 0px 0px 1px 0px hsla(0, 0%, 100%, .15)', - }), - '--heroui-hover-opacity': Type.String({ default: '.9' }), - }, - { default: {} } - ), - light: Type.Object( - { - '--heroui-background': Type.String({ default: '0 0% 100%' }), - '--heroui-foreground-50': Type.String({ default: '240 5.88% 95%' }), - '--heroui-foreground-100': Type.String({ default: '240 3.7% 90%' }), - '--heroui-foreground-200': Type.String({ default: '240 5.26% 80%' }), - '--heroui-foreground-300': Type.String({ default: '240 5.2% 70%' }), - '--heroui-foreground-400': Type.String({ default: '240 3.83% 60%' }), - '--heroui-foreground-500': Type.String({ default: '240 5.03% 50%' }), - '--heroui-foreground-600': Type.String({ default: '240 4.88% 40%' }), - '--heroui-foreground-700': Type.String({ default: '240 5.88% 30%' }), - '--heroui-foreground-800': Type.String({ default: '240 4.76% 20%' }), - '--heroui-foreground-900': Type.String({ default: '0 0% 10%' }), - '--heroui-foreground': Type.String({ default: '210 5.56% 7.06%' }), - '--heroui-focus': Type.String({ default: '212.01999999999998 100% 53.33%' }), - '--heroui-overlay': Type.String({ default: '0 0% 100%' }), - '--heroui-divider': Type.String({ default: '0 0% 0%' }), - '--heroui-divider-opacity': Type.String({ default: '0.85' }), - '--heroui-content1': Type.String({ default: '240 5.88% 95%' }), - '--heroui-content1-foreground': Type.String({ default: '0 0% 10%' }), - '--heroui-content2': Type.String({ default: '240 3.7% 90%' }), - '--heroui-content2-foreground': Type.String({ default: '240 4.76% 20%' }), - '--heroui-content3': Type.String({ default: '240 5.26% 80%' }), - '--heroui-content3-foreground': Type.String({ default: '240 5.88% 30%' }), - '--heroui-content4': Type.String({ default: '240 5.2% 70%' }), - '--heroui-content4-foreground': Type.String({ default: '240 4.88% 40%' }), - '--heroui-default-50': Type.String({ default: '240 5.88% 95%' }), - '--heroui-default-100': Type.String({ default: '240 3.7% 90%' }), - '--heroui-default-200': Type.String({ default: '240 5.26% 80%' }), - '--heroui-default-300': Type.String({ default: '240 5.2% 70%' }), - '--heroui-default-400': Type.String({ default: '240 3.83% 60%' }), - '--heroui-default-500': Type.String({ default: '240 5.03% 50%' }), - '--heroui-default-600': Type.String({ default: '240 4.88% 40%' }), - '--heroui-default-700': Type.String({ default: '240 5.88% 30%' }), - '--heroui-default-800': Type.String({ default: '240 4.76% 20%' }), - '--heroui-default-900': Type.String({ default: '0 0% 10%' }), - '--heroui-default-foreground': Type.String({ default: '0 0% 0%' }), - '--heroui-default': Type.String({ default: '240 5.26% 80%' }), - '--heroui-danger-50': Type.String({ default: '324 90.91% 95.69%' }), - '--heroui-danger-100': Type.String({ default: '350.53 90.48% 91.76%' }), - '--heroui-danger-200': Type.String({ default: '343.42 90.48% 83.53%' }), - '--heroui-danger-300': Type.String({ default: '337.84 83.46% 73.92%' }), - '--heroui-danger-400': Type.String({ default: '331.82 75% 65.49%' }), - '--heroui-danger-500': Type.String({ default: '325.82 69.62% 53.53%' }), - '--heroui-danger-600': Type.String({ default: '319.73 65.64% 44.51%' }), - '--heroui-danger-700': Type.String({ default: '313.85 70.65% 36.08%' }), - '--heroui-danger-800': Type.String({ default: '308.18 76.39% 28.24%' }), - '--heroui-danger-900': Type.String({ default: '301.89 82.61% 22.55%' }), - '--heroui-danger-foreground': Type.String({ default: '0 0% 100%' }), - '--heroui-danger': Type.String({ default: '325.82 69.62% 53.53%' }), - '--heroui-primary-50': Type.String({ default: '339.13 92% 95.1%' }), - '--heroui-primary-100': Type.String({ default: '340 91.84% 90.39%' }), - '--heroui-primary-200': Type.String({ default: '339.33 90% 80.39%' }), - '--heroui-primary-300': Type.String({ default: '339.11 90.6% 70.78%' }), - '--heroui-primary-400': Type.String({ default: '339 90% 60.78%' }), - '--heroui-primary-500': Type.String({ default: '339.2 90.36% 51.18%' }), - '--heroui-primary-600': Type.String({ default: '339 86.54% 40.78%' }), - '--heroui-primary-700': Type.String({ default: '339.11 85.99% 30.78%' }), - '--heroui-primary-800': Type.String({ default: '339.33 86.54% 20.39%' }), - '--heroui-primary-900': Type.String({ default: '340 84.91% 10.39%' }), - '--heroui-primary-foreground': Type.String({ default: '0 0% 100%' }), - '--heroui-primary': Type.String({ default: '339.2 90.36% 51.18%' }), - // 新增 secondary - '--heroui-secondary-50': Type.String({ default: '270 61.54% 94.9%' }), - '--heroui-secondary-100': Type.String({ default: '270 59.26% 89.41%' }), - '--heroui-secondary-200': Type.String({ default: '270 59.26% 78.82%' }), - '--heroui-secondary-300': Type.String({ default: '270 59.26% 68.24%' }), - '--heroui-secondary-400': Type.String({ default: '270 59.26% 57.65%' }), - '--heroui-secondary-500': Type.String({ default: '270 66.67% 47.06%' }), - '--heroui-secondary-600': Type.String({ default: '270 66.67% 37.65%' }), - '--heroui-secondary-700': Type.String({ default: '270 66.67% 28.24%' }), - '--heroui-secondary-800': Type.String({ default: '270 66.67% 18.82%' }), - '--heroui-secondary-900': Type.String({ default: '270 66.67% 9.41%' }), - '--heroui-secondary-foreground': Type.String({ default: '0 0% 100%' }), - '--heroui-secondary': Type.String({ default: '270 66.67% 47.06%' }), - // 新增 success - '--heroui-success-50': Type.String({ default: '146.67 64.29% 94.51%' }), - '--heroui-success-100': Type.String({ default: '145.71 61.4% 88.82%' }), - '--heroui-success-200': Type.String({ default: '146.2 61.74% 77.45%' }), - '--heroui-success-300': Type.String({ default: '145.79 62.57% 66.47%' }), - '--heroui-success-400': Type.String({ default: '146.01 62.45% 55.1%' }), - '--heroui-success-500': Type.String({ default: '145.96 79.46% 43.92%' }), - '--heroui-success-600': Type.String({ default: '146.01 79.89% 35.1%' }), - '--heroui-success-700': Type.String({ default: '145.79 79.26% 26.47%' }), - '--heroui-success-800': Type.String({ default: '146.2 79.78% 17.45%' }), - '--heroui-success-900': Type.String({ default: '145.71 77.78% 8.82%' }), - '--heroui-success-foreground': Type.String({ default: '0 0% 0%' }), - '--heroui-success': Type.String({ default: '145.96 79.46% 43.92%' }), - // 新增 warning - '--heroui-warning-50': Type.String({ default: '54.55 91.67% 95.29%' }), - '--heroui-warning-100': Type.String({ default: '37.14 91.3% 90.98%' }), - '--heroui-warning-200': Type.String({ default: '37.14 91.3% 81.96%' }), - '--heroui-warning-300': Type.String({ default: '36.96 91.24% 73.14%' }), - '--heroui-warning-400': Type.String({ default: '37.01 91.26% 64.12%' }), - '--heroui-warning-500': Type.String({ default: '37.03 91.27% 55.1%' }), - '--heroui-warning-600': Type.String({ default: '37.01 74.22% 44.12%' }), - '--heroui-warning-700': Type.String({ default: '36.96 73.96% 33.14%' }), - '--heroui-warning-800': Type.String({ default: '37.14 75% 21.96%' }), - '--heroui-warning-900': Type.String({ default: '37.14 75% 10.98%' }), - '--heroui-warning-foreground': Type.String({ default: '0 0% 0%' }), - '--heroui-warning': Type.String({ default: '37.03 91.27% 55.1%' }), - // 其它配置 - '--heroui-code-background': Type.String({ default: '221.25 17.39% 18.04%' }), - '--heroui-strong': Type.String({ default: '316.95 100% 65.29%' }), - '--heroui-code-mdx': Type.String({ default: '316.95 100% 65.29%' }), - '--heroui-divider-weight': Type.String({ default: '1px' }), - '--heroui-disabled-opacity': Type.String({ default: '.5' }), - '--heroui-font-size-tiny': Type.String({ default: '0.75rem' }), - '--heroui-font-size-small': Type.String({ default: '0.875rem' }), - '--heroui-font-size-medium': Type.String({ default: '1rem' }), - '--heroui-font-size-large': Type.String({ default: '1.125rem' }), - '--heroui-line-height-tiny': Type.String({ default: '1rem' }), - '--heroui-line-height-small': Type.String({ default: '1.25rem' }), - '--heroui-line-height-medium': Type.String({ default: '1.5rem' }), - '--heroui-line-height-large': Type.String({ default: '1.75rem' }), - '--heroui-radius-small': Type.String({ default: '8px' }), - '--heroui-radius-medium': Type.String({ default: '12px' }), - '--heroui-radius-large': Type.String({ default: '14px' }), - '--heroui-border-width-small': Type.String({ default: '1px' }), - '--heroui-border-width-medium': Type.String({ default: '2px' }), - '--heroui-border-width-large': Type.String({ default: '3px' }), - '--heroui-box-shadow-small': Type.String({ - default: - '0px 0px 5px 0px rgba(0, 0, 0, .02), 0px 2px 10px 0px rgba(0, 0, 0, .06), 0px 0px 1px 0px rgba(0, 0, 0, .3)', - }), - '--heroui-box-shadow-medium': Type.String({ - default: - '0px 0px 15px 0px rgba(0, 0, 0, .03), 0px 2px 30px 0px rgba(0, 0, 0, .08), 0px 0px 1px 0px rgba(0, 0, 0, .3)', - }), - '--heroui-box-shadow-large': Type.String({ - default: - '0px 0px 30px 0px rgba(0, 0, 0, .04), 0px 30px 60px 0px rgba(0, 0, 0, .12), 0px 0px 1px 0px rgba(0, 0, 0, .3)', - }), - '--heroui-hover-opacity': Type.String({ default: '.8' }), - }, - { default: {} } - ), - }, - { default: {} } - ), + theme: themeType, }); export type WebUiConfigType = Static; @@ -352,7 +77,8 @@ export class WebUiConfigWrapper { async UpdateWebUIConfig(newConfig: Partial): Promise { const configPath = resolve(webUiPathWrapper.configPath, './webui.json'); const currentConfig = await this.GetWebUIConfig(); - const updatedConfig = this.validateAndApplyDefaults({ ...currentConfig, ...newConfig }); + const mergedConfig = deepMerge({ ...currentConfig }, newConfig); + const updatedConfig = this.validateAndApplyDefaults(mergedConfig); await this.writeConfig(configPath, updatedConfig); this.WebUiConfigData = updatedConfig; } @@ -442,12 +168,7 @@ export class WebUiConfigWrapper { // 获取主题内容 async GetTheme(): Promise { const config = await this.GetWebUIConfig(); - if (!config.theme || Object.keys(config.theme).length === 0) { - const defaultConfig = this.validateAndApplyDefaults({}); - config.theme = defaultConfig.theme; - // 更新配置文件中的 theme 字段 - await this.UpdateWebUIConfig({ theme: config.theme }); - } + return config.theme; } diff --git a/src/webui/src/types/theme.ts b/src/webui/src/types/theme.ts new file mode 100644 index 00000000..593eb96c --- /dev/null +++ b/src/webui/src/types/theme.ts @@ -0,0 +1,260 @@ +import { Type } from '@sinclair/typebox'; + +export const themeType = Type.Object( + { + dark: Type.Record(Type.String(), Type.String()), + light: Type.Record(Type.String(), Type.String()), + }, + { + default: { + dark: { + '--heroui-background': '0 0% 0%', + '--heroui-foreground-50': '240 5.88% 10%', + '--heroui-foreground-100': '240 3.7% 15.88%', + '--heroui-foreground-200': '240 5.26% 26.08%', + '--heroui-foreground-300': '240 5.2% 33.92%', + '--heroui-foreground-400': '240 3.83% 46.08%', + '--heroui-foreground-500': '240 5.03% 64.9%', + '--heroui-foreground-600': '240 4.88% 83.92%', + '--heroui-foreground-700': '240 5.88% 90%', + '--heroui-foreground-800': '240 4.76% 95.88%', + '--heroui-foreground-900': '0 0% 98.04%', + '--heroui-foreground': '210 5.56% 92.94%', + '--heroui-focus': '212.01999999999998 100% 46.67%', + '--heroui-overlay': '0 0% 0%', + '--heroui-divider': '0 0% 100%', + '--heroui-divider-opacity': '0.15', + '--heroui-content1': '240 5.88% 10%', + '--heroui-content1-foreground': '0 0% 98.04%', + '--heroui-content2': '240 3.7% 15.88%', + '--heroui-content2-foreground': '240 4.76% 95.88%', + '--heroui-content3': '240 5.26% 26.08%', + '--heroui-content3-foreground': '240 5.88% 90%', + '--heroui-content4': '240 5.2% 33.92%', + '--heroui-content4-foreground': '240 4.88% 83.92%', + '--heroui-default-50': '240 5.88% 10%', + '--heroui-default-100': '240 3.7% 15.88%', + '--heroui-default-200': '240 5.26% 26.08%', + '--heroui-default-300': '240 5.2% 33.92%', + '--heroui-default-400': '240 3.83% 46.08%', + '--heroui-default-500': '240 5.03% 64.9%', + '--heroui-default-600': '240 4.88% 83.92%', + '--heroui-default-700': '240 5.88% 90%', + '--heroui-default-800': '240 4.76% 95.88%', + '--heroui-default-900': '0 0% 98.04%', + '--heroui-default-foreground': '0 0% 100%', + '--heroui-default': '240 5.26% 26.08%', + '--heroui-danger-50': '301.89 82.61% 22.55%', + '--heroui-danger-100': '308.18 76.39% 28.24%', + '--heroui-danger-200': '313.85 70.65% 36.08%', + '--heroui-danger-300': '319.73 65.64% 44.51%', + '--heroui-danger-400': '325.82 69.62% 53.53%', + '--heroui-danger-500': '331.82 75% 65.49%', + '--heroui-danger-600': '337.84 83.46% 73.92%', + '--heroui-danger-700': '343.42 90.48% 83.53%', + '--heroui-danger-800': '350.53 90.48% 91.76%', + '--heroui-danger-900': '324 90.91% 95.69%', + '--heroui-danger-foreground': '0 0% 100%', + '--heroui-danger': '325.82 69.62% 53.53%', + '--heroui-primary-50': '340 84.91% 10.39%', + '--heroui-primary-100': '339.33 86.54% 20.39%', + '--heroui-primary-200': '339.11 85.99% 30.78%', + '--heroui-primary-300': '339 86.54% 40.78%', + '--heroui-primary-400': '339.2 90.36% 51.18%', + '--heroui-primary-500': '339 90% 60.78%', + '--heroui-primary-600': '339.11 90.6% 70.78%', + '--heroui-primary-700': '339.33 90% 80.39%', + '--heroui-primary-800': '340 91.84% 90.39%', + '--heroui-primary-900': '339.13 92% 95.1%', + '--heroui-primary-foreground': '0 0% 100%', + '--heroui-primary': '339.2 90.36% 51.18%', + '--heroui-secondary-50': '270 66.67% 9.41%', + '--heroui-secondary-100': '270 66.67% 18.82%', + '--heroui-secondary-200': '270 66.67% 28.24%', + '--heroui-secondary-300': '270 66.67% 37.65%', + '--heroui-secondary-400': '270 66.67% 47.06%', + '--heroui-secondary-500': '270 59.26% 57.65%', + '--heroui-secondary-600': '270 59.26% 68.24%', + '--heroui-secondary-700': '270 59.26% 78.82%', + '--heroui-secondary-800': '270 59.26% 89.41%', + '--heroui-secondary-900': '270 61.54% 94.9%', + '--heroui-secondary-foreground': '0 0% 100%', + '--heroui-secondary': '270 59.26% 57.65%', + '--heroui-success-50': '145.71 77.78% 8.82%', + '--heroui-success-100': '146.2 79.78% 17.45%', + '--heroui-success-200': '145.79 79.26% 26.47%', + '--heroui-success-300': '146.01 79.89% 35.1%', + '--heroui-success-400': '145.96 79.46% 43.92%', + '--heroui-success-500': '146.01 62.45% 55.1%', + '--heroui-success-600': '145.79 62.57% 66.47%', + '--heroui-success-700': '146.2 61.74% 77.45%', + '--heroui-success-800': '145.71 61.4% 88.82%', + '--heroui-success-900': '146.67 64.29% 94.51%', + '--heroui-success-foreground': '0 0% 0%', + '--heroui-success': '145.96 79.46% 43.92%', + '--heroui-warning-50': '37.14 75% 10.98%', + '--heroui-warning-100': '37.14 75% 21.96%', + '--heroui-warning-200': '36.96 73.96% 33.14%', + '--heroui-warning-300': '37.01 74.22% 44.12%', + '--heroui-warning-400': '37.03 91.27% 55.1%', + '--heroui-warning-500': '37.01 91.26% 64.12%', + '--heroui-warning-600': '36.96 91.24% 73.14%', + '--heroui-warning-700': '37.14 91.3% 81.96%', + '--heroui-warning-800': '37.14 91.3% 90.98%', + '--heroui-warning-900': '54.55 91.67% 95.29%', + '--heroui-warning-foreground': '0 0% 0%', + '--heroui-warning': '37.03 91.27% 55.1%', + '--heroui-code-background': '240 5.56% 7.06%', + '--heroui-strong': '190.14 94.67% 44.12%', + '--heroui-code-mdx': '190.14 94.67% 44.12%', + '--heroui-divider-weight': '1px', + '--heroui-disabled-opacity': '.5', + '--heroui-font-size-tiny': '0.75rem', + '--heroui-font-size-small': '0.875rem', + '--heroui-font-size-medium': '1rem', + '--heroui-font-size-large': '1.125rem', + '--heroui-line-height-tiny': '1rem', + '--heroui-line-height-small': '1.25rem', + '--heroui-line-height-medium': '1.5rem', + '--heroui-line-height-large': '1.75rem', + '--heroui-radius-small': '8px', + '--heroui-radius-medium': '12px', + '--heroui-radius-large': '14px', + '--heroui-border-width-small': '1px', + '--heroui-border-width-medium': '2px', + '--heroui-border-width-large': '3px', + '--heroui-box-shadow-small': + '0px 0px 5px 0px rgba(0, 0, 0, .05), 0px 2px 10px 0px rgba(0, 0, 0, .2), inset 0px 0px 1px 0px hsla(0, 0%, 100%, .15)', + '--heroui-box-shadow-medium': + '0px 0px 15px 0px rgba(0, 0, 0, .06), 0px 2px 30px 0px rgba(0, 0, 0, .22), inset 0px 0px 1px 0px hsla(0, 0%, 100%, .15)', + '--heroui-box-shadow-large': + '0px 0px 30px 0px rgba(0, 0, 0, .07), 0px 30px 60px 0px rgba(0, 0, 0, .26), inset 0px 0px 1px 0px hsla(0, 0%, 100%, .15)', + '--heroui-hover-opacity': '.9', + }, + light: { + '--heroui-background': '0 0% 100%', + '--heroui-foreground-50': '240 5.88% 95%', + '--heroui-foreground-100': '240 3.7% 90%', + '--heroui-foreground-200': '240 5.26% 80%', + '--heroui-foreground-300': '240 5.2% 70%', + '--heroui-foreground-400': '240 3.83% 60%', + '--heroui-foreground-500': '240 5.03% 50%', + '--heroui-foreground-600': '240 4.88% 40%', + '--heroui-foreground-700': '240 5.88% 30%', + '--heroui-foreground-800': '240 4.76% 20%', + '--heroui-foreground-900': '0 0% 10%', + '--heroui-foreground': '210 5.56% 7.06%', + '--heroui-focus': '212.01999999999998 100% 53.33%', + '--heroui-overlay': '0 0% 100%', + '--heroui-divider': '0 0% 0%', + '--heroui-divider-opacity': '0.85', + '--heroui-content1': '240 5.88% 95%', + '--heroui-content1-foreground': '0 0% 10%', + '--heroui-content2': '240 3.7% 90%', + '--heroui-content2-foreground': '240 4.76% 20%', + '--heroui-content3': '240 5.26% 80%', + '--heroui-content3-foreground': '240 5.88% 30%', + '--heroui-content4': '240 5.2% 70%', + '--heroui-content4-foreground': '240 4.88% 40%', + '--heroui-default-50': '240 5.88% 95%', + '--heroui-default-100': '240 3.7% 90%', + '--heroui-default-200': '240 5.26% 80%', + '--heroui-default-300': '240 5.2% 70%', + '--heroui-default-400': '240 3.83% 60%', + '--heroui-default-500': '240 5.03% 50%', + '--heroui-default-600': '240 4.88% 40%', + '--heroui-default-700': '240 5.88% 30%', + '--heroui-default-800': '240 4.76% 20%', + '--heroui-default-900': '0 0% 10%', + '--heroui-default-foreground': '0 0% 0%', + '--heroui-default': '240 5.26% 80%', + '--heroui-danger-50': '324 90.91% 95.69%', + '--heroui-danger-100': '350.53 90.48% 91.76%', + '--heroui-danger-200': '343.42 90.48% 83.53%', + '--heroui-danger-300': '337.84 83.46% 73.92%', + '--heroui-danger-400': '331.82 75% 65.49%', + '--heroui-danger-500': '325.82 69.62% 53.53%', + '--heroui-danger-600': '319.73 65.64% 44.51%', + '--heroui-danger-700': '313.85 70.65% 36.08%', + '--heroui-danger-800': '308.18 76.39% 28.24%', + '--heroui-danger-900': '301.89 82.61% 22.55%', + '--heroui-danger-foreground': '0 0% 100%', + '--heroui-danger': '325.82 69.62% 53.53%', + '--heroui-primary-50': '339.13 92% 95.1%', + '--heroui-primary-100': '340 91.84% 90.39%', + '--heroui-primary-200': '339.33 90% 80.39%', + '--heroui-primary-300': '339.11 90.6% 70.78%', + '--heroui-primary-400': '339 90% 60.78%', + '--heroui-primary-500': '339.2 90.36% 51.18%', + '--heroui-primary-600': '339 86.54% 40.78%', + '--heroui-primary-700': '339.11 85.99% 30.78%', + '--heroui-primary-800': '339.33 86.54% 20.39%', + '--heroui-primary-900': '340 84.91% 10.39%', + '--heroui-primary-foreground': '0 0% 100%', + '--heroui-primary': '339.2 90.36% 51.18%', + '--heroui-secondary-50': '270 61.54% 94.9%', + '--heroui-secondary-100': '270 59.26% 89.41%', + '--heroui-secondary-200': '270 59.26% 78.82%', + '--heroui-secondary-300': '270 59.26% 68.24%', + '--heroui-secondary-400': '270 59.26% 57.65%', + '--heroui-secondary-500': '270 66.67% 47.06%', + '--heroui-secondary-600': '270 66.67% 37.65%', + '--heroui-secondary-700': '270 66.67% 28.24%', + '--heroui-secondary-800': '270 66.67% 18.82%', + '--heroui-secondary-900': '270 66.67% 9.41%', + '--heroui-secondary-foreground': '0 0% 100%', + '--heroui-secondary': '270 66.67% 47.06%', + '--heroui-success-50': '146.67 64.29% 94.51%', + '--heroui-success-100': '145.71 61.4% 88.82%', + '--heroui-success-200': '146.2 61.74% 77.45%', + '--heroui-success-300': '145.79 62.57% 66.47%', + '--heroui-success-400': '146.01 62.45% 55.1%', + '--heroui-success-500': '145.96 79.46% 43.92%', + '--heroui-success-600': '146.01 79.89% 35.1%', + '--heroui-success-700': '145.79 79.26% 26.47%', + '--heroui-success-800': '146.2 79.78% 17.45%', + '--heroui-success-900': '145.71 77.78% 8.82%', + '--heroui-success-foreground': '0 0% 0%', + '--heroui-success': '145.96 79.46% 43.92%', + '--heroui-warning-50': '54.55 91.67% 95.29%', + '--heroui-warning-100': '37.14 91.3% 90.98%', + '--heroui-warning-200': '37.14 91.3% 81.96%', + '--heroui-warning-300': '36.96 91.24% 73.14%', + '--heroui-warning-400': '37.01 91.26% 64.12%', + '--heroui-warning-500': '37.03 91.27% 55.1%', + '--heroui-warning-600': '37.01 74.22% 44.12%', + '--heroui-warning-700': '36.96 73.96% 33.14%', + '--heroui-warning-800': '37.14 75% 21.96%', + '--heroui-warning-900': '37.14 75% 10.98%', + '--heroui-warning-foreground': '0 0% 0%', + '--heroui-warning': '37.03 91.27% 55.1%', + '--heroui-code-background': '221.25 17.39% 18.04%', + '--heroui-strong': '316.95 100% 65.29%', + '--heroui-code-mdx': '316.95 100% 65.29%', + '--heroui-divider-weight': '1px', + '--heroui-disabled-opacity': '.5', + '--heroui-font-size-tiny': '0.75rem', + '--heroui-font-size-small': '0.875rem', + '--heroui-font-size-medium': '1rem', + '--heroui-font-size-large': '1.125rem', + '--heroui-line-height-tiny': '1rem', + '--heroui-line-height-small': '1.25rem', + '--heroui-line-height-medium': '1.5rem', + '--heroui-line-height-large': '1.75rem', + '--heroui-radius-small': '8px', + '--heroui-radius-medium': '12px', + '--heroui-radius-large': '14px', + '--heroui-border-width-small': '1px', + '--heroui-border-width-medium': '2px', + '--heroui-border-width-large': '3px', + '--heroui-box-shadow-small': + '0px 0px 5px 0px rgba(0, 0, 0, .02), 0px 2px 10px 0px rgba(0, 0, 0, .06), 0px 0px 1px 0px rgba(0, 0, 0, .3)', + '--heroui-box-shadow-medium': + '0px 0px 15px 0px rgba(0, 0, 0, .03), 0px 2px 30px 0px rgba(0, 0, 0, .08), 0px 0px 1px 0px rgba(0, 0, 0, .3)', + '--heroui-box-shadow-large': + '0px 0px 30px 0px rgba(0, 0, 0, .04), 0px 30px 60px 0px rgba(0, 0, 0, .12), 0px 0px 1px 0px rgba(0, 0, 0, .3)', + '--heroui-hover-opacity': '.8', + }, + }, + } +); diff --git a/src/webui/src/utils/object.ts b/src/webui/src/utils/object.ts new file mode 100644 index 00000000..e0fe8b55 --- /dev/null +++ b/src/webui/src/utils/object.ts @@ -0,0 +1,22 @@ +export function deepMerge>(target: T, source: Partial): T { + for (const key in source) { + if (Object.prototype.hasOwnProperty.call(source, key)) { + // 如果 source[key] 为 undefined,则跳过(保留 target[key]) + if (source[key] === undefined) { + continue; + } + if ( + target[key] !== undefined && + typeof target[key] === 'object' && + !Array.isArray(target[key]) && + typeof source[key] === 'object' && + !Array.isArray(source[key]) + ) { + target[key] = deepMerge({ ...target[key] }, source[key]!) as T[Extract]; + } else { + target[key] = source[key]! as T[Extract]; + } + } + } + return target; +} From a6a11a70267b92e2fd05a0bbd3ef168408c8a8c2 Mon Sep 17 00:00:00 2001 From: bietiaop <1527109126@qq.com> Date: Sat, 8 Feb 2025 23:38:30 +0800 Subject: [PATCH 06/10] fix --- napcat.webui/index.html | 1 + napcat.webui/src/components/ColorPicker.tsx | 24 ++-- .../src/pages/dashboard/config/index.tsx | 19 ++- .../src/pages/dashboard/config/login.tsx | 11 +- .../src/pages/dashboard/config/theme.tsx | 130 ++++++++++++++++-- napcat.webui/vite.config.ts | 3 +- src/webui/index.ts | 18 +++ 7 files changed, 171 insertions(+), 35 deletions(-) diff --git a/napcat.webui/index.html b/napcat.webui/index.html index 995dfcb2..12511914 100644 --- a/napcat.webui/index.html +++ b/napcat.webui/index.html @@ -13,6 +13,7 @@ content="viewport-fit=cover, width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0" name="viewport" /> + diff --git a/napcat.webui/src/components/ColorPicker.tsx b/napcat.webui/src/components/ColorPicker.tsx index 856ecc11..eb9f423a 100644 --- a/napcat.webui/src/components/ColorPicker.tsx +++ b/napcat.webui/src/components/ColorPicker.tsx @@ -6,32 +6,28 @@ import { ColorResult, SketchPicker } from 'react-color' interface ColorPickerProps { color: string - onChange: (color: string) => void + onChange: (color: ColorResult) => void } const ColorPicker: React.FC = ({ color, onChange }) => { const handleChange = (colorResult: ColorResult) => { - const hsl = colorResult.hsl - const color = `${hsl.h} ${hsl.s}% ${hsl.l}%` - onChange(color) + onChange(colorResult) } return ( - +
- + ) diff --git a/napcat.webui/src/pages/dashboard/config/index.tsx b/napcat.webui/src/pages/dashboard/config/index.tsx index f61748ff..067f6c4d 100644 --- a/napcat.webui/src/pages/dashboard/config/index.tsx +++ b/napcat.webui/src/pages/dashboard/config/index.tsx @@ -1,5 +1,6 @@ import { Card, CardBody } from '@heroui/card' import { Tab, Tabs } from '@heroui/tabs' +import clsx from 'clsx' import { useMediaQuery } from 'react-responsive' import { useNavigate, useSearchParams } from 'react-router-dom' @@ -11,13 +12,25 @@ import WebUIConfigCard from './webui' export interface ConfigPageProps { children?: React.ReactNode + size?: 'sm' | 'md' | 'lg' } -const ConfingPageItem: React.FC = ({ children }) => { +const ConfingPageItem: React.FC = ({ + children, + size = 'md' +}) => { return ( -
{children}
+
+ {children} +
) @@ -71,7 +84,7 @@ export default function ConfigPage() { - + diff --git a/napcat.webui/src/pages/dashboard/config/login.tsx b/napcat.webui/src/pages/dashboard/config/login.tsx index 155170f5..8138408c 100644 --- a/napcat.webui/src/pages/dashboard/config/login.tsx +++ b/napcat.webui/src/pages/dashboard/config/login.tsx @@ -1,6 +1,6 @@ import { Input } from '@heroui/input' import { useRequest } from 'ahooks' -import { useEffect, useState } from 'react' +import { useEffect } from 'react' import { Controller, useForm } from 'react-hook-form' import toast from 'react-hot-toast' @@ -16,7 +16,6 @@ const LoginConfigCard = () => { error: quickLoginError, refreshAsync: refreshQuickLogin } = useRequest(QQManager.getQuickLoginQQ) - const [loading, setLoading] = useState(false) const { control, handleSubmit: handleOnebotSubmit, @@ -36,27 +35,21 @@ const LoginConfigCard = () => { const onSubmit = handleOnebotSubmit((data) => { try { - setLoading(true) QQManager.setQuickLoginQQ(data.quickLoginQQ) toast.success('保存成功') } catch (error) { const msg = (error as Error).message toast.error(`保存失败: ${msg}`) - } finally { - setLoading(false) } }) const onRefresh = async () => { try { - setLoading(true) await refreshQuickLogin() toast.success('刷新成功') } catch (error) { const msg = (error as Error).message toast.error(`刷新失败: ${msg}`) - } finally { - setLoading(false) } } @@ -64,7 +57,7 @@ const LoginConfigCard = () => { reset() }, [quickLoginData]) - if (loading) return + if (quickLoginLoading) return return ( <> diff --git a/napcat.webui/src/pages/dashboard/config/theme.tsx b/napcat.webui/src/pages/dashboard/config/theme.tsx index e62582f2..3116fa78 100644 --- a/napcat.webui/src/pages/dashboard/config/theme.tsx +++ b/napcat.webui/src/pages/dashboard/config/theme.tsx @@ -53,6 +53,10 @@ const ThemeConfigCard = () => { } } + useEffect(() => { + reset() + }, [data]) + if (loading) return if (error) @@ -60,10 +64,115 @@ const ThemeConfigCard = () => {
{error.message}
) + // 将颜色 key 补全为 ThemeConfigItem 中定义的所有颜色相关属性 const colorKeys = [ '--heroui-background', + + '--heroui-foreground-50', + '--heroui-foreground-100', + '--heroui-foreground-200', + '--heroui-foreground-300', + '--heroui-foreground-400', + '--heroui-foreground-500', + '--heroui-foreground-600', + '--heroui-foreground-700', + '--heroui-foreground-800', + '--heroui-foreground-900', + '--heroui-foreground', + + '--heroui-content1', + '--heroui-content1-foreground', + '--heroui-content2', + '--heroui-content2-foreground', + '--heroui-content3', + '--heroui-content3-foreground', + '--heroui-content4', + '--heroui-content4-foreground', + + '--heroui-default-50', + '--heroui-default-100', + '--heroui-default-200', + '--heroui-default-300', + '--heroui-default-400', + '--heroui-default-500', + '--heroui-default-600', + '--heroui-default-700', + '--heroui-default-800', + '--heroui-default-900', + '--heroui-default-foreground', + '--heroui-default', + + '--heroui-danger-50', + '--heroui-danger-100', + '--heroui-danger-200', + '--heroui-danger-300', + '--heroui-danger-400', + '--heroui-danger-500', + '--heroui-danger-600', + '--heroui-danger-700', + '--heroui-danger-800', + '--heroui-danger-900', + '--heroui-danger-foreground', + '--heroui-danger', + + '--heroui-primary-50', + '--heroui-primary-100', + '--heroui-primary-200', + '--heroui-primary-300', + '--heroui-primary-400', + '--heroui-primary-500', + '--heroui-primary-600', + '--heroui-primary-700', + '--heroui-primary-800', + '--heroui-primary-900', + '--heroui-primary-foreground', '--heroui-primary', - '--heroui-danger' + + '--heroui-secondary-50', + '--heroui-secondary-100', + '--heroui-secondary-200', + '--heroui-secondary-300', + '--heroui-secondary-400', + '--heroui-secondary-500', + '--heroui-secondary-600', + '--heroui-secondary-700', + '--heroui-secondary-800', + '--heroui-secondary-900', + '--heroui-secondary-foreground', + '--heroui-secondary', + + '--heroui-success-50', + '--heroui-success-100', + '--heroui-success-200', + '--heroui-success-300', + '--heroui-success-400', + '--heroui-success-500', + '--heroui-success-600', + '--heroui-success-700', + '--heroui-success-800', + '--heroui-success-900', + '--heroui-success-foreground', + '--heroui-success', + + '--heroui-warning-50', + '--heroui-warning-100', + '--heroui-warning-200', + '--heroui-warning-300', + '--heroui-warning-400', + '--heroui-warning-500', + '--heroui-warning-600', + '--heroui-warning-700', + '--heroui-warning-800', + '--heroui-warning-900', + '--heroui-warning-foreground', + '--heroui-warning', + + '--heroui-focus', + '--heroui-overlay', + '--heroui-divider', + '--heroui-code-background', + '--heroui-strong', + '--heroui-code-mdx' ] as const return ( @@ -74,19 +183,24 @@ const ThemeConfigCard = () => {

{mode === 'dark' ? '暗色主题' : '亮色主题'}

{colorKeys.map((key) => ( -
- +
+ { - console.log(value) const hslArray = value?.split(' ') ?? [0, 0, 0] const color = `hsl(${hslArray[0]}, ${hslArray[1]}, ${hslArray[2]})` - return + return ( + { + onChange( + `${result.hsl.h} ${result.hsl.s * 100}% ${result.hsl.l * 100}%` + ) + }} + /> + ) }} />
diff --git a/napcat.webui/vite.config.ts b/napcat.webui/vite.config.ts index 043e0bfa..d9cf306c 100644 --- a/napcat.webui/vite.config.ts +++ b/napcat.webui/vite.config.ts @@ -34,7 +34,8 @@ export default defineConfig(({ mode }) => { ws: true, changeOrigin: true }, - '/api': backendDebugUrl + '/api': backendDebugUrl, + '/files': backendDebugUrl } }, build: { diff --git a/src/webui/index.ts b/src/webui/index.ts index bb4d8949..2e35497f 100644 --- a/src/webui/index.ts +++ b/src/webui/index.ts @@ -81,6 +81,24 @@ export async function InitWebUi(logger: LogWrapper, pathWrapper: NapCatPathWrapp } }); + // 如果是自定义色彩,构建一个css文件 + app.use('/files/theme.css', async (_req, res) => { + const colors = await WebUiConfig.GetTheme(); + // 生成css(分为亮色和暗色,靠class和[data-theme="light"]) + let css = '.dark, [data-theme="dark"] {'; + for (const key in colors.dark) { + css += `--${key}: ${colors.dark[key]};`; + } + css += '}'; + css += '.light, [data-theme="light"] {'; + for (const key in colors.light) { + css += `--${key}: ${colors.light[key]};`; + } + css += '}'; + + res.send(css); + }); + // ------------中间件结束------------ // ------------挂载路由------------ From 96d79cf4951b21ae1948f776405bf419fdba1027 Mon Sep 17 00:00:00 2001 From: bietiaop <1527109126@qq.com> Date: Sat, 8 Feb 2025 23:45:33 +0800 Subject: [PATCH 07/10] fix --- napcat.webui/index.html | 1 - napcat.webui/src/main.tsx | 5 +++++ src/webui/index.ts | 4 ++-- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/napcat.webui/index.html b/napcat.webui/index.html index 12511914..995dfcb2 100644 --- a/napcat.webui/index.html +++ b/napcat.webui/index.html @@ -13,7 +13,6 @@ content="viewport-fit=cover, width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0" name="viewport" /> - diff --git a/napcat.webui/src/main.tsx b/napcat.webui/src/main.tsx index 0a549a81..ed4dfb93 100644 --- a/napcat.webui/src/main.tsx +++ b/napcat.webui/src/main.tsx @@ -22,6 +22,11 @@ if (theme && !theme.startsWith('"')) { localStorage.setItem(key.theme, JSON.stringify(theme)) } +const themeStyle = document.createElement('link') +themeStyle.rel = 'stylesheet' +themeStyle.href = '/files/theme.css' +document.head.appendChild(themeStyle) + ReactDOM.createRoot(document.getElementById('root')!).render( // diff --git a/src/webui/index.ts b/src/webui/index.ts index 2e35497f..a2e5c415 100644 --- a/src/webui/index.ts +++ b/src/webui/index.ts @@ -87,12 +87,12 @@ export async function InitWebUi(logger: LogWrapper, pathWrapper: NapCatPathWrapp // 生成css(分为亮色和暗色,靠class和[data-theme="light"]) let css = '.dark, [data-theme="dark"] {'; for (const key in colors.dark) { - css += `--${key}: ${colors.dark[key]};`; + css += `${key}: ${colors.dark[key]};`; } css += '}'; css += '.light, [data-theme="light"] {'; for (const key in colors.light) { - css += `--${key}: ${colors.light[key]};`; + css += `${key}: ${colors.light[key]};`; } css += '}'; From 1702f429b484170d4e31f194b68e434d990e5ca3 Mon Sep 17 00:00:00 2001 From: bietiaop <1527109126@qq.com> Date: Sun, 9 Feb 2025 00:17:49 +0800 Subject: [PATCH 08/10] fix --- napcat.webui/src/main.tsx | 6 ++---- napcat.webui/src/pages/dashboard/config/login.tsx | 4 ++-- .../src/pages/dashboard/config/onebot.tsx | 4 ++-- napcat.webui/src/pages/dashboard/config/theme.tsx | 7 +++++-- napcat.webui/src/utils/theme.ts | 15 +++++++++++++++ 5 files changed, 26 insertions(+), 10 deletions(-) create mode 100644 napcat.webui/src/utils/theme.ts diff --git a/napcat.webui/src/main.tsx b/napcat.webui/src/main.tsx index ed4dfb93..0b9c4f9c 100644 --- a/napcat.webui/src/main.tsx +++ b/napcat.webui/src/main.tsx @@ -8,6 +8,7 @@ import '@/styles/globals.css' import key from './const/key' import WebUIManager from './controllers/webui_manager' +import { loadTheme } from './utils/theme' WebUIManager.checkWebUiLogined() @@ -22,10 +23,7 @@ if (theme && !theme.startsWith('"')) { localStorage.setItem(key.theme, JSON.stringify(theme)) } -const themeStyle = document.createElement('link') -themeStyle.rel = 'stylesheet' -themeStyle.href = '/files/theme.css' -document.head.appendChild(themeStyle) +loadTheme() ReactDOM.createRoot(document.getElementById('root')!).render( // diff --git a/napcat.webui/src/pages/dashboard/config/login.tsx b/napcat.webui/src/pages/dashboard/config/login.tsx index 8138408c..0dc8e4a0 100644 --- a/napcat.webui/src/pages/dashboard/config/login.tsx +++ b/napcat.webui/src/pages/dashboard/config/login.tsx @@ -33,9 +33,9 @@ const LoginConfigCard = () => { setOnebotValue('quickLoginQQ', quickLoginData ?? '') } - const onSubmit = handleOnebotSubmit((data) => { + const onSubmit = handleOnebotSubmit(async (data) => { try { - QQManager.setQuickLoginQQ(data.quickLoginQQ) + await QQManager.setQuickLoginQQ(data.quickLoginQQ) toast.success('保存成功') } catch (error) { const msg = (error as Error).message diff --git a/napcat.webui/src/pages/dashboard/config/onebot.tsx b/napcat.webui/src/pages/dashboard/config/onebot.tsx index 1155db0e..8311b617 100644 --- a/napcat.webui/src/pages/dashboard/config/onebot.tsx +++ b/napcat.webui/src/pages/dashboard/config/onebot.tsx @@ -30,9 +30,9 @@ const OneBotConfigCard = () => { setOnebotValue('parseMultMsg', config.parseMultMsg) } - const onSubmit = handleOnebotSubmit((data) => { + const onSubmit = handleOnebotSubmit(async (data) => { try { - saveConfigWithoutNetwork(data) + await saveConfigWithoutNetwork(data) toast.success('保存成功') } catch (error) { const msg = (error as Error).message diff --git a/napcat.webui/src/pages/dashboard/config/theme.tsx b/napcat.webui/src/pages/dashboard/config/theme.tsx index 3116fa78..2806f8b2 100644 --- a/napcat.webui/src/pages/dashboard/config/theme.tsx +++ b/napcat.webui/src/pages/dashboard/config/theme.tsx @@ -7,6 +7,8 @@ import ColorPicker from '@/components/ColorPicker' import SaveButtons from '@/components/button/save_buttons' import PageLoading from '@/components/page_loading' +import { loadTheme } from '@/utils/theme' + import WebUIManager from '@/controllers/webui_manager' const ThemeConfigCard = () => { @@ -33,10 +35,11 @@ const ThemeConfigCard = () => { if (data) setOnebotValue('theme', data) } - const onSubmit = handleOnebotSubmit((data) => { + const onSubmit = handleOnebotSubmit(async (data) => { try { - WebUIManager.setThemeConfig(data.theme) + await WebUIManager.setThemeConfig(data.theme) toast.success('保存成功') + loadTheme() } catch (error) { const msg = (error as Error).message toast.error(`保存失败: ${msg}`) diff --git a/napcat.webui/src/utils/theme.ts b/napcat.webui/src/utils/theme.ts new file mode 100644 index 00000000..dafe4516 --- /dev/null +++ b/napcat.webui/src/utils/theme.ts @@ -0,0 +1,15 @@ +import { request } from './request' + +const style = document.createElement('style') +document.head.appendChild(style) + +export function loadTheme() { + request('/files/theme.css?_t=' + Date.now()) + .then((res) => res.data) + .then((css) => { + style.innerHTML = css + }) + .catch(() => { + console.error('Failed to load theme.css') + }) +} From 024a3eb760800dc67414e3ad037c5697fee4f243 Mon Sep 17 00:00:00 2001 From: bietiaop <1527109126@qq.com> Date: Sun, 9 Feb 2025 00:18:14 +0800 Subject: [PATCH 09/10] fix --- src/webui/index.ts | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/webui/index.ts b/src/webui/index.ts index a2e5c415..a4eae968 100644 --- a/src/webui/index.ts +++ b/src/webui/index.ts @@ -84,17 +84,17 @@ export async function InitWebUi(logger: LogWrapper, pathWrapper: NapCatPathWrapp // 如果是自定义色彩,构建一个css文件 app.use('/files/theme.css', async (_req, res) => { const colors = await WebUiConfig.GetTheme(); - // 生成css(分为亮色和暗色,靠class和[data-theme="light"]) - let css = '.dark, [data-theme="dark"] {'; - for (const key in colors.dark) { - css += `${key}: ${colors.dark[key]};`; - } - css += '}'; - css += '.light, [data-theme="light"] {'; + + let css = ':root, .light, [data-theme="light"] {'; for (const key in colors.light) { css += `${key}: ${colors.light[key]};`; } css += '}'; + css += '.dark, [data-theme="dark"] {'; + for (const key in colors.dark) { + css += `${key}: ${colors.dark[key]};`; + } + css += '}'; res.send(css); }); From 7ce04cf78109665015a8131ab535ab2cf64f4534 Mon Sep 17 00:00:00 2001 From: bietiaop <1527109126@qq.com> Date: Sun, 9 Feb 2025 00:47:00 +0800 Subject: [PATCH 10/10] final --- napcat.webui/package.json | 1 + napcat.webui/src/components/sidebar/menus.tsx | 5 +- napcat.webui/src/const/themes.ts | 5 + napcat.webui/src/const/themes/nc_pink.ts | 258 ++++++++++++++ .../src/pages/dashboard/config/theme.tsx | 330 ++++++++++-------- napcat.webui/src/types/theme.d.ts | 8 + 6 files changed, 461 insertions(+), 146 deletions(-) create mode 100644 napcat.webui/src/const/themes.ts create mode 100644 napcat.webui/src/const/themes/nc_pink.ts create mode 100644 napcat.webui/src/types/theme.d.ts diff --git a/napcat.webui/package.json b/napcat.webui/package.json index 9a73049a..bd3c4239 100644 --- a/napcat.webui/package.json +++ b/napcat.webui/package.json @@ -13,6 +13,7 @@ "@dnd-kit/core": "^6.3.1", "@dnd-kit/sortable": "^10.0.0", "@dnd-kit/utilities": "^3.2.2", + "@heroui/accordion": "^2.2.8", "@heroui/avatar": "2.2.7", "@heroui/breadcrumbs": "2.2.7", "@heroui/button": "2.2.10", diff --git a/napcat.webui/src/components/sidebar/menus.tsx b/napcat.webui/src/components/sidebar/menus.tsx index 1cf1f645..79f6b08e 100644 --- a/napcat.webui/src/components/sidebar/menus.tsx +++ b/napcat.webui/src/components/sidebar/menus.tsx @@ -58,14 +58,13 @@ const renderItems = (items: MenuItem[], children = false) => { color="primary" endContent={ canOpen ? ( - // div实现箭头V效果
{ 'w-3 h-1.5 rounded-full ml-auto shadow-lg', isActive ? 'bg-primary-500 animate-spinner-ease-spin' - : 'bg-red-300 dark:bg-white' + : 'bg-primary-200 dark:bg-white' )} /> ) diff --git a/napcat.webui/src/const/themes.ts b/napcat.webui/src/const/themes.ts new file mode 100644 index 00000000..781ce351 --- /dev/null +++ b/napcat.webui/src/const/themes.ts @@ -0,0 +1,5 @@ +import nc_pink from './themes/nc_pink' + +const themes: ThemeInfo[] = [nc_pink] + +export default themes diff --git a/napcat.webui/src/const/themes/nc_pink.ts b/napcat.webui/src/const/themes/nc_pink.ts new file mode 100644 index 00000000..69fdec60 --- /dev/null +++ b/napcat.webui/src/const/themes/nc_pink.ts @@ -0,0 +1,258 @@ +const theme: ThemeConfig = { + dark: { + '--heroui-background': '0 0% 0%', + '--heroui-foreground-50': '240 5.88% 10%', + '--heroui-foreground-100': '240 3.7% 15.88%', + '--heroui-foreground-200': '240 5.26% 26.08%', + '--heroui-foreground-300': '240 5.2% 33.92%', + '--heroui-foreground-400': '240 3.83% 46.08%', + '--heroui-foreground-500': '240 5.03% 64.9%', + '--heroui-foreground-600': '240 4.88% 83.92%', + '--heroui-foreground-700': '240 5.88% 90%', + '--heroui-foreground-800': '240 4.76% 95.88%', + '--heroui-foreground-900': '0 0% 98.04%', + '--heroui-foreground': '210 5.56% 92.94%', + '--heroui-focus': '212.01999999999998 100% 46.67%', + '--heroui-overlay': '0 0% 0%', + '--heroui-divider': '0 0% 100%', + '--heroui-divider-opacity': '0.15', + '--heroui-content1': '240 5.88% 10%', + '--heroui-content1-foreground': '0 0% 98.04%', + '--heroui-content2': '240 3.7% 15.88%', + '--heroui-content2-foreground': '240 4.76% 95.88%', + '--heroui-content3': '240 5.26% 26.08%', + '--heroui-content3-foreground': '240 5.88% 90%', + '--heroui-content4': '240 5.2% 33.92%', + '--heroui-content4-foreground': '240 4.88% 83.92%', + '--heroui-default-50': '240 5.88% 10%', + '--heroui-default-100': '240 3.7% 15.88%', + '--heroui-default-200': '240 5.26% 26.08%', + '--heroui-default-300': '240 5.2% 33.92%', + '--heroui-default-400': '240 3.83% 46.08%', + '--heroui-default-500': '240 5.03% 64.9%', + '--heroui-default-600': '240 4.88% 83.92%', + '--heroui-default-700': '240 5.88% 90%', + '--heroui-default-800': '240 4.76% 95.88%', + '--heroui-default-900': '0 0% 98.04%', + '--heroui-default-foreground': '0 0% 100%', + '--heroui-default': '240 5.26% 26.08%', + '--heroui-danger-50': '301.89 82.61% 22.55%', + '--heroui-danger-100': '308.18 76.39% 28.24%', + '--heroui-danger-200': '313.85 70.65% 36.08%', + '--heroui-danger-300': '319.73 65.64% 44.51%', + '--heroui-danger-400': '325.82 69.62% 53.53%', + '--heroui-danger-500': '331.82 75% 65.49%', + '--heroui-danger-600': '337.84 83.46% 73.92%', + '--heroui-danger-700': '343.42 90.48% 83.53%', + '--heroui-danger-800': '350.53 90.48% 91.76%', + '--heroui-danger-900': '324 90.91% 95.69%', + '--heroui-danger-foreground': '0 0% 100%', + '--heroui-danger': '325.82 69.62% 53.53%', + '--heroui-primary-50': '340 84.91% 10.39%', + '--heroui-primary-100': '339.33 86.54% 20.39%', + '--heroui-primary-200': '339.11 85.99% 30.78%', + '--heroui-primary-300': '339 86.54% 40.78%', + '--heroui-primary-400': '339.2 90.36% 51.18%', + '--heroui-primary-500': '339 90% 60.78%', + '--heroui-primary-600': '339.11 90.6% 70.78%', + '--heroui-primary-700': '339.33 90% 80.39%', + '--heroui-primary-800': '340 91.84% 90.39%', + '--heroui-primary-900': '339.13 92% 95.1%', + '--heroui-primary-foreground': '0 0% 100%', + '--heroui-primary': '339.2 90.36% 51.18%', + '--heroui-secondary-50': '270 66.67% 9.41%', + '--heroui-secondary-100': '270 66.67% 18.82%', + '--heroui-secondary-200': '270 66.67% 28.24%', + '--heroui-secondary-300': '270 66.67% 37.65%', + '--heroui-secondary-400': '270 66.67% 47.06%', + '--heroui-secondary-500': '270 59.26% 57.65%', + '--heroui-secondary-600': '270 59.26% 68.24%', + '--heroui-secondary-700': '270 59.26% 78.82%', + '--heroui-secondary-800': '270 59.26% 89.41%', + '--heroui-secondary-900': '270 61.54% 94.9%', + '--heroui-secondary-foreground': '0 0% 100%', + '--heroui-secondary': '270 59.26% 57.65%', + '--heroui-success-50': '145.71 77.78% 8.82%', + '--heroui-success-100': '146.2 79.78% 17.45%', + '--heroui-success-200': '145.79 79.26% 26.47%', + '--heroui-success-300': '146.01 79.89% 35.1%', + '--heroui-success-400': '145.96 79.46% 43.92%', + '--heroui-success-500': '146.01 62.45% 55.1%', + '--heroui-success-600': '145.79 62.57% 66.47%', + '--heroui-success-700': '146.2 61.74% 77.45%', + '--heroui-success-800': '145.71 61.4% 88.82%', + '--heroui-success-900': '146.67 64.29% 94.51%', + '--heroui-success-foreground': '0 0% 0%', + '--heroui-success': '145.96 79.46% 43.92%', + '--heroui-warning-50': '37.14 75% 10.98%', + '--heroui-warning-100': '37.14 75% 21.96%', + '--heroui-warning-200': '36.96 73.96% 33.14%', + '--heroui-warning-300': '37.01 74.22% 44.12%', + '--heroui-warning-400': '37.03 91.27% 55.1%', + '--heroui-warning-500': '37.01 91.26% 64.12%', + '--heroui-warning-600': '36.96 91.24% 73.14%', + '--heroui-warning-700': '37.14 91.3% 81.96%', + '--heroui-warning-800': '37.14 91.3% 90.98%', + '--heroui-warning-900': '54.55 91.67% 95.29%', + '--heroui-warning-foreground': '0 0% 0%', + '--heroui-warning': '37.03 91.27% 55.1%', + '--heroui-code-background': '240 5.56% 7.06%', + '--heroui-strong': '190.14 94.67% 44.12%', + '--heroui-code-mdx': '190.14 94.67% 44.12%', + '--heroui-divider-weight': '1px', + '--heroui-disabled-opacity': '.5', + '--heroui-font-size-tiny': '0.75rem', + '--heroui-font-size-small': '0.875rem', + '--heroui-font-size-medium': '1rem', + '--heroui-font-size-large': '1.125rem', + '--heroui-line-height-tiny': '1rem', + '--heroui-line-height-small': '1.25rem', + '--heroui-line-height-medium': '1.5rem', + '--heroui-line-height-large': '1.75rem', + '--heroui-radius-small': '8px', + '--heroui-radius-medium': '12px', + '--heroui-radius-large': '14px', + '--heroui-border-width-small': '1px', + '--heroui-border-width-medium': '2px', + '--heroui-border-width-large': '3px', + '--heroui-box-shadow-small': + '0px 0px 5px 0px rgba(0, 0, 0, .05), 0px 2px 10px 0px rgba(0, 0, 0, .2), inset 0px 0px 1px 0px hsla(0, 0%, 100%, .15)', + '--heroui-box-shadow-medium': + '0px 0px 15px 0px rgba(0, 0, 0, .06), 0px 2px 30px 0px rgba(0, 0, 0, .22), inset 0px 0px 1px 0px hsla(0, 0%, 100%, .15)', + '--heroui-box-shadow-large': + '0px 0px 30px 0px rgba(0, 0, 0, .07), 0px 30px 60px 0px rgba(0, 0, 0, .26), inset 0px 0px 1px 0px hsla(0, 0%, 100%, .15)', + '--heroui-hover-opacity': '.9' + }, + light: { + '--heroui-background': '0 0% 100%', + '--heroui-foreground-50': '240 5.88% 95%', + '--heroui-foreground-100': '240 3.7% 90%', + '--heroui-foreground-200': '240 5.26% 80%', + '--heroui-foreground-300': '240 5.2% 70%', + '--heroui-foreground-400': '240 3.83% 60%', + '--heroui-foreground-500': '240 5.03% 50%', + '--heroui-foreground-600': '240 4.88% 40%', + '--heroui-foreground-700': '240 5.88% 30%', + '--heroui-foreground-800': '240 4.76% 20%', + '--heroui-foreground-900': '0 0% 10%', + '--heroui-foreground': '210 5.56% 7.06%', + '--heroui-focus': '212.01999999999998 100% 53.33%', + '--heroui-overlay': '0 0% 100%', + '--heroui-divider': '0 0% 0%', + '--heroui-divider-opacity': '0.85', + '--heroui-content1': '240 5.88% 95%', + '--heroui-content1-foreground': '0 0% 10%', + '--heroui-content2': '240 3.7% 90%', + '--heroui-content2-foreground': '240 4.76% 20%', + '--heroui-content3': '240 5.26% 80%', + '--heroui-content3-foreground': '240 5.88% 30%', + '--heroui-content4': '240 5.2% 70%', + '--heroui-content4-foreground': '240 4.88% 40%', + '--heroui-default-50': '240 5.88% 95%', + '--heroui-default-100': '240 3.7% 90%', + '--heroui-default-200': '240 5.26% 80%', + '--heroui-default-300': '240 5.2% 70%', + '--heroui-default-400': '240 3.83% 60%', + '--heroui-default-500': '240 5.03% 50%', + '--heroui-default-600': '240 4.88% 40%', + '--heroui-default-700': '240 5.88% 30%', + '--heroui-default-800': '240 4.76% 20%', + '--heroui-default-900': '0 0% 10%', + '--heroui-default-foreground': '0 0% 0%', + '--heroui-default': '240 5.26% 80%', + '--heroui-danger-50': '324 90.91% 95.69%', + '--heroui-danger-100': '350.53 90.48% 91.76%', + '--heroui-danger-200': '343.42 90.48% 83.53%', + '--heroui-danger-300': '337.84 83.46% 73.92%', + '--heroui-danger-400': '331.82 75% 65.49%', + '--heroui-danger-500': '325.82 69.62% 53.53%', + '--heroui-danger-600': '319.73 65.64% 44.51%', + '--heroui-danger-700': '313.85 70.65% 36.08%', + '--heroui-danger-800': '308.18 76.39% 28.24%', + '--heroui-danger-900': '301.89 82.61% 22.55%', + '--heroui-danger-foreground': '0 0% 100%', + '--heroui-danger': '325.82 69.62% 53.53%', + '--heroui-primary-50': '339.13 92% 95.1%', + '--heroui-primary-100': '340 91.84% 90.39%', + '--heroui-primary-200': '339.33 90% 80.39%', + '--heroui-primary-300': '339.11 90.6% 70.78%', + '--heroui-primary-400': '339 90% 60.78%', + '--heroui-primary-500': '339.2 90.36% 51.18%', + '--heroui-primary-600': '339 86.54% 40.78%', + '--heroui-primary-700': '339.11 85.99% 30.78%', + '--heroui-primary-800': '339.33 86.54% 20.39%', + '--heroui-primary-900': '340 84.91% 10.39%', + '--heroui-primary-foreground': '0 0% 100%', + '--heroui-primary': '339.2 90.36% 51.18%', + '--heroui-secondary-50': '270 61.54% 94.9%', + '--heroui-secondary-100': '270 59.26% 89.41%', + '--heroui-secondary-200': '270 59.26% 78.82%', + '--heroui-secondary-300': '270 59.26% 68.24%', + '--heroui-secondary-400': '270 59.26% 57.65%', + '--heroui-secondary-500': '270 66.67% 47.06%', + '--heroui-secondary-600': '270 66.67% 37.65%', + '--heroui-secondary-700': '270 66.67% 28.24%', + '--heroui-secondary-800': '270 66.67% 18.82%', + '--heroui-secondary-900': '270 66.67% 9.41%', + '--heroui-secondary-foreground': '0 0% 100%', + '--heroui-secondary': '270 66.67% 47.06%', + '--heroui-success-50': '146.67 64.29% 94.51%', + '--heroui-success-100': '145.71 61.4% 88.82%', + '--heroui-success-200': '146.2 61.74% 77.45%', + '--heroui-success-300': '145.79 62.57% 66.47%', + '--heroui-success-400': '146.01 62.45% 55.1%', + '--heroui-success-500': '145.96 79.46% 43.92%', + '--heroui-success-600': '146.01 79.89% 35.1%', + '--heroui-success-700': '145.79 79.26% 26.47%', + '--heroui-success-800': '146.2 79.78% 17.45%', + '--heroui-success-900': '145.71 77.78% 8.82%', + '--heroui-success-foreground': '0 0% 0%', + '--heroui-success': '145.96 79.46% 43.92%', + '--heroui-warning-50': '54.55 91.67% 95.29%', + '--heroui-warning-100': '37.14 91.3% 90.98%', + '--heroui-warning-200': '37.14 91.3% 81.96%', + '--heroui-warning-300': '36.96 91.24% 73.14%', + '--heroui-warning-400': '37.01 91.26% 64.12%', + '--heroui-warning-500': '37.03 91.27% 55.1%', + '--heroui-warning-600': '37.01 74.22% 44.12%', + '--heroui-warning-700': '36.96 73.96% 33.14%', + '--heroui-warning-800': '37.14 75% 21.96%', + '--heroui-warning-900': '37.14 75% 10.98%', + '--heroui-warning-foreground': '0 0% 0%', + '--heroui-warning': '37.03 91.27% 55.1%', + '--heroui-code-background': '221.25 17.39% 18.04%', + '--heroui-strong': '316.95 100% 65.29%', + '--heroui-code-mdx': '316.95 100% 65.29%', + '--heroui-divider-weight': '1px', + '--heroui-disabled-opacity': '.5', + '--heroui-font-size-tiny': '0.75rem', + '--heroui-font-size-small': '0.875rem', + '--heroui-font-size-medium': '1rem', + '--heroui-font-size-large': '1.125rem', + '--heroui-line-height-tiny': '1rem', + '--heroui-line-height-small': '1.25rem', + '--heroui-line-height-medium': '1.5rem', + '--heroui-line-height-large': '1.75rem', + '--heroui-radius-small': '8px', + '--heroui-radius-medium': '12px', + '--heroui-radius-large': '14px', + '--heroui-border-width-small': '1px', + '--heroui-border-width-medium': '2px', + '--heroui-border-width-large': '3px', + '--heroui-box-shadow-small': + '0px 0px 5px 0px rgba(0, 0, 0, .02), 0px 2px 10px 0px rgba(0, 0, 0, .06), 0px 0px 1px 0px rgba(0, 0, 0, .3)', + '--heroui-box-shadow-medium': + '0px 0px 15px 0px rgba(0, 0, 0, .03), 0px 2px 30px 0px rgba(0, 0, 0, .08), 0px 0px 1px 0px rgba(0, 0, 0, .3)', + '--heroui-box-shadow-large': + '0px 0px 30px 0px rgba(0, 0, 0, .04), 0px 30px 60px 0px rgba(0, 0, 0, .12), 0px 0px 1px 0px rgba(0, 0, 0, .3)', + '--heroui-hover-opacity': '.8' + } +} +export default { + theme, + author: 'NapCat', + name: 'nc_pink', + bgColor: 'hsl(339.2,90.36%,51.18%)', + textColor: 'hsl(0,0%,100%)', + description: 'NapCat Pink Theme' +} satisfies ThemeInfo diff --git a/napcat.webui/src/pages/dashboard/config/theme.tsx b/napcat.webui/src/pages/dashboard/config/theme.tsx index 2806f8b2..099c78bf 100644 --- a/napcat.webui/src/pages/dashboard/config/theme.tsx +++ b/napcat.webui/src/pages/dashboard/config/theme.tsx @@ -1,8 +1,11 @@ +import { Accordion, AccordionItem } from '@heroui/accordion' import { useRequest } from 'ahooks' import { useEffect } from 'react' import { Controller, useForm } from 'react-hook-form' import toast from 'react-hot-toast' +import themes from '@/const/themes' + import ColorPicker from '@/components/ColorPicker' import SaveButtons from '@/components/button/save_buttons' import PageLoading from '@/components/page_loading' @@ -11,6 +14,117 @@ import { loadTheme } from '@/utils/theme' import WebUIManager from '@/controllers/webui_manager' +// 将颜色 key 补全为 ThemeConfigItem 中定义的所有颜色相关属性 +const colorKeys = [ + '--heroui-background', + + '--heroui-foreground-50', + '--heroui-foreground-100', + '--heroui-foreground-200', + '--heroui-foreground-300', + '--heroui-foreground-400', + '--heroui-foreground-500', + '--heroui-foreground-600', + '--heroui-foreground-700', + '--heroui-foreground-800', + '--heroui-foreground-900', + '--heroui-foreground', + + '--heroui-content1', + '--heroui-content1-foreground', + '--heroui-content2', + '--heroui-content2-foreground', + '--heroui-content3', + '--heroui-content3-foreground', + '--heroui-content4', + '--heroui-content4-foreground', + + '--heroui-default-50', + '--heroui-default-100', + '--heroui-default-200', + '--heroui-default-300', + '--heroui-default-400', + '--heroui-default-500', + '--heroui-default-600', + '--heroui-default-700', + '--heroui-default-800', + '--heroui-default-900', + '--heroui-default-foreground', + '--heroui-default', + + '--heroui-danger-50', + '--heroui-danger-100', + '--heroui-danger-200', + '--heroui-danger-300', + '--heroui-danger-400', + '--heroui-danger-500', + '--heroui-danger-600', + '--heroui-danger-700', + '--heroui-danger-800', + '--heroui-danger-900', + '--heroui-danger-foreground', + '--heroui-danger', + + '--heroui-primary-50', + '--heroui-primary-100', + '--heroui-primary-200', + '--heroui-primary-300', + '--heroui-primary-400', + '--heroui-primary-500', + '--heroui-primary-600', + '--heroui-primary-700', + '--heroui-primary-800', + '--heroui-primary-900', + '--heroui-primary-foreground', + '--heroui-primary', + + '--heroui-secondary-50', + '--heroui-secondary-100', + '--heroui-secondary-200', + '--heroui-secondary-300', + '--heroui-secondary-400', + '--heroui-secondary-500', + '--heroui-secondary-600', + '--heroui-secondary-700', + '--heroui-secondary-800', + '--heroui-secondary-900', + '--heroui-secondary-foreground', + '--heroui-secondary', + + '--heroui-success-50', + '--heroui-success-100', + '--heroui-success-200', + '--heroui-success-300', + '--heroui-success-400', + '--heroui-success-500', + '--heroui-success-600', + '--heroui-success-700', + '--heroui-success-800', + '--heroui-success-900', + '--heroui-success-foreground', + '--heroui-success', + + '--heroui-warning-50', + '--heroui-warning-100', + '--heroui-warning-200', + '--heroui-warning-300', + '--heroui-warning-400', + '--heroui-warning-500', + '--heroui-warning-600', + '--heroui-warning-700', + '--heroui-warning-800', + '--heroui-warning-900', + '--heroui-warning-foreground', + '--heroui-warning', + + '--heroui-focus', + '--heroui-overlay', + '--heroui-divider', + '--heroui-code-background', + '--heroui-strong', + '--heroui-code-mdx' +] as const + const ThemeConfigCard = () => { const { data, loading, error, refreshAsync } = useRequest( WebUIManager.getThemeConfig @@ -67,155 +181,85 @@ const ThemeConfigCard = () => {
{error.message}
) - // 将颜色 key 补全为 ThemeConfigItem 中定义的所有颜色相关属性 - const colorKeys = [ - '--heroui-background', - - '--heroui-foreground-50', - '--heroui-foreground-100', - '--heroui-foreground-200', - '--heroui-foreground-300', - '--heroui-foreground-400', - '--heroui-foreground-500', - '--heroui-foreground-600', - '--heroui-foreground-700', - '--heroui-foreground-800', - '--heroui-foreground-900', - '--heroui-foreground', - - '--heroui-content1', - '--heroui-content1-foreground', - '--heroui-content2', - '--heroui-content2-foreground', - '--heroui-content3', - '--heroui-content3-foreground', - '--heroui-content4', - '--heroui-content4-foreground', - - '--heroui-default-50', - '--heroui-default-100', - '--heroui-default-200', - '--heroui-default-300', - '--heroui-default-400', - '--heroui-default-500', - '--heroui-default-600', - '--heroui-default-700', - '--heroui-default-800', - '--heroui-default-900', - '--heroui-default-foreground', - '--heroui-default', - - '--heroui-danger-50', - '--heroui-danger-100', - '--heroui-danger-200', - '--heroui-danger-300', - '--heroui-danger-400', - '--heroui-danger-500', - '--heroui-danger-600', - '--heroui-danger-700', - '--heroui-danger-800', - '--heroui-danger-900', - '--heroui-danger-foreground', - '--heroui-danger', - - '--heroui-primary-50', - '--heroui-primary-100', - '--heroui-primary-200', - '--heroui-primary-300', - '--heroui-primary-400', - '--heroui-primary-500', - '--heroui-primary-600', - '--heroui-primary-700', - '--heroui-primary-800', - '--heroui-primary-900', - '--heroui-primary-foreground', - '--heroui-primary', - - '--heroui-secondary-50', - '--heroui-secondary-100', - '--heroui-secondary-200', - '--heroui-secondary-300', - '--heroui-secondary-400', - '--heroui-secondary-500', - '--heroui-secondary-600', - '--heroui-secondary-700', - '--heroui-secondary-800', - '--heroui-secondary-900', - '--heroui-secondary-foreground', - '--heroui-secondary', - - '--heroui-success-50', - '--heroui-success-100', - '--heroui-success-200', - '--heroui-success-300', - '--heroui-success-400', - '--heroui-success-500', - '--heroui-success-600', - '--heroui-success-700', - '--heroui-success-800', - '--heroui-success-900', - '--heroui-success-foreground', - '--heroui-success', - - '--heroui-warning-50', - '--heroui-warning-100', - '--heroui-warning-200', - '--heroui-warning-300', - '--heroui-warning-400', - '--heroui-warning-500', - '--heroui-warning-600', - '--heroui-warning-700', - '--heroui-warning-800', - '--heroui-warning-900', - '--heroui-warning-foreground', - '--heroui-warning', - - '--heroui-focus', - '--heroui-overlay', - '--heroui-divider', - '--heroui-code-background', - '--heroui-strong', - '--heroui-code-mdx' - ] as const - return ( <> 主题配置 - NapCat WebUI -
主题配置
- {(['dark', 'light'] as const).map((mode) => ( -
-

{mode === 'dark' ? '暗色主题' : '亮色主题'}

- {colorKeys.map((key) => ( -
- - { - const hslArray = value?.split(' ') ?? [0, 0, 0] - const color = `hsl(${hslArray[0]}, ${hslArray[1]}, ${hslArray[2]})` - return ( - { - onChange( - `${result.hsl.h} ${result.hsl.s * 100}% ${result.hsl.l * 100}%` - ) - }} - /> - ) + + +
+ {themes.map((theme) => ( +
+ onClick={() => { + setOnebotValue('theme', theme.theme) + onSubmit() + }} + > +
{theme.name}
+
{theme.author}
+
+ ))} +
+
+ + + {(['dark', 'light'] as const).map((mode) => ( +
+

{mode === 'dark' ? '暗色主题' : '亮色主题'}

+ {colorKeys.map((key) => ( +
+ + { + const hslArray = value?.split(' ') ?? [0, 0, 0] + const color = `hsl(${hslArray[0]}, ${hslArray[1]}, ${hslArray[2]})` + return ( + { + onChange( + `${result.hsl.h} ${result.hsl.s * 100}% ${result.hsl.l * 100}%` + ) + }} + /> + ) + }} + /> +
+ ))}
))} -
- ))} - + + + + ) } diff --git a/napcat.webui/src/types/theme.d.ts b/napcat.webui/src/types/theme.d.ts new file mode 100644 index 00000000..75a98cb4 --- /dev/null +++ b/napcat.webui/src/types/theme.d.ts @@ -0,0 +1,8 @@ +interface ThemeInfo { + theme: ThemeConfig + name: string + bgColor: string + textColor: string + description?: string + author?: string +}