feat: Обновление компонента Tooltip с изменением стиля на Tabler UI и улучшением позиционирования. Убрано вычисление координат, теперь подсказка позиционируется относительно триггера с использованием position: absolute.
Publish Fast Tabler Docker image / build-and-push-fast (push) Successful in 1m37s

This commit is contained in:
2025-11-12 10:54:43 +07:00
parent 807471b7b1
commit 1769c07883
+80 -144
View File
@@ -1,8 +1,8 @@
import { useState, useRef, useEffect } from 'react' import { useState, useRef, useEffect } from 'react'
/** /**
* Tooltip компонент для отображения подсказок * Tooltip компонент в стиле Tabler UI
* Поддерживает keyboard shortcuts и различные позиции * Использует position: absolute относительно trigger элемента
*/ */
function Tooltip({ function Tooltip({
children, children,
@@ -13,43 +13,14 @@ function Tooltip({
className = '' className = ''
}) { }) {
const [isVisible, setIsVisible] = useState(false) const [isVisible, setIsVisible] = useState(false)
const [coords, setCoords] = useState({ x: 0, y: 0 })
const timeoutRef = useRef(null) const timeoutRef = useRef(null)
const triggerRef = useRef(null) const triggerRef = useRef(null)
const showTooltip = (e) => { const showTooltip = () => {
if (timeoutRef.current) clearTimeout(timeoutRef.current) if (timeoutRef.current) clearTimeout(timeoutRef.current)
timeoutRef.current = setTimeout(() => { timeoutRef.current = setTimeout(() => {
if (triggerRef.current) { setIsVisible(true)
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) }, delay)
} }
@@ -69,129 +40,94 @@ function Tooltip({
}, []) }, [])
return ( return (
<> <span
<span ref={triggerRef}
ref={triggerRef} onMouseEnter={showTooltip}
onMouseEnter={showTooltip} onMouseLeave={hideTooltip}
onMouseLeave={hideTooltip} onFocus={showTooltip}
onFocus={showTooltip} onBlur={hideTooltip}
onBlur={hideTooltip} className={`tooltip-trigger ${className}`}
className={`tooltip-trigger ${className}`} style={{ position: 'relative', display: 'inline-block' }}
style={{ position: 'relative', display: 'inline-block' }} >
> {children}
{children}
</span>
{isVisible && ( {isVisible && (
<div <div
className={`tooltip-content tooltip-${position}`} className={`tooltip bs-tooltip-${position} show`}
role="tooltip"
style={{ style={{
position: 'fixed', position: 'absolute',
left: `${coords.x}px`, zIndex: 1070,
top: `${coords.y}px`, display: 'block',
zIndex: 9999, margin: 0,
pointerEvents: 'none' pointerEvents: 'none',
...(position === 'top' && {
bottom: '100%',
left: '50%',
transform: 'translateX(-50%)',
marginBottom: '8px'
}),
...(position === 'bottom' && {
top: '100%',
left: '50%',
transform: 'translateX(-50%)',
marginTop: '8px'
}),
...(position === 'left' && {
right: '100%',
top: '50%',
transform: 'translateY(-50%)',
marginRight: '8px'
}),
...(position === 'right' && {
left: '100%',
top: '50%',
transform: 'translateY(-50%)',
marginLeft: '8px'
})
}} }}
> >
<div className="tooltip-arrow" style={(() => {
const styles = {
position: 'absolute',
width: '8px',
height: '8px',
background: 'inherit'
}
if (position === 'top') {
styles.bottom = '0'
styles.left = '50%'
styles.transform = 'translateX(-50%) translateY(50%) rotate(45deg)'
} else if (position === 'bottom') {
styles.top = '0'
styles.left = '50%'
styles.transform = 'translateX(-50%) translateY(-50%) rotate(45deg)'
} else if (position === 'left') {
styles.right = '0'
styles.top = '50%'
styles.transform = 'translateX(50%) translateY(-50%) rotate(45deg)'
} else if (position === 'right') {
styles.left = '0'
styles.top = '50%'
styles.transform = 'translateX(-50%) translateY(-50%) rotate(45deg)'
}
return styles
})()}></div>
<div className="tooltip-inner"> <div className="tooltip-inner">
<div className="tooltip-text">{content}</div> {content}
{shortcut && ( {shortcut && (
<kbd className="tooltip-shortcut ms-2">{shortcut}</kbd> <kbd className="ms-2" style={{
background: 'rgba(255, 255, 255, 0.2)',
padding: '0.125rem 0.375rem',
borderRadius: '0.25rem',
fontSize: '0.75rem',
fontFamily: 'monospace'
}}>{shortcut}</kbd>
)} )}
</div> </div>
</div> </div>
)} )}
</span>
<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);
}
}
@keyframes tooltipFadeInTop {
from {
opacity: 0;
transform: translate(-50%, calc(-100% - 4px)) scale(0.95);
}
to {
opacity: 1;
transform: translate(-50%, calc(-100% - 8px)) scale(1);
}
}
@keyframes tooltipFadeInBottom {
from {
opacity: 0;
transform: translate(-50%, 4px) scale(0.95);
}
to {
opacity: 1;
transform: translate(-50%, 8px) scale(1);
}
}
.tooltip-content.tooltip-top {
animation: tooltipFadeInTop 0.15s ease-out;
}
.tooltip-content.tooltip-bottom {
animation: tooltipFadeInBottom 0.15s ease-out;
}
@media (prefers-color-scheme: dark) {
.tooltip-inner {
background: var(--tblr-gray-800, #1e293b);
}
}
`}</style>
</>
) )
} }