feat: Улучшение компонентов Dashboard, EmptyState, ErrorAlert и Pagination. Добавлены новые функции, такие как индикаторы тренда, возможность перехода на страницу и улучшенные действия с ошибками. Обновлены стили для повышения удобства использования и доступности.
Publish Fast Tabler Docker image / build-and-push-fast (push) Successful in 1m54s
Publish Fast Tabler Docker image / build-and-push-fast (push) Successful in 1m54s
This commit is contained in:
@@ -0,0 +1,169 @@
|
||||
import { useState, useRef, useEffect } from 'react'
|
||||
|
||||
/**
|
||||
* Tooltip компонент для отображения подсказок
|
||||
* Поддерживает keyboard shortcuts и различные позиции
|
||||
*/
|
||||
function Tooltip({
|
||||
children,
|
||||
content,
|
||||
position = 'top', // top, bottom, left, right
|
||||
shortcut, // keyboard shortcut to display
|
||||
delay = 200,
|
||||
className = ''
|
||||
}) {
|
||||
const [isVisible, setIsVisible] = useState(false)
|
||||
const [coords, setCoords] = useState({ x: 0, y: 0 })
|
||||
const timeoutRef = useRef(null)
|
||||
const triggerRef = useRef(null)
|
||||
|
||||
const showTooltip = (e) => {
|
||||
if (timeoutRef.current) clearTimeout(timeoutRef.current)
|
||||
|
||||
timeoutRef.current = setTimeout(() => {
|
||||
if (triggerRef.current) {
|
||||
const rect = triggerRef.current.getBoundingClientRect()
|
||||
let x = 0, y = 0
|
||||
|
||||
switch (position) {
|
||||
case 'top':
|
||||
x = rect.left + rect.width / 2
|
||||
y = rect.top
|
||||
break
|
||||
case 'bottom':
|
||||
x = rect.left + rect.width / 2
|
||||
y = rect.bottom
|
||||
break
|
||||
case 'left':
|
||||
x = rect.left
|
||||
y = rect.top + rect.height / 2
|
||||
break
|
||||
case 'right':
|
||||
x = rect.right
|
||||
y = rect.top + rect.height / 2
|
||||
break
|
||||
default:
|
||||
x = rect.left + rect.width / 2
|
||||
y = rect.top
|
||||
}
|
||||
|
||||
setCoords({ x, y })
|
||||
setIsVisible(true)
|
||||
}
|
||||
}, delay)
|
||||
}
|
||||
|
||||
const hideTooltip = () => {
|
||||
if (timeoutRef.current) {
|
||||
clearTimeout(timeoutRef.current)
|
||||
}
|
||||
setIsVisible(false)
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
return () => {
|
||||
if (timeoutRef.current) {
|
||||
clearTimeout(timeoutRef.current)
|
||||
}
|
||||
}
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<>
|
||||
<span
|
||||
ref={triggerRef}
|
||||
onMouseEnter={showTooltip}
|
||||
onMouseLeave={hideTooltip}
|
||||
onFocus={showTooltip}
|
||||
onBlur={hideTooltip}
|
||||
className={`tooltip-trigger ${className}`}
|
||||
style={{ position: 'relative', display: 'inline-block' }}
|
||||
>
|
||||
{children}
|
||||
</span>
|
||||
|
||||
{isVisible && (
|
||||
<div
|
||||
className={`tooltip-content tooltip-${position}`}
|
||||
style={{
|
||||
position: 'fixed',
|
||||
left: `${coords.x}px`,
|
||||
top: `${coords.y}px`,
|
||||
zIndex: 9999,
|
||||
pointerEvents: 'none'
|
||||
}}
|
||||
>
|
||||
<div className="tooltip-inner">
|
||||
<div className="tooltip-text">{content}</div>
|
||||
{shortcut && (
|
||||
<kbd className="tooltip-shortcut ms-2">{shortcut}</kbd>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<style jsx>{`
|
||||
.tooltip-content {
|
||||
animation: tooltipFadeIn 0.15s ease-out;
|
||||
}
|
||||
|
||||
.tooltip-top {
|
||||
transform: translate(-50%, calc(-100% - 8px));
|
||||
}
|
||||
|
||||
.tooltip-bottom {
|
||||
transform: translate(-50%, 8px);
|
||||
}
|
||||
|
||||
.tooltip-left {
|
||||
transform: translate(calc(-100% - 8px), -50%);
|
||||
}
|
||||
|
||||
.tooltip-right {
|
||||
transform: translate(8px, -50%);
|
||||
}
|
||||
|
||||
.tooltip-inner {
|
||||
background: var(--tblr-dark, #1e293b);
|
||||
color: white;
|
||||
padding: 0.5rem 0.75rem;
|
||||
border-radius: 0.375rem;
|
||||
font-size: 0.875rem;
|
||||
box-shadow: var(--shadow-lg);
|
||||
white-space: nowrap;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
max-width: 300px;
|
||||
}
|
||||
|
||||
.tooltip-shortcut {
|
||||
background: rgba(255, 255, 255, 0.2);
|
||||
padding: 0.125rem 0.375rem;
|
||||
border-radius: 0.25rem;
|
||||
font-size: 0.75rem;
|
||||
font-family: monospace;
|
||||
}
|
||||
|
||||
@keyframes tooltipFadeIn {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translate(-50%, calc(-100% - 4px)) scale(0.95);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translate(-50%, calc(-100% - 8px)) scale(1);
|
||||
}
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
.tooltip-inner {
|
||||
background: var(--tblr-gray-800, #1e293b);
|
||||
}
|
||||
}
|
||||
`}</style>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export default Tooltip
|
||||
|
||||
Reference in New Issue
Block a user