|
|
|
@ -1,6 +1,6 @@
|
|
|
|
|
<script lang="ts" setup> |
|
|
|
|
import { ref, watch, watchEffect } from 'vue' |
|
|
|
|
import { Empty, Input, Pagination, Popover } from 'ant-design-vue' |
|
|
|
|
import { Empty, Input, Popover } from 'ant-design-vue' |
|
|
|
|
import { useDebounceFn } from '@vueuse/core' |
|
|
|
|
import svgIcons from 'virtual:svg-icons-names' |
|
|
|
|
import SvgIcon from './SvgIcon.vue' |
|
|
|
@ -8,7 +8,6 @@ import { getIcons } from './icons'
|
|
|
|
|
import { useDesign } from '@/hooks/web/useDesign' |
|
|
|
|
import { ScrollContainer } from '@/components/Container' |
|
|
|
|
|
|
|
|
|
import { usePagination } from '@/hooks/web/usePagination' |
|
|
|
|
import { useI18n } from '@/hooks/web/useI18n' |
|
|
|
|
import { copyText } from '@/utils/copyTextToClipboard' |
|
|
|
|
|
|
|
|
@ -39,15 +38,13 @@ const icons = isSvgMode ? getSvgIcons() : getIcons()
|
|
|
|
|
|
|
|
|
|
const currentSelect = ref('') |
|
|
|
|
const open = ref(false) |
|
|
|
|
const currentList = ref(icons) |
|
|
|
|
const currentList = ref(icons.slice(0, props.pageSize)) |
|
|
|
|
|
|
|
|
|
const { t } = useI18n() |
|
|
|
|
const { prefixCls } = useDesign('icon-picker') |
|
|
|
|
|
|
|
|
|
const debounceHandleSearchChange = useDebounceFn(handleSearchChange, 100) |
|
|
|
|
|
|
|
|
|
const { getPaginationList, getTotal, setCurrentPage } = usePagination(currentList, props.pageSize) |
|
|
|
|
|
|
|
|
|
watchEffect(() => { |
|
|
|
|
currentSelect.value = props.value |
|
|
|
|
}) |
|
|
|
@ -60,24 +57,27 @@ watch(
|
|
|
|
|
}, |
|
|
|
|
) |
|
|
|
|
|
|
|
|
|
function handlePageChange(page: number) { |
|
|
|
|
setCurrentPage(page) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
function handleClick(icon: string) { |
|
|
|
|
currentSelect.value = icon |
|
|
|
|
if (props.copy) |
|
|
|
|
copyText(icon, t('component.icon.copy')) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
const hiddenLoadMore = ref(false) |
|
|
|
|
function loadMoreIcons() { |
|
|
|
|
currentList.value = icons.slice(0, currentList.value.length + props.pageSize) |
|
|
|
|
hiddenLoadMore.value = currentList.value.length >= icons.length |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
function handleSearchChange(e: ChangeEvent) { |
|
|
|
|
const value = e.target.value |
|
|
|
|
if (!value) { |
|
|
|
|
setCurrentPage(1) |
|
|
|
|
currentList.value = icons |
|
|
|
|
hiddenLoadMore.value = false |
|
|
|
|
currentList.value = icons.slice(0, props.pageSize) |
|
|
|
|
return |
|
|
|
|
} |
|
|
|
|
currentList.value = icons.filter(item => item.includes(value)) |
|
|
|
|
hiddenLoadMore.value = true |
|
|
|
|
} |
|
|
|
|
</script> |
|
|
|
|
|
|
|
|
@ -90,32 +90,37 @@ function handleSearchChange(e: ChangeEvent) {
|
|
|
|
|
<Popover v-model="open" placement="bottomLeft" trigger="click" :overlay-class-name="`${prefixCls}-popover`"> |
|
|
|
|
<template #title> |
|
|
|
|
<div class="flex justify-between"> |
|
|
|
|
<Input :placeholder="t('component.icon.search')" allow-clear @change="debounceHandleSearchChange" /> |
|
|
|
|
<Input placeholder="Search" allow-clear @change="debounceHandleSearchChange"> |
|
|
|
|
<template #prefix> |
|
|
|
|
<span class="i-ant-design:search-outlined text-gray-600" /> |
|
|
|
|
</template> |
|
|
|
|
</Input> |
|
|
|
|
</div> |
|
|
|
|
</template> |
|
|
|
|
|
|
|
|
|
<template #content> |
|
|
|
|
<div v-if="getPaginationList.length"> |
|
|
|
|
<ScrollContainer class="border border-t-0 border-solid"> |
|
|
|
|
<ul class="flex flex-wrap px-2"> |
|
|
|
|
<div v-if="currentList.length"> |
|
|
|
|
<ScrollContainer> |
|
|
|
|
<ul class="grid grid-cols-8 gap-y-2"> |
|
|
|
|
<li |
|
|
|
|
v-for="icon in getPaginationList" :key="icon" |
|
|
|
|
:class="currentSelect === icon ? 'border border-primary' : ''" |
|
|
|
|
class="mr-1 mt-1 w-1/8 flex cursor-pointer items-center justify-center border border-solid p-2 hover:border-primary" |
|
|
|
|
v-for="icon in currentList" :key="icon" |
|
|
|
|
:class="currentSelect === icon ? '!text-primary' : ''" |
|
|
|
|
class="cursor-pointer text-center text-gray-600" |
|
|
|
|
:title="icon" @click="handleClick(icon)" |
|
|
|
|
> |
|
|
|
|
<!-- <Icon :icon="icon" :prefix="prefix" /> --> |
|
|
|
|
<SvgIcon v-if="isSvgMode" :name="icon" /> |
|
|
|
|
<span v-else :class="icon" /> |
|
|
|
|
<span v-else :class="icon" class="text-18px" /> |
|
|
|
|
</li> |
|
|
|
|
</ul> |
|
|
|
|
</ScrollContainer> |
|
|
|
|
<div v-if="getTotal >= pageSize" class="flex items-center justify-center py-2"> |
|
|
|
|
<Pagination show-less-items size="small" :page-size="pageSize" :total="getTotal" @change="handlePageChange" /> |
|
|
|
|
<div v-if="!hiddenLoadMore" class="mt-4 text-center text-gray-600"> |
|
|
|
|
<a-button size="small" @click="loadMoreIcons"> |
|
|
|
|
Load More |
|
|
|
|
</a-button> |
|
|
|
|
</div> |
|
|
|
|
</ScrollContainer> |
|
|
|
|
</div> |
|
|
|
|
<template v-else> |
|
|
|
|
<div class="p-5"> |
|
|
|
|
<div class="p-5 text-gray-600"> |
|
|
|
|
<Empty /> |
|
|
|
|
</div> |
|
|
|
|
</template> |
|
|
|
@ -124,7 +129,7 @@ function handleSearchChange(e: ChangeEvent) {
|
|
|
|
|
<span v-if="isSvgMode && currentSelect" class="flex cursor-pointer items-center px-2 py-1"> |
|
|
|
|
<SvgIcon :name="currentSelect" /> |
|
|
|
|
</span> |
|
|
|
|
<span v-else :class="currentSelect || 'i-ion:apps-outline'" class="cursor-pointer px-4 py-2" /> |
|
|
|
|
<span v-else :class="currentSelect || 'i-ion:apps-outline'" class="cursor-pointer px-4 py-2 text-gray-600" /> |
|
|
|
|
</Popover> |
|
|
|
|
</template> |
|
|
|
|
</Input> |
|
|
|
|