diff --git a/src/renderer/components/select.ts b/src/renderer/components/select.ts index 0c33332..ef2403a 100644 --- a/src/renderer/components/select.ts +++ b/src/renderer/components/select.ts @@ -1,11 +1,77 @@ import { SettingOption } from "./option"; +interface MouseEventExtend extends MouseEvent { + target: HTMLElement, +} + +// +const SelectTemplate = document.createElement('template'); +SelectTemplate.innerHTML = ` +
+
+ + + + +
+ +
`; + +window.customElements.define('ob-setting-select', class extends HTMLElement { + readonly _button: HTMLDivElement; + readonly _text: HTMLInputElement; + readonly _context: HTMLUListElement; + + constructor() { + super(); + + this.attachShadow({ mode: 'open' }); + this.shadowRoot.append(SelectTemplate.content.cloneNode(true)); + + this._button = this.shadowRoot.querySelector('div[part="button"]'); + this._text = this.shadowRoot.querySelector('input[part="current-text"]'); + this._context = this.shadowRoot.querySelector('ul[part="option-list"]'); + + const buttonClick = () => { + const isHidden = this._context.classList.toggle('hidden'); + window[`${isHidden ? 'remove': 'add'}EventListener`]('pointerdown', windowPointerDown); + }; + + const windowPointerDown = ({ target }) => { + if (!this.contains(target)) buttonClick(); + }; + + this._button.addEventListener('click', buttonClick); + this._context.addEventListener('click', ({ target }: MouseEventExtend) => { + if (target.tagName !== 'SETTING-OPTION') return; + buttonClick(); + + if (target.hasAttribute('is-selected')) return; + + this.querySelectorAll('setting-option[is-selected]').forEach(dom => dom.toggleAttribute('is-selected')); + target.toggleAttribute('is-selected'); + + this._text.value = target.textContent; + this.dispatchEvent(new CustomEvent('selected', { + bubbles: true, + composed: true, + detail: { + name: target.textContent, + value: target.dataset.value, + }, + })); + }); + + this._text.value = this.querySelector('setting-option[is-selected]').textContent; + } +}); + export const SettingSelect = (items: Array<{ text: string, value: string }>, configKey?: string, configValue?: any) => { - return ` -
- ${items.map((e, i) => { - return SettingOption(e.text, e.value, (configKey && configValue ? configValue === e.value : i === 0)); - }).join('')} -
-
`; + return ` + ${items.map((e, i) => { + return SettingOption(e.text, e.value, (configKey && configValue ? configValue === e.value : i === 0)); + }).join('')} +`; } \ No newline at end of file diff --git a/src/renderer/index.ts b/src/renderer/index.ts index b8f6b5f..2eccc9e 100644 --- a/src/renderer/index.ts +++ b/src/renderer/index.ts @@ -14,9 +14,6 @@ async function onSettingWindowCreated(view: Element) { const configKey = key.split('.'); if (key.indexOf('ob11') === 0) { - if (configKey[1] === "messagePostFormat") { - value = value ? "string" : "array" - } if (configKey.length === 2) ob11Config[configKey[1]] = value; else ob11Config[key] = value; } else { @@ -95,11 +92,10 @@ async function onSettingWindowCreated(view: Element) { SettingItem( '启用CQ码上报格式,不启用则为消息段格式', '如客户端无特殊需求推荐保持默认设置,两者的详细差异可参考 OneBot v11 文档', - // SettingSelect([ - // {text: '消息段', value: 'array'}, - // {text: 'CQ码', value: 'string'}, - // ], 'ob11.messagePostFormat', config.ob11.messagePostFormat), - SettingSwitch('ob11.messagePostFormat', config.ob11.messagePostFormat === "string"), + SettingSelect([ + {text: '消息段', value: 'array'}, + {text: 'CQ码', value: 'string'}, + ], 'ob11.messagePostFormat', config.ob11.messagePostFormat), ), SettingItem( 'ffmpeg 路径,发送语音、视频需要,同时保证ffprobe和ffmpeg在一起', ` 下载地址 , 路径:${!isEmpty(config.ffmpeg) ? config.ffmpeg : '未指定'}`, @@ -307,7 +303,7 @@ async function onSettingWindowCreated(view: Element) { }); // 下拉框 - doc.querySelectorAll('setting-select').forEach((dom: HTMLElement) => { + doc.querySelectorAll('ob-setting-select[data-config-key]').forEach((dom: HTMLElement) => { dom.addEventListener('selected', (e: CustomEvent) => { const configKey = dom.dataset.configKey; const configValue = e.detail.value; diff --git a/src/renderer/style.css b/src/renderer/style.css index 675442a..243c8a8 100644 --- a/src/renderer/style.css +++ b/src/renderer/style.css @@ -63,10 +63,103 @@ setting-item a:visited { color: var(--text-link); } -#llonebot-error{ +ob-setting-select { + width: 100px; +} + +ob-setting-select, +ob-setting-select::part(parent), +ob-setting-select::part(button) { + display: block; + position: relative; + height: 24px; + font-size: 12px; + line-height: 24px; + box-sizing: border-box; +} + +ob-setting-select::part(button) { + display: flex; + padding: 0px 8px; + background-color: transparent; + border-radius: 4px; + border: 1px solid var(--border_dark); + z-index: 5; + cursor: default; + align-items: center; + flex-direction: row; + flex-wrap: nowrap; +} + +ob-setting-select::part(current-text) { + display: block; + margin-right: 8px; + padding: 0px; + background: none; + background-color: transparent; + font-size: 12px; + color: var(--text_primary); + text-overflow: ellipsis; + border-radius: 0px; + border: none; + outline: none; + overflow: hidden; + appearance: none; + box-sizing: border-box; + cursor: default; + flex: 1; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + -o-user-select: none; + user-select: none; + -webkit-pointer-events: none; + -moz-pointer-events: none; + -ms-pointer-events: none; + -o-pointer-events: none; + pointer-events: none; +} + +ob-setting-select::part(button-arrow) { + position: relative; + display: block; + width: 16px; + height: 16px; + color: var(--icon_primary); +} + +ob-setting-select::part(option-list) { + display: flex; + position: absolute; + top: 100%; + padding: 4px; + margin: 5px 0px; + width: 100%; + max-height: var(--q-contextmenu-max-height); + background-color: var(--blur_middle_standard); + background-clip: padding-box; + backdrop-filter: blur(8px); + font-size: 12px; + box-shadow: var(--shadow_bg_middle_secondary); + border: 1px solid var(--border_secondary); + border-radius: 4px; + box-sizing: border-box; + app-region: no-drag; + overflow-x: hidden; + overflow-y: auto; + list-style: none; + z-index: 999; + flex-direction: column; + align-items: stretch; + flex-wrap: nowrap; + justify-content: flex-start; + gap: 4px; +} + +#llonebot-error { color: red; height: 100px; overflow: visible; display: flex; align-items: center; -} \ No newline at end of file +}