tiny-engine/packages/common/component/MetaSelectIcon.vue

177 lines
4.3 KiB
Vue

<template>
<div class="meta-select-icon">
<tiny-popover popper-class="icon-popover" placement="left">
<template #reference>
<div aria-haspopup="true" aria-expanded="true" class="lowcode-icon">
<span class="icon-box" v-if="state.icon.name">
<component :is="state.icon.component" />
</span>
<span class="icon-text" :title="state.icon.name">{{ state.icon.name || '请选择图标' }}</span>
<icon-close class="icon-close" v-if="state.icon.name" @click="clearIcon($event)"></icon-close>
</div>
</template>
<div>
<div class="icon-manage-search">
<tiny-search
v-model="state.iconSearchValue"
clearable
placeholder="搜索图标"
@update:modelValue="searchIcon"
></tiny-search>
<span class="icon-manage-clear" v-if="state.icon.name" @click="clearIcon($event)">清空</span>
</div>
<ul class="lowcode-icon-list lowcode-scrollbar-thin">
<li v-for="icon in SvgIConsList" :key="icon" @click="selectIcon(icon)">
<component :is="icon.component" />
</li>
</ul>
</div>
</tiny-popover>
</div>
</template>
<script>
import { reactive, ref } from 'vue'
import { Popover, Search } from '@opentiny/vue'
import { iconClose } from '@opentiny/vue-icon'
import SvgICons from '@opentiny/vue-icon'
export default {
components: {
TinySearch: Search,
TinyPopover: Popover,
IconClose: iconClose()
},
props: {
modelValue: {
type: String,
default: '' // 默认值为空
}
},
setup(props, { emit }) {
const state = reactive({
iconSearchValue: '',
icon: {
name: props.modelValue,
component: props.modelValue && SvgICons[props.modelValue]()
},
defaultIcon: {
name: props.modelValue,
component: props.modelValue && SvgICons[props.modelValue]()
}
})
const selectIcon = (icon) => {
state.icon = icon
emit('update:modelValue', icon.name)
}
const clearIcon = (e) => {
e.stopPropagation()
state.icon = state.defaultIcon
emit('update:modelValue', '')
}
const getSvgs = () =>
Object.keys(SvgICons).map((name) => ({
name,
component: name && SvgICons[name]()
}))
const SvgIConsList = ref(getSvgs())
const iconSearchList = getSvgs()
const searchIcon = (value) => {
if (value) {
SvgIConsList.value = iconSearchList.filter((item) => item.name.toLowerCase().includes(value.toLowerCase()))
} else {
SvgIConsList.value = iconSearchList
}
}
return {
state,
SvgIConsList,
searchIcon,
selectIcon,
clearIcon
}
}
}
</script>
<style scoped lang="less">
.lowcode-icon {
position: relative;
height: 30px;
display: flex;
padding-right: 20px;
width: 136px;
cursor: pointer;
background: var(--ti-lowcode-tabs-bg);
color: var(--ti-lowcode-toolbar-breadcrumb-color);
border: 1px solid var(--ti-lowcode-tabs-active-bg);
border-radius: 3px;
.icon-box {
border-right: 1px solid var(--ti-lowcode-tabs-active-bg);
padding: 4px 8px;
.tiny-svg {
color: var(--ti-lowcode-toolbar-breadcrumb-color);
font-size: 14px;
}
}
.icon-text {
padding: 4px 0 4px 8px;
line-height: 20px;
display: block;
overflow: hidden;
text-overflow: ellipsis;
}
.icon-close {
position: absolute;
right: 4px;
height: 30px;
line-height: 20px;
width: 16px;
cursor: pointer;
}
}
.icon-popover {
.icon-manage-search {
display: flex;
align-items: center;
margin-bottom: 5px;
.icon-manage-clear {
display: block;
color: #5e7ce0;
min-width: 48px;
margin-left: 5px;
cursor: pointer;
}
}
.lowcode-icon-list {
width: 320px;
overflow-y: auto;
overflow-x: hidden;
height: 320px;
display: grid;
padding: 4px;
grid-template-columns: repeat(8, 30px);
gap: 15px 10px;
li {
width: 40px;
color: var(--ti-lowcode-icon-popover-color);
cursor: pointer;
text-align: center;
.tiny-svg {
font-size: 24px;
&:hover {
color: var(--ti-lowcode-icon-popover-hover-color);
}
}
}
}
}
</style>