mirror of
https://github.com/NapNeko/NapCatQQ.git
synced 2026-01-17 13:50:36 +00:00
Refactor font handling and theme config, switch to CodeMirror editor
Replaces Monaco editor with CodeMirror in the frontend, removing related dependencies and configuration. Refactors font management to support multiple formats (woff, woff2, ttf, otf) and dynamic font switching, including backend API and frontend theme config UI. Adds gzip compression middleware to backend. Updates theme config to allow font selection and custom font upload, and improves theme preview and color customization UI. Cleans up unused code and improves sidebar and terminal font sizing responsiveness.
This commit is contained in:
parent
50bcd71144
commit
a34a86288b
@ -126,7 +126,7 @@ export class NapCatCore {
|
|||||||
container.bind(TypedEventEmitter).toConstantValue(this.event);
|
container.bind(TypedEventEmitter).toConstantValue(this.event);
|
||||||
ReceiverServiceRegistry.forEach((ServiceClass, serviceName) => {
|
ReceiverServiceRegistry.forEach((ServiceClass, serviceName) => {
|
||||||
container.bind(ServiceClass).toSelf();
|
container.bind(ServiceClass).toSelf();
|
||||||
console.log(`Registering service handler for: ${serviceName}`);
|
//console.log(`Registering service handler for: ${serviceName}`);
|
||||||
this.context.packetHandler.onCmd(serviceName, ({ seq, hex_data }) => {
|
this.context.packetHandler.onCmd(serviceName, ({ seq, hex_data }) => {
|
||||||
const serviceInstance = container.get(ServiceClass);
|
const serviceInstance = container.get(ServiceClass);
|
||||||
return serviceInstance.handler(seq, hex_data);
|
return serviceInstance.handler(seq, hex_data);
|
||||||
|
|||||||
@ -23,6 +23,13 @@ import { ILogWrapper } from 'napcat-common/src/log-interface';
|
|||||||
import { ISubscription } from 'napcat-common/src/subscription-interface';
|
import { ISubscription } from 'napcat-common/src/subscription-interface';
|
||||||
import { IStatusHelperSubscription } from '@/napcat-common/src/status-interface';
|
import { IStatusHelperSubscription } from '@/napcat-common/src/status-interface';
|
||||||
import { handleDebugWebSocket } from '@/napcat-webui-backend/src/api/Debug';
|
import { handleDebugWebSocket } from '@/napcat-webui-backend/src/api/Debug';
|
||||||
|
import compression from 'compression';
|
||||||
|
import { napCatVersion } from 'napcat-common/src/version';
|
||||||
|
import { fileURLToPath } from 'node:url';
|
||||||
|
import { dirname, resolve } from 'node:path';
|
||||||
|
|
||||||
|
const __filename = fileURLToPath(import.meta.url);
|
||||||
|
const __dirname = dirname(__filename);
|
||||||
// 实例化Express
|
// 实例化Express
|
||||||
const app = express();
|
const app = express();
|
||||||
/**
|
/**
|
||||||
@ -143,18 +150,31 @@ export async function InitWebUi (logger: ILogWrapper, pathWrapper: NapCatPathWra
|
|||||||
// ------------注册中间件------------
|
// ------------注册中间件------------
|
||||||
// 使用express的json中间件
|
// 使用express的json中间件
|
||||||
app.use(express.json());
|
app.use(express.json());
|
||||||
|
// 启用gzip压缩(对所有响应启用,阈值1KB)
|
||||||
|
app.use(compression({
|
||||||
|
level: 6, // 压缩级别 1-9,6 是性能和压缩率的平衡点
|
||||||
|
threshold: 1024, // 只压缩大于 1KB 的响应
|
||||||
|
filter: (req, res) => {
|
||||||
|
// 不压缩 SSE 和 WebSocket 升级请求
|
||||||
|
if (req.headers['accept'] === 'text/event-stream') {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// 使用默认过滤器
|
||||||
|
return compression.filter(req, res);
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
|
||||||
// CORS中间件
|
// CORS中间件
|
||||||
// TODO:
|
// TODO:
|
||||||
app.use(cors);
|
app.use(cors);
|
||||||
|
|
||||||
// 如果是webui字体文件,挂载字体文件
|
// 自定义字体文件路由 - 返回用户上传的字体文件
|
||||||
app.use('/webui/fonts/AaCute.woff', async (_req, res, next) => {
|
app.use('/webui/fonts/CustomFont.woff', async (_req, res) => {
|
||||||
const isFontExist = await WebUiConfig.CheckWebUIFontExist();
|
const fontPath = await WebUiConfig.GetWebUIFontPath();
|
||||||
if (isFontExist) {
|
if (fontPath) {
|
||||||
res.sendFile(WebUiConfig.GetWebUIFontPath());
|
res.sendFile(fontPath);
|
||||||
} else {
|
} else {
|
||||||
next();
|
res.status(404).send('Custom font not found');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -176,6 +196,28 @@ export async function InitWebUi (logger: ILogWrapper, pathWrapper: NapCatPathWra
|
|||||||
res.send(css);
|
res.send(css);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// 动态生成 sw.js
|
||||||
|
app.get('/webui/sw.js', async (_req, res) => {
|
||||||
|
try {
|
||||||
|
// 读取模板文件
|
||||||
|
const templatePath = resolve(__dirname, 'src/assets/sw_template.js');
|
||||||
|
let swContent = readFileSync(templatePath, 'utf-8');
|
||||||
|
|
||||||
|
// 替换版本号
|
||||||
|
// 使用 napCatVersion,如果为 alpha 则尝试加上时间戳或其他标识以避免缓存冲突,或者直接使用
|
||||||
|
// 用户要求控制 sw.js 版本,napCatVersion 是核心控制点
|
||||||
|
swContent = swContent.replace('{{VERSION}}', napCatVersion);
|
||||||
|
|
||||||
|
res.header('Content-Type', 'application/javascript');
|
||||||
|
res.header('Service-Worker-Allowed', '/webui/');
|
||||||
|
res.header('Cache-Control', 'no-cache, no-store, must-revalidate');
|
||||||
|
res.send(swContent);
|
||||||
|
} catch (error) {
|
||||||
|
console.error('[NapCat] [WebUi] Error generating sw.js', error);
|
||||||
|
res.status(500).send('Error generating service worker');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
// ------------中间件结束------------
|
// ------------中间件结束------------
|
||||||
|
|
||||||
// ------------挂载路由------------
|
// ------------挂载路由------------
|
||||||
|
|||||||
@ -20,6 +20,7 @@
|
|||||||
"@sinclair/typebox": "^0.34.38",
|
"@sinclair/typebox": "^0.34.38",
|
||||||
"ajv": "^8.13.0",
|
"ajv": "^8.13.0",
|
||||||
"compressing": "^1.10.3",
|
"compressing": "^1.10.3",
|
||||||
|
"compression": "^1.8.1",
|
||||||
"express": "^5.0.0",
|
"express": "^5.0.0",
|
||||||
"express-rate-limit": "^7.5.0",
|
"express-rate-limit": "^7.5.0",
|
||||||
"json5": "^2.2.3",
|
"json5": "^2.2.3",
|
||||||
@ -29,6 +30,7 @@
|
|||||||
"ws": "^8.18.3"
|
"ws": "^8.18.3"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@types/compression": "^1.8.1",
|
||||||
"@types/express": "^5.0.0",
|
"@types/express": "^5.0.0",
|
||||||
"@types/multer": "^1.4.12",
|
"@types/multer": "^1.4.12",
|
||||||
"@types/node": "^22.0.1",
|
"@types/node": "^22.0.1",
|
||||||
|
|||||||
@ -640,10 +640,10 @@ export const UploadWebUIFontHandler: RequestHandler = async (req, res) => {
|
|||||||
// 删除WebUI字体文件处理方法
|
// 删除WebUI字体文件处理方法
|
||||||
export const DeleteWebUIFontHandler: RequestHandler = async (_req, res) => {
|
export const DeleteWebUIFontHandler: RequestHandler = async (_req, res) => {
|
||||||
try {
|
try {
|
||||||
const fontPath = WebUiConfig.GetWebUIFontPath();
|
const fontPath = await WebUiConfig.GetWebUIFontPath();
|
||||||
const exists = await WebUiConfig.CheckWebUIFontExist();
|
const exists = await WebUiConfig.CheckWebUIFontExist();
|
||||||
|
|
||||||
if (!exists) {
|
if (!exists || !fontPath) {
|
||||||
return sendSuccess(res, true);
|
return sendSuccess(res, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
132
packages/napcat-webui-backend/src/assets/sw_template.js
Normal file
132
packages/napcat-webui-backend/src/assets/sw_template.js
Normal file
@ -0,0 +1,132 @@
|
|||||||
|
const CACHE_NAME = 'napcat-webui-v{{VERSION}}';
|
||||||
|
const ASSETS_TO_CACHE = [
|
||||||
|
'/webui/'
|
||||||
|
];
|
||||||
|
|
||||||
|
// 安装阶段:预缓存核心文件
|
||||||
|
self.addEventListener('install', (event) => {
|
||||||
|
self.skipWaiting(); // 强制立即接管
|
||||||
|
event.waitUntil(
|
||||||
|
caches.open(CACHE_NAME).then((cache) => {
|
||||||
|
// 这里的资源如果加载失败不应该阻断 SW 安装
|
||||||
|
return cache.addAll(ASSETS_TO_CACHE).catch(err => console.warn('Failed to cache core assets', err));
|
||||||
|
})
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
// 激活阶段:清理旧缓存
|
||||||
|
self.addEventListener('activate', (event) => {
|
||||||
|
event.waitUntil(
|
||||||
|
caches.keys().then((cacheNames) => {
|
||||||
|
return Promise.all(
|
||||||
|
cacheNames.map((cacheName) => {
|
||||||
|
if (cacheName.startsWith('napcat-webui-') && cacheName !== CACHE_NAME) {
|
||||||
|
console.log('[SW] Deleting old cache:', cacheName);
|
||||||
|
return caches.delete(cacheName);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
);
|
||||||
|
})
|
||||||
|
);
|
||||||
|
self.clients.claim(); // 立即控制所有客户端
|
||||||
|
});
|
||||||
|
|
||||||
|
// 拦截请求
|
||||||
|
self.addEventListener('fetch', (event) => {
|
||||||
|
const url = new URL(event.request.url);
|
||||||
|
|
||||||
|
// 1. API 请求:仅网络 (Network Only)
|
||||||
|
if (url.pathname.startsWith('/api/') || url.pathname.includes('/socket')) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. 强缓存策略 (Cache First)
|
||||||
|
// - 外部 QQ 头像 (q1.qlogo.cn)
|
||||||
|
// - 静态资源 (assets, fonts)
|
||||||
|
// - 常见静态文件后缀
|
||||||
|
const isQLogo = url.hostname === 'q1.qlogo.cn';
|
||||||
|
const isCustomFont = url.pathname.includes('CustomFont.woff'); // 用户自定义字体,不强缓存
|
||||||
|
const isThemeCss = url.pathname.includes('files/theme.css'); // 主题 CSS,不强缓存
|
||||||
|
const isStaticAsset = url.pathname.includes('/webui/assets/') ||
|
||||||
|
url.pathname.includes('/webui/fonts/');
|
||||||
|
const isStaticFile = /\.(js|css|png|jpg|jpeg|gif|svg|woff|woff2|ttf|eot|ico)$/i.test(url.pathname);
|
||||||
|
|
||||||
|
if (!isCustomFont && !isThemeCss && (isQLogo || isStaticAsset || isStaticFile)) {
|
||||||
|
event.respondWith(
|
||||||
|
caches.match(event.request).then((response) => {
|
||||||
|
if (response) {
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 跨域请求 (qlogo) 需要 mode: 'no-cors' 才能缓存 opaque response,
|
||||||
|
// 但 fetch(event.request) 默认会继承 request 的 mode。
|
||||||
|
// 如果是 img标签发起的请求,通常 mode 是 no-cors 或 cors。
|
||||||
|
// 对于 opaque response (status 0), cache API 允许缓存。
|
||||||
|
return fetch(event.request).then((response) => {
|
||||||
|
// 对 qlogo 允许 status 0 (opaque)
|
||||||
|
// 对其他资源要求 status 200
|
||||||
|
const isValidResponse = response && (
|
||||||
|
response.status === 200 ||
|
||||||
|
response.type === 'basic' ||
|
||||||
|
(isQLogo && response.type === 'opaque')
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!isValidResponse) {
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
|
||||||
|
const responseToCache = response.clone();
|
||||||
|
caches.open(CACHE_NAME).then((cache) => {
|
||||||
|
cache.put(event.request, responseToCache);
|
||||||
|
});
|
||||||
|
return response;
|
||||||
|
});
|
||||||
|
})
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. HTML 页面 / 导航请求 -> 网络优先 (Network First)
|
||||||
|
if (event.request.mode === 'navigate') {
|
||||||
|
event.respondWith(
|
||||||
|
fetch(event.request)
|
||||||
|
.then((response) => {
|
||||||
|
const responseToCache = response.clone();
|
||||||
|
caches.open(CACHE_NAME).then((cache) => {
|
||||||
|
cache.put(event.request, responseToCache);
|
||||||
|
});
|
||||||
|
return response;
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
return caches.match(event.request);
|
||||||
|
})
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4. 其他 Same-Origin 请求 -> Stale-While-Revalidate
|
||||||
|
// 优先返回缓存,同时后台更新缓存,保证下次访问是新的
|
||||||
|
if (url.origin === self.location.origin) {
|
||||||
|
event.respondWith(
|
||||||
|
caches.match(event.request).then((cachedResponse) => {
|
||||||
|
const fetchPromise = fetch(event.request).then((networkResponse) => {
|
||||||
|
if (networkResponse && networkResponse.status === 200) {
|
||||||
|
const responseToCache = networkResponse.clone();
|
||||||
|
caches.open(CACHE_NAME).then((cache) => {
|
||||||
|
cache.put(event.request, responseToCache);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return networkResponse;
|
||||||
|
});
|
||||||
|
// 如果有缓存,返回缓存;否则等待网络
|
||||||
|
return cachedResponse || fetchPromise;
|
||||||
|
})
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 默认:网络优先
|
||||||
|
event.respondWith(
|
||||||
|
fetch(event.request).catch(() => caches.match(event.request))
|
||||||
|
);
|
||||||
|
});
|
||||||
@ -176,17 +176,35 @@ export class WebUiConfigWrapper {
|
|||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
// 判断字体是否存在(webui.woff)
|
// 判断字体是否存在(支持多种格式)
|
||||||
async CheckWebUIFontExist (): Promise<boolean> {
|
async CheckWebUIFontExist (): Promise<boolean> {
|
||||||
const fontsPath = resolve(webUiPathWrapper.configPath, './fonts');
|
const fontPath = await this.GetWebUIFontPath();
|
||||||
|
if (!fontPath) return false;
|
||||||
return await fs
|
return await fs
|
||||||
.access(resolve(fontsPath, './webui.woff'), constants.F_OK)
|
.access(fontPath, constants.F_OK)
|
||||||
.then(() => true)
|
.then(() => true)
|
||||||
.catch(() => false);
|
.catch(() => false);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取webui字体文件路径
|
// 获取webui字体文件路径(支持多种格式)
|
||||||
GetWebUIFontPath (): string {
|
async GetWebUIFontPath (): Promise<string | null> {
|
||||||
|
const fontsPath = resolve(webUiPathWrapper.configPath, './fonts');
|
||||||
|
const extensions = ['.woff', '.woff2', '.ttf', '.otf'];
|
||||||
|
for (const ext of extensions) {
|
||||||
|
const fontPath = resolve(fontsPath, `webui${ext}`);
|
||||||
|
const exists = await fs
|
||||||
|
.access(fontPath, constants.F_OK)
|
||||||
|
.then(() => true)
|
||||||
|
.catch(() => false);
|
||||||
|
if (exists) {
|
||||||
|
return fontPath;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 同步版本,用于 multer 配置
|
||||||
|
GetWebUIFontPathSync (): string {
|
||||||
return resolve(webUiPathWrapper.configPath, './fonts/webui.woff');
|
return resolve(webUiPathWrapper.configPath, './fonts/webui.woff');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -4,9 +4,11 @@ export const themeType = Type.Object(
|
|||||||
{
|
{
|
||||||
dark: Type.Record(Type.String(), Type.String()),
|
dark: Type.Record(Type.String(), Type.String()),
|
||||||
light: Type.Record(Type.String(), Type.String()),
|
light: Type.Record(Type.String(), Type.String()),
|
||||||
|
fontMode: Type.String({ default: 'system' }),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
default: {
|
default: {
|
||||||
|
fontMode: 'system',
|
||||||
dark: {
|
dark: {
|
||||||
'--heroui-background': '0 0% 0%',
|
'--heroui-background': '0 0% 0%',
|
||||||
'--heroui-foreground-50': '240 5.88% 10%',
|
'--heroui-foreground-50': '240 5.88% 10%',
|
||||||
|
|||||||
@ -4,30 +4,51 @@ import fs from 'fs';
|
|||||||
import type { Request, Response } from 'express';
|
import type { Request, Response } from 'express';
|
||||||
import { WebUiConfig } from '@/napcat-webui-backend/index';
|
import { WebUiConfig } from '@/napcat-webui-backend/index';
|
||||||
|
|
||||||
|
// 支持的字体格式
|
||||||
|
const SUPPORTED_FONT_EXTENSIONS = ['.woff', '.woff2', '.ttf', '.otf'];
|
||||||
|
|
||||||
|
// 清理旧的字体文件
|
||||||
|
const cleanOldFontFiles = (fontsPath: string) => {
|
||||||
|
for (const ext of SUPPORTED_FONT_EXTENSIONS) {
|
||||||
|
const fontPath = path.join(fontsPath, `webui${ext}`);
|
||||||
|
try {
|
||||||
|
if (fs.existsSync(fontPath)) {
|
||||||
|
fs.unlinkSync(fontPath);
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
// 忽略删除失败
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
export const webUIFontStorage = multer.diskStorage({
|
export const webUIFontStorage = multer.diskStorage({
|
||||||
destination: (_, __, cb) => {
|
destination: (_, __, cb) => {
|
||||||
try {
|
try {
|
||||||
const fontsPath = path.dirname(WebUiConfig.GetWebUIFontPath());
|
const fontsPath = path.dirname(WebUiConfig.GetWebUIFontPathSync());
|
||||||
// 确保字体目录存在
|
// 确保字体目录存在
|
||||||
fs.mkdirSync(fontsPath, { recursive: true });
|
fs.mkdirSync(fontsPath, { recursive: true });
|
||||||
|
// 清理旧的字体文件
|
||||||
|
cleanOldFontFiles(fontsPath);
|
||||||
cb(null, fontsPath);
|
cb(null, fontsPath);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
// 确保错误信息被正确传递
|
// 确保错误信息被正确传递
|
||||||
cb(new Error(`创建字体目录失败:${(error as Error).message}`), '');
|
cb(new Error(`创建字体目录失败:${(error as Error).message}`), '');
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
filename: (_, __, cb) => {
|
filename: (_, file, cb) => {
|
||||||
// 统一保存为webui.woff
|
// 保留原始扩展名,统一文件名为 webui
|
||||||
cb(null, 'webui.woff');
|
const ext = path.extname(file.originalname).toLowerCase();
|
||||||
|
cb(null, `webui${ext}`);
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
export const webUIFontUpload = multer({
|
export const webUIFontUpload = multer({
|
||||||
storage: webUIFontStorage,
|
storage: webUIFontStorage,
|
||||||
fileFilter: (_, file, cb) => {
|
fileFilter: (_, file, cb) => {
|
||||||
// 再次验证文件类型
|
// 验证文件类型
|
||||||
if (!file.originalname.toLowerCase().endsWith('.woff')) {
|
const ext = path.extname(file.originalname).toLowerCase();
|
||||||
cb(new Error('只支持WOFF格式的字体文件'));
|
if (!SUPPORTED_FONT_EXTENSIONS.includes(ext)) {
|
||||||
|
cb(new Error('只支持 WOFF/WOFF2/TTF/OTF 格式的字体文件'));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
cb(null, true);
|
cb(null, true);
|
||||||
@ -41,8 +62,6 @@ const webUIFontUploader = (req: Request, res: Response) => {
|
|||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
webUIFontUpload(req, res, (error) => {
|
webUIFontUpload(req, res, (error) => {
|
||||||
if (error) {
|
if (error) {
|
||||||
// 错误处理
|
|
||||||
// sendError(res, error.message, true);
|
|
||||||
return reject(error);
|
return reject(error);
|
||||||
}
|
}
|
||||||
return resolve(true);
|
return resolve(true);
|
||||||
|
|||||||
@ -5,13 +5,19 @@
|
|||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "vite --host=0.0.0.0",
|
"dev": "vite --host=0.0.0.0",
|
||||||
"build": "tsc && vite build",
|
"build": "vite build",
|
||||||
|
"build:full": "tsc && vite build",
|
||||||
"fontmin": "node scripts/fontmin.cjs",
|
"fontmin": "node scripts/fontmin.cjs",
|
||||||
"typecheck": "tsc --noEmit",
|
"typecheck": "tsc --noEmit",
|
||||||
"lint": "eslint -c eslint.config.mjs ./src/**/**/*.{ts,tsx} --fix",
|
"lint": "eslint -c eslint.config.mjs ./src/**/**/*.{ts,tsx} --fix",
|
||||||
"preview": "vite preview"
|
"preview": "vite preview"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@codemirror/lang-css": "^6.3.1",
|
||||||
|
"@codemirror/lang-javascript": "^6.2.4",
|
||||||
|
"@codemirror/lang-json": "^6.0.2",
|
||||||
|
"@codemirror/theme-one-dark": "^6.1.3",
|
||||||
|
"@codemirror/view": "^6.39.6",
|
||||||
"@dnd-kit/core": "^6.3.1",
|
"@dnd-kit/core": "^6.3.1",
|
||||||
"@dnd-kit/sortable": "^10.0.0",
|
"@dnd-kit/sortable": "^10.0.0",
|
||||||
"@dnd-kit/utilities": "^3.2.2",
|
"@dnd-kit/utilities": "^3.2.2",
|
||||||
@ -47,10 +53,10 @@
|
|||||||
"@heroui/theme": "2.4.6",
|
"@heroui/theme": "2.4.6",
|
||||||
"@heroui/tooltip": "2.2.8",
|
"@heroui/tooltip": "2.2.8",
|
||||||
"@monaco-editor/loader": "^1.4.0",
|
"@monaco-editor/loader": "^1.4.0",
|
||||||
"@monaco-editor/react": "4.7.0-rc.0",
|
|
||||||
"@react-aria/visually-hidden": "^3.8.19",
|
"@react-aria/visually-hidden": "^3.8.19",
|
||||||
"@reduxjs/toolkit": "^2.5.1",
|
"@reduxjs/toolkit": "^2.5.1",
|
||||||
"@uidotdev/usehooks": "^2.4.1",
|
"@uidotdev/usehooks": "^2.4.1",
|
||||||
|
"@uiw/react-codemirror": "^4.25.4",
|
||||||
"@xterm/addon-canvas": "^0.7.0",
|
"@xterm/addon-canvas": "^0.7.0",
|
||||||
"@xterm/addon-fit": "^0.10.0",
|
"@xterm/addon-fit": "^0.10.0",
|
||||||
"@xterm/addon-web-links": "^0.11.0",
|
"@xterm/addon-web-links": "^0.11.0",
|
||||||
@ -60,7 +66,6 @@
|
|||||||
"clsx": "^2.1.1",
|
"clsx": "^2.1.1",
|
||||||
"crypto-js": "^4.2.0",
|
"crypto-js": "^4.2.0",
|
||||||
"event-source-polyfill": "^1.0.31",
|
"event-source-polyfill": "^1.0.31",
|
||||||
"monaco-editor": "^0.52.2",
|
|
||||||
"motion": "^12.0.6",
|
"motion": "^12.0.6",
|
||||||
"path-browserify": "^1.0.1",
|
"path-browserify": "^1.0.1",
|
||||||
"qface": "^1.4.1",
|
"qface": "^1.4.1",
|
||||||
@ -104,15 +109,18 @@
|
|||||||
"eslint-plugin-node": "^11.1.0",
|
"eslint-plugin-node": "^11.1.0",
|
||||||
"eslint-plugin-prettier": "5.2.3",
|
"eslint-plugin-prettier": "5.2.3",
|
||||||
"eslint-plugin-unused-imports": "^4.1.4",
|
"eslint-plugin-unused-imports": "^4.1.4",
|
||||||
|
"fontmin": "^0.9.9",
|
||||||
|
"glob": "^10.3.10",
|
||||||
"postcss": "^8.5.1",
|
"postcss": "^8.5.1",
|
||||||
"prettier": "^3.4.2",
|
"prettier": "^3.4.2",
|
||||||
|
"sharp": "^0.34.5",
|
||||||
"typescript": "^5.7.3",
|
"typescript": "^5.7.3",
|
||||||
"vite": "^6.0.5",
|
"vite": "^6.0.5",
|
||||||
|
"vite-plugin-compression": "^0.5.1",
|
||||||
"vite-plugin-font": "^5.1.2",
|
"vite-plugin-font": "^5.1.2",
|
||||||
|
"vite-plugin-image-optimizer": "^2.0.3",
|
||||||
"vite-plugin-static-copy": "^2.2.0",
|
"vite-plugin-static-copy": "^2.2.0",
|
||||||
"vite-tsconfig-paths": "^5.1.4",
|
"vite-tsconfig-paths": "^5.1.4"
|
||||||
"fontmin": "^0.9.9",
|
|
||||||
"glob": "^10.3.10"
|
|
||||||
},
|
},
|
||||||
"overrides": {
|
"overrides": {
|
||||||
"ahooks": {
|
"ahooks": {
|
||||||
|
|||||||
@ -1,46 +1,126 @@
|
|||||||
import Editor, { OnMount, loader } from '@monaco-editor/react';
|
import React, { useImperativeHandle, useEffect, useState } from 'react';
|
||||||
|
import CodeMirror, { ReactCodeMirrorRef } from '@uiw/react-codemirror';
|
||||||
import React from 'react';
|
import { json } from '@codemirror/lang-json';
|
||||||
|
import { oneDark } from '@codemirror/theme-one-dark';
|
||||||
import { useTheme } from '@/hooks/use-theme';
|
import { useTheme } from '@/hooks/use-theme';
|
||||||
|
import { EditorView } from '@codemirror/view';
|
||||||
|
import clsx from 'clsx';
|
||||||
|
|
||||||
import monaco from '@/monaco';
|
const getLanguageExtension = (lang?: string) => {
|
||||||
|
switch (lang) {
|
||||||
|
case 'json': return json();
|
||||||
|
default: return [];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
loader.config({
|
export interface CodeEditorProps {
|
||||||
monaco,
|
value?: string;
|
||||||
});
|
defaultValue?: string;
|
||||||
|
language?: string;
|
||||||
export interface CodeEditorProps extends React.ComponentProps<typeof Editor> {
|
defaultLanguage?: string;
|
||||||
test?: string;
|
onChange?: (value: string | undefined) => void;
|
||||||
|
height?: string;
|
||||||
|
options?: any;
|
||||||
|
onMount?: any;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type CodeEditorRef = monaco.editor.IStandaloneCodeEditor;
|
export interface CodeEditorRef {
|
||||||
|
getValue: () => string;
|
||||||
|
}
|
||||||
|
|
||||||
const CodeEditor = React.forwardRef<CodeEditorRef, CodeEditorProps>(
|
const CodeEditor = React.forwardRef<CodeEditorRef, CodeEditorProps>((props, ref) => {
|
||||||
(props, ref) => {
|
|
||||||
const { isDark } = useTheme();
|
const { isDark } = useTheme();
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
|
const [val, setVal] = useState(props.value || props.defaultValue || '');
|
||||||
|
const internalRef = React.useRef<ReactCodeMirrorRef>(null);
|
||||||
|
|
||||||
const handleEditorDidMount: OnMount = (editor, monaco) => {
|
useEffect(() => {
|
||||||
if (ref) {
|
if (props.value !== undefined) {
|
||||||
if (typeof ref === 'function') {
|
setVal(props.value);
|
||||||
ref(editor);
|
|
||||||
} else {
|
|
||||||
(ref as React.RefObject<CodeEditorRef>).current = editor;
|
|
||||||
}
|
}
|
||||||
|
}, [props.value]);
|
||||||
|
|
||||||
|
useImperativeHandle(ref, () => ({
|
||||||
|
getValue: () => {
|
||||||
|
// Prefer getting dynamic value from view, fallback to state
|
||||||
|
return internalRef.current?.view?.state.doc.toString() || val;
|
||||||
}
|
}
|
||||||
if (props.onMount) {
|
}));
|
||||||
props.onMount(editor, monaco);
|
|
||||||
}
|
const customTheme = EditorView.theme({
|
||||||
};
|
"&": {
|
||||||
|
fontSize: "14px",
|
||||||
|
height: "100% !important",
|
||||||
|
},
|
||||||
|
".cm-scroller": {
|
||||||
|
fontFamily: "'JetBrains Mono', 'Fira Code', Consolas, monospace",
|
||||||
|
lineHeight: "1.6",
|
||||||
|
overflow: "auto !important",
|
||||||
|
height: "100% !important",
|
||||||
|
},
|
||||||
|
".cm-gutters": {
|
||||||
|
backgroundColor: "transparent",
|
||||||
|
borderRight: "none",
|
||||||
|
color: isDark ? "#ffffff50" : "#00000040",
|
||||||
|
},
|
||||||
|
".cm-gutterElement": {
|
||||||
|
paddingLeft: "12px",
|
||||||
|
paddingRight: "12px",
|
||||||
|
},
|
||||||
|
".cm-activeLineGutter": {
|
||||||
|
backgroundColor: "transparent",
|
||||||
|
color: isDark ? "#fff" : "#000",
|
||||||
|
},
|
||||||
|
".cm-content": {
|
||||||
|
caretColor: isDark ? "#fff" : "#000",
|
||||||
|
paddingTop: "12px",
|
||||||
|
paddingBottom: "12px",
|
||||||
|
},
|
||||||
|
".cm-activeLine": {
|
||||||
|
backgroundColor: isDark ? "#ffffff10" : "#00000008",
|
||||||
|
},
|
||||||
|
".cm-selectionMatch": {
|
||||||
|
backgroundColor: isDark ? "#ffffff20" : "#00000010",
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const extensions = [
|
||||||
|
customTheme,
|
||||||
|
getLanguageExtension(props.language || props.defaultLanguage),
|
||||||
|
props.options?.wordWrap === 'on' ? EditorView.lineWrapping : [],
|
||||||
|
props.options?.readOnly ? EditorView.editable.of(false) : [],
|
||||||
|
].flat();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Editor
|
<div
|
||||||
{...props}
|
style={{ fontSize: props.options?.fontSize || 14, height: props.height || '100%', display: 'flex', flexDirection: 'column' }}
|
||||||
onMount={handleEditorDidMount}
|
className={clsx(
|
||||||
theme={isDark ? 'vs-dark' : 'light'}
|
'rounded-xl border overflow-hidden transition-colors',
|
||||||
|
isDark
|
||||||
|
? 'border-white/10 bg-[#282c34]'
|
||||||
|
: 'border-default-200 bg-white'
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
<CodeMirror
|
||||||
|
ref={internalRef}
|
||||||
|
value={props.value ?? props.defaultValue}
|
||||||
|
height="100%"
|
||||||
|
className="h-full w-full"
|
||||||
|
theme={isDark ? oneDark : 'light'}
|
||||||
|
extensions={extensions}
|
||||||
|
onChange={(value) => {
|
||||||
|
setVal(value);
|
||||||
|
props.onChange?.(value);
|
||||||
|
}}
|
||||||
|
readOnly={props.options?.readOnly}
|
||||||
|
basicSetup={{
|
||||||
|
lineNumbers: props.options?.lineNumbers !== 'off',
|
||||||
|
foldGutter: props.options?.folding !== false,
|
||||||
|
highlightActiveLine: props.options?.renderLineHighlight !== 'none',
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
|
</div>
|
||||||
);
|
);
|
||||||
}
|
});
|
||||||
);
|
|
||||||
|
|
||||||
export default CodeEditor;
|
export default CodeEditor;
|
||||||
|
|||||||
@ -11,11 +11,11 @@ import {
|
|||||||
import CodeEditor from '@/components/code_editor';
|
import CodeEditor from '@/components/code_editor';
|
||||||
|
|
||||||
interface FileEditModalProps {
|
interface FileEditModalProps {
|
||||||
isOpen: boolean
|
isOpen: boolean;
|
||||||
file: { path: string; content: string } | null
|
file: { path: string; content: string; } | null;
|
||||||
onClose: () => void
|
onClose: () => void;
|
||||||
onSave: () => void
|
onSave: () => void;
|
||||||
onContentChange: (newContent?: string) => void
|
onContentChange: (newContent?: string) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function FileEditModal ({
|
export default function FileEditModal ({
|
||||||
@ -65,12 +65,20 @@ export default function FileEditModal ({
|
|||||||
return (
|
return (
|
||||||
<Modal size='full' isOpen={isOpen} onClose={onClose}>
|
<Modal size='full' isOpen={isOpen} onClose={onClose}>
|
||||||
<ModalContent>
|
<ModalContent>
|
||||||
<ModalHeader className='flex items-center gap-2 bg-content2 bg-opacity-50'>
|
<ModalHeader className='flex items-center gap-2 border-b border-default-200/50'>
|
||||||
<span>编辑文件</span>
|
<span>编辑文件</span>
|
||||||
<Code className='text-xs'>{file?.path}</Code>
|
<Code className='text-xs'>{file?.path}</Code>
|
||||||
|
<div className="ml-auto text-xs text-default-400 font-normal px-2">
|
||||||
|
按 <span className="px-1 py-0.5 rounded border border-default-300 bg-default-100">Ctrl/Cmd + S</span> 保存
|
||||||
|
</div>
|
||||||
</ModalHeader>
|
</ModalHeader>
|
||||||
<ModalBody className='p-0'>
|
<ModalBody className='p-4 bg-content2/50'>
|
||||||
<div className='h-full'>
|
<div className='h-full' onKeyDown={(e) => {
|
||||||
|
if ((e.ctrlKey || e.metaKey) && e.key === 's') {
|
||||||
|
e.preventDefault();
|
||||||
|
onSave();
|
||||||
|
}
|
||||||
|
}}>
|
||||||
<CodeEditor
|
<CodeEditor
|
||||||
height='100%'
|
height='100%'
|
||||||
value={file?.content || ''}
|
value={file?.content || ''}
|
||||||
@ -80,7 +88,7 @@ export default function FileEditModal ({
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</ModalBody>
|
</ModalBody>
|
||||||
<ModalFooter>
|
<ModalFooter className="border-t border-default-200/50">
|
||||||
<Button color='primary' variant='flat' onPress={onClose}>
|
<Button color='primary' variant='flat' onPress={onClose}>
|
||||||
取消
|
取消
|
||||||
</Button>
|
</Button>
|
||||||
|
|||||||
@ -274,8 +274,9 @@ const OneBotApiDebug: React.FC<OneBotApiDebugProps> = (props) => {
|
|||||||
|
|
||||||
<div className='flex-1 min-h-0 relative px-3 pb-2 mt-1'>
|
<div className='flex-1 min-h-0 relative px-3 pb-2 mt-1'>
|
||||||
<div className={clsx(
|
<div className={clsx(
|
||||||
'h-full rounded-xl overflow-y-auto no-scrollbar transition-all',
|
'h-full transition-all',
|
||||||
hasBackground ? 'bg-transparent' : 'bg-white/10 dark:bg-black/10'
|
activeTab !== 'request' && 'rounded-xl overflow-y-auto no-scrollbar',
|
||||||
|
hasBackground ? 'bg-transparent' : (activeTab !== 'request' && 'bg-white/10 dark:bg-black/10')
|
||||||
)}>
|
)}>
|
||||||
{activeTab === 'request' ? (
|
{activeTab === 'request' ? (
|
||||||
<CodeEditor
|
<CodeEditor
|
||||||
@ -351,7 +352,7 @@ const OneBotApiDebug: React.FC<OneBotApiDebugProps> = (props) => {
|
|||||||
|
|
||||||
{/* Response Content - Code Editor */}
|
{/* Response Content - Code Editor */}
|
||||||
{responseExpanded && (
|
{responseExpanded && (
|
||||||
<div style={{ height: responseHeight }} className="relative bg-black/5 dark:bg-black/20">
|
<div style={{ height: responseHeight }} className="relative bg-transparent">
|
||||||
<PageLoading loading={isFetching} />
|
<PageLoading loading={isFetching} />
|
||||||
<CodeEditor
|
<CodeEditor
|
||||||
value={responseContent || '// Waiting for response...'}
|
value={responseContent || '// Waiting for response...'}
|
||||||
|
|||||||
@ -61,7 +61,7 @@ const OneBotSendModal: React.FC<OneBotSendModalProps> = (props) => {
|
|||||||
构造请求
|
构造请求
|
||||||
</ModalHeader>
|
</ModalHeader>
|
||||||
<ModalBody>
|
<ModalBody>
|
||||||
<div className='h-96 dark:bg-[rgb(30,30,30)] p-2 rounded-md border border-default-100'>
|
<div className='h-96'>
|
||||||
<CodeEditor
|
<CodeEditor
|
||||||
height='100%'
|
height='100%'
|
||||||
defaultLanguage='json'
|
defaultLanguage='json'
|
||||||
|
|||||||
@ -2,13 +2,13 @@ import { Spinner } from '@heroui/spinner';
|
|||||||
import clsx from 'clsx';
|
import clsx from 'clsx';
|
||||||
|
|
||||||
export interface PageLoadingProps {
|
export interface PageLoadingProps {
|
||||||
loading?: boolean
|
loading?: boolean;
|
||||||
}
|
}
|
||||||
const PageLoading: React.FC<PageLoadingProps> = ({ loading }) => {
|
const PageLoading: React.FC<PageLoadingProps> = ({ loading }) => {
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={clsx(
|
className={clsx(
|
||||||
'absolute top-0 left-0 w-full h-full bg-zinc-500 bg-opacity-10 z-50 flex justify-center items-center backdrop-blur',
|
'absolute top-0 left-0 w-full h-full bg-zinc-500 bg-opacity-10 z-30 flex justify-center items-center backdrop-blur',
|
||||||
{
|
{
|
||||||
hidden: !loading,
|
hidden: !loading,
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,12 +1,10 @@
|
|||||||
import { Button } from '@heroui/button';
|
import { Button } from '@heroui/button';
|
||||||
import { useLocalStorage } from '@uidotdev/usehooks';
|
|
||||||
import clsx from 'clsx';
|
import clsx from 'clsx';
|
||||||
import { AnimatePresence, motion } from 'motion/react';
|
import { AnimatePresence, motion } from 'motion/react';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { IoMdLogOut } from 'react-icons/io';
|
import { IoMdLogOut } from 'react-icons/io';
|
||||||
import { MdDarkMode, MdLightMode } from 'react-icons/md';
|
import { MdDarkMode, MdLightMode } from 'react-icons/md';
|
||||||
|
|
||||||
import key from '@/const/key';
|
|
||||||
import useAuth from '@/hooks/auth';
|
import useAuth from '@/hooks/auth';
|
||||||
import useDialog from '@/hooks/use-dialog';
|
import useDialog from '@/hooks/use-dialog';
|
||||||
import { useTheme } from '@/hooks/use-theme';
|
import { useTheme } from '@/hooks/use-theme';
|
||||||
@ -24,7 +22,6 @@ const SideBar: React.FC<SideBarProps> = (props) => {
|
|||||||
const { open, items, onClose } = props;
|
const { open, items, onClose } = props;
|
||||||
const { toggleTheme, isDark } = useTheme();
|
const { toggleTheme, isDark } = useTheme();
|
||||||
const { revokeAuth } = useAuth();
|
const { revokeAuth } = useAuth();
|
||||||
const [b64img] = useLocalStorage(key.backgroundImage, '');
|
|
||||||
const dialog = useDialog();
|
const dialog = useDialog();
|
||||||
const onRevokeAuth = () => {
|
const onRevokeAuth = () => {
|
||||||
dialog.confirm({
|
dialog.confirm({
|
||||||
@ -50,9 +47,9 @@ const SideBar: React.FC<SideBarProps> = (props) => {
|
|||||||
</AnimatePresence>
|
</AnimatePresence>
|
||||||
<motion.div
|
<motion.div
|
||||||
className={clsx(
|
className={clsx(
|
||||||
'overflow-hidden fixed top-0 left-0 h-full z-50 md:static shadow-md md:shadow-none rounded-r-md md:rounded-none',
|
'overflow-hidden fixed top-0 left-0 h-full z-50 md:static md:shadow-none rounded-r-2xl md:rounded-none',
|
||||||
b64img ? 'bg-black/20 backdrop-blur-md border-r border-white/10' : 'bg-background',
|
'bg-content1/70 backdrop-blur-xl backdrop-saturate-150 shadow-xl',
|
||||||
'md:bg-transparent md:border-r-0 md:backdrop-blur-none'
|
'md:bg-transparent md:backdrop-blur-none md:backdrop-saturate-100 md:shadow-none'
|
||||||
)}
|
)}
|
||||||
initial={{ width: 0 }}
|
initial={{ width: 0 }}
|
||||||
animate={{ width: open ? '16rem' : 0 }}
|
animate={{ width: open ? '16rem' : 0 }}
|
||||||
|
|||||||
@ -36,8 +36,18 @@ const XTerm = forwardRef<XTermRef, XTermProps>((props, ref) => {
|
|||||||
const { theme } = useTheme();
|
const { theme } = useTheme();
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
// 根据屏幕宽度决定字体大小,手机端使用更小的字体
|
// 根据屏幕宽度决定字体大小,手机端使用更小的字体
|
||||||
const isMobile = window.innerWidth < 768;
|
const width = window.innerWidth;
|
||||||
const fontSize = isMobile ? 11 : 14;
|
// 按屏幕宽度自适应字体大小
|
||||||
|
let fontSize = 16;
|
||||||
|
if (width < 400) {
|
||||||
|
fontSize = 4;
|
||||||
|
} else if (width < 600) {
|
||||||
|
fontSize = 5;
|
||||||
|
} else if (width < 900) {
|
||||||
|
fontSize = 6;
|
||||||
|
} else if (width < 1280) {
|
||||||
|
fontSize = 12;
|
||||||
|
} // ≥1280: 16
|
||||||
|
|
||||||
const terminal = new Terminal({
|
const terminal = new Terminal({
|
||||||
allowTransparency: true,
|
allowTransparency: true,
|
||||||
@ -60,10 +70,8 @@ const XTerm = forwardRef<XTermRef, XTermProps>((props, ref) => {
|
|||||||
terminal.loadAddon(fitAddon);
|
terminal.loadAddon(fitAddon);
|
||||||
terminal.open(domRef.current!);
|
terminal.open(domRef.current!);
|
||||||
|
|
||||||
// 只在非手机端使用 Canvas 渲染器,手机端使用默认 DOM 渲染器以避免渲染问题
|
// 所有端都使用 Canvas 渲染器(包括手机端)
|
||||||
if (!isMobile) {
|
|
||||||
terminal.loadAddon(new CanvasAddon());
|
terminal.loadAddon(new CanvasAddon());
|
||||||
}
|
|
||||||
terminal.onData((data) => {
|
terminal.onData((data) => {
|
||||||
if (onInput) {
|
if (onInput) {
|
||||||
onInput(data);
|
onInput(data);
|
||||||
|
|||||||
@ -8,7 +8,7 @@ import '@/styles/globals.css';
|
|||||||
|
|
||||||
import key from './const/key';
|
import key from './const/key';
|
||||||
import WebUIManager from './controllers/webui_manager';
|
import WebUIManager from './controllers/webui_manager';
|
||||||
import { loadTheme } from './utils/theme';
|
import { initFont, loadTheme } from './utils/theme';
|
||||||
|
|
||||||
WebUIManager.checkWebUiLogined();
|
WebUIManager.checkWebUiLogined();
|
||||||
|
|
||||||
@ -24,6 +24,7 @@ if (theme && !theme.startsWith('"')) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
loadTheme();
|
loadTheme();
|
||||||
|
initFont();
|
||||||
|
|
||||||
ReactDOM.createRoot(document.getElementById('root')!).render(
|
ReactDOM.createRoot(document.getElementById('root')!).render(
|
||||||
// <React.StrictMode>
|
// <React.StrictMode>
|
||||||
@ -34,3 +35,19 @@ ReactDOM.createRoot(document.getElementById('root')!).render(
|
|||||||
</BrowserRouter>
|
</BrowserRouter>
|
||||||
// </React.StrictMode>
|
// </React.StrictMode>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if (!import.meta.env.DEV) {
|
||||||
|
if ('serviceWorker' in navigator) {
|
||||||
|
window.addEventListener('load', () => {
|
||||||
|
const baseUrl = import.meta.env.BASE_URL;
|
||||||
|
const swUrl = `${baseUrl}sw.js`;
|
||||||
|
navigator.serviceWorker.register(swUrl, { scope: baseUrl })
|
||||||
|
.then((registration) => {
|
||||||
|
console.log('SW registered: ', registration);
|
||||||
|
})
|
||||||
|
.catch((registrationError) => {
|
||||||
|
console.log('SW registration failed: ', registrationError);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -1,20 +0,0 @@
|
|||||||
import * as monaco from 'monaco-editor';
|
|
||||||
import editorWorker from 'monaco-editor/esm/vs/editor/editor.worker?worker';
|
|
||||||
import jsonWorker from 'monaco-editor/esm/vs/language/json/json.worker?worker';
|
|
||||||
|
|
||||||
// Monaco Environment - Only load JSON worker for performance
|
|
||||||
// Other languages will use basic editor worker (no IntelliSense, but syntax highlighting works)
|
|
||||||
self.MonacoEnvironment = {
|
|
||||||
getWorker (_: unknown, label: string) {
|
|
||||||
if (label === 'json') {
|
|
||||||
// eslint-disable-next-line new-cap
|
|
||||||
return new jsonWorker();
|
|
||||||
}
|
|
||||||
// For all other languages, use the basic editor worker
|
|
||||||
// This provides syntax highlighting but no language-specific IntelliSense
|
|
||||||
// eslint-disable-next-line new-cap
|
|
||||||
return new editorWorker();
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
export default monaco;
|
|
||||||
@ -1,28 +1,34 @@
|
|||||||
import { Accordion, AccordionItem } from '@heroui/accordion';
|
import { Accordion, AccordionItem } from '@heroui/accordion';
|
||||||
|
import { Button } from '@heroui/button';
|
||||||
import { Card, CardBody, CardHeader } from '@heroui/card';
|
import { Card, CardBody, CardHeader } from '@heroui/card';
|
||||||
|
import { Select, SelectItem } from '@heroui/select';
|
||||||
|
import { Chip } from '@heroui/chip';
|
||||||
import { useRequest } from 'ahooks';
|
import { useRequest } from 'ahooks';
|
||||||
import clsx from 'clsx';
|
import clsx from 'clsx';
|
||||||
import { useEffect, useRef } from 'react';
|
import { useEffect, useRef, useState, useMemo, useCallback } from 'react';
|
||||||
import { Controller, useForm, useWatch } from 'react-hook-form';
|
import { Controller, useForm, useWatch } from 'react-hook-form';
|
||||||
import toast from 'react-hot-toast';
|
import toast from 'react-hot-toast';
|
||||||
import { FaUserAstronaut } from 'react-icons/fa';
|
import { FaFont, FaUserAstronaut, FaCheck } from 'react-icons/fa';
|
||||||
import { FaPaintbrush } from 'react-icons/fa6';
|
import { FaPaintbrush } from 'react-icons/fa6';
|
||||||
import { IoIosColorPalette } from 'react-icons/io';
|
import { IoIosColorPalette } from 'react-icons/io';
|
||||||
import { MdDarkMode, MdLightMode } from 'react-icons/md';
|
import { MdDarkMode, MdLightMode } from 'react-icons/md';
|
||||||
|
import { IoMdRefresh } from 'react-icons/io';
|
||||||
|
|
||||||
import themes from '@/const/themes';
|
import themes from '@/const/themes';
|
||||||
|
|
||||||
import ColorPicker from '@/components/ColorPicker';
|
import ColorPicker from '@/components/ColorPicker';
|
||||||
import SaveButtons from '@/components/button/save_buttons';
|
import FileInput from '@/components/input/file_input';
|
||||||
import PageLoading from '@/components/page_loading';
|
import PageLoading from '@/components/page_loading';
|
||||||
|
|
||||||
import { colorKeys, generateTheme, loadTheme } from '@/utils/theme';
|
import FileManager from '@/controllers/file_manager';
|
||||||
|
import { applyFont, colorKeys, generateTheme, loadTheme, updateFontCache } from '@/utils/theme';
|
||||||
|
|
||||||
import WebUIManager from '@/controllers/webui_manager';
|
import WebUIManager from '@/controllers/webui_manager';
|
||||||
|
|
||||||
export type PreviewThemeCardProps = {
|
export type PreviewThemeCardProps = {
|
||||||
theme: ThemeInfo;
|
theme: ThemeInfo;
|
||||||
onPreview: () => void;
|
onPreview: () => void;
|
||||||
|
isSelected?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
const values = [
|
const values = [
|
||||||
@ -47,7 +53,7 @@ const colors = [
|
|||||||
'default',
|
'default',
|
||||||
];
|
];
|
||||||
|
|
||||||
function PreviewThemeCard ({ theme, onPreview }: PreviewThemeCardProps) {
|
function PreviewThemeCard ({ theme, onPreview, isSelected }: PreviewThemeCardProps) {
|
||||||
const style = document.createElement('style');
|
const style = document.createElement('style');
|
||||||
style.innerHTML = generateTheme(theme.theme, theme.name);
|
style.innerHTML = generateTheme(theme.theme, theme.name);
|
||||||
const cardRef = useRef<HTMLDivElement>(null);
|
const cardRef = useRef<HTMLDivElement>(null);
|
||||||
@ -64,8 +70,19 @@ function PreviewThemeCard ({ theme, onPreview }: PreviewThemeCardProps) {
|
|||||||
radius='sm'
|
radius='sm'
|
||||||
isPressable
|
isPressable
|
||||||
onPress={onPreview}
|
onPress={onPreview}
|
||||||
className={clsx('text-primary bg-primary-50', theme.name)}
|
className={clsx(
|
||||||
|
'text-primary bg-primary-50 relative transition-all',
|
||||||
|
theme.name,
|
||||||
|
isSelected && 'ring-2 ring-primary ring-offset-2'
|
||||||
|
)}
|
||||||
>
|
>
|
||||||
|
{isSelected && (
|
||||||
|
<div className="absolute top-1 right-1 z-10">
|
||||||
|
<Chip size="sm" color="primary" variant="solid">
|
||||||
|
<FaCheck size={10} />
|
||||||
|
</Chip>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
<CardHeader className='pb-0 flex flex-col items-start gap-1'>
|
<CardHeader className='pb-0 flex flex-col items-start gap-1'>
|
||||||
<div className='px-1 rounded-md bg-primary text-primary-foreground'>
|
<div className='px-1 rounded-md bg-primary text-primary-foreground'>
|
||||||
{theme.name}
|
{theme.name}
|
||||||
@ -100,6 +117,29 @@ function PreviewThemeCard ({ theme, onPreview }: PreviewThemeCardProps) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 比较两个主题配置是否相同(不比较 fontMode)
|
||||||
|
const isThemeColorsEqual = (a: ThemeConfig, b: ThemeConfig): boolean => {
|
||||||
|
if (!a || !b) return false;
|
||||||
|
const aKeys = [...Object.keys(a.light || {}), ...Object.keys(a.dark || {})];
|
||||||
|
const bKeys = [...Object.keys(b.light || {}), ...Object.keys(b.dark || {})];
|
||||||
|
if (aKeys.length !== bKeys.length) return false;
|
||||||
|
|
||||||
|
for (const key of Object.keys(a.light || {})) {
|
||||||
|
if (a.light?.[key as keyof ThemeConfigItem] !== b.light?.[key as keyof ThemeConfigItem]) return false;
|
||||||
|
}
|
||||||
|
for (const key of Object.keys(a.dark || {})) {
|
||||||
|
if (a.dark?.[key as keyof ThemeConfigItem] !== b.dark?.[key as keyof ThemeConfigItem]) return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
// 字体模式显示名称映射
|
||||||
|
const fontModeNames: Record<string, string> = {
|
||||||
|
'aacute': 'Aa 偷吃可爱长大的',
|
||||||
|
'system': '系统默认',
|
||||||
|
'custom': '自定义字体',
|
||||||
|
};
|
||||||
|
|
||||||
const ThemeConfigCard = () => {
|
const ThemeConfigCard = () => {
|
||||||
const { data, loading, error, refreshAsync } = useRequest(
|
const { data, loading, error, refreshAsync } = useRequest(
|
||||||
WebUIManager.getThemeConfig
|
WebUIManager.getThemeConfig
|
||||||
@ -116,12 +156,17 @@ const ThemeConfigCard = () => {
|
|||||||
theme: {
|
theme: {
|
||||||
dark: {},
|
dark: {},
|
||||||
light: {},
|
light: {},
|
||||||
|
fontMode: 'aacute',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const [dataLoaded, setDataLoaded] = useState(false);
|
||||||
|
const [hasUnsavedChanges, setHasUnsavedChanges] = useState(false);
|
||||||
|
|
||||||
// 使用 useRef 存储 style 标签引用
|
// 使用 useRef 存储 style 标签引用
|
||||||
const styleTagRef = useRef<HTMLStyleElement | null>(null);
|
const styleTagRef = useRef<HTMLStyleElement | null>(null);
|
||||||
|
const originalDataRef = useRef<ThemeConfig | null>(null);
|
||||||
|
|
||||||
// 在组件挂载时创建 style 标签,并在卸载时清理
|
// 在组件挂载时创建 style 标签,并在卸载时清理
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@ -137,13 +182,45 @@ const ThemeConfigCard = () => {
|
|||||||
|
|
||||||
const theme = useWatch({ control, name: 'theme' });
|
const theme = useWatch({ control, name: 'theme' });
|
||||||
|
|
||||||
const reset = () => {
|
// 检测是否有未保存的更改
|
||||||
if (data) setOnebotValue('theme', data);
|
useEffect(() => {
|
||||||
};
|
if (originalDataRef.current && dataLoaded) {
|
||||||
|
const colorsChanged = !isThemeColorsEqual(theme, originalDataRef.current);
|
||||||
|
const fontChanged = theme.fontMode !== originalDataRef.current.fontMode;
|
||||||
|
setHasUnsavedChanges(colorsChanged || fontChanged);
|
||||||
|
}
|
||||||
|
}, [theme, dataLoaded]);
|
||||||
|
|
||||||
const onSubmit = handleOnebotSubmit(async (data) => {
|
const reset = useCallback(() => {
|
||||||
|
if (data) {
|
||||||
|
setOnebotValue('theme', data);
|
||||||
|
originalDataRef.current = data;
|
||||||
|
// 应用已保存的字体设置
|
||||||
|
if (data.fontMode) {
|
||||||
|
applyFont(data.fontMode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
setDataLoaded(true);
|
||||||
|
setHasUnsavedChanges(false);
|
||||||
|
}, [data, setOnebotValue]);
|
||||||
|
|
||||||
|
// 实时应用字体预设(预览)
|
||||||
|
useEffect(() => {
|
||||||
|
if (dataLoaded && theme.fontMode) {
|
||||||
|
applyFont(theme.fontMode);
|
||||||
|
}
|
||||||
|
}, [theme.fontMode, dataLoaded]);
|
||||||
|
|
||||||
|
const onSubmit = handleOnebotSubmit(async (formData) => {
|
||||||
try {
|
try {
|
||||||
await WebUIManager.setThemeConfig(data.theme);
|
await WebUIManager.setThemeConfig(formData.theme);
|
||||||
|
// 更新原始数据引用
|
||||||
|
originalDataRef.current = formData.theme;
|
||||||
|
// 更新字体缓存
|
||||||
|
if (formData.theme.fontMode) {
|
||||||
|
updateFontCache(formData.theme.fontMode);
|
||||||
|
}
|
||||||
|
setHasUnsavedChanges(false);
|
||||||
toast.success('保存成功');
|
toast.success('保存成功');
|
||||||
loadTheme();
|
loadTheme();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@ -164,7 +241,7 @@ const ThemeConfigCard = () => {
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
reset();
|
reset();
|
||||||
}, [data]);
|
}, [data, reset]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (theme && styleTagRef.current) {
|
if (theme && styleTagRef.current) {
|
||||||
@ -173,6 +250,25 @@ const ThemeConfigCard = () => {
|
|||||||
}
|
}
|
||||||
}, [theme]);
|
}, [theme]);
|
||||||
|
|
||||||
|
// 找到当前选中的主题(预览中的)
|
||||||
|
const selectedThemeName = useMemo(() => {
|
||||||
|
return themes.find(t => isThemeColorsEqual(t.theme, theme))?.name;
|
||||||
|
}, [theme]);
|
||||||
|
|
||||||
|
// 找到已保存的主题名称
|
||||||
|
const savedThemeName = useMemo(() => {
|
||||||
|
if (!originalDataRef.current) return null;
|
||||||
|
return themes.find(t => isThemeColorsEqual(t.theme, originalDataRef.current!))?.name || '自定义';
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
|
}, [dataLoaded, hasUnsavedChanges]);
|
||||||
|
|
||||||
|
// 已保存的字体模式显示名称
|
||||||
|
const savedFontModeDisplayName = useMemo(() => {
|
||||||
|
const mode = originalDataRef.current?.fontMode || 'aacute';
|
||||||
|
return fontModeNames[mode] || mode;
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
|
}, [dataLoaded, hasUnsavedChanges]);
|
||||||
|
|
||||||
if (loading) return <PageLoading loading />;
|
if (loading) return <PageLoading loading />;
|
||||||
|
|
||||||
if (error) {
|
if (error) {
|
||||||
@ -185,30 +281,146 @@ const ThemeConfigCard = () => {
|
|||||||
<>
|
<>
|
||||||
<title>主题配置 - NapCat WebUI</title>
|
<title>主题配置 - NapCat WebUI</title>
|
||||||
|
|
||||||
<SaveButtons
|
{/* 顶部操作栏 */}
|
||||||
onSubmit={onSubmit}
|
<div className="sticky top-0 z-20 bg-background/80 backdrop-blur-md border-b border-divider">
|
||||||
reset={reset}
|
<div className="flex items-center justify-between p-4">
|
||||||
isSubmitting={isSubmitting}
|
<div className="flex items-center gap-3 flex-wrap">
|
||||||
refresh={onRefresh}
|
<div className="flex items-center gap-2 text-sm">
|
||||||
className='items-end w-full p-4'
|
<span className="text-default-400">当前主题:</span>
|
||||||
|
<Chip size="sm" color="primary" variant="flat">
|
||||||
|
{savedThemeName || '加载中...'}
|
||||||
|
</Chip>
|
||||||
|
</div>
|
||||||
|
<div className="flex items-center gap-2 text-sm">
|
||||||
|
<span className="text-default-400">字体:</span>
|
||||||
|
<Chip size="sm" color="secondary" variant="flat">
|
||||||
|
{savedFontModeDisplayName}
|
||||||
|
</Chip>
|
||||||
|
</div>
|
||||||
|
{hasUnsavedChanges && (
|
||||||
|
<Chip size="sm" color="warning" variant="solid">
|
||||||
|
有未保存的更改
|
||||||
|
</Chip>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
<div className="flex items-center gap-2">
|
||||||
|
<Button
|
||||||
|
size="sm"
|
||||||
|
radius="full"
|
||||||
|
variant="flat"
|
||||||
|
className="font-medium bg-default-100 text-default-600 dark:bg-default-50/50"
|
||||||
|
onPress={() => {
|
||||||
|
reset();
|
||||||
|
toast.success('已重置');
|
||||||
|
}}
|
||||||
|
isDisabled={!hasUnsavedChanges}
|
||||||
|
>
|
||||||
|
取消更改
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
size="sm"
|
||||||
|
color='primary'
|
||||||
|
radius="full"
|
||||||
|
className="font-medium shadow-md shadow-primary/20"
|
||||||
|
isLoading={isSubmitting}
|
||||||
|
onPress={() => onSubmit()}
|
||||||
|
isDisabled={!hasUnsavedChanges}
|
||||||
|
>
|
||||||
|
保存
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
size="sm"
|
||||||
|
isIconOnly
|
||||||
|
radius='full'
|
||||||
|
variant='flat'
|
||||||
|
className="text-default-500 bg-default-100 dark:bg-default-50/50"
|
||||||
|
onPress={onRefresh}
|
||||||
|
>
|
||||||
|
<IoMdRefresh size={18} />
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="p-4">
|
||||||
|
<Accordion variant='splitted' defaultExpandedKeys={['font', 'select']}>
|
||||||
|
<AccordionItem
|
||||||
|
key='font'
|
||||||
|
aria-label='Font Settings'
|
||||||
|
title='字体设置'
|
||||||
|
subtitle='自定义WebUI显示的字体'
|
||||||
|
className='shadow-small'
|
||||||
|
startContent={<FaFont />}
|
||||||
|
>
|
||||||
|
<div className='flex flex-col gap-4'>
|
||||||
|
<Controller
|
||||||
|
control={control}
|
||||||
|
name="theme.fontMode"
|
||||||
|
render={({ field }) => (
|
||||||
|
<Select
|
||||||
|
label="字体预设"
|
||||||
|
selectedKeys={field.value ? [field.value] : ['aacute']}
|
||||||
|
onChange={(e) => field.onChange(e.target.value)}
|
||||||
|
className="max-w-xs"
|
||||||
|
disallowEmptySelection
|
||||||
|
>
|
||||||
|
<SelectItem key="aacute">Aa 偷吃可爱长大的</SelectItem>
|
||||||
|
<SelectItem key="system">系统默认</SelectItem>
|
||||||
|
<SelectItem key="custom">自定义字体</SelectItem>
|
||||||
|
</Select>
|
||||||
|
)}
|
||||||
/>
|
/>
|
||||||
<div className='px-4 text-sm text-default-600'>实时预览,记得保存!</div>
|
<div className='p-3 rounded-lg bg-default-100 dark:bg-default-50/30'>
|
||||||
<Accordion variant='splitted' defaultExpandedKeys={['select']}>
|
<div className='text-sm text-default-500 mb-2'>
|
||||||
|
上传自定义字体(仅在选择"自定义字体"时生效)
|
||||||
|
</div>
|
||||||
|
<FileInput
|
||||||
|
label='上传字体文件'
|
||||||
|
placeholder='选择字体文件 (.woff/.woff2/.ttf/.otf)'
|
||||||
|
accept='.ttf,.otf,.woff,.woff2'
|
||||||
|
onChange={async (file) => {
|
||||||
|
try {
|
||||||
|
await FileManager.uploadWebUIFont(file);
|
||||||
|
toast.success('上传成功,即将刷新页面');
|
||||||
|
setTimeout(() => {
|
||||||
|
window.location.reload();
|
||||||
|
}, 1000);
|
||||||
|
} catch (error) {
|
||||||
|
toast.error('上传失败: ' + (error as Error).message);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
onDelete={async () => {
|
||||||
|
try {
|
||||||
|
await FileManager.deleteWebUIFont();
|
||||||
|
toast.success('删除成功,即将刷新页面');
|
||||||
|
setTimeout(() => {
|
||||||
|
window.location.reload();
|
||||||
|
}, 1000);
|
||||||
|
} catch (error) {
|
||||||
|
toast.error('删除失败: ' + (error as Error).message);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</AccordionItem>
|
||||||
|
|
||||||
<AccordionItem
|
<AccordionItem
|
||||||
key='select'
|
key='select'
|
||||||
aria-label='Pick Color'
|
aria-label='Pick Color'
|
||||||
title='选择主题'
|
title='选择主题'
|
||||||
subtitle='可以切换夜间/白昼模式查看对应颜色'
|
subtitle='点击主题卡片即可预览,记得保存'
|
||||||
className='shadow-small'
|
className='shadow-small'
|
||||||
startContent={<IoIosColorPalette />}
|
startContent={<IoIosColorPalette />}
|
||||||
>
|
>
|
||||||
<div className='flex flex-wrap gap-2'>
|
<div className='grid grid-cols-2 sm:grid-cols-3 md:grid-cols-4 lg:grid-cols-5 gap-3'>
|
||||||
{themes.map((theme) => (
|
{themes.map((t) => (
|
||||||
<PreviewThemeCard
|
<PreviewThemeCard
|
||||||
key={theme.name}
|
key={t.name}
|
||||||
theme={theme}
|
theme={t}
|
||||||
|
isSelected={selectedThemeName === t.name}
|
||||||
onPreview={() => {
|
onPreview={() => {
|
||||||
setOnebotValue('theme', theme.theme);
|
setOnebotValue('theme', { ...t.theme, fontMode: theme.fontMode });
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
@ -219,40 +431,32 @@ const ThemeConfigCard = () => {
|
|||||||
key='pick'
|
key='pick'
|
||||||
aria-label='Pick Color'
|
aria-label='Pick Color'
|
||||||
title='自定义配色'
|
title='自定义配色'
|
||||||
|
subtitle='精细调整每个颜色变量'
|
||||||
className='shadow-small'
|
className='shadow-small'
|
||||||
startContent={<FaPaintbrush />}
|
startContent={<FaPaintbrush />}
|
||||||
>
|
>
|
||||||
<div className='space-y-2'>
|
<div className='space-y-4'>
|
||||||
{(['dark', 'light'] as const).map((mode) => (
|
{(['light', 'dark'] as const).map((mode) => (
|
||||||
<div
|
<div
|
||||||
key={mode}
|
key={mode}
|
||||||
className={clsx(
|
className={clsx(
|
||||||
'p-2 rounded-md',
|
'p-4 rounded-lg',
|
||||||
mode === 'dark' ? 'text-white' : 'text-black',
|
mode === 'dark' ? 'bg-zinc-900 text-white' : 'bg-zinc-100 text-black'
|
||||||
mode === 'dark'
|
|
||||||
? 'bg-content1-foreground dark:bg-content1'
|
|
||||||
: 'bg-content1 dark:bg-content1-foreground'
|
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<h3 className='text-center p-2 rounded-md bg-content2 mb-2 text-default-800 flex items-center justify-center'>
|
<h3 className='flex items-center justify-center gap-2 p-2 rounded-md bg-opacity-20 mb-4 font-medium'>
|
||||||
{mode === 'dark'
|
{mode === 'dark' ? <MdDarkMode size={20} /> : <MdLightMode size={20} />}
|
||||||
? (
|
{mode === 'dark' ? '深色模式' : '浅色模式'}
|
||||||
<MdDarkMode size={24} />
|
|
||||||
)
|
|
||||||
: (
|
|
||||||
<MdLightMode size={24} />
|
|
||||||
)}
|
|
||||||
{mode === 'dark' ? '夜间模式主题' : '白昼模式主题'}
|
|
||||||
</h3>
|
</h3>
|
||||||
{colorKeys.map((key) => (
|
<div className='grid grid-cols-1 sm:grid-cols-2 gap-3'>
|
||||||
|
{colorKeys.map((colorKey) => (
|
||||||
<div
|
<div
|
||||||
key={key}
|
key={colorKey}
|
||||||
className='grid grid-cols-2 items-center mb-2 gap-2'
|
className='flex items-center gap-2 p-2 rounded bg-black/5 dark:bg-white/5'
|
||||||
>
|
>
|
||||||
<label className='text-right'>{key}</label>
|
|
||||||
<Controller
|
<Controller
|
||||||
control={control}
|
control={control}
|
||||||
name={`theme.${mode}.${key}`}
|
name={`theme.${mode}.${colorKey}`}
|
||||||
render={({ field: { value, onChange } }) => {
|
render={({ field: { value, onChange } }) => {
|
||||||
const hslArray = value?.split(' ') ?? [0, 0, 0];
|
const hslArray = value?.split(' ') ?? [0, 0, 0];
|
||||||
const color = `hsl(${hslArray[0]}, ${hslArray[1]}, ${hslArray[2]})`;
|
const color = `hsl(${hslArray[0]}, ${hslArray[1]}, ${hslArray[2]})`;
|
||||||
@ -268,13 +472,18 @@ const ThemeConfigCard = () => {
|
|||||||
);
|
);
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
<span className='text-xs font-mono truncate flex-1' title={colorKey}>
|
||||||
|
{colorKey.replace('--heroui-', '')}
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
</AccordionItem>
|
</AccordionItem>
|
||||||
</Accordion>
|
</Accordion>
|
||||||
|
</div>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -7,11 +7,9 @@ import toast from 'react-hot-toast';
|
|||||||
import key from '@/const/key';
|
import key from '@/const/key';
|
||||||
|
|
||||||
import SaveButtons from '@/components/button/save_buttons';
|
import SaveButtons from '@/components/button/save_buttons';
|
||||||
import FileInput from '@/components/input/file_input';
|
|
||||||
import ImageInput from '@/components/input/image_input';
|
import ImageInput from '@/components/input/image_input';
|
||||||
|
|
||||||
import { siteConfig } from '@/config/site';
|
import { siteConfig } from '@/config/site';
|
||||||
import FileManager from '@/controllers/file_manager';
|
|
||||||
import WebUIManager from '@/controllers/webui_manager';
|
import WebUIManager from '@/controllers/webui_manager';
|
||||||
|
|
||||||
// Base64URL to Uint8Array converter
|
// Base64URL to Uint8Array converter
|
||||||
@ -37,10 +35,10 @@ const WebUIConfigCard = () => {
|
|||||||
handleSubmit: handleWebuiSubmit,
|
handleSubmit: handleWebuiSubmit,
|
||||||
formState: { isSubmitting },
|
formState: { isSubmitting },
|
||||||
setValue: setWebuiValue,
|
setValue: setWebuiValue,
|
||||||
} = useForm<IConfig['webui']>({
|
} = useForm({
|
||||||
defaultValues: {
|
defaultValues: {
|
||||||
background: '',
|
background: '',
|
||||||
customIcons: {},
|
customIcons: {} as Record<string, string>,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -92,39 +90,6 @@ const WebUIConfigCard = () => {
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<title>WebUI配置 - NapCat WebUI</title>
|
<title>WebUI配置 - NapCat WebUI</title>
|
||||||
<div className='flex flex-col gap-2'>
|
|
||||||
<div className='flex-shrink-0 w-full font-bold text-default-600 dark:text-default-400 px-1'>WebUI字体</div>
|
|
||||||
<div className='text-sm text-default-400'>
|
|
||||||
此项不需要手动保存,上传成功后需清空网页缓存并刷新
|
|
||||||
<FileInput
|
|
||||||
label='中文字体'
|
|
||||||
placeholder='选择字体文件'
|
|
||||||
accept='.ttf,.otf,.woff,.woff2'
|
|
||||||
onChange={async (file) => {
|
|
||||||
try {
|
|
||||||
await FileManager.uploadWebUIFont(file);
|
|
||||||
toast.success('上传成功');
|
|
||||||
setTimeout(() => {
|
|
||||||
window.location.reload();
|
|
||||||
}, 1000);
|
|
||||||
} catch (error) {
|
|
||||||
toast.error('上传失败: ' + (error as Error).message);
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
onDelete={async () => {
|
|
||||||
try {
|
|
||||||
await FileManager.deleteWebUIFont();
|
|
||||||
toast.success('删除成功');
|
|
||||||
setTimeout(() => {
|
|
||||||
window.location.reload();
|
|
||||||
}, 1000);
|
|
||||||
} catch (error) {
|
|
||||||
toast.error('删除失败: ' + (error as Error).message);
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className='flex flex-col gap-2'>
|
<div className='flex flex-col gap-2'>
|
||||||
<div className='flex-shrink-0 w-full font-bold text-default-600 dark:text-default-400 px-1'>背景图</div>
|
<div className='flex-shrink-0 w-full font-bold text-default-600 dark:text-default-400 px-1'>背景图</div>
|
||||||
<Controller
|
<Controller
|
||||||
|
|||||||
@ -1,16 +1,10 @@
|
|||||||
@font-face {
|
@font-face {
|
||||||
font-family: 'Aa偷吃可爱长大的';
|
font-family: 'JetBrains Mono';
|
||||||
src: url('/fonts/AaCute.woff') format('woff');
|
src: url('/webui/fonts/JetBrainsMono.ttf') format('truetype');
|
||||||
font-display: swap;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@font-face {
|
@font-face {
|
||||||
font-family: 'JetBrains Mono';
|
font-family: 'JetBrains Mono';
|
||||||
src: url('/fonts/JetBrainsMono.ttf') format('truetype');
|
src: url('/webui/fonts/JetBrainsMono-Italic.ttf') format('truetype');
|
||||||
}
|
|
||||||
|
|
||||||
@font-face {
|
|
||||||
font-family: 'JetBrains Mono';
|
|
||||||
src: url('/fonts/JetBrainsMono-Italic.ttf') format('truetype');
|
|
||||||
font-style: italic;
|
font-style: italic;
|
||||||
}
|
}
|
||||||
@ -5,20 +5,7 @@
|
|||||||
@tailwind utilities;
|
@tailwind utilities;
|
||||||
|
|
||||||
body {
|
body {
|
||||||
font-family:
|
font-family: var(--font-family-base, 'Quicksand', 'Nunito', 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, 'PingFang SC', 'Microsoft YaHei', sans-serif) !important;
|
||||||
'Aa偷吃可爱长大的',
|
|
||||||
'Quicksand',
|
|
||||||
'Nunito',
|
|
||||||
'Inter',
|
|
||||||
-apple-system,
|
|
||||||
BlinkMacSystemFont,
|
|
||||||
'Segoe UI',
|
|
||||||
Roboto,
|
|
||||||
'Helvetica Neue',
|
|
||||||
Arial,
|
|
||||||
'PingFang SC',
|
|
||||||
'Microsoft YaHei',
|
|
||||||
sans-serif !important;
|
|
||||||
-webkit-font-smoothing: antialiased;
|
-webkit-font-smoothing: antialiased;
|
||||||
-moz-osx-font-smoothing: grayscale;
|
-moz-osx-font-smoothing: grayscale;
|
||||||
text-rendering: optimizeLegibility;
|
text-rendering: optimizeLegibility;
|
||||||
@ -27,6 +14,9 @@ body {
|
|||||||
}
|
}
|
||||||
|
|
||||||
:root {
|
:root {
|
||||||
|
/* 字体变量:可被 JS 动态覆盖 */
|
||||||
|
--font-family-fallbacks: 'Quicksand', 'Nunito', 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, 'PingFang SC', 'Microsoft YaHei', sans-serif;
|
||||||
|
--font-family-base: var(--font-family-fallbacks);
|
||||||
--heroui-primary: 217.2 91.2% 59.8%;
|
--heroui-primary: 217.2 91.2% 59.8%;
|
||||||
/* 自然的现代蓝 */
|
/* 自然的现代蓝 */
|
||||||
--heroui-primary-foreground: 210 40% 98%;
|
--heroui-primary-foreground: 210 40% 98%;
|
||||||
@ -153,21 +143,3 @@ h6 {
|
|||||||
.ql-editor img {
|
.ql-editor img {
|
||||||
@apply inline-block;
|
@apply inline-block;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* GPU-accelerated navigation indicator animation */
|
|
||||||
@keyframes nav-indicator-spin {
|
|
||||||
0% {
|
|
||||||
transform: rotate(0deg) translateZ(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
100% {
|
|
||||||
transform: rotate(360deg) translateZ(0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.animate-nav-spin {
|
|
||||||
animation: nav-indicator-spin 2s cubic-bezier(0.5, 0, 0.5, 1) infinite;
|
|
||||||
will-change: transform;
|
|
||||||
backface-visibility: hidden;
|
|
||||||
perspective: 1000px;
|
|
||||||
}
|
|
||||||
317
packages/napcat-webui-frontend/src/types/server.d.ts
vendored
317
packages/napcat-webui-frontend/src/types/server.d.ts
vendored
@ -1,191 +1,192 @@
|
|||||||
interface ServerResponse<T> {
|
interface ServerResponse<T> {
|
||||||
code: number
|
code: number;
|
||||||
data: T
|
data: T;
|
||||||
message: string
|
message: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface AuthResponse {
|
interface AuthResponse {
|
||||||
Credential: string
|
Credential: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface LoginListItem {
|
interface LoginListItem {
|
||||||
uin: string
|
uin: string;
|
||||||
uid: string
|
uid: string;
|
||||||
nickName: string
|
nickName: string;
|
||||||
faceUrl: string
|
faceUrl: string;
|
||||||
facePath: string
|
facePath: string;
|
||||||
loginType: 1 // 1是二维码登录?
|
loginType: 1; // 1是二维码登录?
|
||||||
isQuickLogin: boolean // 是否可以快速登录
|
isQuickLogin: boolean; // 是否可以快速登录
|
||||||
isAutoLogin: boolean // 是否可以自动登录
|
isAutoLogin: boolean; // 是否可以自动登录
|
||||||
}
|
}
|
||||||
|
|
||||||
interface PackageInfo {
|
interface PackageInfo {
|
||||||
name: string
|
name: string;
|
||||||
version: string
|
version: string;
|
||||||
private: boolean
|
private: boolean;
|
||||||
type: string
|
type: string;
|
||||||
scripts: Record<string, string>
|
scripts: Record<string, string>;
|
||||||
dependencies: Record<string, string>
|
dependencies: Record<string, string>;
|
||||||
devDependencies: Record<string, string>
|
devDependencies: Record<string, string>;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface SystemStatus {
|
interface SystemStatus {
|
||||||
cpu: {
|
cpu: {
|
||||||
core: number
|
core: number;
|
||||||
model: string
|
model: string;
|
||||||
speed: string
|
speed: string;
|
||||||
usage: {
|
usage: {
|
||||||
system: string
|
system: string;
|
||||||
qq: string
|
qq: string;
|
||||||
}
|
};
|
||||||
}
|
};
|
||||||
memory: {
|
memory: {
|
||||||
total: string
|
total: string;
|
||||||
usage: {
|
usage: {
|
||||||
system: string
|
system: string;
|
||||||
qq: string
|
qq: string;
|
||||||
}
|
};
|
||||||
}
|
};
|
||||||
arch: string
|
arch: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface ThemeConfigItem {
|
interface ThemeConfigItem {
|
||||||
'--heroui-background': string
|
'--heroui-background': string;
|
||||||
'--heroui-foreground-50': string
|
'--heroui-foreground-50': string;
|
||||||
'--heroui-foreground-100': string
|
'--heroui-foreground-100': string;
|
||||||
'--heroui-foreground-200': string
|
'--heroui-foreground-200': string;
|
||||||
'--heroui-foreground-300': string
|
'--heroui-foreground-300': string;
|
||||||
'--heroui-foreground-400': string
|
'--heroui-foreground-400': string;
|
||||||
'--heroui-foreground-500': string
|
'--heroui-foreground-500': string;
|
||||||
'--heroui-foreground-600': string
|
'--heroui-foreground-600': string;
|
||||||
'--heroui-foreground-700': string
|
'--heroui-foreground-700': string;
|
||||||
'--heroui-foreground-800': string
|
'--heroui-foreground-800': string;
|
||||||
'--heroui-foreground-900': string
|
'--heroui-foreground-900': string;
|
||||||
'--heroui-foreground': string
|
'--heroui-foreground': string;
|
||||||
'--heroui-focus': string
|
'--heroui-focus': string;
|
||||||
'--heroui-overlay': string
|
'--heroui-overlay': string;
|
||||||
'--heroui-divider': string
|
'--heroui-divider': string;
|
||||||
'--heroui-divider-opacity': string
|
'--heroui-divider-opacity': string;
|
||||||
'--heroui-content1': string
|
'--heroui-content1': string;
|
||||||
'--heroui-content1-foreground': string
|
'--heroui-content1-foreground': string;
|
||||||
'--heroui-content2': string
|
'--heroui-content2': string;
|
||||||
'--heroui-content2-foreground': string
|
'--heroui-content2-foreground': string;
|
||||||
'--heroui-content3': string
|
'--heroui-content3': string;
|
||||||
'--heroui-content3-foreground': string
|
'--heroui-content3-foreground': string;
|
||||||
'--heroui-content4': string
|
'--heroui-content4': string;
|
||||||
'--heroui-content4-foreground': string
|
'--heroui-content4-foreground': string;
|
||||||
'--heroui-default-50': string
|
'--heroui-default-50': string;
|
||||||
'--heroui-default-100': string
|
'--heroui-default-100': string;
|
||||||
'--heroui-default-200': string
|
'--heroui-default-200': string;
|
||||||
'--heroui-default-300': string
|
'--heroui-default-300': string;
|
||||||
'--heroui-default-400': string
|
'--heroui-default-400': string;
|
||||||
'--heroui-default-500': string
|
'--heroui-default-500': string;
|
||||||
'--heroui-default-600': string
|
'--heroui-default-600': string;
|
||||||
'--heroui-default-700': string
|
'--heroui-default-700': string;
|
||||||
'--heroui-default-800': string
|
'--heroui-default-800': string;
|
||||||
'--heroui-default-900': string
|
'--heroui-default-900': string;
|
||||||
'--heroui-default-foreground': string
|
'--heroui-default-foreground': string;
|
||||||
'--heroui-default': string
|
'--heroui-default': string;
|
||||||
// 新增 danger
|
// 新增 danger
|
||||||
'--heroui-danger-50': string
|
'--heroui-danger-50': string;
|
||||||
'--heroui-danger-100': string
|
'--heroui-danger-100': string;
|
||||||
'--heroui-danger-200': string
|
'--heroui-danger-200': string;
|
||||||
'--heroui-danger-300': string
|
'--heroui-danger-300': string;
|
||||||
'--heroui-danger-400': string
|
'--heroui-danger-400': string;
|
||||||
'--heroui-danger-500': string
|
'--heroui-danger-500': string;
|
||||||
'--heroui-danger-600': string
|
'--heroui-danger-600': string;
|
||||||
'--heroui-danger-700': string
|
'--heroui-danger-700': string;
|
||||||
'--heroui-danger-800': string
|
'--heroui-danger-800': string;
|
||||||
'--heroui-danger-900': string
|
'--heroui-danger-900': string;
|
||||||
'--heroui-danger-foreground': string
|
'--heroui-danger-foreground': string;
|
||||||
'--heroui-danger': string
|
'--heroui-danger': string;
|
||||||
// 新增 primary
|
// 新增 primary
|
||||||
'--heroui-primary-50': string
|
'--heroui-primary-50': string;
|
||||||
'--heroui-primary-100': string
|
'--heroui-primary-100': string;
|
||||||
'--heroui-primary-200': string
|
'--heroui-primary-200': string;
|
||||||
'--heroui-primary-300': string
|
'--heroui-primary-300': string;
|
||||||
'--heroui-primary-400': string
|
'--heroui-primary-400': string;
|
||||||
'--heroui-primary-500': string
|
'--heroui-primary-500': string;
|
||||||
'--heroui-primary-600': string
|
'--heroui-primary-600': string;
|
||||||
'--heroui-primary-700': string
|
'--heroui-primary-700': string;
|
||||||
'--heroui-primary-800': string
|
'--heroui-primary-800': string;
|
||||||
'--heroui-primary-900': string
|
'--heroui-primary-900': string;
|
||||||
'--heroui-primary-foreground': string
|
'--heroui-primary-foreground': string;
|
||||||
'--heroui-primary': string
|
'--heroui-primary': string;
|
||||||
// 新增 secondary
|
// 新增 secondary
|
||||||
'--heroui-secondary-50': string
|
'--heroui-secondary-50': string;
|
||||||
'--heroui-secondary-100': string
|
'--heroui-secondary-100': string;
|
||||||
'--heroui-secondary-200': string
|
'--heroui-secondary-200': string;
|
||||||
'--heroui-secondary-300': string
|
'--heroui-secondary-300': string;
|
||||||
'--heroui-secondary-400': string
|
'--heroui-secondary-400': string;
|
||||||
'--heroui-secondary-500': string
|
'--heroui-secondary-500': string;
|
||||||
'--heroui-secondary-600': string
|
'--heroui-secondary-600': string;
|
||||||
'--heroui-secondary-700': string
|
'--heroui-secondary-700': string;
|
||||||
'--heroui-secondary-800': string
|
'--heroui-secondary-800': string;
|
||||||
'--heroui-secondary-900': string
|
'--heroui-secondary-900': string;
|
||||||
'--heroui-secondary-foreground': string
|
'--heroui-secondary-foreground': string;
|
||||||
'--heroui-secondary': string
|
'--heroui-secondary': string;
|
||||||
// 新增 success
|
// 新增 success
|
||||||
'--heroui-success-50': string
|
'--heroui-success-50': string;
|
||||||
'--heroui-success-100': string
|
'--heroui-success-100': string;
|
||||||
'--heroui-success-200': string
|
'--heroui-success-200': string;
|
||||||
'--heroui-success-300': string
|
'--heroui-success-300': string;
|
||||||
'--heroui-success-400': string
|
'--heroui-success-400': string;
|
||||||
'--heroui-success-500': string
|
'--heroui-success-500': string;
|
||||||
'--heroui-success-600': string
|
'--heroui-success-600': string;
|
||||||
'--heroui-success-700': string
|
'--heroui-success-700': string;
|
||||||
'--heroui-success-800': string
|
'--heroui-success-800': string;
|
||||||
'--heroui-success-900': string
|
'--heroui-success-900': string;
|
||||||
'--heroui-success-foreground': string
|
'--heroui-success-foreground': string;
|
||||||
'--heroui-success': string
|
'--heroui-success': string;
|
||||||
// 新增 warning
|
// 新增 warning
|
||||||
'--heroui-warning-50': string
|
'--heroui-warning-50': string;
|
||||||
'--heroui-warning-100': string
|
'--heroui-warning-100': string;
|
||||||
'--heroui-warning-200': string
|
'--heroui-warning-200': string;
|
||||||
'--heroui-warning-300': string
|
'--heroui-warning-300': string;
|
||||||
'--heroui-warning-400': string
|
'--heroui-warning-400': string;
|
||||||
'--heroui-warning-500': string
|
'--heroui-warning-500': string;
|
||||||
'--heroui-warning-600': string
|
'--heroui-warning-600': string;
|
||||||
'--heroui-warning-700': string
|
'--heroui-warning-700': string;
|
||||||
'--heroui-warning-800': string
|
'--heroui-warning-800': string;
|
||||||
'--heroui-warning-900': string
|
'--heroui-warning-900': string;
|
||||||
'--heroui-warning-foreground': string
|
'--heroui-warning-foreground': string;
|
||||||
'--heroui-warning': string
|
'--heroui-warning': string;
|
||||||
// 其它配置
|
// 其它配置
|
||||||
'--heroui-code-background': string
|
'--heroui-code-background': string;
|
||||||
'--heroui-strong': string
|
'--heroui-strong': string;
|
||||||
'--heroui-code-mdx': string
|
'--heroui-code-mdx': string;
|
||||||
'--heroui-divider-weight': string
|
'--heroui-divider-weight': string;
|
||||||
'--heroui-disabled-opacity': string
|
'--heroui-disabled-opacity': string;
|
||||||
'--heroui-font-size-tiny': string
|
'--heroui-font-size-tiny': string;
|
||||||
'--heroui-font-size-small': string
|
'--heroui-font-size-small': string;
|
||||||
'--heroui-font-size-medium': string
|
'--heroui-font-size-medium': string;
|
||||||
'--heroui-font-size-large': string
|
'--heroui-font-size-large': string;
|
||||||
'--heroui-line-height-tiny': string
|
'--heroui-line-height-tiny': string;
|
||||||
'--heroui-line-height-small': string
|
'--heroui-line-height-small': string;
|
||||||
'--heroui-line-height-medium': string
|
'--heroui-line-height-medium': string;
|
||||||
'--heroui-line-height-large': string
|
'--heroui-line-height-large': string;
|
||||||
'--heroui-radius-small': string
|
'--heroui-radius-small': string;
|
||||||
'--heroui-radius-medium': string
|
'--heroui-radius-medium': string;
|
||||||
'--heroui-radius-large': string
|
'--heroui-radius-large': string;
|
||||||
'--heroui-border-width-small': string
|
'--heroui-border-width-small': string;
|
||||||
'--heroui-border-width-medium': string
|
'--heroui-border-width-medium': string;
|
||||||
'--heroui-border-width-large': string
|
'--heroui-border-width-large': string;
|
||||||
'--heroui-box-shadow-small': string
|
'--heroui-box-shadow-small': string;
|
||||||
'--heroui-box-shadow-medium': string
|
'--heroui-box-shadow-medium': string;
|
||||||
'--heroui-box-shadow-large': string
|
'--heroui-box-shadow-large': string;
|
||||||
'--heroui-hover-opacity': string
|
'--heroui-hover-opacity': string;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface ThemeConfig {
|
interface ThemeConfig {
|
||||||
dark: ThemeConfigItem
|
dark: ThemeConfigItem;
|
||||||
light: ThemeConfigItem
|
light: ThemeConfigItem;
|
||||||
|
fontMode?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface WebUIConfig {
|
interface WebUIConfig {
|
||||||
host: string
|
host: string;
|
||||||
port: number
|
port: number;
|
||||||
loginRate: number
|
loginRate: number;
|
||||||
disableWebUI: boolean
|
disableWebUI: boolean;
|
||||||
disableNonLANAccess: boolean
|
disableNonLANAccess: boolean;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,6 +3,11 @@ import { request } from './request';
|
|||||||
const style = document.createElement('style');
|
const style = document.createElement('style');
|
||||||
document.head.appendChild(style);
|
document.head.appendChild(style);
|
||||||
|
|
||||||
|
// 字体样式标签
|
||||||
|
const fontStyle = document.createElement('style');
|
||||||
|
fontStyle.id = 'dynamic-font-style';
|
||||||
|
document.head.appendChild(fontStyle);
|
||||||
|
|
||||||
export function loadTheme () {
|
export function loadTheme () {
|
||||||
request('/files/theme.css?_t=' + Date.now())
|
request('/files/theme.css?_t=' + Date.now())
|
||||||
.then((res) => res.data)
|
.then((res) => res.data)
|
||||||
@ -14,6 +19,29 @@ export function loadTheme () {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 动态加载字体 CSS
|
||||||
|
const loadFontCSS = (mode: string) => {
|
||||||
|
let css = '';
|
||||||
|
|
||||||
|
if (mode === 'aacute') {
|
||||||
|
css = `
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Aa偷吃可爱长大的';
|
||||||
|
src: url('/webui/fonts/AaCute.woff') format('woff');
|
||||||
|
font-display: swap;
|
||||||
|
}`;
|
||||||
|
} else if (mode === 'custom') {
|
||||||
|
css = `
|
||||||
|
@font-face {
|
||||||
|
font-family: 'CustomFont';
|
||||||
|
src: url('/webui/fonts/CustomFont.woff') format('woff');
|
||||||
|
font-display: swap;
|
||||||
|
}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
fontStyle.innerHTML = css;
|
||||||
|
};
|
||||||
|
|
||||||
export const colorKeys = [
|
export const colorKeys = [
|
||||||
'--heroui-background',
|
'--heroui-background',
|
||||||
|
|
||||||
@ -139,3 +167,53 @@ export const generateTheme = (theme: ThemeConfig, validField?: string) => {
|
|||||||
css += '}';
|
css += '}';
|
||||||
return css;
|
return css;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const applyFont = (mode: string) => {
|
||||||
|
const root = document.documentElement;
|
||||||
|
|
||||||
|
// 先加载字体 CSS
|
||||||
|
loadFontCSS(mode);
|
||||||
|
|
||||||
|
if (mode === 'aacute') {
|
||||||
|
root.style.setProperty('--font-family-base', "'Aa偷吃可爱长大的', var(--font-family-fallbacks)", 'important');
|
||||||
|
} else if (mode === 'custom') {
|
||||||
|
root.style.setProperty('--font-family-base', "'CustomFont', var(--font-family-fallbacks)", 'important');
|
||||||
|
} else {
|
||||||
|
// system or default - restore default
|
||||||
|
root.style.setProperty('--font-family-base', 'var(--font-family-fallbacks)', 'important');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const FONT_MODE_CACHE_KEY = 'webui-font-mode-cache';
|
||||||
|
|
||||||
|
export const initFont = () => {
|
||||||
|
// 先从缓存读取,立即应用
|
||||||
|
const cached = localStorage.getItem(FONT_MODE_CACHE_KEY);
|
||||||
|
if (cached) {
|
||||||
|
applyFont(cached);
|
||||||
|
} else {
|
||||||
|
// 默认使用系统字体
|
||||||
|
applyFont('system');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 后台拉取最新配置并更新缓存
|
||||||
|
request('/api/base/Theme')
|
||||||
|
.then((res) => {
|
||||||
|
const data = res.data as { data: ThemeConfig; };
|
||||||
|
const fontMode = data?.data?.fontMode || 'system';
|
||||||
|
// 更新缓存
|
||||||
|
localStorage.setItem(FONT_MODE_CACHE_KEY, fontMode);
|
||||||
|
// 如果与当前不同,则应用新字体
|
||||||
|
if (fontMode !== cached) {
|
||||||
|
applyFont(fontMode);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch((e) => {
|
||||||
|
console.error('Failed to fetch font config', e);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// 保存时更新缓存
|
||||||
|
export const updateFontCache = (fontMode: string) => {
|
||||||
|
localStorage.setItem(FONT_MODE_CACHE_KEY, fontMode);
|
||||||
|
};
|
||||||
|
|||||||
@ -1,13 +1,9 @@
|
|||||||
import react from '@vitejs/plugin-react';
|
import react from '@vitejs/plugin-react';
|
||||||
import path from 'node:path';
|
import { defineConfig, loadEnv } from 'vite';
|
||||||
import { defineConfig, loadEnv, normalizePath } from 'vite';
|
import viteCompression from 'vite-plugin-compression';
|
||||||
import { viteStaticCopy } from 'vite-plugin-static-copy';
|
import { ViteImageOptimizer } from 'vite-plugin-image-optimizer';
|
||||||
import tsconfigPaths from 'vite-tsconfig-paths';
|
import tsconfigPaths from 'vite-tsconfig-paths';
|
||||||
|
|
||||||
const monacoEditorPath = normalizePath(
|
|
||||||
path.resolve(__dirname, 'node_modules/monaco-editor/min/vs')
|
|
||||||
);
|
|
||||||
|
|
||||||
// https://vitejs.dev/config/
|
// https://vitejs.dev/config/
|
||||||
export default defineConfig(({ mode }) => {
|
export default defineConfig(({ mode }) => {
|
||||||
const env = loadEnv(mode, process.cwd());
|
const env = loadEnv(mode, process.cwd());
|
||||||
@ -17,14 +13,7 @@ export default defineConfig(({ mode }) => {
|
|||||||
plugins: [
|
plugins: [
|
||||||
react(),
|
react(),
|
||||||
tsconfigPaths(),
|
tsconfigPaths(),
|
||||||
viteStaticCopy({
|
ViteImageOptimizer({}),
|
||||||
targets: [
|
|
||||||
{
|
|
||||||
src: monacoEditorPath,
|
|
||||||
dest: 'monaco-editor/min',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
}),
|
|
||||||
],
|
],
|
||||||
base: '/webui/',
|
base: '/webui/',
|
||||||
server: {
|
server: {
|
||||||
@ -41,19 +30,41 @@ export default defineConfig(({ mode }) => {
|
|||||||
},
|
},
|
||||||
'/api': backendDebugUrl,
|
'/api': backendDebugUrl,
|
||||||
'/files': backendDebugUrl,
|
'/files': backendDebugUrl,
|
||||||
|
'/webui/fonts/CustomFont.woff': backendDebugUrl,
|
||||||
|
'/webui/sw.js': backendDebugUrl,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
build: {
|
build: {
|
||||||
assetsInlineLimit: 0,
|
assetsInlineLimit: 0,
|
||||||
rollupOptions: {
|
rollupOptions: {
|
||||||
output: {
|
output: {
|
||||||
manualChunks: {
|
manualChunks (id) {
|
||||||
'monaco-editor': ['monaco-editor'],
|
if (id.includes('node_modules')) {
|
||||||
'react-dom': ['react-dom'],
|
if (id.includes('@heroui/')) {
|
||||||
'react-router-dom': ['react-router-dom'],
|
return 'heroui';
|
||||||
'react-hook-form': ['react-hook-form'],
|
}
|
||||||
'react-hot-toast': ['react-hot-toast'],
|
if (id.includes('react-dom')) {
|
||||||
qface: ['qface'],
|
return 'react-dom';
|
||||||
|
}
|
||||||
|
if (id.includes('react-router-dom')) {
|
||||||
|
return 'react-router-dom';
|
||||||
|
}
|
||||||
|
if (id.includes('react-hook-form')) {
|
||||||
|
return 'react-hook-form';
|
||||||
|
}
|
||||||
|
if (id.includes('react-hot-toast')) {
|
||||||
|
return 'react-hot-toast';
|
||||||
|
}
|
||||||
|
if (id.includes('qface')) {
|
||||||
|
return 'qface';
|
||||||
|
}
|
||||||
|
if (id.includes('@uiw/react-codemirror') || id.includes('@codemirror/view') || id.includes('@codemirror/theme-one-dark')) {
|
||||||
|
return 'codemirror-core';
|
||||||
|
}
|
||||||
|
if (id.includes('@codemirror/lang-')) {
|
||||||
|
return 'codemirror-lang';
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
685
pnpm-lock.yaml
685
pnpm-lock.yaml
@ -323,6 +323,9 @@ importers:
|
|||||||
compressing:
|
compressing:
|
||||||
specifier: ^1.10.3
|
specifier: ^1.10.3
|
||||||
version: 1.10.3
|
version: 1.10.3
|
||||||
|
compression:
|
||||||
|
specifier: ^1.8.1
|
||||||
|
version: 1.8.1
|
||||||
express:
|
express:
|
||||||
specifier: ^5.0.0
|
specifier: ^5.0.0
|
||||||
version: 5.1.0
|
version: 5.1.0
|
||||||
@ -345,6 +348,9 @@ importers:
|
|||||||
specifier: ^8.18.3
|
specifier: ^8.18.3
|
||||||
version: 8.18.3
|
version: 8.18.3
|
||||||
devDependencies:
|
devDependencies:
|
||||||
|
'@types/compression':
|
||||||
|
specifier: ^1.8.1
|
||||||
|
version: 1.8.1
|
||||||
'@types/express':
|
'@types/express':
|
||||||
specifier: ^5.0.0
|
specifier: ^5.0.0
|
||||||
version: 5.0.5
|
version: 5.0.5
|
||||||
@ -360,6 +366,21 @@ importers:
|
|||||||
|
|
||||||
packages/napcat-webui-frontend:
|
packages/napcat-webui-frontend:
|
||||||
dependencies:
|
dependencies:
|
||||||
|
'@codemirror/lang-css':
|
||||||
|
specifier: ^6.3.1
|
||||||
|
version: 6.3.1
|
||||||
|
'@codemirror/lang-javascript':
|
||||||
|
specifier: ^6.2.4
|
||||||
|
version: 6.2.4
|
||||||
|
'@codemirror/lang-json':
|
||||||
|
specifier: ^6.0.2
|
||||||
|
version: 6.0.2
|
||||||
|
'@codemirror/theme-one-dark':
|
||||||
|
specifier: ^6.1.3
|
||||||
|
version: 6.1.3
|
||||||
|
'@codemirror/view':
|
||||||
|
specifier: ^6.39.6
|
||||||
|
version: 6.39.6
|
||||||
'@dnd-kit/core':
|
'@dnd-kit/core':
|
||||||
specifier: ^6.3.1
|
specifier: ^6.3.1
|
||||||
version: 6.3.1(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
|
version: 6.3.1(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
|
||||||
@ -465,9 +486,6 @@ importers:
|
|||||||
'@monaco-editor/loader':
|
'@monaco-editor/loader':
|
||||||
specifier: ^1.4.0
|
specifier: ^1.4.0
|
||||||
version: 1.6.1
|
version: 1.6.1
|
||||||
'@monaco-editor/react':
|
|
||||||
specifier: 4.7.0-rc.0
|
|
||||||
version: 4.7.0-rc.0(monaco-editor@0.52.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
|
|
||||||
'@react-aria/visually-hidden':
|
'@react-aria/visually-hidden':
|
||||||
specifier: ^3.8.19
|
specifier: ^3.8.19
|
||||||
version: 3.8.28(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
|
version: 3.8.28(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
|
||||||
@ -477,6 +495,9 @@ importers:
|
|||||||
'@uidotdev/usehooks':
|
'@uidotdev/usehooks':
|
||||||
specifier: ^2.4.1
|
specifier: ^2.4.1
|
||||||
version: 2.4.1(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
|
version: 2.4.1(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
|
||||||
|
'@uiw/react-codemirror':
|
||||||
|
specifier: ^4.25.4
|
||||||
|
version: 4.25.4(@babel/runtime@7.28.4)(@codemirror/autocomplete@6.20.0)(@codemirror/language@6.12.1)(@codemirror/lint@6.9.2)(@codemirror/search@6.5.11)(@codemirror/state@6.5.3)(@codemirror/theme-one-dark@6.1.3)(@codemirror/view@6.39.6)(codemirror@6.0.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
|
||||||
'@xterm/addon-canvas':
|
'@xterm/addon-canvas':
|
||||||
specifier: ^0.7.0
|
specifier: ^0.7.0
|
||||||
version: 0.7.0(@xterm/xterm@5.5.0)
|
version: 0.7.0(@xterm/xterm@5.5.0)
|
||||||
@ -504,9 +525,6 @@ importers:
|
|||||||
event-source-polyfill:
|
event-source-polyfill:
|
||||||
specifier: ^1.0.31
|
specifier: ^1.0.31
|
||||||
version: 1.0.31
|
version: 1.0.31
|
||||||
monaco-editor:
|
|
||||||
specifier: ^0.52.2
|
|
||||||
version: 0.52.2
|
|
||||||
motion:
|
motion:
|
||||||
specifier: ^12.0.6
|
specifier: ^12.0.6
|
||||||
version: 12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
|
version: 12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
|
||||||
@ -643,15 +661,24 @@ importers:
|
|||||||
prettier:
|
prettier:
|
||||||
specifier: ^3.4.2
|
specifier: ^3.4.2
|
||||||
version: 3.6.2
|
version: 3.6.2
|
||||||
|
sharp:
|
||||||
|
specifier: ^0.34.5
|
||||||
|
version: 0.34.5
|
||||||
typescript:
|
typescript:
|
||||||
specifier: ^5.7.3
|
specifier: ^5.7.3
|
||||||
version: 5.9.3
|
version: 5.9.3
|
||||||
vite:
|
vite:
|
||||||
specifier: ^6.0.5
|
specifier: ^6.0.5
|
||||||
version: 6.4.1(@types/node@22.19.1)(jiti@1.21.7)
|
version: 6.4.1(@types/node@22.19.1)(jiti@1.21.7)
|
||||||
|
vite-plugin-compression:
|
||||||
|
specifier: ^0.5.1
|
||||||
|
version: 0.5.1(vite@6.4.1(@types/node@22.19.1)(jiti@1.21.7))
|
||||||
vite-plugin-font:
|
vite-plugin-font:
|
||||||
specifier: ^5.1.2
|
specifier: ^5.1.2
|
||||||
version: 5.1.2(encoding@0.1.13)
|
version: 5.1.2(encoding@0.1.13)
|
||||||
|
vite-plugin-image-optimizer:
|
||||||
|
specifier: ^2.0.3
|
||||||
|
version: 2.0.3(sharp@0.34.5)(vite@6.4.1(@types/node@22.19.1)(jiti@1.21.7))
|
||||||
vite-plugin-static-copy:
|
vite-plugin-static-copy:
|
||||||
specifier: ^2.2.0
|
specifier: ^2.2.0
|
||||||
version: 2.3.2(vite@6.4.1(@types/node@22.19.1)(jiti@1.21.7))
|
version: 2.3.2(vite@6.4.1(@types/node@22.19.1)(jiti@1.21.7))
|
||||||
@ -764,6 +791,39 @@ packages:
|
|||||||
'@capsizecss/unpack@2.4.0':
|
'@capsizecss/unpack@2.4.0':
|
||||||
resolution: {integrity: sha512-GrSU71meACqcmIUxPYOJvGKF0yryjN/L1aCuE9DViCTJI7bfkjgYDPD1zbNDcINJwSSP6UaBZY9GAbYDO7re0Q==}
|
resolution: {integrity: sha512-GrSU71meACqcmIUxPYOJvGKF0yryjN/L1aCuE9DViCTJI7bfkjgYDPD1zbNDcINJwSSP6UaBZY9GAbYDO7re0Q==}
|
||||||
|
|
||||||
|
'@codemirror/autocomplete@6.20.0':
|
||||||
|
resolution: {integrity: sha512-bOwvTOIJcG5FVo5gUUupiwYh8MioPLQ4UcqbcRf7UQ98X90tCa9E1kZ3Z7tqwpZxYyOvh1YTYbmZE9RTfTp5hg==}
|
||||||
|
|
||||||
|
'@codemirror/commands@6.10.1':
|
||||||
|
resolution: {integrity: sha512-uWDWFypNdQmz2y1LaNJzK7fL7TYKLeUAU0npEC685OKTF3KcQ2Vu3klIM78D7I6wGhktme0lh3CuQLv0ZCrD9Q==}
|
||||||
|
|
||||||
|
'@codemirror/lang-css@6.3.1':
|
||||||
|
resolution: {integrity: sha512-kr5fwBGiGtmz6l0LSJIbno9QrifNMUusivHbnA1H6Dmqy4HZFte3UAICix1VuKo0lMPKQr2rqB+0BkKi/S3Ejg==}
|
||||||
|
|
||||||
|
'@codemirror/lang-javascript@6.2.4':
|
||||||
|
resolution: {integrity: sha512-0WVmhp1QOqZ4Rt6GlVGwKJN3KW7Xh4H2q8ZZNGZaP6lRdxXJzmjm4FqvmOojVj6khWJHIb9sp7U/72W7xQgqAA==}
|
||||||
|
|
||||||
|
'@codemirror/lang-json@6.0.2':
|
||||||
|
resolution: {integrity: sha512-x2OtO+AvwEHrEwR0FyyPtfDUiloG3rnVTSZV1W8UteaLL8/MajQd8DpvUb2YVzC+/T18aSDv0H9mu+xw0EStoQ==}
|
||||||
|
|
||||||
|
'@codemirror/language@6.12.1':
|
||||||
|
resolution: {integrity: sha512-Fa6xkSiuGKc8XC8Cn96T+TQHYj4ZZ7RdFmXA3i9xe/3hLHfwPZdM+dqfX0Cp0zQklBKhVD8Yzc8LS45rkqcwpQ==}
|
||||||
|
|
||||||
|
'@codemirror/lint@6.9.2':
|
||||||
|
resolution: {integrity: sha512-sv3DylBiIyi+xKwRCJAAsBZZZWo82shJ/RTMymLabAdtbkV5cSKwWDeCgtUq3v8flTaXS2y1kKkICuRYtUswyQ==}
|
||||||
|
|
||||||
|
'@codemirror/search@6.5.11':
|
||||||
|
resolution: {integrity: sha512-KmWepDE6jUdL6n8cAAqIpRmLPBZ5ZKnicE8oGU/s3QrAVID+0VhLFrzUucVKHG5035/BSykhExDL/Xm7dHthiA==}
|
||||||
|
|
||||||
|
'@codemirror/state@6.5.3':
|
||||||
|
resolution: {integrity: sha512-MerMzJzlXogk2fxWFU1nKp36bY5orBG59HnPiz0G9nLRebWa0zXuv2siH6PLIHBvv5TH8CkQRqjBs0MlxCZu+A==}
|
||||||
|
|
||||||
|
'@codemirror/theme-one-dark@6.1.3':
|
||||||
|
resolution: {integrity: sha512-NzBdIvEJmx6fjeremiGp3t/okrLPYT0d9orIc7AFun8oZcRk58aejkqhv6spnz4MLAevrKNPMQYXEWMg4s+sKA==}
|
||||||
|
|
||||||
|
'@codemirror/view@6.39.6':
|
||||||
|
resolution: {integrity: sha512-/N+SoP5NndJjkGInp3BwlUa3KQKD6bDo0TV6ep37ueAdQ7BVu/PqlZNywmgjCq0MQoZadZd8T+MZucSr7fktyQ==}
|
||||||
|
|
||||||
'@colors/colors@1.6.0':
|
'@colors/colors@1.6.0':
|
||||||
resolution: {integrity: sha512-Ir+AOibqzrIsL6ajt3Rz3LskB7OiMVHqltZmspbW/TJuTVuyOMirVqAkjfY6JISiLHgyNqicAC8AyHHGzNd/dA==}
|
resolution: {integrity: sha512-Ir+AOibqzrIsL6ajt3Rz3LskB7OiMVHqltZmspbW/TJuTVuyOMirVqAkjfY6JISiLHgyNqicAC8AyHHGzNd/dA==}
|
||||||
engines: {node: '>=0.1.90'}
|
engines: {node: '>=0.1.90'}
|
||||||
@ -1569,6 +1629,159 @@ packages:
|
|||||||
peerDependencies:
|
peerDependencies:
|
||||||
react: '*'
|
react: '*'
|
||||||
|
|
||||||
|
'@img/colour@1.0.0':
|
||||||
|
resolution: {integrity: sha512-A5P/LfWGFSl6nsckYtjw9da+19jB8hkJ6ACTGcDfEJ0aE+l2n2El7dsVM7UVHZQ9s2lmYMWlrS21YLy2IR1LUw==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
|
||||||
|
'@img/sharp-darwin-arm64@0.34.5':
|
||||||
|
resolution: {integrity: sha512-imtQ3WMJXbMY4fxb/Ndp6HBTNVtWCUI0WdobyheGf5+ad6xX8VIDO8u2xE4qc/fr08CKG/7dDseFtn6M6g/r3w==}
|
||||||
|
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
|
||||||
|
cpu: [arm64]
|
||||||
|
os: [darwin]
|
||||||
|
|
||||||
|
'@img/sharp-darwin-x64@0.34.5':
|
||||||
|
resolution: {integrity: sha512-YNEFAF/4KQ/PeW0N+r+aVVsoIY0/qxxikF2SWdp+NRkmMB7y9LBZAVqQ4yhGCm/H3H270OSykqmQMKLBhBJDEw==}
|
||||||
|
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
|
||||||
|
cpu: [x64]
|
||||||
|
os: [darwin]
|
||||||
|
|
||||||
|
'@img/sharp-libvips-darwin-arm64@1.2.4':
|
||||||
|
resolution: {integrity: sha512-zqjjo7RatFfFoP0MkQ51jfuFZBnVE2pRiaydKJ1G/rHZvnsrHAOcQALIi9sA5co5xenQdTugCvtb1cuf78Vf4g==}
|
||||||
|
cpu: [arm64]
|
||||||
|
os: [darwin]
|
||||||
|
|
||||||
|
'@img/sharp-libvips-darwin-x64@1.2.4':
|
||||||
|
resolution: {integrity: sha512-1IOd5xfVhlGwX+zXv2N93k0yMONvUlANylbJw1eTah8K/Jtpi15KC+WSiaX/nBmbm2HxRM1gZ0nSdjSsrZbGKg==}
|
||||||
|
cpu: [x64]
|
||||||
|
os: [darwin]
|
||||||
|
|
||||||
|
'@img/sharp-libvips-linux-arm64@1.2.4':
|
||||||
|
resolution: {integrity: sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw==}
|
||||||
|
cpu: [arm64]
|
||||||
|
os: [linux]
|
||||||
|
libc: [glibc]
|
||||||
|
|
||||||
|
'@img/sharp-libvips-linux-arm@1.2.4':
|
||||||
|
resolution: {integrity: sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A==}
|
||||||
|
cpu: [arm]
|
||||||
|
os: [linux]
|
||||||
|
libc: [glibc]
|
||||||
|
|
||||||
|
'@img/sharp-libvips-linux-ppc64@1.2.4':
|
||||||
|
resolution: {integrity: sha512-FMuvGijLDYG6lW+b/UvyilUWu5Ayu+3r2d1S8notiGCIyYU/76eig1UfMmkZ7vwgOrzKzlQbFSuQfgm7GYUPpA==}
|
||||||
|
cpu: [ppc64]
|
||||||
|
os: [linux]
|
||||||
|
libc: [glibc]
|
||||||
|
|
||||||
|
'@img/sharp-libvips-linux-riscv64@1.2.4':
|
||||||
|
resolution: {integrity: sha512-oVDbcR4zUC0ce82teubSm+x6ETixtKZBh/qbREIOcI3cULzDyb18Sr/Wcyx7NRQeQzOiHTNbZFF1UwPS2scyGA==}
|
||||||
|
cpu: [riscv64]
|
||||||
|
os: [linux]
|
||||||
|
libc: [glibc]
|
||||||
|
|
||||||
|
'@img/sharp-libvips-linux-s390x@1.2.4':
|
||||||
|
resolution: {integrity: sha512-qmp9VrzgPgMoGZyPvrQHqk02uyjA0/QrTO26Tqk6l4ZV0MPWIW6LTkqOIov+J1yEu7MbFQaDpwdwJKhbJvuRxQ==}
|
||||||
|
cpu: [s390x]
|
||||||
|
os: [linux]
|
||||||
|
libc: [glibc]
|
||||||
|
|
||||||
|
'@img/sharp-libvips-linux-x64@1.2.4':
|
||||||
|
resolution: {integrity: sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw==}
|
||||||
|
cpu: [x64]
|
||||||
|
os: [linux]
|
||||||
|
libc: [glibc]
|
||||||
|
|
||||||
|
'@img/sharp-libvips-linuxmusl-arm64@1.2.4':
|
||||||
|
resolution: {integrity: sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw==}
|
||||||
|
cpu: [arm64]
|
||||||
|
os: [linux]
|
||||||
|
libc: [musl]
|
||||||
|
|
||||||
|
'@img/sharp-libvips-linuxmusl-x64@1.2.4':
|
||||||
|
resolution: {integrity: sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg==}
|
||||||
|
cpu: [x64]
|
||||||
|
os: [linux]
|
||||||
|
libc: [musl]
|
||||||
|
|
||||||
|
'@img/sharp-linux-arm64@0.34.5':
|
||||||
|
resolution: {integrity: sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg==}
|
||||||
|
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
|
||||||
|
cpu: [arm64]
|
||||||
|
os: [linux]
|
||||||
|
libc: [glibc]
|
||||||
|
|
||||||
|
'@img/sharp-linux-arm@0.34.5':
|
||||||
|
resolution: {integrity: sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw==}
|
||||||
|
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
|
||||||
|
cpu: [arm]
|
||||||
|
os: [linux]
|
||||||
|
libc: [glibc]
|
||||||
|
|
||||||
|
'@img/sharp-linux-ppc64@0.34.5':
|
||||||
|
resolution: {integrity: sha512-7zznwNaqW6YtsfrGGDA6BRkISKAAE1Jo0QdpNYXNMHu2+0dTrPflTLNkpc8l7MUP5M16ZJcUvysVWWrMefZquA==}
|
||||||
|
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
|
||||||
|
cpu: [ppc64]
|
||||||
|
os: [linux]
|
||||||
|
libc: [glibc]
|
||||||
|
|
||||||
|
'@img/sharp-linux-riscv64@0.34.5':
|
||||||
|
resolution: {integrity: sha512-51gJuLPTKa7piYPaVs8GmByo7/U7/7TZOq+cnXJIHZKavIRHAP77e3N2HEl3dgiqdD/w0yUfiJnII77PuDDFdw==}
|
||||||
|
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
|
||||||
|
cpu: [riscv64]
|
||||||
|
os: [linux]
|
||||||
|
libc: [glibc]
|
||||||
|
|
||||||
|
'@img/sharp-linux-s390x@0.34.5':
|
||||||
|
resolution: {integrity: sha512-nQtCk0PdKfho3eC5MrbQoigJ2gd1CgddUMkabUj+rBevs8tZ2cULOx46E7oyX+04WGfABgIwmMC0VqieTiR4jg==}
|
||||||
|
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
|
||||||
|
cpu: [s390x]
|
||||||
|
os: [linux]
|
||||||
|
libc: [glibc]
|
||||||
|
|
||||||
|
'@img/sharp-linux-x64@0.34.5':
|
||||||
|
resolution: {integrity: sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ==}
|
||||||
|
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
|
||||||
|
cpu: [x64]
|
||||||
|
os: [linux]
|
||||||
|
libc: [glibc]
|
||||||
|
|
||||||
|
'@img/sharp-linuxmusl-arm64@0.34.5':
|
||||||
|
resolution: {integrity: sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg==}
|
||||||
|
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
|
||||||
|
cpu: [arm64]
|
||||||
|
os: [linux]
|
||||||
|
libc: [musl]
|
||||||
|
|
||||||
|
'@img/sharp-linuxmusl-x64@0.34.5':
|
||||||
|
resolution: {integrity: sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q==}
|
||||||
|
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
|
||||||
|
cpu: [x64]
|
||||||
|
os: [linux]
|
||||||
|
libc: [musl]
|
||||||
|
|
||||||
|
'@img/sharp-wasm32@0.34.5':
|
||||||
|
resolution: {integrity: sha512-OdWTEiVkY2PHwqkbBI8frFxQQFekHaSSkUIJkwzclWZe64O1X4UlUjqqqLaPbUpMOQk6FBu/HtlGXNblIs0huw==}
|
||||||
|
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
|
||||||
|
cpu: [wasm32]
|
||||||
|
|
||||||
|
'@img/sharp-win32-arm64@0.34.5':
|
||||||
|
resolution: {integrity: sha512-WQ3AgWCWYSb2yt+IG8mnC6Jdk9Whs7O0gxphblsLvdhSpSTtmu69ZG1Gkb6NuvxsNACwiPV6cNSZNzt0KPsw7g==}
|
||||||
|
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
|
||||||
|
cpu: [arm64]
|
||||||
|
os: [win32]
|
||||||
|
|
||||||
|
'@img/sharp-win32-ia32@0.34.5':
|
||||||
|
resolution: {integrity: sha512-FV9m/7NmeCmSHDD5j4+4pNI8Cp3aW+JvLoXcTUo0IqyjSfAZJ8dIUmijx1qaJsIiU+Hosw6xM5KijAWRJCSgNg==}
|
||||||
|
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
|
||||||
|
cpu: [ia32]
|
||||||
|
os: [win32]
|
||||||
|
|
||||||
|
'@img/sharp-win32-x64@0.34.5':
|
||||||
|
resolution: {integrity: sha512-+29YMsqY2/9eFEiW93eqWnuLcWcufowXewwSNIT6UwZdUUCrM3oFjMWH/Z6/TMmb4hlFenmfAVbpWeup2jryCw==}
|
||||||
|
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
|
||||||
|
cpu: [x64]
|
||||||
|
os: [win32]
|
||||||
|
|
||||||
'@internationalized/date@3.10.0':
|
'@internationalized/date@3.10.0':
|
||||||
resolution: {integrity: sha512-oxDR/NTEJ1k+UFVQElaNIk65E/Z83HK1z1WI3lQyhTtnNg4R5oVXaPzK3jcpKG8UHKDVuDQHzn+wsxSz8RP3aw==}
|
resolution: {integrity: sha512-oxDR/NTEJ1k+UFVQElaNIk65E/Z83HK1z1WI3lQyhTtnNg4R5oVXaPzK3jcpKG8UHKDVuDQHzn+wsxSz8RP3aw==}
|
||||||
|
|
||||||
@ -1637,16 +1850,30 @@ packages:
|
|||||||
'@levischuck/tiny-cbor@0.2.11':
|
'@levischuck/tiny-cbor@0.2.11':
|
||||||
resolution: {integrity: sha512-llBRm4dT4Z89aRsm6u2oEZ8tfwL/2l6BwpZ7JcyieouniDECM5AqNgr/y08zalEIvW3RSK4upYyybDcmjXqAow==}
|
resolution: {integrity: sha512-llBRm4dT4Z89aRsm6u2oEZ8tfwL/2l6BwpZ7JcyieouniDECM5AqNgr/y08zalEIvW3RSK4upYyybDcmjXqAow==}
|
||||||
|
|
||||||
|
'@lezer/common@1.5.0':
|
||||||
|
resolution: {integrity: sha512-PNGcolp9hr4PJdXR4ix7XtixDrClScvtSCYW3rQG106oVMOOI+jFb+0+J3mbeL/53g1Zd6s0kJzaw6Ri68GmAA==}
|
||||||
|
|
||||||
|
'@lezer/css@1.3.0':
|
||||||
|
resolution: {integrity: sha512-pBL7hup88KbI7hXnZV3PQsn43DHy6TWyzuyk2AO9UyoXcDltvIdqWKE1dLL/45JVZ+YZkHe1WVHqO6wugZZWcw==}
|
||||||
|
|
||||||
|
'@lezer/highlight@1.2.3':
|
||||||
|
resolution: {integrity: sha512-qXdH7UqTvGfdVBINrgKhDsVTJTxactNNxLk7+UMwZhU13lMHaOBlJe9Vqp907ya56Y3+ed2tlqzys7jDkTmW0g==}
|
||||||
|
|
||||||
|
'@lezer/javascript@1.5.4':
|
||||||
|
resolution: {integrity: sha512-vvYx3MhWqeZtGPwDStM2dwgljd5smolYD2lR2UyFcHfxbBQebqx8yjmFmxtJ/E6nN6u1D9srOiVWm3Rb4tmcUA==}
|
||||||
|
|
||||||
|
'@lezer/json@1.0.3':
|
||||||
|
resolution: {integrity: sha512-BP9KzdF9Y35PDpv04r0VeSTKDeox5vVr3efE7eBbx3r4s3oNLfunchejZhjArmeieBH+nVOpgIiBJpEAv8ilqQ==}
|
||||||
|
|
||||||
|
'@lezer/lr@1.4.5':
|
||||||
|
resolution: {integrity: sha512-/YTRKP5yPPSo1xImYQk7AZZMAgap0kegzqCSYHjAL9x1AZ0ZQW+IpcEzMKagCsbTsLnVeWkxYrCNeXG8xEPrjg==}
|
||||||
|
|
||||||
|
'@marijn/find-cluster-break@1.0.2':
|
||||||
|
resolution: {integrity: sha512-l0h88YhZFyKdXIFNfSWpyjStDjGHwZ/U7iobcK1cQQD8sejsONdQtTVU+1wVN1PBw40PiiHB1vA5S7VTfQiP9g==}
|
||||||
|
|
||||||
'@monaco-editor/loader@1.6.1':
|
'@monaco-editor/loader@1.6.1':
|
||||||
resolution: {integrity: sha512-w3tEnj9HYEC73wtjdpR089AqkUPskFRcdkxsiSFt3SoUc3OHpmu+leP94CXBm4mHfefmhsdfI0ZQu6qJ0wgtPg==}
|
resolution: {integrity: sha512-w3tEnj9HYEC73wtjdpR089AqkUPskFRcdkxsiSFt3SoUc3OHpmu+leP94CXBm4mHfefmhsdfI0ZQu6qJ0wgtPg==}
|
||||||
|
|
||||||
'@monaco-editor/react@4.7.0-rc.0':
|
|
||||||
resolution: {integrity: sha512-YfjXkDK0bcwS0zo8PXptvQdCQfOPPtzGsAzmIv7PnoUGFdIohsR+NVDyjbajMddF+3cWUm/3q9NzP/DUke9a+w==}
|
|
||||||
peerDependencies:
|
|
||||||
monaco-editor: '>= 0.25.0 < 1'
|
|
||||||
react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0
|
|
||||||
react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0
|
|
||||||
|
|
||||||
'@napi-rs/wasm-runtime@0.2.12':
|
'@napi-rs/wasm-runtime@0.2.12':
|
||||||
resolution: {integrity: sha512-ZVWUcfwY4E/yPitQJl481FjFo3K22D6qF0DuFH6Y/nbnE11GY5uguDxZMGXPQ8WQ0128MXQD7TnfHyK4oWoIJQ==}
|
resolution: {integrity: sha512-ZVWUcfwY4E/yPitQJl481FjFo3K22D6qF0DuFH6Y/nbnE11GY5uguDxZMGXPQ8WQ0128MXQD7TnfHyK4oWoIJQ==}
|
||||||
|
|
||||||
@ -2571,6 +2798,9 @@ packages:
|
|||||||
'@types/chai@5.2.3':
|
'@types/chai@5.2.3':
|
||||||
resolution: {integrity: sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==}
|
resolution: {integrity: sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==}
|
||||||
|
|
||||||
|
'@types/compression@1.8.1':
|
||||||
|
resolution: {integrity: sha512-kCFuWS0ebDbmxs0AXYn6e2r2nrGAb5KwQhknjSPSPgJcGd8+HVSILlUyFhGqML2gk39HcG7D1ydW9/qpYkN00Q==}
|
||||||
|
|
||||||
'@types/connect@3.4.38':
|
'@types/connect@3.4.38':
|
||||||
resolution: {integrity: sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==}
|
resolution: {integrity: sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==}
|
||||||
|
|
||||||
@ -2765,6 +2995,28 @@ packages:
|
|||||||
react: '>=18.0.0'
|
react: '>=18.0.0'
|
||||||
react-dom: '>=18.0.0'
|
react-dom: '>=18.0.0'
|
||||||
|
|
||||||
|
'@uiw/codemirror-extensions-basic-setup@4.25.4':
|
||||||
|
resolution: {integrity: sha512-YzNwkm0AbPv1EXhCHYR5v0nqfemG2jEB0Z3Att4rBYqKrlG7AA9Rhjc3IyBaOzsBu18wtrp9/+uhTyu7TXSRng==}
|
||||||
|
peerDependencies:
|
||||||
|
'@codemirror/autocomplete': '>=6.0.0'
|
||||||
|
'@codemirror/commands': '>=6.0.0'
|
||||||
|
'@codemirror/language': '>=6.0.0'
|
||||||
|
'@codemirror/lint': '>=6.0.0'
|
||||||
|
'@codemirror/search': '>=6.0.0'
|
||||||
|
'@codemirror/state': '>=6.0.0'
|
||||||
|
'@codemirror/view': '>=6.0.0'
|
||||||
|
|
||||||
|
'@uiw/react-codemirror@4.25.4':
|
||||||
|
resolution: {integrity: sha512-ipO067oyfUw+DVaXhQCxkB0ZD9b7RnY+ByrprSYSKCHaULvJ3sqWYC/Zen6zVQ8/XC4o5EPBfatGiX20kC7XGA==}
|
||||||
|
peerDependencies:
|
||||||
|
'@babel/runtime': '>=7.11.0'
|
||||||
|
'@codemirror/state': '>=6.0.0'
|
||||||
|
'@codemirror/theme-one-dark': '>=6.0.0'
|
||||||
|
'@codemirror/view': '>=6.0.0'
|
||||||
|
codemirror: '>=6.0.0'
|
||||||
|
react: '>=17.0.0'
|
||||||
|
react-dom: '>=17.0.0'
|
||||||
|
|
||||||
'@ungap/structured-clone@1.3.0':
|
'@ungap/structured-clone@1.3.0':
|
||||||
resolution: {integrity: sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==}
|
resolution: {integrity: sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==}
|
||||||
|
|
||||||
@ -2980,6 +3232,10 @@ packages:
|
|||||||
ajv@8.17.1:
|
ajv@8.17.1:
|
||||||
resolution: {integrity: sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==}
|
resolution: {integrity: sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==}
|
||||||
|
|
||||||
|
ansi-colors@4.1.3:
|
||||||
|
resolution: {integrity: sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==}
|
||||||
|
engines: {node: '>=6'}
|
||||||
|
|
||||||
ansi-regex@5.0.1:
|
ansi-regex@5.0.1:
|
||||||
resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==}
|
resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==}
|
||||||
engines: {node: '>=8'}
|
engines: {node: '>=8'}
|
||||||
@ -3336,6 +3592,9 @@ packages:
|
|||||||
code-points@2.0.0-1:
|
code-points@2.0.0-1:
|
||||||
resolution: {integrity: sha512-PuPoUdSqHY96e+CvEGe0+J9XkEqnQ4o79X+k+PJlZ84sZDoSJ2Q8/1OJT4dqYn8yL5EUxGCq/x2EcLEfvcGqaw==}
|
resolution: {integrity: sha512-PuPoUdSqHY96e+CvEGe0+J9XkEqnQ4o79X+k+PJlZ84sZDoSJ2Q8/1OJT4dqYn8yL5EUxGCq/x2EcLEfvcGqaw==}
|
||||||
|
|
||||||
|
codemirror@6.0.2:
|
||||||
|
resolution: {integrity: sha512-VhydHotNW5w1UGK0Qj96BwSk/Zqbp9WbnyK2W/eVMv4QyF41INRGpjUhFJY7/uDNuudSc33a/PKr4iDqRduvHw==}
|
||||||
|
|
||||||
color-convert@2.0.1:
|
color-convert@2.0.1:
|
||||||
resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==}
|
resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==}
|
||||||
engines: {node: '>=7.0.0'}
|
engines: {node: '>=7.0.0'}
|
||||||
@ -3400,10 +3659,18 @@ packages:
|
|||||||
resolution: {integrity: sha512-buhp5kePrmda3vhc5B9t7pUQXAb2Tnd0qgpkIhPhkHXxJpiPJ11H0ZEU0oBpJ2QztSbzG/ZxMj/CHsYJqRHmyg==}
|
resolution: {integrity: sha512-buhp5kePrmda3vhc5B9t7pUQXAb2Tnd0qgpkIhPhkHXxJpiPJ11H0ZEU0oBpJ2QztSbzG/ZxMj/CHsYJqRHmyg==}
|
||||||
engines: {node: '>= 12.0.0'}
|
engines: {node: '>= 12.0.0'}
|
||||||
|
|
||||||
|
compressible@2.0.18:
|
||||||
|
resolution: {integrity: sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==}
|
||||||
|
engines: {node: '>= 0.6'}
|
||||||
|
|
||||||
compressing@1.10.3:
|
compressing@1.10.3:
|
||||||
resolution: {integrity: sha512-F3RxWLU4UNfNYFVNwCK58HwQnv/5drvUW176FC//3i0pwpdahoZxMM7dkxWuA2MEafqfwDc+iudk70Sx/VMUIw==}
|
resolution: {integrity: sha512-F3RxWLU4UNfNYFVNwCK58HwQnv/5drvUW176FC//3i0pwpdahoZxMM7dkxWuA2MEafqfwDc+iudk70Sx/VMUIw==}
|
||||||
engines: {node: '>= 4.0.0'}
|
engines: {node: '>= 4.0.0'}
|
||||||
|
|
||||||
|
compression@1.8.1:
|
||||||
|
resolution: {integrity: sha512-9mAqGPHLakhCLeNyxPkK4xVo746zQ/czLH1Ky+vkitMnWfWZps8r0qXuwhwizagCRttsL4lfG4pIOvaWLpAP0w==}
|
||||||
|
engines: {node: '>= 0.8.0'}
|
||||||
|
|
||||||
compute-scroll-into-view@3.1.1:
|
compute-scroll-into-view@3.1.1:
|
||||||
resolution: {integrity: sha512-VRhuHOLoKYOy4UbilLbUzbYg93XLjv2PncJC50EuTWPA3gaja1UjBsUP/D/9/juV3vQFr6XBEzn9KCAHdUvOHw==}
|
resolution: {integrity: sha512-VRhuHOLoKYOy4UbilLbUzbYg93XLjv2PncJC50EuTWPA3gaja1UjBsUP/D/9/juV3vQFr6XBEzn9KCAHdUvOHw==}
|
||||||
|
|
||||||
@ -3453,6 +3720,9 @@ packages:
|
|||||||
resolution: {integrity: sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==}
|
resolution: {integrity: sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==}
|
||||||
engines: {node: '>= 0.10'}
|
engines: {node: '>= 0.10'}
|
||||||
|
|
||||||
|
crelt@1.0.6:
|
||||||
|
resolution: {integrity: sha512-VQ2MBenTq1fWZUH9DJNGti7kKv6EeAuYr3cLwxUWhIu1baTaXh4Ib5W2CqHVqib4/MqbYGJqiL3Zb8GJZr3l4g==}
|
||||||
|
|
||||||
cross-fetch@3.2.0:
|
cross-fetch@3.2.0:
|
||||||
resolution: {integrity: sha512-Q+xVJLoGOeIMXZmbUK4HYk+69cQH6LudR0Vu/pRm2YlU/hDV9CiS0gKUMaWY5f2NeUH9C1nV3bsTlCo0FsTV1Q==}
|
resolution: {integrity: sha512-Q+xVJLoGOeIMXZmbUK4HYk+69cQH6LudR0Vu/pRm2YlU/hDV9CiS0gKUMaWY5f2NeUH9C1nV3bsTlCo0FsTV1Q==}
|
||||||
|
|
||||||
@ -3496,6 +3766,14 @@ packages:
|
|||||||
dayjs@1.11.19:
|
dayjs@1.11.19:
|
||||||
resolution: {integrity: sha512-t5EcLVS6QPBNqM2z8fakk/NKel+Xzshgt8FFKAn+qwlD1pzZWxh0nVCrvFK7ZDb6XucZeF9z8C7CBWTRIVApAw==}
|
resolution: {integrity: sha512-t5EcLVS6QPBNqM2z8fakk/NKel+Xzshgt8FFKAn+qwlD1pzZWxh0nVCrvFK7ZDb6XucZeF9z8C7CBWTRIVApAw==}
|
||||||
|
|
||||||
|
debug@2.6.9:
|
||||||
|
resolution: {integrity: sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==}
|
||||||
|
peerDependencies:
|
||||||
|
supports-color: '*'
|
||||||
|
peerDependenciesMeta:
|
||||||
|
supports-color:
|
||||||
|
optional: true
|
||||||
|
|
||||||
debug@3.2.7:
|
debug@3.2.7:
|
||||||
resolution: {integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==}
|
resolution: {integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
@ -4095,6 +4373,10 @@ packages:
|
|||||||
fs-constants@1.0.0:
|
fs-constants@1.0.0:
|
||||||
resolution: {integrity: sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==}
|
resolution: {integrity: sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==}
|
||||||
|
|
||||||
|
fs-extra@10.1.0:
|
||||||
|
resolution: {integrity: sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==}
|
||||||
|
engines: {node: '>=12'}
|
||||||
|
|
||||||
fs-extra@11.3.2:
|
fs-extra@11.3.2:
|
||||||
resolution: {integrity: sha512-Xr9F6z6up6Ws+NjzMCZc6WXg2YFRlrLP9NQDO3VQrWrfiojdhS56TzueT88ze0uBdCTwEIhQ3ptnmKeWGFAe0A==}
|
resolution: {integrity: sha512-Xr9F6z6up6Ws+NjzMCZc6WXg2YFRlrLP9NQDO3VQrWrfiojdhS56TzueT88ze0uBdCTwEIhQ3ptnmKeWGFAe0A==}
|
||||||
engines: {node: '>=14.14'}
|
engines: {node: '>=14.14'}
|
||||||
@ -5033,9 +5315,6 @@ packages:
|
|||||||
mlly@1.8.0:
|
mlly@1.8.0:
|
||||||
resolution: {integrity: sha512-l8D9ODSRWLe2KHJSifWGwBqpTZXIXTeo8mlKjY+E2HAakaTeNpqAyBZ8GSqLzHgw4XmHmC8whvpjJNMbFZN7/g==}
|
resolution: {integrity: sha512-l8D9ODSRWLe2KHJSifWGwBqpTZXIXTeo8mlKjY+E2HAakaTeNpqAyBZ8GSqLzHgw4XmHmC8whvpjJNMbFZN7/g==}
|
||||||
|
|
||||||
monaco-editor@0.52.2:
|
|
||||||
resolution: {integrity: sha512-GEQWEZmfkOGLdd3XK8ryrfWz3AIP8YymVXiPHEdewrUq7mh0qrKrfHLNCXcbB6sTnMLnOZ3ztSiKcciFUkIJwQ==}
|
|
||||||
|
|
||||||
motion-dom@12.23.23:
|
motion-dom@12.23.23:
|
||||||
resolution: {integrity: sha512-n5yolOs0TQQBRUFImrRfs/+6X4p3Q4n1dUEqt/H58Vx7OW6RF+foWEgmTVDhIWJIMXOuNNL0apKH2S16en9eiA==}
|
resolution: {integrity: sha512-n5yolOs0TQQBRUFImrRfs/+6X4p3Q4n1dUEqt/H58Vx7OW6RF+foWEgmTVDhIWJIMXOuNNL0apKH2S16en9eiA==}
|
||||||
|
|
||||||
@ -5060,6 +5339,9 @@ packages:
|
|||||||
resolution: {integrity: sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ==}
|
resolution: {integrity: sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ==}
|
||||||
engines: {node: '>=10'}
|
engines: {node: '>=10'}
|
||||||
|
|
||||||
|
ms@2.0.0:
|
||||||
|
resolution: {integrity: sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==}
|
||||||
|
|
||||||
ms@2.1.3:
|
ms@2.1.3:
|
||||||
resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==}
|
resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==}
|
||||||
|
|
||||||
@ -5201,6 +5483,10 @@ packages:
|
|||||||
resolution: {integrity: sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==}
|
resolution: {integrity: sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==}
|
||||||
engines: {node: '>= 0.8'}
|
engines: {node: '>= 0.8'}
|
||||||
|
|
||||||
|
on-headers@1.1.0:
|
||||||
|
resolution: {integrity: sha512-737ZY3yNnXy37FHkQxPzt4UZ2UWPWiCZWLvFZ4fu5cueciegX0zGPnrlY6bwRg4FdQOe9YU8MkmJwGhoMybl8A==}
|
||||||
|
engines: {node: '>= 0.8'}
|
||||||
|
|
||||||
once@1.4.0:
|
once@1.4.0:
|
||||||
resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==}
|
resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==}
|
||||||
|
|
||||||
@ -5830,6 +6116,10 @@ packages:
|
|||||||
setprototypeof@1.2.0:
|
setprototypeof@1.2.0:
|
||||||
resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==}
|
resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==}
|
||||||
|
|
||||||
|
sharp@0.34.5:
|
||||||
|
resolution: {integrity: sha512-Ou9I5Ft9WNcCbXrU9cMgPBcCK8LiwLqcbywW3t4oDV37n1pzpuNLsYiAV8eODnjbtQlSDwZ2cUEeQz4E54Hltg==}
|
||||||
|
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
|
||||||
|
|
||||||
shebang-command@2.0.0:
|
shebang-command@2.0.0:
|
||||||
resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==}
|
resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==}
|
||||||
engines: {node: '>=8'}
|
engines: {node: '>=8'}
|
||||||
@ -6032,6 +6322,9 @@ packages:
|
|||||||
resolution: {integrity: sha512-KIy5nylvC5le1OdaaoCJ07L+8iQzJHGH6pWDuzS+d07Cu7n1MZ2x26P8ZKIWfbK02+XIL8Mp4RkWeqdUCrDMfg==}
|
resolution: {integrity: sha512-KIy5nylvC5le1OdaaoCJ07L+8iQzJHGH6pWDuzS+d07Cu7n1MZ2x26P8ZKIWfbK02+XIL8Mp4RkWeqdUCrDMfg==}
|
||||||
engines: {node: '>=18'}
|
engines: {node: '>=18'}
|
||||||
|
|
||||||
|
style-mod@4.1.3:
|
||||||
|
resolution: {integrity: sha512-i/n8VsZydrugj3Iuzll8+x/00GH2vnYsk1eomD8QiRrSAeW6ItbCQDtfXCeJHd0iwiNagqjQkvpvREEPtW3IoQ==}
|
||||||
|
|
||||||
style-to-js@1.1.19:
|
style-to-js@1.1.19:
|
||||||
resolution: {integrity: sha512-Ev+SgeqiNGT1ufsXyVC5RrJRXdrkRJ1Gol9Qw7Pb72YCKJXrBvP0ckZhBeVSrw2m06DJpei2528uIpjMb4TsoQ==}
|
resolution: {integrity: sha512-Ev+SgeqiNGT1ufsXyVC5RrJRXdrkRJ1Gol9Qw7Pb72YCKJXrBvP0ckZhBeVSrw2m06DJpei2528uIpjMb4TsoQ==}
|
||||||
|
|
||||||
@ -6435,6 +6728,11 @@ packages:
|
|||||||
resolution: {integrity: sha512-LII3bXRFBZLlezoG5FfZVcXflZgWP/4dCwKtxd5ky9+LOtM4CS3bIRQsmR1KMnMW07jpE8fqR2lcxPZ+8sJIcw==}
|
resolution: {integrity: sha512-LII3bXRFBZLlezoG5FfZVcXflZgWP/4dCwKtxd5ky9+LOtM4CS3bIRQsmR1KMnMW07jpE8fqR2lcxPZ+8sJIcw==}
|
||||||
engines: {node: '>= 0.10'}
|
engines: {node: '>= 0.10'}
|
||||||
|
|
||||||
|
vite-plugin-compression@0.5.1:
|
||||||
|
resolution: {integrity: sha512-5QJKBDc+gNYVqL/skgFAP81Yuzo9R+EAf19d+EtsMF/i8kFUpNi3J/H01QD3Oo8zBQn+NzoCIFkpPLynoOzaJg==}
|
||||||
|
peerDependencies:
|
||||||
|
vite: '>=2.0.0'
|
||||||
|
|
||||||
vite-plugin-cp@6.0.3:
|
vite-plugin-cp@6.0.3:
|
||||||
resolution: {integrity: sha512-qxKGH3v9wPwUDbDchJf4IH4mRE1zkLWgzZSxwrl8LapwUWm48IFS7SlbRmcF4NquC/fESA5cHFge9E2Ps+woxg==}
|
resolution: {integrity: sha512-qxKGH3v9wPwUDbDchJf4IH4mRE1zkLWgzZSxwrl8LapwUWm48IFS7SlbRmcF4NquC/fESA5cHFge9E2Ps+woxg==}
|
||||||
engines: {node: '>=14.18.0', vite: '>=3.1.0'}
|
engines: {node: '>=14.18.0', vite: '>=3.1.0'}
|
||||||
@ -6442,6 +6740,19 @@ packages:
|
|||||||
vite-plugin-font@5.1.2:
|
vite-plugin-font@5.1.2:
|
||||||
resolution: {integrity: sha512-Aec3NPRtON9Z+ro4MvZvjiTau7tE3xn6L0wQddVoDYeyMGWzm43D9MWhd5cjF8ohkU6ikGD1V04Q5Tr9O8G4FQ==}
|
resolution: {integrity: sha512-Aec3NPRtON9Z+ro4MvZvjiTau7tE3xn6L0wQddVoDYeyMGWzm43D9MWhd5cjF8ohkU6ikGD1V04Q5Tr9O8G4FQ==}
|
||||||
|
|
||||||
|
vite-plugin-image-optimizer@2.0.3:
|
||||||
|
resolution: {integrity: sha512-1vrFOTcpSvv6DCY7h8UXab4wqMAjTJB/ndOzG/Kmj1oDOuPF6mbjkNQoGzzCEYeWGe7qU93jc8oQqvoJ57al3A==}
|
||||||
|
engines: {node: '>=18.17.0'}
|
||||||
|
peerDependencies:
|
||||||
|
sharp: '>=0.34.0'
|
||||||
|
svgo: '>=4'
|
||||||
|
vite: '>=5'
|
||||||
|
peerDependenciesMeta:
|
||||||
|
sharp:
|
||||||
|
optional: true
|
||||||
|
svgo:
|
||||||
|
optional: true
|
||||||
|
|
||||||
vite-plugin-static-copy@2.3.2:
|
vite-plugin-static-copy@2.3.2:
|
||||||
resolution: {integrity: sha512-iwrrf+JupY4b9stBttRWzGHzZbeMjAHBhkrn67MNACXJVjEMRpCI10Q3AkxdBkl45IHaTfw/CNVevzQhP7yTwg==}
|
resolution: {integrity: sha512-iwrrf+JupY4b9stBttRWzGHzZbeMjAHBhkrn67MNACXJVjEMRpCI10Q3AkxdBkl45IHaTfw/CNVevzQhP7yTwg==}
|
||||||
engines: {node: ^18.0.0 || >=20.0.0}
|
engines: {node: ^18.0.0 || >=20.0.0}
|
||||||
@ -6534,6 +6845,9 @@ packages:
|
|||||||
resolution: {integrity: sha512-2HUCkqI0uwgBti1/+utRu7Hvk/I3HeowBQfRlEL3487r+LpW1w91kk6uTZbwOd6I2Sj3aAxBE0HxYNC/NLbuhA==}
|
resolution: {integrity: sha512-2HUCkqI0uwgBti1/+utRu7Hvk/I3HeowBQfRlEL3487r+LpW1w91kk6uTZbwOd6I2Sj3aAxBE0HxYNC/NLbuhA==}
|
||||||
engines: {node: '>=14.18.0', vite: '>=3.1.0'}
|
engines: {node: '>=14.18.0', vite: '>=3.1.0'}
|
||||||
|
|
||||||
|
w3c-keyname@2.2.8:
|
||||||
|
resolution: {integrity: sha512-dpojBhNsCNN7T82Tm7k26A6G9ML3NkhDsnw9n/eoxSRlVBB4CEtIQ/KTCLI2Fwf3ataSXRhYFkQi3SlnFwPvPQ==}
|
||||||
|
|
||||||
webidl-conversions@3.0.1:
|
webidl-conversions@3.0.1:
|
||||||
resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==}
|
resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==}
|
||||||
|
|
||||||
@ -6766,6 +7080,82 @@ snapshots:
|
|||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- encoding
|
- encoding
|
||||||
|
|
||||||
|
'@codemirror/autocomplete@6.20.0':
|
||||||
|
dependencies:
|
||||||
|
'@codemirror/language': 6.12.1
|
||||||
|
'@codemirror/state': 6.5.3
|
||||||
|
'@codemirror/view': 6.39.6
|
||||||
|
'@lezer/common': 1.5.0
|
||||||
|
|
||||||
|
'@codemirror/commands@6.10.1':
|
||||||
|
dependencies:
|
||||||
|
'@codemirror/language': 6.12.1
|
||||||
|
'@codemirror/state': 6.5.3
|
||||||
|
'@codemirror/view': 6.39.6
|
||||||
|
'@lezer/common': 1.5.0
|
||||||
|
|
||||||
|
'@codemirror/lang-css@6.3.1':
|
||||||
|
dependencies:
|
||||||
|
'@codemirror/autocomplete': 6.20.0
|
||||||
|
'@codemirror/language': 6.12.1
|
||||||
|
'@codemirror/state': 6.5.3
|
||||||
|
'@lezer/common': 1.5.0
|
||||||
|
'@lezer/css': 1.3.0
|
||||||
|
|
||||||
|
'@codemirror/lang-javascript@6.2.4':
|
||||||
|
dependencies:
|
||||||
|
'@codemirror/autocomplete': 6.20.0
|
||||||
|
'@codemirror/language': 6.12.1
|
||||||
|
'@codemirror/lint': 6.9.2
|
||||||
|
'@codemirror/state': 6.5.3
|
||||||
|
'@codemirror/view': 6.39.6
|
||||||
|
'@lezer/common': 1.5.0
|
||||||
|
'@lezer/javascript': 1.5.4
|
||||||
|
|
||||||
|
'@codemirror/lang-json@6.0.2':
|
||||||
|
dependencies:
|
||||||
|
'@codemirror/language': 6.12.1
|
||||||
|
'@lezer/json': 1.0.3
|
||||||
|
|
||||||
|
'@codemirror/language@6.12.1':
|
||||||
|
dependencies:
|
||||||
|
'@codemirror/state': 6.5.3
|
||||||
|
'@codemirror/view': 6.39.6
|
||||||
|
'@lezer/common': 1.5.0
|
||||||
|
'@lezer/highlight': 1.2.3
|
||||||
|
'@lezer/lr': 1.4.5
|
||||||
|
style-mod: 4.1.3
|
||||||
|
|
||||||
|
'@codemirror/lint@6.9.2':
|
||||||
|
dependencies:
|
||||||
|
'@codemirror/state': 6.5.3
|
||||||
|
'@codemirror/view': 6.39.6
|
||||||
|
crelt: 1.0.6
|
||||||
|
|
||||||
|
'@codemirror/search@6.5.11':
|
||||||
|
dependencies:
|
||||||
|
'@codemirror/state': 6.5.3
|
||||||
|
'@codemirror/view': 6.39.6
|
||||||
|
crelt: 1.0.6
|
||||||
|
|
||||||
|
'@codemirror/state@6.5.3':
|
||||||
|
dependencies:
|
||||||
|
'@marijn/find-cluster-break': 1.0.2
|
||||||
|
|
||||||
|
'@codemirror/theme-one-dark@6.1.3':
|
||||||
|
dependencies:
|
||||||
|
'@codemirror/language': 6.12.1
|
||||||
|
'@codemirror/state': 6.5.3
|
||||||
|
'@codemirror/view': 6.39.6
|
||||||
|
'@lezer/highlight': 1.2.3
|
||||||
|
|
||||||
|
'@codemirror/view@6.39.6':
|
||||||
|
dependencies:
|
||||||
|
'@codemirror/state': 6.5.3
|
||||||
|
crelt: 1.0.6
|
||||||
|
style-mod: 4.1.3
|
||||||
|
w3c-keyname: 2.2.8
|
||||||
|
|
||||||
'@colors/colors@1.6.0': {}
|
'@colors/colors@1.6.0': {}
|
||||||
|
|
||||||
'@dabh/diagnostics@2.0.8':
|
'@dabh/diagnostics@2.0.8':
|
||||||
@ -7883,6 +8273,102 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
react: 19.2.0
|
react: 19.2.0
|
||||||
|
|
||||||
|
'@img/colour@1.0.0': {}
|
||||||
|
|
||||||
|
'@img/sharp-darwin-arm64@0.34.5':
|
||||||
|
optionalDependencies:
|
||||||
|
'@img/sharp-libvips-darwin-arm64': 1.2.4
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@img/sharp-darwin-x64@0.34.5':
|
||||||
|
optionalDependencies:
|
||||||
|
'@img/sharp-libvips-darwin-x64': 1.2.4
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@img/sharp-libvips-darwin-arm64@1.2.4':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@img/sharp-libvips-darwin-x64@1.2.4':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@img/sharp-libvips-linux-arm64@1.2.4':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@img/sharp-libvips-linux-arm@1.2.4':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@img/sharp-libvips-linux-ppc64@1.2.4':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@img/sharp-libvips-linux-riscv64@1.2.4':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@img/sharp-libvips-linux-s390x@1.2.4':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@img/sharp-libvips-linux-x64@1.2.4':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@img/sharp-libvips-linuxmusl-arm64@1.2.4':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@img/sharp-libvips-linuxmusl-x64@1.2.4':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@img/sharp-linux-arm64@0.34.5':
|
||||||
|
optionalDependencies:
|
||||||
|
'@img/sharp-libvips-linux-arm64': 1.2.4
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@img/sharp-linux-arm@0.34.5':
|
||||||
|
optionalDependencies:
|
||||||
|
'@img/sharp-libvips-linux-arm': 1.2.4
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@img/sharp-linux-ppc64@0.34.5':
|
||||||
|
optionalDependencies:
|
||||||
|
'@img/sharp-libvips-linux-ppc64': 1.2.4
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@img/sharp-linux-riscv64@0.34.5':
|
||||||
|
optionalDependencies:
|
||||||
|
'@img/sharp-libvips-linux-riscv64': 1.2.4
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@img/sharp-linux-s390x@0.34.5':
|
||||||
|
optionalDependencies:
|
||||||
|
'@img/sharp-libvips-linux-s390x': 1.2.4
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@img/sharp-linux-x64@0.34.5':
|
||||||
|
optionalDependencies:
|
||||||
|
'@img/sharp-libvips-linux-x64': 1.2.4
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@img/sharp-linuxmusl-arm64@0.34.5':
|
||||||
|
optionalDependencies:
|
||||||
|
'@img/sharp-libvips-linuxmusl-arm64': 1.2.4
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@img/sharp-linuxmusl-x64@0.34.5':
|
||||||
|
optionalDependencies:
|
||||||
|
'@img/sharp-libvips-linuxmusl-x64': 1.2.4
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@img/sharp-wasm32@0.34.5':
|
||||||
|
dependencies:
|
||||||
|
'@emnapi/runtime': 1.7.1
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@img/sharp-win32-arm64@0.34.5':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@img/sharp-win32-ia32@0.34.5':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@img/sharp-win32-x64@0.34.5':
|
||||||
|
optional: true
|
||||||
|
|
||||||
'@internationalized/date@3.10.0':
|
'@internationalized/date@3.10.0':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@swc/helpers': 0.5.17
|
'@swc/helpers': 0.5.17
|
||||||
@ -7968,17 +8454,40 @@ snapshots:
|
|||||||
|
|
||||||
'@levischuck/tiny-cbor@0.2.11': {}
|
'@levischuck/tiny-cbor@0.2.11': {}
|
||||||
|
|
||||||
|
'@lezer/common@1.5.0': {}
|
||||||
|
|
||||||
|
'@lezer/css@1.3.0':
|
||||||
|
dependencies:
|
||||||
|
'@lezer/common': 1.5.0
|
||||||
|
'@lezer/highlight': 1.2.3
|
||||||
|
'@lezer/lr': 1.4.5
|
||||||
|
|
||||||
|
'@lezer/highlight@1.2.3':
|
||||||
|
dependencies:
|
||||||
|
'@lezer/common': 1.5.0
|
||||||
|
|
||||||
|
'@lezer/javascript@1.5.4':
|
||||||
|
dependencies:
|
||||||
|
'@lezer/common': 1.5.0
|
||||||
|
'@lezer/highlight': 1.2.3
|
||||||
|
'@lezer/lr': 1.4.5
|
||||||
|
|
||||||
|
'@lezer/json@1.0.3':
|
||||||
|
dependencies:
|
||||||
|
'@lezer/common': 1.5.0
|
||||||
|
'@lezer/highlight': 1.2.3
|
||||||
|
'@lezer/lr': 1.4.5
|
||||||
|
|
||||||
|
'@lezer/lr@1.4.5':
|
||||||
|
dependencies:
|
||||||
|
'@lezer/common': 1.5.0
|
||||||
|
|
||||||
|
'@marijn/find-cluster-break@1.0.2': {}
|
||||||
|
|
||||||
'@monaco-editor/loader@1.6.1':
|
'@monaco-editor/loader@1.6.1':
|
||||||
dependencies:
|
dependencies:
|
||||||
state-local: 1.0.7
|
state-local: 1.0.7
|
||||||
|
|
||||||
'@monaco-editor/react@4.7.0-rc.0(monaco-editor@0.52.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)':
|
|
||||||
dependencies:
|
|
||||||
'@monaco-editor/loader': 1.6.1
|
|
||||||
monaco-editor: 0.52.2
|
|
||||||
react: 19.2.0
|
|
||||||
react-dom: 19.2.0(react@19.2.0)
|
|
||||||
|
|
||||||
'@napi-rs/wasm-runtime@0.2.12':
|
'@napi-rs/wasm-runtime@0.2.12':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@emnapi/core': 1.7.1
|
'@emnapi/core': 1.7.1
|
||||||
@ -9216,6 +9725,11 @@ snapshots:
|
|||||||
'@types/deep-eql': 4.0.2
|
'@types/deep-eql': 4.0.2
|
||||||
assertion-error: 2.0.1
|
assertion-error: 2.0.1
|
||||||
|
|
||||||
|
'@types/compression@1.8.1':
|
||||||
|
dependencies:
|
||||||
|
'@types/express': 5.0.5
|
||||||
|
'@types/node': 22.19.1
|
||||||
|
|
||||||
'@types/connect@3.4.38':
|
'@types/connect@3.4.38':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@types/node': 22.19.1
|
'@types/node': 22.19.1
|
||||||
@ -9449,6 +9963,33 @@ snapshots:
|
|||||||
react: 19.2.0
|
react: 19.2.0
|
||||||
react-dom: 19.2.0(react@19.2.0)
|
react-dom: 19.2.0(react@19.2.0)
|
||||||
|
|
||||||
|
'@uiw/codemirror-extensions-basic-setup@4.25.4(@codemirror/autocomplete@6.20.0)(@codemirror/commands@6.10.1)(@codemirror/language@6.12.1)(@codemirror/lint@6.9.2)(@codemirror/search@6.5.11)(@codemirror/state@6.5.3)(@codemirror/view@6.39.6)':
|
||||||
|
dependencies:
|
||||||
|
'@codemirror/autocomplete': 6.20.0
|
||||||
|
'@codemirror/commands': 6.10.1
|
||||||
|
'@codemirror/language': 6.12.1
|
||||||
|
'@codemirror/lint': 6.9.2
|
||||||
|
'@codemirror/search': 6.5.11
|
||||||
|
'@codemirror/state': 6.5.3
|
||||||
|
'@codemirror/view': 6.39.6
|
||||||
|
|
||||||
|
'@uiw/react-codemirror@4.25.4(@babel/runtime@7.28.4)(@codemirror/autocomplete@6.20.0)(@codemirror/language@6.12.1)(@codemirror/lint@6.9.2)(@codemirror/search@6.5.11)(@codemirror/state@6.5.3)(@codemirror/theme-one-dark@6.1.3)(@codemirror/view@6.39.6)(codemirror@6.0.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)':
|
||||||
|
dependencies:
|
||||||
|
'@babel/runtime': 7.28.4
|
||||||
|
'@codemirror/commands': 6.10.1
|
||||||
|
'@codemirror/state': 6.5.3
|
||||||
|
'@codemirror/theme-one-dark': 6.1.3
|
||||||
|
'@codemirror/view': 6.39.6
|
||||||
|
'@uiw/codemirror-extensions-basic-setup': 4.25.4(@codemirror/autocomplete@6.20.0)(@codemirror/commands@6.10.1)(@codemirror/language@6.12.1)(@codemirror/lint@6.9.2)(@codemirror/search@6.5.11)(@codemirror/state@6.5.3)(@codemirror/view@6.39.6)
|
||||||
|
codemirror: 6.0.2
|
||||||
|
react: 19.2.0
|
||||||
|
react-dom: 19.2.0(react@19.2.0)
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- '@codemirror/autocomplete'
|
||||||
|
- '@codemirror/language'
|
||||||
|
- '@codemirror/lint'
|
||||||
|
- '@codemirror/search'
|
||||||
|
|
||||||
'@ungap/structured-clone@1.3.0': {}
|
'@ungap/structured-clone@1.3.0': {}
|
||||||
|
|
||||||
'@unrs/resolver-binding-android-arm-eabi@1.11.1':
|
'@unrs/resolver-binding-android-arm-eabi@1.11.1':
|
||||||
@ -9653,6 +10194,8 @@ snapshots:
|
|||||||
json-schema-traverse: 1.0.0
|
json-schema-traverse: 1.0.0
|
||||||
require-from-string: 2.0.2
|
require-from-string: 2.0.2
|
||||||
|
|
||||||
|
ansi-colors@4.1.3: {}
|
||||||
|
|
||||||
ansi-regex@5.0.1: {}
|
ansi-regex@5.0.1: {}
|
||||||
|
|
||||||
ansi-regex@6.2.2: {}
|
ansi-regex@6.2.2: {}
|
||||||
@ -10070,6 +10613,16 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
code-point: 1.1.0
|
code-point: 1.1.0
|
||||||
|
|
||||||
|
codemirror@6.0.2:
|
||||||
|
dependencies:
|
||||||
|
'@codemirror/autocomplete': 6.20.0
|
||||||
|
'@codemirror/commands': 6.10.1
|
||||||
|
'@codemirror/language': 6.12.1
|
||||||
|
'@codemirror/lint': 6.9.2
|
||||||
|
'@codemirror/search': 6.5.11
|
||||||
|
'@codemirror/state': 6.5.3
|
||||||
|
'@codemirror/view': 6.39.6
|
||||||
|
|
||||||
color-convert@2.0.1:
|
color-convert@2.0.1:
|
||||||
dependencies:
|
dependencies:
|
||||||
color-name: 1.1.4
|
color-name: 1.1.4
|
||||||
@ -10121,6 +10674,10 @@ snapshots:
|
|||||||
|
|
||||||
comment-parser@1.4.1: {}
|
comment-parser@1.4.1: {}
|
||||||
|
|
||||||
|
compressible@2.0.18:
|
||||||
|
dependencies:
|
||||||
|
mime-db: 1.54.0
|
||||||
|
|
||||||
compressing@1.10.3:
|
compressing@1.10.3:
|
||||||
dependencies:
|
dependencies:
|
||||||
'@eggjs/yauzl': 2.11.0
|
'@eggjs/yauzl': 2.11.0
|
||||||
@ -10133,6 +10690,18 @@ snapshots:
|
|||||||
tar-stream: 1.6.2
|
tar-stream: 1.6.2
|
||||||
yazl: 2.5.1
|
yazl: 2.5.1
|
||||||
|
|
||||||
|
compression@1.8.1:
|
||||||
|
dependencies:
|
||||||
|
bytes: 3.1.2
|
||||||
|
compressible: 2.0.18
|
||||||
|
debug: 2.6.9
|
||||||
|
negotiator: 0.6.4
|
||||||
|
on-headers: 1.1.0
|
||||||
|
safe-buffer: 5.2.1
|
||||||
|
vary: 1.1.2
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- supports-color
|
||||||
|
|
||||||
compute-scroll-into-view@3.1.1: {}
|
compute-scroll-into-view@3.1.1: {}
|
||||||
|
|
||||||
concat-map@0.0.1: {}
|
concat-map@0.0.1: {}
|
||||||
@ -10171,6 +10740,8 @@ snapshots:
|
|||||||
object-assign: 4.1.1
|
object-assign: 4.1.1
|
||||||
vary: 1.1.2
|
vary: 1.1.2
|
||||||
|
|
||||||
|
crelt@1.0.6: {}
|
||||||
|
|
||||||
cross-fetch@3.2.0(encoding@0.1.13):
|
cross-fetch@3.2.0(encoding@0.1.13):
|
||||||
dependencies:
|
dependencies:
|
||||||
node-fetch: 2.7.0(encoding@0.1.13)
|
node-fetch: 2.7.0(encoding@0.1.13)
|
||||||
@ -10218,6 +10789,10 @@ snapshots:
|
|||||||
|
|
||||||
dayjs@1.11.19: {}
|
dayjs@1.11.19: {}
|
||||||
|
|
||||||
|
debug@2.6.9:
|
||||||
|
dependencies:
|
||||||
|
ms: 2.0.0
|
||||||
|
|
||||||
debug@3.2.7:
|
debug@3.2.7:
|
||||||
dependencies:
|
dependencies:
|
||||||
ms: 2.1.3
|
ms: 2.1.3
|
||||||
@ -11001,6 +11576,12 @@ snapshots:
|
|||||||
|
|
||||||
fs-constants@1.0.0: {}
|
fs-constants@1.0.0: {}
|
||||||
|
|
||||||
|
fs-extra@10.1.0:
|
||||||
|
dependencies:
|
||||||
|
graceful-fs: 4.2.11
|
||||||
|
jsonfile: 6.2.0
|
||||||
|
universalify: 2.0.1
|
||||||
|
|
||||||
fs-extra@11.3.2:
|
fs-extra@11.3.2:
|
||||||
dependencies:
|
dependencies:
|
||||||
graceful-fs: 4.2.11
|
graceful-fs: 4.2.11
|
||||||
@ -12185,8 +12766,6 @@ snapshots:
|
|||||||
pkg-types: 1.3.1
|
pkg-types: 1.3.1
|
||||||
ufo: 1.6.1
|
ufo: 1.6.1
|
||||||
|
|
||||||
monaco-editor@0.52.2: {}
|
|
||||||
|
|
||||||
motion-dom@12.23.23:
|
motion-dom@12.23.23:
|
||||||
dependencies:
|
dependencies:
|
||||||
motion-utils: 12.23.6
|
motion-utils: 12.23.6
|
||||||
@ -12203,6 +12782,8 @@ snapshots:
|
|||||||
|
|
||||||
mrmime@2.0.1: {}
|
mrmime@2.0.1: {}
|
||||||
|
|
||||||
|
ms@2.0.0: {}
|
||||||
|
|
||||||
ms@2.1.3: {}
|
ms@2.1.3: {}
|
||||||
|
|
||||||
multer@2.0.2:
|
multer@2.0.2:
|
||||||
@ -12369,6 +12950,8 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
ee-first: 1.1.1
|
ee-first: 1.1.1
|
||||||
|
|
||||||
|
on-headers@1.1.0: {}
|
||||||
|
|
||||||
once@1.4.0:
|
once@1.4.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
wrappy: 1.0.2
|
wrappy: 1.0.2
|
||||||
@ -13086,6 +13669,37 @@ snapshots:
|
|||||||
|
|
||||||
setprototypeof@1.2.0: {}
|
setprototypeof@1.2.0: {}
|
||||||
|
|
||||||
|
sharp@0.34.5:
|
||||||
|
dependencies:
|
||||||
|
'@img/colour': 1.0.0
|
||||||
|
detect-libc: 2.1.2
|
||||||
|
semver: 7.7.3
|
||||||
|
optionalDependencies:
|
||||||
|
'@img/sharp-darwin-arm64': 0.34.5
|
||||||
|
'@img/sharp-darwin-x64': 0.34.5
|
||||||
|
'@img/sharp-libvips-darwin-arm64': 1.2.4
|
||||||
|
'@img/sharp-libvips-darwin-x64': 1.2.4
|
||||||
|
'@img/sharp-libvips-linux-arm': 1.2.4
|
||||||
|
'@img/sharp-libvips-linux-arm64': 1.2.4
|
||||||
|
'@img/sharp-libvips-linux-ppc64': 1.2.4
|
||||||
|
'@img/sharp-libvips-linux-riscv64': 1.2.4
|
||||||
|
'@img/sharp-libvips-linux-s390x': 1.2.4
|
||||||
|
'@img/sharp-libvips-linux-x64': 1.2.4
|
||||||
|
'@img/sharp-libvips-linuxmusl-arm64': 1.2.4
|
||||||
|
'@img/sharp-libvips-linuxmusl-x64': 1.2.4
|
||||||
|
'@img/sharp-linux-arm': 0.34.5
|
||||||
|
'@img/sharp-linux-arm64': 0.34.5
|
||||||
|
'@img/sharp-linux-ppc64': 0.34.5
|
||||||
|
'@img/sharp-linux-riscv64': 0.34.5
|
||||||
|
'@img/sharp-linux-s390x': 0.34.5
|
||||||
|
'@img/sharp-linux-x64': 0.34.5
|
||||||
|
'@img/sharp-linuxmusl-arm64': 0.34.5
|
||||||
|
'@img/sharp-linuxmusl-x64': 0.34.5
|
||||||
|
'@img/sharp-wasm32': 0.34.5
|
||||||
|
'@img/sharp-win32-arm64': 0.34.5
|
||||||
|
'@img/sharp-win32-ia32': 0.34.5
|
||||||
|
'@img/sharp-win32-x64': 0.34.5
|
||||||
|
|
||||||
shebang-command@2.0.0:
|
shebang-command@2.0.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
shebang-regex: 3.0.0
|
shebang-regex: 3.0.0
|
||||||
@ -13312,6 +13926,8 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
'@tokenizer/token': 0.3.0
|
'@tokenizer/token': 0.3.0
|
||||||
|
|
||||||
|
style-mod@4.1.3: {}
|
||||||
|
|
||||||
style-to-js@1.1.19:
|
style-to-js@1.1.19:
|
||||||
dependencies:
|
dependencies:
|
||||||
style-to-object: 1.0.12
|
style-to-object: 1.0.12
|
||||||
@ -13824,6 +14440,15 @@ snapshots:
|
|||||||
remove-trailing-separator: 1.1.0
|
remove-trailing-separator: 1.1.0
|
||||||
replace-ext: 1.0.1
|
replace-ext: 1.0.1
|
||||||
|
|
||||||
|
vite-plugin-compression@0.5.1(vite@6.4.1(@types/node@22.19.1)(jiti@1.21.7)):
|
||||||
|
dependencies:
|
||||||
|
chalk: 4.1.2
|
||||||
|
debug: 4.4.3
|
||||||
|
fs-extra: 10.1.0
|
||||||
|
vite: 6.4.1(@types/node@22.19.1)(jiti@1.21.7)
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- supports-color
|
||||||
|
|
||||||
vite-plugin-cp@6.0.3:
|
vite-plugin-cp@6.0.3:
|
||||||
dependencies:
|
dependencies:
|
||||||
fs-extra: 11.3.2
|
fs-extra: 11.3.2
|
||||||
@ -13845,6 +14470,14 @@ snapshots:
|
|||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- encoding
|
- encoding
|
||||||
|
|
||||||
|
vite-plugin-image-optimizer@2.0.3(sharp@0.34.5)(vite@6.4.1(@types/node@22.19.1)(jiti@1.21.7)):
|
||||||
|
dependencies:
|
||||||
|
ansi-colors: 4.1.3
|
||||||
|
pathe: 2.0.3
|
||||||
|
vite: 6.4.1(@types/node@22.19.1)(jiti@1.21.7)
|
||||||
|
optionalDependencies:
|
||||||
|
sharp: 0.34.5
|
||||||
|
|
||||||
vite-plugin-static-copy@2.3.2(vite@6.4.1(@types/node@22.19.1)(jiti@1.21.7)):
|
vite-plugin-static-copy@2.3.2(vite@6.4.1(@types/node@22.19.1)(jiti@1.21.7)):
|
||||||
dependencies:
|
dependencies:
|
||||||
chokidar: 3.6.0
|
chokidar: 3.6.0
|
||||||
@ -13929,6 +14562,8 @@ snapshots:
|
|||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
|
|
||||||
|
w3c-keyname@2.2.8: {}
|
||||||
|
|
||||||
webidl-conversions@3.0.1: {}
|
webidl-conversions@3.0.1: {}
|
||||||
|
|
||||||
webpack-virtual-modules@0.6.2: {}
|
webpack-virtual-modules@0.6.2: {}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user