This commit is contained in:
Generated
+433
-342
File diff suppressed because it is too large
Load Diff
@@ -1,4 +1,4 @@
|
||||
import { type FC, useState, useEffect } from 'react'
|
||||
import { type FC, type UIEvent, useState, useEffect, useMemo, useRef } from 'react'
|
||||
import DefaulModal from '@/components/DefaulModal'
|
||||
import type { Icon, IconGroup } from '../types/Types'
|
||||
import { TickCircle } from 'iconsax-react'
|
||||
@@ -18,14 +18,64 @@ const IconSelectModal: FC<Props> = ({
|
||||
onSelect,
|
||||
selectedUrl
|
||||
}) => {
|
||||
const ICONS_PAGE_SIZE = 120
|
||||
const [selectedIconUrl, setSelectedIconUrl] = useState<string | undefined>(
|
||||
selectedUrl
|
||||
)
|
||||
const [visibleIconsCount, setVisibleIconsCount] = useState(ICONS_PAGE_SIZE)
|
||||
const scrollContainerRef = useRef<HTMLDivElement>(null)
|
||||
|
||||
useEffect(() => {
|
||||
setSelectedIconUrl(selectedUrl)
|
||||
}, [selectedUrl, open])
|
||||
|
||||
useEffect(() => {
|
||||
if (open) {
|
||||
setVisibleIconsCount(ICONS_PAGE_SIZE)
|
||||
if (scrollContainerRef.current) {
|
||||
scrollContainerRef.current.scrollTop = 0
|
||||
}
|
||||
}
|
||||
}, [open, icons])
|
||||
|
||||
const totalIcons = useMemo(
|
||||
() => icons.reduce((total, group) => total + group.icons.length, 0),
|
||||
[icons]
|
||||
)
|
||||
|
||||
const hasMoreIcons = visibleIconsCount < totalIcons
|
||||
|
||||
const paginatedGroups = useMemo(() => {
|
||||
let remainingIcons = visibleIconsCount
|
||||
|
||||
return icons
|
||||
.map((group) => {
|
||||
const visibleIcons = group.icons.slice(
|
||||
0,
|
||||
Math.max(0, Math.min(group.icons.length, remainingIcons))
|
||||
)
|
||||
remainingIcons -= visibleIcons.length
|
||||
|
||||
return {
|
||||
...group,
|
||||
icons: visibleIcons
|
||||
}
|
||||
})
|
||||
.filter((group) => group.icons.length > 0)
|
||||
}, [icons, visibleIconsCount])
|
||||
|
||||
const handleScroll = (event: UIEvent<HTMLDivElement>) => {
|
||||
if (!hasMoreIcons) return
|
||||
|
||||
const target = event.currentTarget
|
||||
const isNearBottom =
|
||||
target.scrollTop + target.clientHeight >= target.scrollHeight - 200
|
||||
|
||||
if (isNearBottom) {
|
||||
setVisibleIconsCount((prev) => Math.min(prev + ICONS_PAGE_SIZE, totalIcons))
|
||||
}
|
||||
}
|
||||
|
||||
const handleSelect = (url: string) => {
|
||||
setSelectedIconUrl(url)
|
||||
onSelect(url)
|
||||
@@ -40,7 +90,11 @@ const IconSelectModal: FC<Props> = ({
|
||||
title_header="انتخاب آیکون"
|
||||
width={700}
|
||||
>
|
||||
<div className="max-h-[65vh] overflow-y-auto py-2">
|
||||
<div
|
||||
ref={scrollContainerRef}
|
||||
onScroll={handleScroll}
|
||||
className="max-h-[65vh] overflow-y-auto py-2"
|
||||
>
|
||||
{icons.length === 0 ? (
|
||||
<div className="text-center py-12 text-gray-500">
|
||||
<div className="text-base mb-2">آیکونی یافت نشد</div>
|
||||
@@ -50,7 +104,7 @@ const IconSelectModal: FC<Props> = ({
|
||||
</div>
|
||||
) : (
|
||||
<div className="space-y-8">
|
||||
{icons.map((group) => (
|
||||
{paginatedGroups.map((group) => (
|
||||
<div key={group.id} className="border-b border-gray-100 last:border-0 pb-6 last:pb-0">
|
||||
<div className="flex items-center gap-2 mb-4">
|
||||
<h3 className="text-base font-semibold text-gray-800">
|
||||
@@ -78,6 +132,8 @@ const IconSelectModal: FC<Props> = ({
|
||||
<img
|
||||
src={icon.url}
|
||||
alt="icon"
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
className="w-full h-full object-contain transition-opacity duration-200 max-w-full max-h-full"
|
||||
style={{
|
||||
imageRendering: 'auto',
|
||||
@@ -106,6 +162,11 @@ const IconSelectModal: FC<Props> = ({
|
||||
)}
|
||||
</div>
|
||||
))}
|
||||
{hasMoreIcons && (
|
||||
<div className="text-center text-sm text-gray-500 py-2">
|
||||
در حال بارگذاری آیکون های بیشتر...
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user