feat: 迁移至 ExtraOptionsPanel

This commit is contained in:
Tinhone 2023-10-11 07:49:43 +08:00
parent 2288a37aec
commit 5f3e401239
6 changed files with 156 additions and 170 deletions

View File

@ -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>

View File

@ -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,

View File

@ -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">
<template #eop-c-o-input-slot-0>
<TextArea v-model="inputFontFamily" />
</div>
</div>
</div>
</VPopup>
</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;
}
}

View File

@ -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;
}

View File

@ -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',
},
],
},
}

View File

@ -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()
}