Files
Keep/keep-notes/components/connections-badge.tsx

73 lines
2.2 KiB
TypeScript

'use client'
import { memo, useState, useEffect, useRef, useCallback } from 'react'
import { Sparkles } from 'lucide-react'
import { cn } from '@/lib/utils'
import { useLanguage } from '@/lib/i18n/LanguageProvider'
import { getConnectionsCount } from '@/lib/connections-cache'
interface ConnectionsBadgeProps {
noteId: string
onClick?: () => void
className?: string
}
export const ConnectionsBadge = memo(function ConnectionsBadge({ noteId, onClick, className }: ConnectionsBadgeProps) {
const { t } = useLanguage()
const [connectionCount, setConnectionCount] = useState<number>(0)
const [isHovered, setIsHovered] = useState(false)
const containerRef = useRef<HTMLSpanElement>(null)
const fetchedRef = useRef(false)
const fetchConnections = useCallback(async () => {
if (fetchedRef.current) return
fetchedRef.current = true
try {
const count = await getConnectionsCount(noteId)
setConnectionCount(count)
} catch {
setConnectionCount(0)
}
}, [noteId])
useEffect(() => {
const el = containerRef.current
if (!el) return
const observer = new IntersectionObserver(
([entry]) => {
if (entry.isIntersecting) {
fetchConnections()
observer.disconnect()
}
},
{ rootMargin: '200px' }
)
observer.observe(el)
return () => observer.disconnect()
}, [fetchConnections])
if (connectionCount === 0) {
return <span ref={containerRef} className="hidden" />
}
const plural = connectionCount > 1 ? 's' : ''
const badgeText = t('memoryEcho.connectionsBadge', { count: connectionCount, plural })
return (
<div className={cn(
'inline-flex items-center gap-1 px-2 py-0.5 rounded-full text-xs font-medium bg-amber-100 dark:bg-amber-900/30 text-amber-700 dark:text-amber-400 border border-amber-200 dark:border-amber-800 transition-all duration-150 ease-out',
isHovered && 'scale-105',
className
)}
onClick={onClick}
onMouseEnter={() => setIsHovered(true)}
onMouseLeave={() => setIsHovered(false)}
title={badgeText}
>
<Sparkles className="h-2.5 w-2.5 inline-block mr-1" />
{badgeText}
</div>
)
})