mirror of
https://github.com/kailong321200875/vue-element-plus-admin.git
synced 2024-12-15 01:50:03 +08:00
feat: IconPicker
This commit is contained in:
parent
1098790ee9
commit
4490d5eeeb
@ -29,9 +29,9 @@ async function generateIcon() {
|
||||
// name: 'useType',
|
||||
// choices: [
|
||||
// { key: 'local', value: 'local', name: 'Local' },
|
||||
// { key: 'onLine', value: 'onLine', name: 'OnLine' },
|
||||
// { key: 'onLine', value: 'onLine', name: 'OnLine' }
|
||||
// ],
|
||||
// message: 'How to use icons?',
|
||||
// message: 'How to use icons?'
|
||||
// },
|
||||
{
|
||||
type: 'list',
|
||||
@ -39,16 +39,11 @@ async function generateIcon() {
|
||||
choices: choices,
|
||||
message: 'Select the icon set that needs to be generated?'
|
||||
}
|
||||
// {
|
||||
// type: 'input',
|
||||
// name: 'output',
|
||||
// message: 'Select the icon set that needs to be generated?',
|
||||
// default: 'src/components/Icon/data',
|
||||
// },
|
||||
])
|
||||
// ↓命令行问答的答案
|
||||
.then(async (answers) => {
|
||||
const { iconSet } = answers
|
||||
// const isOnLine = useType === 'onLine'
|
||||
const outputDir = path.resolve(process.cwd(), 'src/components/IconPicker/src/data')
|
||||
fs.ensureDir(outputDir)
|
||||
const genCollections = collections.filter((item) => [iconSet].includes(item.id))
|
||||
@ -67,8 +62,6 @@ async function generateIcon() {
|
||||
prefixSet.push(prefix)
|
||||
}
|
||||
}
|
||||
// 将vite的缓存清空
|
||||
// fs.emptyDir(path.join(process.cwd(), 'node_modules/.vite'))
|
||||
console.log(
|
||||
`✨ ${chalk.cyan(`[${pkg.name}]`)}` + ' - Icon generated successfully:' + `[${prefixSet}]`
|
||||
)
|
||||
|
@ -2,10 +2,167 @@
|
||||
import epIcons from './data/icons.ep'
|
||||
import antIcons from './data/icons.ant-design'
|
||||
import tIcons from './data/icons.tdesign'
|
||||
import { useDesign } from '@/hooks/web/useDesign'
|
||||
import { ElInput, ElPopover, ElScrollbar, ElTabs, ElTabPane, ElPagination } from 'element-plus'
|
||||
import { useAppStore } from '@/store/modules/app'
|
||||
import { computed, CSSProperties, ref, unref, watch } from 'vue'
|
||||
import { nextTick } from 'vue'
|
||||
|
||||
console.log(epIcons, antIcons, tIcons)
|
||||
const modelValue = defineModel<string>()
|
||||
|
||||
const appStore = useAppStore()
|
||||
|
||||
const size = computed(() => appStore.getCurrentSize)
|
||||
|
||||
const iconSize = computed(() => {
|
||||
return size.value === 'small'
|
||||
? 'var(--el-component-size-small)'
|
||||
: size.value === 'large'
|
||||
? 'var(--el-component-size-large)'
|
||||
: 'var(--el-component-size)'
|
||||
})
|
||||
|
||||
const iconWrapStyle = computed((): CSSProperties => {
|
||||
return {
|
||||
width: iconSize.value,
|
||||
height: iconSize.value,
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
boxShadow: '0 0 0 1px var(--el-input-border-color,var(--el-border-color)) inset',
|
||||
position: 'relative',
|
||||
left: '-1px',
|
||||
cursor: 'pointer'
|
||||
}
|
||||
})
|
||||
|
||||
const { getPrefixCls } = useDesign()
|
||||
|
||||
const prefixCls = getPrefixCls('icon-picker')
|
||||
|
||||
const icons = [epIcons, antIcons, tIcons]
|
||||
|
||||
const iconName = ref(icons[0].prefix)
|
||||
|
||||
const currentIconNameIndex = computed(() => {
|
||||
return icons.findIndex((item) => item.prefix === iconName.value)
|
||||
})
|
||||
|
||||
const tabChange = () => {
|
||||
currentPage.value = 1
|
||||
}
|
||||
|
||||
const pageSize = ref(63)
|
||||
|
||||
const currentPage = ref(1)
|
||||
|
||||
const filterIcons = (icons: string[]) => {
|
||||
const start = (currentPage.value - 1) * pageSize.value
|
||||
const end = currentPage.value * pageSize.value
|
||||
return icons.slice(start, end)
|
||||
}
|
||||
|
||||
watch(
|
||||
() => modelValue.value,
|
||||
(val) => {
|
||||
init(val)
|
||||
},
|
||||
{
|
||||
immediate: true
|
||||
}
|
||||
)
|
||||
|
||||
async function init(icon?: string) {
|
||||
if (!icon) return
|
||||
const iconInfo = icon.split(':')
|
||||
iconName.value = iconInfo[0]
|
||||
const wrapIndex = icons.findIndex((item) => item.prefix === iconInfo[0])
|
||||
// 查询当前icon的索引
|
||||
const index = icons[wrapIndex].icons.findIndex((item) => item === icon)
|
||||
// 计算当前icon的页码
|
||||
await nextTick()
|
||||
currentPage.value = Math.ceil((index + 1) / pageSize.value)
|
||||
}
|
||||
|
||||
const popoverShow = () => {
|
||||
init(unref(modelValue))
|
||||
}
|
||||
|
||||
const iconSelect = (icon: string) => {
|
||||
modelValue.value = icon
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div> 2222 </div>
|
||||
<div :class="prefixCls" class="flex justify-center items-center box">
|
||||
<ElInput disabled v-model="modelValue" />
|
||||
<ElPopover
|
||||
placement="bottom"
|
||||
trigger="click"
|
||||
:width="450"
|
||||
popper-style="box-shadow: rgb(14 18 22 / 35%) 0px 10px 38px -10px, rgb(14 18 22 / 20%) 0px 10px 20px -15px; height: 400px;"
|
||||
@show="popoverShow"
|
||||
>
|
||||
<template #reference>
|
||||
<div v-if="modelValue" :style="iconWrapStyle">
|
||||
<Icon :icon="modelValue" />
|
||||
</div>
|
||||
</template>
|
||||
<ElScrollbar class="h-[calc(100%-50px)]!">
|
||||
<ElTabs tab-position="left" v-model="iconName" @tab-change="tabChange">
|
||||
<ElTabPane v-for="item in icons" :key="item.name" :label="item.name" :name="item.prefix">
|
||||
<div class="flex flex-wrap box-border">
|
||||
<div
|
||||
v-for="icon in filterIcons(item.icons)"
|
||||
:key="icon"
|
||||
:style="{
|
||||
width: iconSize,
|
||||
height: iconSize,
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
cursor: 'pointer',
|
||||
border: `1px solid ${
|
||||
icon === modelValue ? 'var(--el-color-primary)' : 'var(--el-border-color)'
|
||||
}`,
|
||||
boxSizing: 'border-box',
|
||||
margin: '2px'
|
||||
}"
|
||||
@click="iconSelect(icon)"
|
||||
>
|
||||
<Icon
|
||||
:icon="icon"
|
||||
:color="icon === modelValue ? 'var(--el-color-primary)' : 'inherit'"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</ElTabPane>
|
||||
</ElTabs>
|
||||
</ElScrollbar>
|
||||
<div
|
||||
class="h-50px absolute bottom-0 left-0 flex items-center pl-[var(--el-popover-padding)] pr-[var(--el-popover-padding)]"
|
||||
>
|
||||
<ElPagination
|
||||
v-model:current-page="currentPage"
|
||||
v-model:page-size="pageSize"
|
||||
:pager-count="5"
|
||||
small
|
||||
:page-sizes="[100, 200, 300, 400]"
|
||||
layout="total, prev, pager, next, jumper"
|
||||
:total="icons[currentIconNameIndex].icons.length"
|
||||
/>
|
||||
</div>
|
||||
</ElPopover>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="less" scoped>
|
||||
@prefix-cls: ~'@{namespace}-icon-picker';
|
||||
|
||||
.@{prefix-cls} {
|
||||
:deep(.@{elNamespace}-input__wrapper) {
|
||||
border-top-right-radius: 0;
|
||||
border-bottom-right-radius: 0;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
@ -1,7 +1,16 @@
|
||||
<script setup lang="ts">
|
||||
import { IconPicker } from '@/components/IconPicker'
|
||||
import { ref } from 'vue'
|
||||
import { ContentWrap } from '@/components/ContentWrap'
|
||||
import { useI18n } from '@/hooks/web/useI18n'
|
||||
|
||||
const { t } = useI18n()
|
||||
|
||||
const currentIcon = ref('tdesign:book-open')
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<IconPicker />
|
||||
<ContentWrap :title="t('router.iconPicker')">
|
||||
<IconPicker v-model="currentIcon" />
|
||||
</ContentWrap>
|
||||
</template>
|
||||
|
4
types/components.d.ts
vendored
4
types/components.d.ts
vendored
@ -1,7 +1,7 @@
|
||||
declare module 'vue' {
|
||||
export interface GlobalComponents {
|
||||
Icon: typeof import('../components/Icon/src/Icon.vue')['default']
|
||||
Permission: typeof import('../components/Permission/src/Permission.vue')['default']
|
||||
Icon: (typeof import('../components/Icon/src/Icon.vue'))['default']
|
||||
Permission: (typeof import('../components/Permission/src/Permission.vue'))['default']
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user