From b672a47d4e96d885056603ef8370eb99d975132e Mon Sep 17 00:00:00 2001 From: linyuchen <lin.yu.chen@hotmail.com> Date: Mon, 4 Mar 2024 23:56:00 +0800 Subject: [PATCH 01/20] Update README.md --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index b4d2a7c..01c2b4e 100644 --- a/README.md +++ b/README.md @@ -34,9 +34,9 @@ wget -O fastboot.sh https://cdn.jsdelivr.net/gh/MliKiowa/llonebot-docker/fastboo ``` ├── plugins │ ├── LLOneBot -│ │ └── main.js -│ │ └── preload.js -│ │ └── renderer.js +│ │ └── main/ +│ │ └── preload/ +│ │ └── renderer/ │ │ └── manifest.json │ │ └── node_modules/... ``` From 1fc7356628d825a0bbba7be8521b6ab58161a8f1 Mon Sep 17 00:00:00 2001 From: Misa Liu <misaliu@misaliu.top> Date: Mon, 4 Mar 2024 21:27:19 +0800 Subject: [PATCH 02/20] feat: Create setting components --- src/renderer/components/button.ts | 4 ++++ src/renderer/components/index.ts | 5 +++++ src/renderer/components/item.ts | 10 ++++++++++ src/renderer/components/list.ts | 10 ++++++++++ src/renderer/components/option.ts | 4 ++++ src/renderer/components/select.ts | 11 +++++++++++ src/renderer/components/switch.ts | 9 +++++++++ src/{renderer.ts => renderer/index.ts} | 0 8 files changed, 53 insertions(+) create mode 100644 src/renderer/components/button.ts create mode 100644 src/renderer/components/index.ts create mode 100644 src/renderer/components/item.ts create mode 100644 src/renderer/components/list.ts create mode 100644 src/renderer/components/option.ts create mode 100644 src/renderer/components/select.ts create mode 100644 src/renderer/components/switch.ts rename src/{renderer.ts => renderer/index.ts} (100%) diff --git a/src/renderer/components/button.ts b/src/renderer/components/button.ts new file mode 100644 index 0000000..fda59c8 --- /dev/null +++ b/src/renderer/components/button.ts @@ -0,0 +1,4 @@ + +export const SettingButton = (text: string, id?: string, type: string = 'secondary') => { + return `<setting-button ${type ? `data-type="${type}"` : ''} ${id ? `id="${id}"` : ''}>${text}</setting-button>`; +} \ No newline at end of file diff --git a/src/renderer/components/index.ts b/src/renderer/components/index.ts new file mode 100644 index 0000000..7fd2fe8 --- /dev/null +++ b/src/renderer/components/index.ts @@ -0,0 +1,5 @@ +export * from './list'; +export * from './item'; +export * from './button'; +export * from './switch'; +export * from './select'; diff --git a/src/renderer/components/item.ts b/src/renderer/components/item.ts new file mode 100644 index 0000000..2f054a0 --- /dev/null +++ b/src/renderer/components/item.ts @@ -0,0 +1,10 @@ + +export const SettingItem = (title: string, subtitle?: string, action?: string, id?: string, visible: boolean = true) => { + return `<setting-item ${id ? `id="${id}"` : ''} ${!visible ? 'is-hidden' : ''}> + <div> + <setting-text>${title}</setting-text> + ${subtitle ? `<setting-text data-type="secondary">${subtitle}</setting-text>` : ''} + </div> + ${action ? `<div>${action}</div>` : ''} +</setting-item>`; +} \ No newline at end of file diff --git a/src/renderer/components/list.ts b/src/renderer/components/list.ts new file mode 100644 index 0000000..af2d8ff --- /dev/null +++ b/src/renderer/components/list.ts @@ -0,0 +1,10 @@ + +export const SettingList = (items: string[], title?: string, isCollapsible: boolean = false, direction: string = 'column') => { + return `<setting-section ${title && !isCollapsible ? `data-title="${title}"` : ''}> + <setting-panel> + <setting-list ${direction ? `data-direction="${direction}"` : ''} ${isCollapsible ? 'is-collapsible' : ''} ${title && isCollapsible ? `data-title="${title}"` : ''}> + ${items.join('')} + </setting-list> + </setting-panel> +</setting-section>`; +} \ No newline at end of file diff --git a/src/renderer/components/option.ts b/src/renderer/components/option.ts new file mode 100644 index 0000000..d134ba3 --- /dev/null +++ b/src/renderer/components/option.ts @@ -0,0 +1,4 @@ + +export const SettingOption = (text: string, value?: string, isSelected: boolean = false) => { + return `<setting-option ${value ? `data-value="${value}"` : ''} ${isSelected ? 'is-selected' : ''}>${text}</setting-option>`; +} \ No newline at end of file diff --git a/src/renderer/components/select.ts b/src/renderer/components/select.ts new file mode 100644 index 0000000..0c33332 --- /dev/null +++ b/src/renderer/components/select.ts @@ -0,0 +1,11 @@ +import { SettingOption } from "./option"; + +export const SettingSelect = (items: Array<{ text: string, value: string }>, configKey?: string, configValue?: any) => { + return `<setting-select ${configKey ? `data-config-key="${configKey}"` : ''}> + <div> + ${items.map((e, i) => { + return SettingOption(e.text, e.value, (configKey && configValue ? configValue === e.value : i === 0)); + }).join('')} + </div> +</setting-select>`; +} \ No newline at end of file diff --git a/src/renderer/components/switch.ts b/src/renderer/components/switch.ts new file mode 100644 index 0000000..1978a47 --- /dev/null +++ b/src/renderer/components/switch.ts @@ -0,0 +1,9 @@ + +export const SettingSwitch = (configKey?: string, isActive: boolean = false, extraData?: Record<string, string>) => { + return `<setting-switch + ${configKey ? `data-config-key="${configKey}"` : ''} + ${isActive ? 'is-active' : ''} + ${extraData ? Object.keys(extraData).map(key => `data-${key}="${extraData[key]}"`) : ''} + > +</setting-switch>`; +} \ No newline at end of file diff --git a/src/renderer.ts b/src/renderer/index.ts similarity index 100% rename from src/renderer.ts rename to src/renderer/index.ts From b668f948dffde01a6f3b2351eeb33e6bbc6a9890 Mon Sep 17 00:00:00 2001 From: Misa Liu <misaliu@misaliu.top> Date: Mon, 4 Mar 2024 21:30:55 +0800 Subject: [PATCH 03/20] feat: Init new setting page --- src/renderer/index.ts | 459 +++++++++-------------------------------- src/renderer/style.css | 39 ++++ 2 files changed, 141 insertions(+), 357 deletions(-) create mode 100644 src/renderer/style.css diff --git a/src/renderer/index.ts b/src/renderer/index.ts index 7611793..a15c791 100644 --- a/src/renderer/index.ts +++ b/src/renderer/index.ts @@ -1,365 +1,110 @@ -/// <reference path="./global.d.ts" /> +/// <reference path="../global.d.ts" /> +import { + SettingButton, + SettingItem, + SettingList, + SettingSelect, + SettingSwitch +} from './components'; +import StyleRaw from './style.css?raw'; // 打开设置界面时触发 -async function onSettingWindowCreated (view: Element) { - window.llonebot.log('setting window created') - const isEmpty = (value: any) => value === undefined || value === null || value === '' - const config = await window.llonebot.getConfig() - const httpClass = 'http' - const httpPostClass = 'http-post' - const wsClass = 'ws' - const reverseWSClass = 'reverse-ws' - const llonebotError = await window.llonebot.getError() - window.llonebot.log('获取error' + JSON.stringify(llonebotError)) +async function onSettingWindowCreated(view: Element) { + window.llonebot.log("setting window created"); + const isEmpty = (value: any) => value === undefined || value === null || value === ''; + let config = await window.llonebot.getConfig() - function createHttpHostEleStr (host: string) { - const eleStr = ` - <setting-item data-direction="row" class="hostItem vertical-list-item ${httpPostClass}"> - <h2>HTTP事件上报地址(http)</h2> - <input class="httpHost input-text" type="text" value="${host}" - style="width:60%;padding: 5px" - placeholder="如:http://127.0.0.1:8080/onebot/v11/http"/> - </setting-item> - ` - return eleStr - } + const parser = new DOMParser(); + const doc = parser.parseFromString([ + '<div>', + `<style>${StyleRaw}</style>`, + SettingList([ + SettingItem('启用 HTTP 服务', null, + SettingSwitch('ob11.enableHttp', config.ob11.enableHttp, { 'control-display-id': 'config-ob11-httpPort' }), + ), + SettingItem('HTTP 服务监听端口', null, + '<div class="q-input"><input class="q-input__inner" /></div>', + 'config-ob11-httpPort', config.ob11.enableHttp + ), + SettingItem('启用 HTTP 事件上报', null, + SettingSwitch('ob11.enableHttpPost', config.ob11.enableHttpPost, { 'control-display-id': 'config-ob11-httpPost' }), + ), + SettingItem('HTTP 事件上报地址', null, + '<div></div>', + 'config-ob11-httpPost', config.ob11.enableHttpPost + ), + SettingItem('启用正向 WebSocket 服务', null, + SettingSwitch('ob11.enableWs', config.ob11.enableWs, { 'config-display-id': 'config-ob11-wsPort' }), + ), + SettingItem('正向 WebSocket 服务监听端口', null, + '<div class="q-input"><input class="q-input__inner" /></div>', + 'config-ob11-wsPort', config.ob11.enableWs + ), + SettingItem('启用反向 WebSocket 服务', null, + SettingSwitch('ob11.enableWsReverse', config.ob11.enableWsReverse, { 'config-display-id': 'config-ob11-wsHosts' }), + ), + SettingItem('反向 WebSocket 监听地址', null, + '<div></div>', + 'config-ob11-wsHosts', config.ob11.enableWsReverse + ), + SettingItem( + 'ffmpeg 路径', `${!isEmpty(config.ffmpeg) ? config.ffmpeg : '未指定'}`, + SettingButton('选择', 'config-ffmpeg-select'), + 'config-ffmpeg-path', + ), + SettingItem( + '', null, + SettingButton('保存', 'config-ob11-save', 'primary'), + ) + ]), + SettingList([ + SettingItem( + '消息上报格式类型', + '如客户端无特殊需求推荐保持默认设置,两者的详细差异可参考 <a href="javascript:LiteLoader.api.openExternal(\'https://github.com/botuniverse/onebot-11/tree/master/message#readme\');">OneBot v11 文档</a>', + SettingSelect([ + { text: '消息段', value: 'array' }, + { text: 'CQ码', value: 'string' }, + ], 'ob11.messagePostFormat', config.ob11.messagePostFormat), + ), + SettingItem( + '使用 Base64 编码获取文件', + '开启后,调用 /get_image、/get_record 时,获取不到 url 时添加一个 Base64 字段', + SettingSwitch('enableLocalFile2Url', config.enableLocalFile2Url), + ), + SettingItem( + '调试模式', + '开启后上报信息会添加 raw 字段以附带原始信息', + SettingSwitch('debug', config.debug), + ), + SettingItem( + '上报 Bot 自身发送的消息', + '慎用,可能会导致自己跟自己聊个不停', + SettingSwitch('reportSelfMessage', config.reportSelfMessage), + ), + SettingItem( + '写入日志', + `日志文件目录:${window.LiteLoader.plugins['LLOneBot'].path.data}`, + SettingButton('打开', 'config-open-log-path'), + ), + SettingItem( + '自动删除收到的文件', + '在收到文件后的指定时间内删除该文件', + SettingSwitch('autoDeleteFile', config.autoDeleteFile, { 'config-display-id': 'config-auto-delete-file-second' }), + ), + SettingItem( + '自动删除文件时间', + '单位为秒', + '<div class="q-input"><input class="q-input__inner" /></div>', + 'config-auto-delete-file-second', config.autoDeleteFile + ), + ]), + '</div>', + ].join(''), "text/html"); - function createWsHostEleStr (host: string) { - const eleStr = ` - <setting-item data-direction="row" class="hostItem vertical-list-item ${reverseWSClass}"> - <h2>反向websocket地址:</h2> - <input class="wsHost input-text" type="text" value="${host}" - style="width:60%;padding: 5px" - placeholder="如: ws://127.0.0.1:5410/onebot"/> - </setting-item> - ` - return eleStr - } - - let httpHostsEleStr = '' - for (const host of config.ob11.httpHosts) { - httpHostsEleStr += createHttpHostEleStr(host) - } - - let wsHostsEleStr = '' - for (const host of config.ob11.wsHosts) { - wsHostsEleStr += createWsHostEleStr(host) - } - - const html = ` - <div class="config_view llonebot"> - <setting-section> - <setting-panel id="llonebotError" style="display:${llonebotError.ffmpegError || llonebotError.otherError ? '' : 'none'}"> - <setting-item id="ffmpegError" data-direction="row" - style="diplay:${llonebotError.ffmpegError ? '' : 'none'}" - class="hostItem vertical-list-item"> - <setting-text data-type="secondary" class="err-content">${llonebotError.ffmpegError}</setting-text> - </setting-item> - <setting-item id="otherError" data-direction="row" - style="diplay:${llonebotError.otherError ? '' : 'none'}" - class="hostItem vertical-list-item"> - <setting-text data-type="secondary" class="err-content">${llonebotError.otherError}</setting-text> - </setting-item> - </setting-panel> - <setting-panel> - <setting-list class="wrap"> - <setting-item data-direction="row" class="hostItem vertical-list-item"> - <div> - <div>启用HTTP服务</div> - </div> - <setting-switch id="http" ${config.ob11.enableHttp ? 'is-active' : ''}></setting-switch> - </setting-item> - <setting-item class="vertical-list-item ${httpClass}" data-direction="row" style="display: ${config.ob11.enableHttp ? '' : 'none'}"> - <setting-text>HTTP监听端口</setting-text> - <input id="httpPort" type="number" value="${config.ob11.httpPort}"/> - </setting-item> - <setting-item data-direction="row" class="hostItem vertical-list-item"> - <div> - <div>启用HTTP事件上报</div> - </div> - <setting-switch id="httpPost" ${config.ob11.enableHttpPost ? 'is-active' : ''}></setting-switch> - </setting-item> - <div class="${httpPostClass}" style="display: ${config.ob11.enableHttpPost ? '' : 'none'}"> - <div > - <button id="addHttpHost" class="q-button">添加HTTP POST上报地址</button> - </div> - <div id="httpHostItems"> - ${httpHostsEleStr} - </div> - </div> - <setting-item data-direction="row" class="hostItem vertical-list-item"> - <div> - <div>启用正向Websocket协议</div> - </div> - <setting-switch id="websocket" ${config.ob11.enableWs ? 'is-active' : ''}></setting-switch> - </setting-item> - <setting-item class="vertical-list-item ${wsClass}" data-direction="row" style="display: ${config.ob11.enableWs ? '' : 'none'}"> - <setting-text>正向Websocket监听端口</setting-text> - <input id="wsPort" type="number" value="${config.ob11.wsPort}"/> - </setting-item> - - <setting-item data-direction="row" class="hostItem vertical-list-item"> - <div> - <div>启用反向Websocket协议</div> - </div> - <setting-switch id="websocketReverse" ${config.ob11.enableWsReverse ? 'is-active' : ''}></setting-switch> - </setting-item> - <div class="${reverseWSClass}" style="display: ${config.ob11.enableWsReverse ? '' : 'none'}"> - <div> - <button id="addWsHost" class="q-button">添加反向Websocket地址</button> - </div> - <div id="wsHostItems"> - ${wsHostsEleStr} - </div> - </div> - <setting-item class="vertical-list-item" data-direction="row"> - <setting-text>Access Token</setting-text> - <input id="token" type="text" placeholder="可为空" value="${config.token}"/> - </setting-item> - <setting-item data-direction="row" class="vertical-list-item"> - <setting-item data-direction="row" class="vertical-list-item" style="width: 80%"> - <setting-text>ffmpeg路径</setting-text> - <input id="ffmpegPath" class="input-text" type="text" - style="width:80%;padding: 5px" - value="${config.ffmpeg || ''}"/> - </setting-item> - <button id="selectFFMPEG" class="q-button q-button--small q-button--secondary">选择ffmpeg</button> - </setting-item> - <button id="save" class="q-button">保存</button> - </setting-list> - </setting-panel> - <setting-panel> - - <setting-item data-direction="row" class="vertical-list-item"> - <div> - <setting-text>消息上报数据类型</setting-text> - <setting-text data-type="secondary">如客户端无特殊需求推荐保持默认设置,两者的详细差异可参考 <a href="javascript:LiteLoader.api.openExternal('https://github.com/botuniverse/onebot-11/tree/master/message#readme');">OneBot v11 文档</a></setting-text> - </div> - <setting-select id="messagePostFormat"> - <setting-option data-value="array" ${config.ob11.messagePostFormat !== 'string' ? 'is-selected' : ''}>消息段</setting-option> - <setting-option data-value="string" ${config.ob11.messagePostFormat === 'string' ? 'is-selected' : ''}>CQ码</setting-option> - </setting-select> - </setting-item> - <setting-item data-direction="row" class="vertical-list-item"> - <div> - <div>获取文件使用base64编码</div> - <div class="tips">开启后,调用/get_image、/get_record时,获取不到url时添加一个base64字段</div> - </div> - <setting-switch id="switchFileUrl" ${config.enableLocalFile2Url ? 'is-active' : ''}></setting-switch> - </setting-item> - <setting-item data-direction="row" class="vertical-list-item"> - <div> - <div>debug模式</div> - <div class="tips">开启后上报消息添加raw字段附带原始消息</div> - </div> - <setting-switch id="debug" ${config.debug ? 'is-active' : ''}></setting-switch> - </setting-item> - <setting-item data-direction="row" class="vertical-list-item"> - <div> - <div>上报自身发送消息</div> - <div class="tips"></div> - </div> - <setting-switch id="reportSelfMessage" ${config.reportSelfMessage ? 'is-active' : ''}></setting-switch> - </setting-item> - <setting-item data-direction="row" class="vertical-list-item"> - <div> - <div>日志</div> - <div class="tips">目录:${window.LiteLoader.plugins.LLOneBot.path.data}</div> - </div> - <setting-switch id="log" ${config.log ? 'is-active' : ''}></setting-switch> - </setting-item> - <setting-item data-direction="row" class="vertical-list-item"> - <div> - <div>自动删除收到的文件</div> - <div class="tips"> - 收到文件 - <input id="autoDeleteMin" - min="1" style="width: 50px" - value="${config.autoDeleteFileSecond || 60}" type="number"/>秒后自动删除 - </div> - </div> - <setting-switch id="autoDeleteFile" ${config.autoDeleteFile ? 'is-active' : ''}></setting-switch> - </setting-item> - </setting-panel> - </setting-section> - </div> - <style> - setting-panel { - padding: 10px; - } - .tips { - font-size: 0.75rem; - } - @media (prefers-color-scheme: dark){ - .llonebot input { - color: white; - } - } - </style> - ` - - const parser = new DOMParser() - const doc = parser.parseFromString(html, 'text/html') - - const getError = async () => { - const llonebotError = await window.llonebot.getError() - console.log(llonebotError) - const llonebotErrorEle = document.getElementById('llonebotError') - const ffmpegErrorEle = document.getElementById('ffmpegError') - const otherErrorEle = document.getElementById('otherError') - if (llonebotError.otherError || llonebotError.ffmpegError) { - llonebotErrorEle.style.display = '' - } else { - llonebotErrorEle.style.display = 'none' - } - if (llonebotError.ffmpegError) { - const errContentEle = doc.querySelector('#ffmpegError .err-content') - // const errContent = ffmpegErrorEle.getElementsByClassName("err-content")[0]; - errContentEle.textContent = llonebotError.ffmpegError; - (ffmpegErrorEle).style.display = '' - } else { - ffmpegErrorEle.style.display = '' - } - if (llonebotError.otherError) { - const errContentEle = doc.querySelector('#otherError .err-content') - errContentEle.textContent = llonebotError.otherError - otherErrorEle.style.display = '' - } else { - otherErrorEle.style.display = 'none' - } - } - - function addHostEle (type: string, initValue: string = '') { - let addressEle, hostItemsEle - if (type === 'ws') { - const addressDoc = parser.parseFromString(createWsHostEleStr(initValue), 'text/html') - addressEle = addressDoc.querySelector('setting-item') - hostItemsEle = document.getElementById('wsHostItems') - } else { - const addressDoc = parser.parseFromString(createHttpHostEleStr(initValue), 'text/html') - addressEle = addressDoc.querySelector('setting-item') - hostItemsEle = document.getElementById('httpHostItems') - } - - hostItemsEle.appendChild(addressEle) - } - - doc.getElementById('addHttpHost').addEventListener('click', () => { - addHostEle('http') - }) - doc.getElementById('addWsHost').addEventListener('click', () => { - addHostEle('ws') - }) - doc.getElementById('messagePostFormat').addEventListener('selected', (e: CustomEvent) => { - config.ob11.messagePostFormat = e.detail && !isEmpty(e.detail.value) ? e.detail.value : 'array' - window.llonebot.setConfig(config) - }) - - function switchClick (eleId: string, configKey: string, _config = null) { - if (!_config) { - _config = config - } - doc.getElementById(eleId)?.addEventListener('click', (e) => { - const switchEle = e.target as HTMLInputElement - if (_config[configKey]) { - _config[configKey] = false - switchEle.removeAttribute('is-active') - } else { - _config[configKey] = true - switchEle.setAttribute('is-active', '') - } - // 妈蛋,手动操作DOM越写越麻烦,要不用vue算了 - const keyClassMap = { - enableHttp: httpClass, - enableHttpPost: httpPostClass, - enableWs: wsClass, - enableWsReverse: reverseWSClass - } - for (const e of document.getElementsByClassName(keyClassMap[configKey])) { - (e as HTMLElement).style.display = _config[configKey] ? '' : 'none' - } - - window.llonebot.setConfig(config) - }) - } - - switchClick('http', 'enableHttp', config.ob11) - switchClick('httpPost', 'enableHttpPost', config.ob11) - switchClick('websocket', 'enableWs', config.ob11) - switchClick('websocketReverse', 'enableWsReverse', config.ob11) - switchClick('debug', 'debug') - switchClick('switchFileUrl', 'enableLocalFile2Url') - switchClick('reportSelfMessage', 'reportSelfMessage') - switchClick('log', 'log') - switchClick('autoDeleteFile', 'autoDeleteFile') - - doc.getElementById('save')?.addEventListener('click', - () => { - const httpPortEle: HTMLInputElement = document.getElementById('httpPort') as HTMLInputElement - const httpHostEles: HTMLCollectionOf<HTMLInputElement> = document.getElementsByClassName('httpHost') as HTMLCollectionOf<HTMLInputElement> - const wsPortEle: HTMLInputElement = document.getElementById('wsPort') as HTMLInputElement - const wsHostEles: HTMLCollectionOf<HTMLInputElement> = document.getElementsByClassName('wsHost') as HTMLCollectionOf<HTMLInputElement> - const tokenEle = document.getElementById('token') as HTMLInputElement - const ffmpegPathEle = document.getElementById('ffmpegPath') as HTMLInputElement - - // 获取端口和host - const httpPort = httpPortEle.value - const httpHosts: string[] = [] - - for (const hostEle of httpHostEles) { - const value = hostEle.value.trim() - value && httpHosts.push(value) - } - - const wsPort = wsPortEle.value - const token = tokenEle.value.trim() - const wsHosts: string[] = [] - - for (const hostEle of wsHostEles) { - const value = hostEle.value.trim() - value && wsHosts.push(value) - } - - config.ob11.httpPort = parseInt(httpPort) - config.ob11.httpHosts = httpHosts - config.ob11.wsPort = parseInt(wsPort) - config.ob11.wsHosts = wsHosts - config.token = token - config.ffmpeg = ffmpegPathEle.value.trim() - window.llonebot.setConfig(config) - setTimeout(() => { - getError().then() - }, 1000) - alert('保存成功') - }) - - doc.getElementById('selectFFMPEG')?.addEventListener('click', () => { - window.llonebot.selectFile().then(selectPath => { - if (selectPath) { - config.ffmpeg = (document.getElementById('ffmpegPath') as HTMLInputElement).value = selectPath - // window.llonebot.setConfig(config); - } - }) - }) - - // 自动保存删除文件延时时间 - const autoDeleteMinEle = doc.getElementById('autoDeleteMin') as HTMLInputElement - let st = null - autoDeleteMinEle.addEventListener('change', () => { - if (st) { - clearTimeout(st) - } - st = setTimeout(() => { - console.log('auto delete file minute change') - config.autoDeleteFileSecond = parseInt(autoDeleteMinEle.value) || 1 - window.llonebot.setConfig(config) - }, 1000) - }) - - doc.body.childNodes.forEach(node => { - view.appendChild(node) - }) + doc.body.childNodes.forEach(node => { + view.appendChild(node); + }); } function init () { diff --git a/src/renderer/style.css b/src/renderer/style.css new file mode 100644 index 0000000..421117b --- /dev/null +++ b/src/renderer/style.css @@ -0,0 +1,39 @@ +setting-item[is-hidden], +setting-item[is-hidden] + setting-divider { + display: none !important; +} + +setting-item .q-input { + height: 24px; + width: 100px; + border-top-left-radius: 4px; + border-top-right-radius: 4px; + border-bottom-right-radius: 4px; + border-bottom-left-radius: 4px; + box-sizing: border-box; + position: relative; + background: var(--bg_bottom_light); + border: 1px solid var(--border_dark); +} + +setting-item .q-input .q-input__inner { + border-top-left-radius: 4px; + border-top-right-radius: 4px; + border-bottom-right-radius: 4px; + border-bottom-left-radius: 4px; + box-sizing: border-box; + color: var(--text_primary); + font-family: inherit; + font-size: 12px; + height: 24px; + line-height: 24px; + width: 100%; + border: 1px solid transparent; + padding: 0px 8px; +} + +setting-item .q-input input[type=number].q-input__inner::-webkit-outer-spin-button, +setting-item .q-input input[type=number].q-input__inner::-webkit-inner-spin-button { + -webkit-appearance: none; + margin: 0; +} From f4fbe198e922c5a4e0f47d255e19ce801b73bcc3 Mon Sep 17 00:00:00 2001 From: Misa Liu <misaliu@misaliu.top> Date: Mon, 4 Mar 2024 21:57:26 +0800 Subject: [PATCH 04/20] feat: Made switch works (UI) --- src/renderer/index.ts | 28 ++++++++++++++++++++++------ 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/src/renderer/index.ts b/src/renderer/index.ts index a15c791..cf7543f 100644 --- a/src/renderer/index.ts +++ b/src/renderer/index.ts @@ -24,7 +24,7 @@ async function onSettingWindowCreated(view: Element) { SettingSwitch('ob11.enableHttp', config.ob11.enableHttp, { 'control-display-id': 'config-ob11-httpPort' }), ), SettingItem('HTTP 服务监听端口', null, - '<div class="q-input"><input class="q-input__inner" /></div>', + `<div class="q-input"><input class="q-input__inner" type="number" min="1" max="65534" value="${config.ob11.httpPort}" placeholder="${config.ob11.httpPort}" /></div>`, 'config-ob11-httpPort', config.ob11.enableHttp ), SettingItem('启用 HTTP 事件上报', null, @@ -35,14 +35,14 @@ async function onSettingWindowCreated(view: Element) { 'config-ob11-httpPost', config.ob11.enableHttpPost ), SettingItem('启用正向 WebSocket 服务', null, - SettingSwitch('ob11.enableWs', config.ob11.enableWs, { 'config-display-id': 'config-ob11-wsPort' }), + SettingSwitch('ob11.enableWs', config.ob11.enableWs, { 'control-display-id': 'config-ob11-wsPort' }), ), SettingItem('正向 WebSocket 服务监听端口', null, - '<div class="q-input"><input class="q-input__inner" /></div>', + `<div class="q-input"><input class="q-input__inner" type="number" min="1" max="65534" value="${config.ob11.wsPort}" placeholder="${config.ob11.wsPort}" /></div>`, 'config-ob11-wsPort', config.ob11.enableWs ), SettingItem('启用反向 WebSocket 服务', null, - SettingSwitch('ob11.enableWsReverse', config.ob11.enableWsReverse, { 'config-display-id': 'config-ob11-wsHosts' }), + SettingSwitch('ob11.enableWsReverse', config.ob11.enableWsReverse, { 'control-display-id': 'config-ob11-wsHosts' }), ), SettingItem('反向 WebSocket 监听地址', null, '<div></div>', @@ -90,18 +90,34 @@ async function onSettingWindowCreated(view: Element) { SettingItem( '自动删除收到的文件', '在收到文件后的指定时间内删除该文件', - SettingSwitch('autoDeleteFile', config.autoDeleteFile, { 'config-display-id': 'config-auto-delete-file-second' }), + SettingSwitch('autoDeleteFile', config.autoDeleteFile, { 'control-display-id': 'config-auto-delete-file-second' }), ), SettingItem( '自动删除文件时间', '单位为秒', - '<div class="q-input"><input class="q-input__inner" /></div>', + `<div class="q-input"><input class="q-input__inner" type="number" min="1" value="${config.autoDeleteFileSecond}" placeholder="${config.autoDeleteFileSecond}" /></div>`, 'config-auto-delete-file-second', config.autoDeleteFile ), ]), '</div>', ].join(''), "text/html"); + // 开关 + doc.querySelectorAll('setting-switch[data-config-key]').forEach((dom: HTMLElement) => { + dom.addEventListener('click', () => { + const active = dom.getAttribute('is-active') === null; + + if (active) dom.setAttribute('is-active', ''); + else dom.removeAttribute('is-active'); + + if (!isEmpty(dom.dataset.controlDisplayId)) { + const displayDom = document.querySelector(`#${dom.dataset.controlDisplayId}`); + if (active) displayDom.removeAttribute('is-hidden'); + else displayDom.setAttribute('is-hidden', ''); + } + }); + }); + doc.body.childNodes.forEach(node => { view.appendChild(node); }); From 9acb0665d8600b32ab8e2600acd0a5fa4e8bfbc8 Mon Sep 17 00:00:00 2001 From: Misa Liu <misaliu@misaliu.top> Date: Mon, 4 Mar 2024 22:00:33 +0800 Subject: [PATCH 05/20] fix: Missing setting option --- src/renderer/index.ts | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/renderer/index.ts b/src/renderer/index.ts index cf7543f..2329bce 100644 --- a/src/renderer/index.ts +++ b/src/renderer/index.ts @@ -82,11 +82,6 @@ async function onSettingWindowCreated(view: Element) { '慎用,可能会导致自己跟自己聊个不停', SettingSwitch('reportSelfMessage', config.reportSelfMessage), ), - SettingItem( - '写入日志', - `日志文件目录:${window.LiteLoader.plugins['LLOneBot'].path.data}`, - SettingButton('打开', 'config-open-log-path'), - ), SettingItem( '自动删除收到的文件', '在收到文件后的指定时间内删除该文件', @@ -98,6 +93,16 @@ async function onSettingWindowCreated(view: Element) { `<div class="q-input"><input class="q-input__inner" type="number" min="1" value="${config.autoDeleteFileSecond}" placeholder="${config.autoDeleteFileSecond}" /></div>`, 'config-auto-delete-file-second', config.autoDeleteFile ), + SettingItem( + '写入日志', + `将日志文件写入插件的数据文件夹`, + SettingSwitch('log', config.log), + ), + SettingItem( + '日志文件目录', + `${window.LiteLoader.plugins['LLOneBot'].path.data}`, + SettingButton('打开', 'config-open-log-path'), + ), ]), '</div>', ].join(''), "text/html"); From a5877fec1786293fcda542e0297d86f236336728 Mon Sep 17 00:00:00 2001 From: Misa Liu <misaliu@misaliu.top> Date: Mon, 4 Mar 2024 22:08:08 +0800 Subject: [PATCH 06/20] feat: Write config --- src/renderer/index.ts | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/renderer/index.ts b/src/renderer/index.ts index 2329bce..a69f13a 100644 --- a/src/renderer/index.ts +++ b/src/renderer/index.ts @@ -13,7 +13,17 @@ import StyleRaw from './style.css?raw'; async function onSettingWindowCreated(view: Element) { window.llonebot.log("setting window created"); const isEmpty = (value: any) => value === undefined || value === null || value === ''; - let config = await window.llonebot.getConfig() + let config = await window.llonebot.getConfig(); + const setConfig = (key: string, value: any) => { + const configKey = key.split('.'); + + if (configKey.length === 2) config[configKey[0]][configKey[1]] = value; + else config[key] = value; + + if (key.indexOf('ob11') === -1) window.llonebot.setConfig(config); + + console.log(config); + }; const parser = new DOMParser(); const doc = parser.parseFromString([ @@ -112,6 +122,8 @@ async function onSettingWindowCreated(view: Element) { dom.addEventListener('click', () => { const active = dom.getAttribute('is-active') === null; + setConfig(dom.dataset.configKey, active); + if (active) dom.setAttribute('is-active', ''); else dom.removeAttribute('is-active'); From 66fbce9e4c8dad3a7a28b447cb26d95cbe45b43e Mon Sep 17 00:00:00 2001 From: Misa Liu <misaliu@misaliu.top> Date: Mon, 4 Mar 2024 22:10:35 +0800 Subject: [PATCH 07/20] fix: Add missing setting option --- src/renderer/index.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/renderer/index.ts b/src/renderer/index.ts index a69f13a..6e8591c 100644 --- a/src/renderer/index.ts +++ b/src/renderer/index.ts @@ -58,6 +58,9 @@ async function onSettingWindowCreated(view: Element) { '<div></div>', 'config-ob11-wsHosts', config.ob11.enableWsReverse ), + SettingItem('Access token', null + `<div class="q-input"><input class="q-input__inner" type="text" value="${config.token}" placeholder="未设置" /></div>`, + ), SettingItem( 'ffmpeg 路径', `${!isEmpty(config.ffmpeg) ? config.ffmpeg : '未指定'}`, SettingButton('选择', 'config-ffmpeg-select'), From cbb732c778133d52bc8a717011808ce79f331ef1 Mon Sep 17 00:00:00 2001 From: Misa Liu <misaliu@misaliu.top> Date: Mon, 4 Mar 2024 22:23:03 +0800 Subject: [PATCH 08/20] feat: Made inputs work --- src/renderer/index.ts | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/src/renderer/index.ts b/src/renderer/index.ts index 6e8591c..48f751d 100644 --- a/src/renderer/index.ts +++ b/src/renderer/index.ts @@ -34,7 +34,7 @@ async function onSettingWindowCreated(view: Element) { SettingSwitch('ob11.enableHttp', config.ob11.enableHttp, { 'control-display-id': 'config-ob11-httpPort' }), ), SettingItem('HTTP 服务监听端口', null, - `<div class="q-input"><input class="q-input__inner" type="number" min="1" max="65534" value="${config.ob11.httpPort}" placeholder="${config.ob11.httpPort}" /></div>`, + `<div class="q-input"><input class="q-input__inner" data-config-key="ob11.httpPort" type="number" min="1" max="65534" value="${config.ob11.httpPort}" placeholder="${config.ob11.httpPort}" /></div>`, 'config-ob11-httpPort', config.ob11.enableHttp ), SettingItem('启用 HTTP 事件上报', null, @@ -48,7 +48,7 @@ async function onSettingWindowCreated(view: Element) { SettingSwitch('ob11.enableWs', config.ob11.enableWs, { 'control-display-id': 'config-ob11-wsPort' }), ), SettingItem('正向 WebSocket 服务监听端口', null, - `<div class="q-input"><input class="q-input__inner" type="number" min="1" max="65534" value="${config.ob11.wsPort}" placeholder="${config.ob11.wsPort}" /></div>`, + `<div class="q-input"><input class="q-input__inner" data-config-key="ob11.wsPort" type="number" min="1" max="65534" value="${config.ob11.wsPort}" placeholder="${config.ob11.wsPort}" /></div>`, 'config-ob11-wsPort', config.ob11.enableWs ), SettingItem('启用反向 WebSocket 服务', null, @@ -58,8 +58,8 @@ async function onSettingWindowCreated(view: Element) { '<div></div>', 'config-ob11-wsHosts', config.ob11.enableWsReverse ), - SettingItem('Access token', null - `<div class="q-input"><input class="q-input__inner" type="text" value="${config.token}" placeholder="未设置" /></div>`, + SettingItem('Access token', null, + `<div class="q-input" style="width:210px;"><input class="q-input__inner" data-config-key="token" type="text" value="${config.token}" placeholder="未设置" /></div>`, ), SettingItem( 'ffmpeg 路径', `${!isEmpty(config.ffmpeg) ? config.ffmpeg : '未指定'}`, @@ -103,7 +103,7 @@ async function onSettingWindowCreated(view: Element) { SettingItem( '自动删除文件时间', '单位为秒', - `<div class="q-input"><input class="q-input__inner" type="number" min="1" value="${config.autoDeleteFileSecond}" placeholder="${config.autoDeleteFileSecond}" /></div>`, + `<div class="q-input"><input class="q-input__inner" data-config-key="autoDeleteFileSecond" type="number" min="1" value="${config.autoDeleteFileSecond}" placeholder="${config.autoDeleteFileSecond}" /></div>`, 'config-auto-delete-file-second', config.autoDeleteFile ), SettingItem( @@ -138,6 +138,17 @@ async function onSettingWindowCreated(view: Element) { }); }); + // 输入框 + doc.querySelectorAll('setting-item .q-input input.q-input__inner[data-config-key]').forEach((dom: HTMLInputElement) => { + dom.addEventListener('input', () => { + const Type = dom.getAttribute('type'); + const configKey = dom.dataset.configKey; + const configValue = Type === 'number' ? (parseInt(dom.value) >= 1 ? parseInt(dom.value) : 1) : dom.value; + + setConfig(configKey, configValue); + }); + }); + doc.body.childNodes.forEach(node => { view.appendChild(node); }); From afacc79b567eba5503eff510e543ef21740f1ca6 Mon Sep 17 00:00:00 2001 From: Misa Liu <misaliu@misaliu.top> Date: Mon, 4 Mar 2024 22:28:38 +0800 Subject: [PATCH 09/20] feat: Made select works --- src/renderer/index.ts | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/src/renderer/index.ts b/src/renderer/index.ts index 48f751d..00a7734 100644 --- a/src/renderer/index.ts +++ b/src/renderer/index.ts @@ -61,6 +61,14 @@ async function onSettingWindowCreated(view: Element) { SettingItem('Access token', null, `<div class="q-input" style="width:210px;"><input class="q-input__inner" data-config-key="token" type="text" value="${config.token}" placeholder="未设置" /></div>`, ), + SettingItem( + '消息上报格式类型', + '如客户端无特殊需求推荐保持默认设置,两者的详细差异可参考 <a href="javascript:LiteLoader.api.openExternal(\'https://github.com/botuniverse/onebot-11/tree/master/message#readme\');">OneBot v11 文档</a>', + SettingSelect([ + { text: '消息段', value: 'array' }, + { text: 'CQ码', value: 'string' }, + ], 'ob11.messagePostFormat', config.ob11.messagePostFormat), + ), SettingItem( 'ffmpeg 路径', `${!isEmpty(config.ffmpeg) ? config.ffmpeg : '未指定'}`, SettingButton('选择', 'config-ffmpeg-select'), @@ -72,14 +80,6 @@ async function onSettingWindowCreated(view: Element) { ) ]), SettingList([ - SettingItem( - '消息上报格式类型', - '如客户端无特殊需求推荐保持默认设置,两者的详细差异可参考 <a href="javascript:LiteLoader.api.openExternal(\'https://github.com/botuniverse/onebot-11/tree/master/message#readme\');">OneBot v11 文档</a>', - SettingSelect([ - { text: '消息段', value: 'array' }, - { text: 'CQ码', value: 'string' }, - ], 'ob11.messagePostFormat', config.ob11.messagePostFormat), - ), SettingItem( '使用 Base64 编码获取文件', '开启后,调用 /get_image、/get_record 时,获取不到 url 时添加一个 Base64 字段', @@ -149,6 +149,16 @@ async function onSettingWindowCreated(view: Element) { }); }); + // 下拉框 + doc.querySelectorAll('setting-select').forEach((dom: HTMLElement) => { + dom.addEventListener('selected', (e: CustomEvent) => { + const configKey = dom.dataset.configKey; + const configValue = e.detail.value; + + setConfig(configKey, configValue); + }); + }); + doc.body.childNodes.forEach(node => { view.appendChild(node); }); From 9e6ec926285e635b9fb4cc71b2ab3eef2a16cddc Mon Sep 17 00:00:00 2001 From: Misa Liu <misaliu@misaliu.top> Date: Mon, 4 Mar 2024 22:35:06 +0800 Subject: [PATCH 10/20] feat: Made save button work --- src/renderer/index.ts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/renderer/index.ts b/src/renderer/index.ts index 00a7734..b09259a 100644 --- a/src/renderer/index.ts +++ b/src/renderer/index.ts @@ -159,6 +159,12 @@ async function onSettingWindowCreated(view: Element) { }); }); + // 保存按钮 + doc.querySelector('#config-ob11-save').addEventListener('click', () => { + window.llonebot.setConfig(config) + alert('保存成功'); + }); + doc.body.childNodes.forEach(node => { view.appendChild(node); }); From 67cb8b2f0e7db2f8075d559b737b9af6ee6cf65f Mon Sep 17 00:00:00 2001 From: Misa Liu <misaliu@misaliu.top> Date: Mon, 4 Mar 2024 22:45:52 +0800 Subject: [PATCH 11/20] fix: Add missing setting option --- src/renderer/index.ts | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/src/renderer/index.ts b/src/renderer/index.ts index b09259a..108f5c5 100644 --- a/src/renderer/index.ts +++ b/src/renderer/index.ts @@ -14,15 +14,21 @@ async function onSettingWindowCreated(view: Element) { window.llonebot.log("setting window created"); const isEmpty = (value: any) => value === undefined || value === null || value === ''; let config = await window.llonebot.getConfig(); + let ob11Config = { ...config.ob11 }; const setConfig = (key: string, value: any) => { const configKey = key.split('.'); - if (configKey.length === 2) config[configKey[0]][configKey[1]] = value; - else config[key] = value; + if (key.indexOf('ob11') === 0) { + if (configKey.length === 2) ob11Config[configKey[1]] = value; + else ob11Config[key] = value; + } else { + if (configKey.length === 2) config[configKey[0]][configKey[1]] = value; + else config[key] = value; - if (key.indexOf('ob11') === -1) window.llonebot.setConfig(config); + window.llonebot.setConfig(config); + } - console.log(config); + console.log(config, ob11Config); }; const parser = new DOMParser(); @@ -54,6 +60,10 @@ async function onSettingWindowCreated(view: Element) { SettingItem('启用反向 WebSocket 服务', null, SettingSwitch('ob11.enableWsReverse', config.ob11.enableWsReverse, { 'control-display-id': 'config-ob11-wsHosts' }), ), + SettingItem('反向 WebSocket 服务心跳间隔', + '控制每隔多久发送一个心跳包,单位为毫秒', + `<div class="q-input"><input class="q-input__inner" data-config-key="heartInterval" type="number" min="1000" value="${config.heartInterval}" placeholder="${config.heartInterval}" /></div>`, + ), SettingItem('反向 WebSocket 监听地址', null, '<div></div>', 'config-ob11-wsHosts', config.ob11.enableWsReverse @@ -70,7 +80,7 @@ async function onSettingWindowCreated(view: Element) { ], 'ob11.messagePostFormat', config.ob11.messagePostFormat), ), SettingItem( - 'ffmpeg 路径', `${!isEmpty(config.ffmpeg) ? config.ffmpeg : '未指定'}`, + 'ffmpeg 路径', `<span id="config-ffmpeg-path">${!isEmpty(config.ffmpeg) ? config.ffmpeg : '未指定'}</span>`, SettingButton('选择', 'config-ffmpeg-select'), 'config-ffmpeg-path', ), @@ -161,7 +171,9 @@ async function onSettingWindowCreated(view: Element) { // 保存按钮 doc.querySelector('#config-ob11-save').addEventListener('click', () => { - window.llonebot.setConfig(config) + config.ob11 = ob11Config; + + window.llonebot.setConfig(config); alert('保存成功'); }); From 0f51db62c9287cf261b70c5efed2d7eee62cc702 Mon Sep 17 00:00:00 2001 From: Misa Liu <misaliu@misaliu.top> Date: Mon, 4 Mar 2024 23:33:12 +0800 Subject: [PATCH 12/20] feat: Generate reverse host list --- src/renderer/index.ts | 72 +++++++++++++++++++++++++++++++++++++----- src/renderer/style.css | 14 ++++++++ 2 files changed, 78 insertions(+), 8 deletions(-) diff --git a/src/renderer/index.ts b/src/renderer/index.ts index 108f5c5..b4b9386 100644 --- a/src/renderer/index.ts +++ b/src/renderer/index.ts @@ -8,6 +8,41 @@ import { } from './components'; import StyleRaw from './style.css?raw'; +const buildHostList = (hosts: string[], type: string) => { + const result: HTMLElement[] = []; + + hosts.forEach((host, index) => { + const dom = { + container: document.createElement('setting-item'), + input: document.createElement('input'), + inputContainer: document.createElement('div'), + deleteBtn: document.createElement('setting-button'), + }; + + dom.container.classList.add('setting-host-list-item'); + dom.container.dataset.direction = 'row'; + dom.container.dataset.configArrayKey = type; + dom.container.dataset.configArrayIndex = `${index}`; + + dom.input.classList.add('q-input__inner'); + dom.input.type = 'url'; + dom.input.value = host; + + dom.inputContainer.classList.add('q-input'); + dom.inputContainer.appendChild(dom.input); + + dom.deleteBtn.innerHTML = '删除'; + dom.deleteBtn.dataset.type = 'secondary'; + + dom.container.appendChild(dom.inputContainer); + dom.container.appendChild(dom.deleteBtn); + + result.push(dom.container); + }); + + return result; +} + // 打开设置界面时触发 async function onSettingWindowCreated(view: Element) { @@ -46,10 +81,15 @@ async function onSettingWindowCreated(view: Element) { SettingItem('启用 HTTP 事件上报', null, SettingSwitch('ob11.enableHttpPost', config.ob11.enableHttpPost, { 'control-display-id': 'config-ob11-httpPost' }), ), - SettingItem('HTTP 事件上报地址', null, - '<div></div>', - 'config-ob11-httpPost', config.ob11.enableHttpPost - ), + `<div class="config-host-list" id="config-ob11-httpPost" ${config.ob11.enableHttpPost ? '' : 'is-hidden'}> + <setting-item data-direction="row"> + <div> + <setting-text>HTTP 事件上报地址</setting-text> + </div> + <setting-button data-type="primary">添加</setting-button> + </setting-item> + <div id="config-ob11-httpPost-list"></div> + </div>`, SettingItem('启用正向 WebSocket 服务', null, SettingSwitch('ob11.enableWs', config.ob11.enableWs, { 'control-display-id': 'config-ob11-wsPort' }), ), @@ -60,14 +100,19 @@ async function onSettingWindowCreated(view: Element) { SettingItem('启用反向 WebSocket 服务', null, SettingSwitch('ob11.enableWsReverse', config.ob11.enableWsReverse, { 'control-display-id': 'config-ob11-wsHosts' }), ), + `<div class="config-host-list" id="config-ob11-wsHosts" ${config.ob11.enableWsReverse ? '' : 'is-hidden'}> + <setting-item data-direction="row"> + <div> + <setting-text>反向 WebSocket 监听地址</setting-text> + </div> + <setting-button data-type="primary">添加</setting-button> + </setting-item> + <div id="config-ob11-wsHosts-list"></div> + </div>`, SettingItem('反向 WebSocket 服务心跳间隔', '控制每隔多久发送一个心跳包,单位为毫秒', `<div class="q-input"><input class="q-input__inner" data-config-key="heartInterval" type="number" min="1000" value="${config.heartInterval}" placeholder="${config.heartInterval}" /></div>`, ), - SettingItem('反向 WebSocket 监听地址', null, - '<div></div>', - 'config-ob11-wsHosts', config.ob11.enableWsReverse - ), SettingItem('Access token', null, `<div class="q-input" style="width:210px;"><input class="q-input__inner" data-config-key="token" type="text" value="${config.token}" placeholder="未设置" /></div>`, ), @@ -169,6 +214,17 @@ async function onSettingWindowCreated(view: Element) { }); }); + // 生成反向地址列表 + const httpHostContainerDom = doc.querySelector('#config-ob11-httpPost-list'); + buildHostList(ob11Config.httpHosts, 'httpHosts').forEach(dom => { + httpHostContainerDom.appendChild(dom); + }); + + const wsHostContainerDom = doc.querySelector('#config-ob11-wsHosts-list'); + buildHostList(ob11Config.wsHosts, 'wsHosts').forEach(dom => { + wsHostContainerDom.appendChild(dom); + }); + // 保存按钮 doc.querySelector('#config-ob11-save').addEventListener('click', () => { config.ob11 = ob11Config; diff --git a/src/renderer/style.css b/src/renderer/style.css index 421117b..96d7a38 100644 --- a/src/renderer/style.css +++ b/src/renderer/style.css @@ -3,6 +3,16 @@ setting-item[is-hidden] + setting-divider { display: none !important; } +.config-host-list { + width: 100%; + padding-left: 16px; + box-sizing: border-box; +} +.config-host-list[is-hidden], +.config-host-list[is-hidden] + setting-divider { + display: none !important; +} + setting-item .q-input { height: 24px; width: 100px; @@ -37,3 +47,7 @@ setting-item .q-input input[type=number].q-input__inner::-webkit-inner-spin-butt -webkit-appearance: none; margin: 0; } + +.config-host-list setting-item.setting-host-list-item .q-input { + width: 260px; +} \ No newline at end of file From 68dc2222d4d21f1b8f3f719107eed6aa5c1c2090 Mon Sep 17 00:00:00 2001 From: Misa Liu <misaliu@misaliu.top> Date: Mon, 4 Mar 2024 23:59:12 +0800 Subject: [PATCH 13/20] feat: Made delete work in host list --- src/renderer/index.ts | 102 ++++++++++++++++++++++-------------------- 1 file changed, 53 insertions(+), 49 deletions(-) diff --git a/src/renderer/index.ts b/src/renderer/index.ts index b4b9386..5069c11 100644 --- a/src/renderer/index.ts +++ b/src/renderer/index.ts @@ -8,41 +8,6 @@ import { } from './components'; import StyleRaw from './style.css?raw'; -const buildHostList = (hosts: string[], type: string) => { - const result: HTMLElement[] = []; - - hosts.forEach((host, index) => { - const dom = { - container: document.createElement('setting-item'), - input: document.createElement('input'), - inputContainer: document.createElement('div'), - deleteBtn: document.createElement('setting-button'), - }; - - dom.container.classList.add('setting-host-list-item'); - dom.container.dataset.direction = 'row'; - dom.container.dataset.configArrayKey = type; - dom.container.dataset.configArrayIndex = `${index}`; - - dom.input.classList.add('q-input__inner'); - dom.input.type = 'url'; - dom.input.value = host; - - dom.inputContainer.classList.add('q-input'); - dom.inputContainer.appendChild(dom.input); - - dom.deleteBtn.innerHTML = '删除'; - dom.deleteBtn.dataset.type = 'secondary'; - - dom.container.appendChild(dom.inputContainer); - dom.container.appendChild(dom.deleteBtn); - - result.push(dom.container); - }); - - return result; -} - // 打开设置界面时触发 async function onSettingWindowCreated(view: Element) { @@ -79,16 +44,16 @@ async function onSettingWindowCreated(view: Element) { 'config-ob11-httpPort', config.ob11.enableHttp ), SettingItem('启用 HTTP 事件上报', null, - SettingSwitch('ob11.enableHttpPost', config.ob11.enableHttpPost, { 'control-display-id': 'config-ob11-httpPost' }), + SettingSwitch('ob11.enableHttpPost', config.ob11.enableHttpPost, { 'control-display-id': 'config-ob11-httpHosts' }), ), - `<div class="config-host-list" id="config-ob11-httpPost" ${config.ob11.enableHttpPost ? '' : 'is-hidden'}> + `<div class="config-host-list" id="config-ob11-httpHosts" ${config.ob11.enableHttpPost ? '' : 'is-hidden'}> <setting-item data-direction="row"> <div> <setting-text>HTTP 事件上报地址</setting-text> </div> <setting-button data-type="primary">添加</setting-button> </setting-item> - <div id="config-ob11-httpPost-list"></div> + <div id="config-ob11-httpHosts-list"></div> </div>`, SettingItem('启用正向 WebSocket 服务', null, SettingSwitch('ob11.enableWs', config.ob11.enableWs, { 'control-display-id': 'config-ob11-wsPort' }), @@ -175,6 +140,56 @@ async function onSettingWindowCreated(view: Element) { '</div>', ].join(''), "text/html"); + // 生成反向地址列表 + const buildHostList = (hosts: string[], type: string) => { + const result: HTMLElement[] = []; + + hosts.forEach((host, index) => { + const dom = { + container: document.createElement('setting-item'), + input: document.createElement('input'), + inputContainer: document.createElement('div'), + deleteBtn: document.createElement('setting-button'), + }; + + dom.container.classList.add('setting-host-list-item'); + dom.container.dataset.direction = 'row'; + dom.container.dataset.configArrayKey = type; + dom.container.dataset.configArrayIndex = `${index}`; + + dom.input.classList.add('q-input__inner'); + dom.input.type = 'url'; + dom.input.value = host; + + dom.inputContainer.classList.add('q-input'); + dom.inputContainer.appendChild(dom.input); + + dom.deleteBtn.innerHTML = '删除'; + dom.deleteBtn.dataset.type = 'secondary'; + dom.deleteBtn.addEventListener('click', () => { + ob11Config[type].splice(index, 1); + console.log(ob11Config); + initReverseHost(type); + }); + + dom.container.appendChild(dom.inputContainer); + dom.container.appendChild(dom.deleteBtn); + + result.push(dom.container); + }); + + return result; + }; + const initReverseHost = (type: string, doc: Document = document) => { + const hostContainerDom = doc.body.querySelector(`#config-ob11-${type}-list`); + [ ...hostContainerDom.childNodes ].forEach(dom => dom.remove()); + buildHostList(ob11Config[type], type).forEach(dom => { + hostContainerDom.appendChild(dom); + }); + }; + initReverseHost('httpHosts', doc); + initReverseHost('wsHosts', doc); + // 开关 doc.querySelectorAll('setting-switch[data-config-key]').forEach((dom: HTMLElement) => { dom.addEventListener('click', () => { @@ -214,17 +229,6 @@ async function onSettingWindowCreated(view: Element) { }); }); - // 生成反向地址列表 - const httpHostContainerDom = doc.querySelector('#config-ob11-httpPost-list'); - buildHostList(ob11Config.httpHosts, 'httpHosts').forEach(dom => { - httpHostContainerDom.appendChild(dom); - }); - - const wsHostContainerDom = doc.querySelector('#config-ob11-wsHosts-list'); - buildHostList(ob11Config.wsHosts, 'wsHosts').forEach(dom => { - wsHostContainerDom.appendChild(dom); - }); - // 保存按钮 doc.querySelector('#config-ob11-save').addEventListener('click', () => { config.ob11 = ob11Config; From aec06d37b6570c4f95cf1eb513d89b839abcd811 Mon Sep 17 00:00:00 2001 From: Misa Liu <misaliu@misaliu.top> Date: Tue, 5 Mar 2024 00:03:41 +0800 Subject: [PATCH 14/20] feat: Made reverse host list editable --- src/renderer/index.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/renderer/index.ts b/src/renderer/index.ts index 5069c11..df8ea30 100644 --- a/src/renderer/index.ts +++ b/src/renderer/index.ts @@ -154,12 +154,13 @@ async function onSettingWindowCreated(view: Element) { dom.container.classList.add('setting-host-list-item'); dom.container.dataset.direction = 'row'; - dom.container.dataset.configArrayKey = type; - dom.container.dataset.configArrayIndex = `${index}`; dom.input.classList.add('q-input__inner'); dom.input.type = 'url'; dom.input.value = host; + dom.input.addEventListener('input', () => { + ob11Config[type][index] = dom.input.value; + }); dom.inputContainer.classList.add('q-input'); dom.inputContainer.appendChild(dom.input); From 7d36e49bb27558da6c951ca11c3f904f4c75bd91 Mon Sep 17 00:00:00 2001 From: Misa Liu <misaliu@misaliu.top> Date: Tue, 5 Mar 2024 00:10:28 +0800 Subject: [PATCH 15/20] feat: Made add button of reverse list work --- src/renderer/index.ts | 79 ++++++++++++++++++++++++------------------- 1 file changed, 45 insertions(+), 34 deletions(-) diff --git a/src/renderer/index.ts b/src/renderer/index.ts index df8ea30..165ecd7 100644 --- a/src/renderer/index.ts +++ b/src/renderer/index.ts @@ -51,7 +51,7 @@ async function onSettingWindowCreated(view: Element) { <div> <setting-text>HTTP 事件上报地址</setting-text> </div> - <setting-button data-type="primary">添加</setting-button> + <setting-button id="config-ob11-httpHosts-add" data-type="primary">添加</setting-button> </setting-item> <div id="config-ob11-httpHosts-list"></div> </div>`, @@ -70,7 +70,7 @@ async function onSettingWindowCreated(view: Element) { <div> <setting-text>反向 WebSocket 监听地址</setting-text> </div> - <setting-button data-type="primary">添加</setting-button> + <setting-button id="config-ob11-wsHosts-add" data-type="primary">添加</setting-button> </setting-item> <div id="config-ob11-wsHosts-list"></div> </div>`, @@ -141,46 +141,54 @@ async function onSettingWindowCreated(view: Element) { ].join(''), "text/html"); // 生成反向地址列表 + const buildHostListItem = (type: string, host: string, index: number) => { + const dom = { + container: document.createElement('setting-item'), + input: document.createElement('input'), + inputContainer: document.createElement('div'), + deleteBtn: document.createElement('setting-button'), + }; + + dom.container.classList.add('setting-host-list-item'); + dom.container.dataset.direction = 'row'; + + dom.input.classList.add('q-input__inner'); + dom.input.type = 'url'; + dom.input.value = host; + dom.input.addEventListener('input', () => { + ob11Config[type][index] = dom.input.value; + }); + + dom.inputContainer.classList.add('q-input'); + dom.inputContainer.appendChild(dom.input); + + dom.deleteBtn.innerHTML = '删除'; + dom.deleteBtn.dataset.type = 'secondary'; + dom.deleteBtn.addEventListener('click', () => { + ob11Config[type].splice(index, 1); + console.log(ob11Config); + initReverseHost(type); + }); + + dom.container.appendChild(dom.inputContainer); + dom.container.appendChild(dom.deleteBtn); + + return dom.container; + }; const buildHostList = (hosts: string[], type: string) => { const result: HTMLElement[] = []; hosts.forEach((host, index) => { - const dom = { - container: document.createElement('setting-item'), - input: document.createElement('input'), - inputContainer: document.createElement('div'), - deleteBtn: document.createElement('setting-button'), - }; - - dom.container.classList.add('setting-host-list-item'); - dom.container.dataset.direction = 'row'; - - dom.input.classList.add('q-input__inner'); - dom.input.type = 'url'; - dom.input.value = host; - dom.input.addEventListener('input', () => { - ob11Config[type][index] = dom.input.value; - }); - - dom.inputContainer.classList.add('q-input'); - dom.inputContainer.appendChild(dom.input); - - dom.deleteBtn.innerHTML = '删除'; - dom.deleteBtn.dataset.type = 'secondary'; - dom.deleteBtn.addEventListener('click', () => { - ob11Config[type].splice(index, 1); - console.log(ob11Config); - initReverseHost(type); - }); - - dom.container.appendChild(dom.inputContainer); - dom.container.appendChild(dom.deleteBtn); - - result.push(dom.container); + result.push(buildHostListItem(type, host, index)); }); return result; }; + const addReverseHost = (type: string, doc: Document = document) => { + const hostContainerDom = doc.body.querySelector(`#config-ob11-${type}-list`); + hostContainerDom.appendChild(buildHostListItem(type, '', ob11Config[type].length)); + ob11Config[type].push(''); + }; const initReverseHost = (type: string, doc: Document = document) => { const hostContainerDom = doc.body.querySelector(`#config-ob11-${type}-list`); [ ...hostContainerDom.childNodes ].forEach(dom => dom.remove()); @@ -191,6 +199,9 @@ async function onSettingWindowCreated(view: Element) { initReverseHost('httpHosts', doc); initReverseHost('wsHosts', doc); + doc.querySelector('#config-ob11-httpHosts-add').addEventListener('click', () => addReverseHost('httpHosts')); + doc.querySelector('#config-ob11-wsHosts-add').addEventListener('click', () => addReverseHost('wsHosts')); + // 开关 doc.querySelectorAll('setting-switch[data-config-key]').forEach((dom: HTMLElement) => { dom.addEventListener('click', () => { From 9ff851ebb4134394960f1e264c73acd69f8da2c9 Mon Sep 17 00:00:00 2001 From: Misa Liu <misaliu@misaliu.top> Date: Tue, 5 Mar 2024 00:15:48 +0800 Subject: [PATCH 16/20] feat: Made ffmpeg select button work --- src/renderer/index.ts | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/renderer/index.ts b/src/renderer/index.ts index 165ecd7..23de1eb 100644 --- a/src/renderer/index.ts +++ b/src/renderer/index.ts @@ -90,9 +90,8 @@ async function onSettingWindowCreated(view: Element) { ], 'ob11.messagePostFormat', config.ob11.messagePostFormat), ), SettingItem( - 'ffmpeg 路径', `<span id="config-ffmpeg-path">${!isEmpty(config.ffmpeg) ? config.ffmpeg : '未指定'}</span>`, + 'ffmpeg 路径', `<span id="config-ffmpeg-path-text">${!isEmpty(config.ffmpeg) ? config.ffmpeg : '未指定'}</span>`, SettingButton('选择', 'config-ffmpeg-select'), - 'config-ffmpeg-path', ), SettingItem( '', null, @@ -202,6 +201,16 @@ async function onSettingWindowCreated(view: Element) { doc.querySelector('#config-ob11-httpHosts-add').addEventListener('click', () => addReverseHost('httpHosts')); doc.querySelector('#config-ob11-wsHosts-add').addEventListener('click', () => addReverseHost('wsHosts')); + doc.querySelector('#config-ffmpeg-select').addEventListener('click', () => { + window.llonebot.selectFile() + .then(path => { + if (!isEmpty(path)) { + setConfig('ffmpeg', path); + document.querySelector('#config-ffmpeg-path-text').innerHTML = path; + } + }) + }); + // 开关 doc.querySelectorAll('setting-switch[data-config-key]').forEach((dom: HTMLElement) => { dom.addEventListener('click', () => { From 1cc726bcdc667a6e07e7d8fb836adadedfb8723c Mon Sep 17 00:00:00 2001 From: Misa Liu <misaliu@misaliu.top> Date: Tue, 5 Mar 2024 00:17:20 +0800 Subject: [PATCH 17/20] feat: Made open config path button work --- src/renderer/index.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/renderer/index.ts b/src/renderer/index.ts index 23de1eb..a77498b 100644 --- a/src/renderer/index.ts +++ b/src/renderer/index.ts @@ -211,6 +211,10 @@ async function onSettingWindowCreated(view: Element) { }) }); + doc.querySelector('#config-open-log-path').addEventListener('click', () => { + window.LiteLoader.api.openPath(window.LiteLoader.plugins['LLOneBot'].path.data); + }) + // 开关 doc.querySelectorAll('setting-switch[data-config-key]').forEach((dom: HTMLElement) => { dom.addEventListener('click', () => { From beb372d102361ba0a146f04c37a2d1b57b7deeb8 Mon Sep 17 00:00:00 2001 From: Misa Liu <misaliu@misaliu.top> Date: Tue, 5 Mar 2024 00:21:54 +0800 Subject: [PATCH 18/20] feat: Add style to link(s) --- src/renderer/style.css | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/renderer/style.css b/src/renderer/style.css index 96d7a38..028aa96 100644 --- a/src/renderer/style.css +++ b/src/renderer/style.css @@ -50,4 +50,15 @@ setting-item .q-input input[type=number].q-input__inner::-webkit-inner-spin-butt .config-host-list setting-item.setting-host-list-item .q-input { width: 260px; +} + +setting-item a { + color: var(--text-link); +} +setting-item a:hover { + color: var(--hover-link); +} +setting-item a:active, +setting-item a:visited { + color: var(--text-link); } \ No newline at end of file From f02ad6f788bcb6111d37bf790cda483891d83953 Mon Sep 17 00:00:00 2001 From: Misa Liu <misaliu@misaliu.top> Date: Tue, 5 Mar 2024 00:22:17 +0800 Subject: [PATCH 19/20] feat: Finishing code --- src/renderer/index.ts | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/renderer/index.ts b/src/renderer/index.ts index a77498b..98f0a1c 100644 --- a/src/renderer/index.ts +++ b/src/renderer/index.ts @@ -27,8 +27,6 @@ async function onSettingWindowCreated(view: Element) { window.llonebot.setConfig(config); } - - console.log(config, ob11Config); }; const parser = new DOMParser(); @@ -165,7 +163,6 @@ async function onSettingWindowCreated(view: Element) { dom.deleteBtn.dataset.type = 'secondary'; dom.deleteBtn.addEventListener('click', () => { ob11Config[type].splice(index, 1); - console.log(ob11Config); initReverseHost(type); }); From 3cea9918391ecee6c2b1dbb70b3c02ab43bc87b0 Mon Sep 17 00:00:00 2001 From: Misa Liu <misaliu@misaliu.top> Date: Tue, 5 Mar 2024 00:22:36 +0800 Subject: [PATCH 20/20] chore: Edit config(s) --- electron.vite.config.ts | 4 ++-- manifest.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/electron.vite.config.ts b/electron.vite.config.ts index a72dbd8..a30979c 100644 --- a/electron.vite.config.ts +++ b/electron.vite.config.ts @@ -52,11 +52,11 @@ let config = { emptyOutDir: true, lib: { formats: ["es"], - entry: { "renderer": "src/renderer.ts" }, + entry: { "renderer": "src/renderer/index.ts" }, }, rollupOptions: { // external: externalAll, - input: "src/renderer.ts", + input: "src/renderer/index.ts", } }, resolve:{ diff --git a/manifest.json b/manifest.json index 2152c02..4f19d6f 100644 --- a/manifest.json +++ b/manifest.json @@ -26,7 +26,7 @@ "darwin" ], "injects": { - "renderer": "./renderer/renderer.js", + "renderer": "./renderer/index.js", "main": "./main/main.cjs", "preload": "./preload/preload.cjs" }