mirror of
https://github.com/NapNeko/NapCatQQ.git
synced 2025-07-19 12:03:37 +00:00
feat:webui-2
This commit is contained in:
@@ -1,20 +1,9 @@
|
|||||||
/// <reference path="../global.d.ts" />
|
|
||||||
import { CheckVersion } from '../common/types'
|
|
||||||
import { SettingButton, SettingItem, SettingList, SettingSwitch, SettingSelect } from './components'
|
|
||||||
// @ts-ignore
|
|
||||||
import StyleRaw from './style.css?raw'
|
import StyleRaw from './style.css?raw'
|
||||||
import { iconSvg } from './icon'
|
|
||||||
|
|
||||||
// 打开设置界面时触发
|
// 打开设置界面时触发
|
||||||
|
|
||||||
function aprilFoolsEgg(node: Element) {
|
function aprilFoolsEgg(node: Element) {
|
||||||
let today = new Date()
|
|
||||||
if (today.getDate() === 1) {
|
|
||||||
console.log('超时空猫猫!!!')
|
|
||||||
node.querySelector('.name').innerHTML = 'ChronoCat'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function initSideBar() {
|
function initSideBar() {
|
||||||
document.querySelectorAll('.nav-item.liteloader').forEach((node) => {
|
document.querySelectorAll('.nav-item.liteloader').forEach((node) => {
|
||||||
if (node.textContent.startsWith('LLOneBot')) {
|
if (node.textContent.startsWith('LLOneBot')) {
|
||||||
|
3
static/components/SettingButton.ts
Normal file
3
static/components/SettingButton.ts
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
export const SettingButton = (text: string, id?: string, type: string = 'secondary') => {
|
||||||
|
return `<setting-button ${type ? `data-type="${type}"` : ''} ${id ? `id="${id}"` : ''}>${text}</setting-button>`
|
||||||
|
}
|
15
static/components/SettingItem.ts
Normal file
15
static/components/SettingItem.ts
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
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>`
|
||||||
|
}
|
14
static/components/SettingList.ts
Normal file
14
static/components/SettingList.ts
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
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>`
|
||||||
|
}
|
3
static/components/SettingOption.ts
Normal file
3
static/components/SettingOption.ts
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
export const SettingOption = (text: string, value?: string, isSelected: boolean = false) => {
|
||||||
|
return `<setting-option ${value ? `data-value="${value}"` : ''} ${isSelected ? 'is-selected' : ''}>${text}</setting-option>`
|
||||||
|
}
|
84
static/components/SettingSelect.ts
Normal file
84
static/components/SettingSelect.ts
Normal file
@@ -0,0 +1,84 @@
|
|||||||
|
import { SettingOption } from './option'
|
||||||
|
|
||||||
|
interface MouseEventExtend extends MouseEvent {
|
||||||
|
target: HTMLElement
|
||||||
|
}
|
||||||
|
|
||||||
|
// <ob-setting-select>
|
||||||
|
const SelectTemplate = document.createElement('template')
|
||||||
|
SelectTemplate.innerHTML = `<style>
|
||||||
|
.hidden { display: none !important; }
|
||||||
|
</style>
|
||||||
|
<div part="parent">
|
||||||
|
<div part="button">
|
||||||
|
<input type="text" placeholder="请选择" part="current-text" />
|
||||||
|
<svg viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg" part="button-arrow">
|
||||||
|
<path d="M12 6.0001L8.00004 10L4 6" stroke="currentColor" stroke-linejoin="round"></path>
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
<ul class="hidden" part="option-list"><slot></slot></ul>
|
||||||
|
</div>`
|
||||||
|
|
||||||
|
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 `<ob-setting-select ${configKey ? `data-config-key="${configKey}"` : ''}>
|
||||||
|
${items
|
||||||
|
.map((e, i) => {
|
||||||
|
return SettingOption(e.text, e.value, configKey && configValue ? configValue === e.value : i === 0)
|
||||||
|
})
|
||||||
|
.join('')}
|
||||||
|
</ob-setting-select>`
|
||||||
|
}
|
8
static/components/SettingSwitch.ts
Normal file
8
static/components/SettingSwitch.ts
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
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>`
|
||||||
|
}
|
Reference in New Issue
Block a user