feat: 更新IconSelect组件,支持未分类图标并优化图标数据处理逻辑

This commit is contained in:
chansee97 2025-06-18 17:14:57 +08:00
parent bc968dc7f7
commit 3e4e9005de

View File

@ -1,6 +1,4 @@
<script setup lang="ts">
import { mapEntries } from 'radash'
interface Props {
disabled?: boolean
}
@ -14,12 +12,13 @@ interface IconList {
icons: string[]
title: string
total: number
categories: Record<string, string[]>
categories?: Record<string, string[]>
uncategorized?: string[]
}
const value = defineModel('value', { type: String })
//
const nameList = ['icon-park-outline', 'carbon']
// https://icon-sets.iconify.design/
const nameList = ['icon-park-outline', 'carbon', 'ant-design']
//
async function fetchIconList(name: string): Promise<IconList> {
@ -28,47 +27,39 @@ async function fetchIconList(name: string): Promise<IconList> {
//
async function fetchIconAllList(nameList: string[]) {
const namePromises = nameList.map(name => fetchIconList(name))
const targets = await Promise.all(namePromises)
//
const targets = await Promise.all(nameList.map(fetchIconList))
return targets.map((i) => {
i.icons = Object.entries(i.categories).reduce((prev, next) => {
const [_key, value] = next
return prev.concat(value)
}, [] as string[])
return i
})
}
// svg
function getSvgName(path: string) {
const regex = /\/([^/]+)\.svg$/
const match = path.match(regex)
if (match) {
const fileName = match[1]
return fileName
}
return path
}
//
function generateLocalIconList() {
const localSvgList = import.meta.glob('@/assets/svg-icons/*.svg', {
query: '?raw',
import: 'default',
eager: true,
//
const iconList = targets.map((item) => {
const icons = [
...(item.categories ? Object.values(item.categories).flat() : []),
...(item.uncategorized ? Object.values(item.uncategorized).flat() : []),
]
return { ...item, icons }
})
return mapEntries(localSvgList, (key, value) => {
return [getSvgName(key), value]
//
const svgNames = Object.keys(import.meta.glob('@/assets/svg-icons/*.svg')).map(
path => path.split('/').pop()?.replace('.svg', ''),
).filter(Boolean) as string[] // undefined string[]
//
iconList.unshift({
prefix: 'local',
title: 'Local Icons',
icons: svgNames,
total: svgNames.length,
uncategorized: svgNames,
})
return iconList
}
const iconList = shallowRef<IconList[]>([])
const LocalIconList = shallowRef({})
onMounted(async () => {
iconList.value = await fetchIconAllList(nameList)
LocalIconList.value = generateLocalIconList()
})
// tab
@ -76,17 +67,19 @@ const currentTab = shallowRef(0)
// tag
const currentTag = shallowRef('')
// tab
function handleChangeTab(index: number) {
currentTab.value = index
currentTag.value = ''
}
//
const searchValue = ref('')
//
const currentPage = shallowRef(1)
// tab
function handleChangeTab(index: number) {
currentTab.value = index
currentTag.value = ''
currentPage.value = 1
}
// tag
function handleSelectIconTag(icon: string) {
currentTag.value = currentTag.value === icon ? '' : icon
@ -99,7 +92,7 @@ const icons = computed(() => {
return []
const hasTag = !!currentTag.value
return hasTag
? iconList.value[currentTab.value]?.categories[currentTag.value] || []
? iconList.value[currentTab.value]?.categories?.[currentTag.value] || [] // 使
: iconList.value[currentTab.value].icons || []
})
@ -150,18 +143,6 @@ function clearIcon() {
</template>
<n-tabs :value="currentTab" type="line" animated placement="left" @update:value="handleChangeTab">
<n-tab-pane name="local" tab="local">
<n-flex :size="2">
<n-el
v-for="(_icon, key) in LocalIconList" :key="key"
class="hover:(text-[var(--primary-color)] ring-1) ring-[var(--primary-color)] p-1 rounded flex-center"
:title="`local:${key}`"
@click="handleSelectIcon(`local:${key}`)"
>
<nova-icon :icon="`local:${key}`" :size="24" />
</n-el>
</n-flex>
</n-tab-pane>
<n-tab-pane v-for="(list, index) in iconList" :key="list.prefix" :name="index" :tab="list.title">
<n-flex vertical>
<n-flex size="small">