mirror of
https://github.com/the1812/Bilibili-Evolved.git
synced 2025-11-04 21:22:45 +08:00
feat: 迁移至 ExtraOptionsPanel
This commit is contained in:
parent
2288a37aec
commit
5f3e401239
@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<div class="custom-font-family-extra-options-entry">
|
||||
<VButton ref="button" @mouseover="loadExtraOptions()" @click="toggleExtraOptionsDisplay()">
|
||||
<VButton ref="button" @mouseover="loadPanel()" @click="togglePanelDisplay()">
|
||||
字体设置<VIcon icon="right-arrow" :size="16"></VIcon>
|
||||
</VButton>
|
||||
</div>
|
||||
@ -9,12 +9,7 @@
|
||||
<script lang="ts">
|
||||
import { defineComponent } from 'vue'
|
||||
import { VIcon, VButton } from '@/ui'
|
||||
import {
|
||||
setTriggerElement,
|
||||
getExtraOptionsLoadState,
|
||||
loadExtraOptions,
|
||||
toggleExtraOptionsDisplay,
|
||||
} from './vm'
|
||||
import { getPanelLoadState, mountPanel, togglePanelDisplay } from './vm'
|
||||
|
||||
export default defineComponent({
|
||||
components: {
|
||||
@ -23,15 +18,13 @@ export default defineComponent({
|
||||
},
|
||||
|
||||
methods: {
|
||||
async loadExtraOptions() {
|
||||
const isLoaded = await getExtraOptionsLoadState()
|
||||
async loadPanel() {
|
||||
const isLoaded = await getPanelLoadState()
|
||||
if (!isLoaded) {
|
||||
await loadExtraOptions()
|
||||
const triggerButton = this.$refs.button.$el as HTMLElement
|
||||
setTriggerElement(triggerButton)
|
||||
await mountPanel()
|
||||
}
|
||||
},
|
||||
toggleExtraOptionsDisplay,
|
||||
togglePanelDisplay,
|
||||
},
|
||||
})
|
||||
</script>
|
||||
|
||||
@ -1,12 +1,5 @@
|
||||
<template>
|
||||
<VPopup
|
||||
ref="popup"
|
||||
v-model="popupOpen"
|
||||
class="extra-options-panel"
|
||||
fixed
|
||||
:lazy="false"
|
||||
:trigger-element="triggerElement"
|
||||
>
|
||||
<VPopup v-model="popupOpen" class="extra-options-panel" fixed :lazy="false">
|
||||
<div class="eop-header">
|
||||
<div class="eop-h-left">
|
||||
<VIcon class="eop-h-l-symbol" :icon="initData.header.title.icon" :size="24"></VIcon>
|
||||
@ -17,7 +10,8 @@
|
||||
<VIcon
|
||||
v-for="action in initData.header.actions"
|
||||
:key="action.id"
|
||||
:class="`eop-h-r-${action.classNameSuffix}`"
|
||||
:ref="`action${action.id}`"
|
||||
:class="`eop-h-r-${action.iconClassNameSuffix}`"
|
||||
:title="action.title"
|
||||
:icon="action.icon"
|
||||
:size="24"
|
||||
@ -35,11 +29,11 @@
|
||||
<div class="eop-separator"></div>
|
||||
|
||||
<div class="eop-content">
|
||||
<div v-for="section in initData.content.sections" :key="section.id" class="eop-c-section">
|
||||
<div class="eop-c-s-title">{{ section.title }}</div>
|
||||
<div class="eop-c-s-description">{{ section.description }}</div>
|
||||
<div class="eop-c-s-input" :class="section.inputClassName">
|
||||
<slot :name="`eop-c-s-input-slot-${section.id}`">
|
||||
<div v-for="option in initData.content.options" :key="option.id" class="eop-c-option">
|
||||
<div class="eop-c-o-title">{{ option.title }}</div>
|
||||
<div class="eop-c-o-description">{{ option.description }}</div>
|
||||
<div class="eop-c-o-input" :class="option.inputClassName">
|
||||
<slot :name="`eop-c-o-input-slot-${option.id}`">
|
||||
选项输入入口默认文字,使用含 v-slot 指令的 template 元素以替换默认内容
|
||||
</slot>
|
||||
</div>
|
||||
@ -51,46 +45,7 @@
|
||||
<script lang="ts">
|
||||
import { defineComponent } from 'vue'
|
||||
import { VPopup, VIcon } from '@/ui'
|
||||
import { ExtraOptionsPanelInitData } from './extra-options-panel'
|
||||
|
||||
const defaultInitData: ExtraOptionsPanelInitData = {
|
||||
header: {
|
||||
title: {
|
||||
text: '默认标题',
|
||||
icon: 'mdi-format-font',
|
||||
},
|
||||
actions: [
|
||||
{
|
||||
id: 0,
|
||||
title: '默认动作 0',
|
||||
icon: 'mdi-cog-sync-outline',
|
||||
classNameSuffix: 'default-action-0',
|
||||
},
|
||||
{
|
||||
id: 1,
|
||||
title: '默认动作 1',
|
||||
icon: 'mdi-eye-outline',
|
||||
classNameSuffix: 'default-action-1',
|
||||
},
|
||||
],
|
||||
},
|
||||
content: {
|
||||
sections: [
|
||||
{
|
||||
id: 0,
|
||||
title: '默认选项 0',
|
||||
description: '默认选项 0 的说明',
|
||||
inputClassName: 'default-option-0',
|
||||
},
|
||||
{
|
||||
id: 1,
|
||||
title: '默认选项 1',
|
||||
description: '默认选项 1 的说明',
|
||||
inputClassName: 'default-option-1',
|
||||
},
|
||||
],
|
||||
},
|
||||
}
|
||||
import { defaultInitData } from './extra-options-panel'
|
||||
|
||||
export default defineComponent({
|
||||
name: 'ExtraOptionsPanel',
|
||||
@ -101,10 +56,6 @@ export default defineComponent({
|
||||
},
|
||||
|
||||
props: {
|
||||
triggerElement: {
|
||||
type: HTMLElement,
|
||||
default: null,
|
||||
},
|
||||
initData: {
|
||||
type: Object,
|
||||
default: defaultInitData,
|
||||
|
||||
@ -1,86 +1,73 @@
|
||||
<template>
|
||||
<VPopup
|
||||
ref="popup"
|
||||
v-model="popupOpen"
|
||||
class="custom-font-family-extra-options-panel extra-options-panel"
|
||||
fixed
|
||||
:lazy="false"
|
||||
:trigger-element="triggerElement"
|
||||
<ExtraOptionsPanel
|
||||
ref="extraOptionsPanel"
|
||||
class="custom-font-family-extra-options-panel"
|
||||
:class="{ peek: isPeeking }"
|
||||
:init-data="initData"
|
||||
>
|
||||
<div class="eop-header">
|
||||
<div class="eop-h-left">
|
||||
<VIcon class="eop-h-l-symbol" icon="mdi-format-font" :size="24"></VIcon>
|
||||
<div class="eop-h-l-title">字体设置</div>
|
||||
</div>
|
||||
|
||||
<div class="eop-h-right">
|
||||
<VIcon
|
||||
class="eop-h-r-reset"
|
||||
title="重置面板中的所有选项为默认值"
|
||||
icon="mdi-cog-sync-outline"
|
||||
:size="24"
|
||||
@click="confirmResetOptions()"
|
||||
></VIcon>
|
||||
<VIcon
|
||||
class="eop-h-r-peek"
|
||||
title="透视"
|
||||
icon="mdi-eye-outline"
|
||||
:size="24"
|
||||
@mouseover="mouseOnPeekIcon = true"
|
||||
@mouseout="mouseOnPeekIcon = false"
|
||||
></VIcon>
|
||||
<VIcon
|
||||
class="eop-h-r-close"
|
||||
title="关闭"
|
||||
icon="mdi-close"
|
||||
:size="24"
|
||||
@click="popupOpen = false"
|
||||
></VIcon>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="eop-separator"></div>
|
||||
|
||||
<div class="eop-content">
|
||||
<div class="eop-c-section">
|
||||
<div class="eop-c-s-title">自定义字体</div>
|
||||
<div class="eop-c-s-description">输入字体,不同字体之间必须以英文逗号分隔</div>
|
||||
<div class="eop-c-s-input input-font-family">
|
||||
<TextArea v-model="inputFontFamily" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</VPopup>
|
||||
<template #eop-c-o-input-slot-0>
|
||||
<TextArea v-model="inputFontFamily" />
|
||||
</template>
|
||||
</ExtraOptionsPanel>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent } from 'vue'
|
||||
import { VPopup, VIcon, TextArea } from '@/ui'
|
||||
import { TextArea } from '@/ui'
|
||||
import ExtraOptionsPanel from './ExtraOptionsPanel.vue'
|
||||
import { getComponentSettings } from '@/core/settings'
|
||||
import { Toast } from '@/core/toast'
|
||||
import { delay } from '@/core/utils'
|
||||
import { useScopedConsole } from '@/core/utils/log'
|
||||
import { fontFamilyDefaultValue } from '../font-family-default-value'
|
||||
import { ExtraOptionsPanelInitData } from './extra-options-panel'
|
||||
|
||||
const initData: ExtraOptionsPanelInitData = {
|
||||
header: {
|
||||
title: {
|
||||
text: '自定义字体',
|
||||
icon: 'mdi-format-font',
|
||||
},
|
||||
actions: [
|
||||
{
|
||||
id: 0,
|
||||
title: '重置面板中的所有选项为默认值',
|
||||
icon: 'mdi-cog-sync-outline',
|
||||
iconClassNameSuffix: 'reset',
|
||||
},
|
||||
{
|
||||
id: 1,
|
||||
title: '透视',
|
||||
icon: 'mdi-eye-outline',
|
||||
iconClassNameSuffix: 'peek',
|
||||
},
|
||||
],
|
||||
},
|
||||
content: {
|
||||
options: [
|
||||
{
|
||||
id: 0,
|
||||
title: '自定义字体',
|
||||
description: '输入需要设置的字体,不同字体之间必须以英文逗号分隔',
|
||||
inputClassName: 'input-font-family',
|
||||
},
|
||||
],
|
||||
},
|
||||
}
|
||||
|
||||
const console = useScopedConsole('自定义字体')
|
||||
|
||||
export default defineComponent({
|
||||
components: {
|
||||
VPopup,
|
||||
VIcon,
|
||||
ExtraOptionsPanel,
|
||||
TextArea,
|
||||
},
|
||||
|
||||
props: {
|
||||
triggerElement: {
|
||||
type: HTMLElement,
|
||||
default: null,
|
||||
},
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
popupOpen: false,
|
||||
isPeeking: false,
|
||||
mouseOnPeekIcon: false,
|
||||
isMouseOverPeekIcon: false,
|
||||
initData,
|
||||
// 设置 inputFontFamily 初始值为组件 fontFamily 选项的值
|
||||
inputFontFamily: getComponentSettings('customFontFamily').options.fontFamily,
|
||||
}
|
||||
@ -92,7 +79,7 @@ export default defineComponent({
|
||||
getComponentSettings('customFontFamily').options.fontFamily = value
|
||||
}, 500),
|
||||
|
||||
async mouseOnPeekIcon(value: boolean) {
|
||||
async isMouseOverPeekIcon(value: boolean) {
|
||||
if (!value) {
|
||||
this.isPeeking = false
|
||||
return
|
||||
@ -100,13 +87,38 @@ export default defineComponent({
|
||||
if (value) {
|
||||
await delay(200)
|
||||
}
|
||||
if (this.mouseOnPeekIcon) {
|
||||
if (this.isMouseOverPeekIcon) {
|
||||
this.isPeeking = true
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
mounted() {
|
||||
// 当在 v-for 中使用模板引用时,相应的引用中包含的值是一个数组
|
||||
// 但 ref 数组并不保证与源数组相同的顺序,所以统一命名且不加用以区分的后缀,仅靠数组选择元素是不现实的
|
||||
// https://cn.vuejs.org/guide/essentials/template-refs.html#refs-inside-v-for
|
||||
|
||||
const action0Reset = this.$refs.extraOptionsPanel.$refs.action0[0].$el as HTMLElement
|
||||
action0Reset.addEventListener('click', this.confirmResetOptions)
|
||||
|
||||
const action1Peek = this.$refs.extraOptionsPanel.$refs.action1[0].$el as HTMLElement
|
||||
action1Peek.addEventListener('mouseover', this.setIsMouseOverPeekIconToTrue)
|
||||
action1Peek.addEventListener('mouseout', this.setIsMouseOverPeekIconToFalse)
|
||||
},
|
||||
|
||||
methods: {
|
||||
toggleDisplay() {
|
||||
this.$refs.extraOptionsPanel.popupOpen = !this.$refs.extraOptionsPanel.popupOpen
|
||||
},
|
||||
|
||||
setIsMouseOverPeekIconToTrue() {
|
||||
this.isMouseOverPeekIcon = true
|
||||
},
|
||||
|
||||
setIsMouseOverPeekIconToFalse() {
|
||||
this.isMouseOverPeekIcon = false
|
||||
},
|
||||
|
||||
confirmResetOptions() {
|
||||
if (confirm('确定将面板中的所有选项重置为默认值吗?')) {
|
||||
this.resetOptions()
|
||||
@ -116,20 +128,20 @@ export default defineComponent({
|
||||
resetOptions() {
|
||||
getComponentSettings('customFontFamily').options.fontFamily = fontFamilyDefaultValue
|
||||
this.inputFontFamily = fontFamilyDefaultValue
|
||||
const console = useScopedConsole('自定义字体')
|
||||
console.log('已将字体设置面板中的所有选项重置为默认值')
|
||||
Toast.success('成功将字体设置面板中的所有选项重置为默认值', '自定义字体', 2000)
|
||||
console.log('成功将字体设置面板中的所有选项重置为默认值')
|
||||
},
|
||||
},
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
@import './extra-options-panel';
|
||||
|
||||
.custom-font-family-extra-options-panel {
|
||||
@include extra-options-panel;
|
||||
&.peek {
|
||||
opacity: 0.1;
|
||||
}
|
||||
|
||||
> .eop-content > .eop-c-section > .eop-c-s-input.input-font-family .be-text-area {
|
||||
> .eop-content > .eop-c-option > .eop-c-o-input.input-font-family > .be-text-area {
|
||||
min-height: 160px;
|
||||
}
|
||||
}
|
||||
|
||||
@ -5,7 +5,7 @@ $prefH: 'eop-h';
|
||||
$prefHL: 'eop-h-l';
|
||||
$prefHR: 'eop-h-r';
|
||||
$prefC: 'eop-c';
|
||||
$prefCS: 'eop-c-s';
|
||||
$prefCO: 'eop-c-o';
|
||||
|
||||
$panelPadding: 22px;
|
||||
|
||||
@ -28,10 +28,6 @@ $panelPadding: 22px;
|
||||
transform: translateX(-50%) translateY(-50%) scale(1);
|
||||
}
|
||||
|
||||
&.peek {
|
||||
opacity: 0.1;
|
||||
}
|
||||
|
||||
> .#{$pref}-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
@ -81,25 +77,25 @@ $panelPadding: 22px;
|
||||
flex-grow: 1;
|
||||
flex-shrink: 1;
|
||||
|
||||
> .#{$prefC}-section {
|
||||
> .#{$prefC}-option {
|
||||
margin: 18px 0;
|
||||
|
||||
&:nth-child(1):nth-last-child(1) {
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
> .#{$prefCS}-title {
|
||||
> .#{$prefCO}-title {
|
||||
margin-bottom: 2px;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
> .#{$prefCS}-description {
|
||||
> .#{$prefCO}-description {
|
||||
margin-bottom: 8px;
|
||||
opacity: 0.6;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
> .#{$prefCS}-input {
|
||||
> .#{$prefCO}-input {
|
||||
@include h-center();
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
@ -7,19 +7,19 @@ export interface ExtraOptionsPanelInitData {
|
||||
icon: string
|
||||
}
|
||||
actions: {
|
||||
/** 动作按钮序号,从 0 开始增长,不可重复 */
|
||||
/** 动作按钮序号,从 0 开始增长,重复将会导致渲染异常 */
|
||||
id: number
|
||||
/** 动作按钮标题 */
|
||||
title: string
|
||||
/** 动作按钮图标 */
|
||||
icon: string
|
||||
/** 动作按钮类名的后缀,直接写一个贴切的名字就好了 */
|
||||
classNameSuffix: string
|
||||
iconClassNameSuffix: string
|
||||
}[]
|
||||
}
|
||||
content: {
|
||||
sections: {
|
||||
/** 选项序号,从 0 开始增长,不可重复 */
|
||||
options: {
|
||||
/** 选项序号,从 0 开始增长,重复将会导致渲染异常。另外会在类似 eop-c-s-input-slot-0 的具名插槽用到 */
|
||||
id: number
|
||||
/** 选项标题 */
|
||||
title: string
|
||||
@ -30,3 +30,42 @@ export interface ExtraOptionsPanelInitData {
|
||||
}[]
|
||||
}
|
||||
}
|
||||
|
||||
export const defaultInitData: ExtraOptionsPanelInitData = {
|
||||
header: {
|
||||
title: {
|
||||
text: '默认标题',
|
||||
icon: 'mdi-format-font',
|
||||
},
|
||||
actions: [
|
||||
{
|
||||
id: 0,
|
||||
title: '默认动作 0',
|
||||
icon: 'mdi-cog-sync-outline',
|
||||
iconClassNameSuffix: 'default-action-0',
|
||||
},
|
||||
{
|
||||
id: 1,
|
||||
title: '默认动作 1',
|
||||
icon: 'mdi-eye-outline',
|
||||
iconClassNameSuffix: 'default-action-1',
|
||||
},
|
||||
],
|
||||
},
|
||||
content: {
|
||||
options: [
|
||||
{
|
||||
id: 0,
|
||||
title: '默认选项 0',
|
||||
description: '默认选项 0 的说明',
|
||||
inputClassName: 'default-option-0',
|
||||
},
|
||||
{
|
||||
id: 1,
|
||||
title: '默认选项 1',
|
||||
description: '默认选项 1 的说明',
|
||||
inputClassName: 'default-option-1',
|
||||
},
|
||||
],
|
||||
},
|
||||
}
|
||||
|
||||
@ -1,24 +1,19 @@
|
||||
import { mountVueComponent } from '@/core/utils'
|
||||
|
||||
let extraOptionsVm: Vue & {
|
||||
popupOpen: boolean
|
||||
triggerElement: HTMLElement
|
||||
let panelVm: Vue & {
|
||||
toggleDisplay: () => void
|
||||
}
|
||||
|
||||
export const setTriggerElement = (element: HTMLElement) => {
|
||||
extraOptionsVm.triggerElement = element
|
||||
export const getPanelLoadState = async () => {
|
||||
return Boolean(panelVm)
|
||||
}
|
||||
|
||||
export const getExtraOptionsLoadState = async () => {
|
||||
return Boolean(extraOptionsVm)
|
||||
export const mountPanel = async () => {
|
||||
const panel = await import('./Panel1.vue').then(m => m.default)
|
||||
panelVm = mountVueComponent(panel)
|
||||
document.body.insertAdjacentElement('beforeend', panelVm.$el)
|
||||
}
|
||||
|
||||
export const loadExtraOptions = async () => {
|
||||
const extraOptions = await import('./Panel1.vue').then(m => m.default)
|
||||
extraOptionsVm = mountVueComponent(extraOptions)
|
||||
document.body.insertAdjacentElement('beforeend', extraOptionsVm.$el)
|
||||
}
|
||||
|
||||
export const toggleExtraOptionsDisplay = async () => {
|
||||
extraOptionsVm.popupOpen = !extraOptionsVm.popupOpen
|
||||
export const togglePanelDisplay = async () => {
|
||||
panelVm.toggleDisplay()
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user