Spaces:
Sleeping
Sleeping
| /** | |
| * Ultimate Liquid Tooltip System (TXA Tooltip V2) | |
| * High performance, mouse-following, glassmorphism design | |
| * Supports data-txa-tooltip, data-txatooltip, and .txatooltip class | |
| */ | |
| (function () { | |
| 'use strict'; | |
| if (window.isTxaTooltipInit) return; | |
| window.isTxaTooltipInit = true; | |
| const tooltip = document.getElementById('txa-tooltip') || document.createElement('div'); | |
| if (!tooltip.id) { | |
| tooltip.id = 'txa-tooltip'; | |
| tooltip.style.cssText = ` | |
| position: fixed; | |
| pointer-events: none; | |
| z-index: 2147483647; | |
| padding: 12px 18px; | |
| background: rgba(15, 23, 42, 0.96); | |
| backdrop-filter: blur(20px) saturate(180%); | |
| -webkit-backdrop-filter: blur(20px) saturate(180%); | |
| border: 1px solid rgba(255, 255, 255, 0.2); | |
| border-radius: 16px; | |
| color: #fff; | |
| font-size: 14px; | |
| font-weight: 500; | |
| box-shadow: 0 20px 50px rgba(0,0,0,0.6), 0 0 20px rgba(99, 102, 241, 0.2); | |
| opacity: 0; | |
| transform: scale(0.95) translateY(10px); | |
| transition: opacity 0.3s cubic-bezier(0.16, 1, 0.3, 1), transform 0.3s cubic-bezier(0.16, 1, 0.3, 1); | |
| white-space: normal; | |
| max-width: 320px; | |
| line-height: 1.6; | |
| text-align: left; | |
| word-break: break-word; | |
| font-family: 'Outfit', sans-serif; | |
| `; | |
| } | |
| function initTooltip() { | |
| if (!document.body) { | |
| window.addEventListener('DOMContentLoaded', initTooltip); | |
| return; | |
| } | |
| if (!document.getElementById('txa-tooltip')) { | |
| document.body.appendChild(tooltip); | |
| } | |
| } | |
| window.initTxaTooltips = initTooltip; | |
| initTooltip(); | |
| document.addEventListener('astro:page-load', initTooltip); | |
| let currentTarget = null; | |
| let hideTimeout = null; | |
| let isMouseOnTooltip = false; | |
| tooltip.addEventListener('mouseenter', () => { | |
| isMouseOnTooltip = true; | |
| clearTimeout(hideTimeout); | |
| }); | |
| tooltip.addEventListener('mouseleave', () => { | |
| isMouseOnTooltip = false; | |
| if (!currentTarget) hideTooltip(); | |
| }); | |
| function showTooltip(text, target, e = null) { | |
| if (!text) return; | |
| clearTimeout(hideTimeout); | |
| const link = target.getAttribute('data-tooltip-link'); | |
| const linkTitle = target.getAttribute('data-tooltip-link-title') || 'Xem chi tiết'; | |
| let content = `<div class="txa-tooltip-content">${text}</div>`; | |
| if (link) { | |
| content += ` | |
| <div class="txa-tooltip-action" style="margin-top: 12px; border-top: 1px solid rgba(255,255,255,0.1); padding-top: 10px;"> | |
| <a href="${link}" class="txa-tooltip-btn" style="display: block; width: 100%; padding: 8px 12px; background: linear-gradient(90deg, #6366f1, #a855f7); color: #fff; border-radius: 8px; text-align: center; font-weight: 700; font-size: 12px; transition: all 0.2s; text-decoration: none;"> | |
| <i class="fas fa-external-link-alt me-1"></i> ${linkTitle} | |
| </a> | |
| </div> | |
| `; | |
| tooltip.style.pointerEvents = 'auto'; | |
| } else { | |
| tooltip.style.pointerEvents = 'none'; | |
| } | |
| tooltip.innerHTML = content; | |
| // Dynamic alignment | |
| tooltip.style.textAlign = text.length > 40 ? 'left' : 'center'; | |
| tooltip.style.opacity = '1'; | |
| tooltip.style.transform = 'scale(1) translateY(0)'; | |
| currentTarget = target; | |
| if (e) { | |
| updatePosition(e); | |
| } | |
| } | |
| function hideTooltip() { | |
| if (isMouseOnTooltip) return; | |
| hideTimeout = setTimeout(() => { | |
| if (isMouseOnTooltip) return; | |
| tooltip.style.opacity = '0'; | |
| tooltip.style.transform = 'scale(0.95) translateY(10px)'; | |
| currentTarget = null; | |
| }, 100); | |
| } | |
| function updatePosition(e) { | |
| if (tooltip.style.opacity === '0' || isMouseOnTooltip) return; | |
| const offset = 20; | |
| const rect = tooltip.getBoundingClientRect(); | |
| let x = e.clientX - (rect.width / 2); | |
| let y = e.clientY - rect.height - offset; | |
| const padding = 15; | |
| if (x < padding) x = padding; | |
| if (x + rect.width + padding > window.innerWidth) { | |
| x = window.innerWidth - rect.width - padding; | |
| } | |
| if (y < padding) { | |
| y = e.clientY + offset; | |
| } | |
| tooltip.style.left = x + 'px'; | |
| tooltip.style.top = y + 'px'; | |
| } | |
| document.addEventListener('mouseover', (e) => { | |
| const target = e.target.closest('[data-txa-tooltip], [data-txatooltip], .txatooltip, .txaxtooltip'); | |
| if (target) { | |
| // Logic for sidebar menu items (collapsed state) | |
| if (target.classList.contains('menu-item') || target.classList.contains('sidebar-link')) { | |
| const isSidebarCollapsed = document.body.classList.contains('sidebar-collapsed'); | |
| if (!isSidebarCollapsed && window.innerWidth > 992) return; | |
| } | |
| const tooltipText = target.getAttribute('data-txa-tooltip') || target.getAttribute('data-txatooltip') || target.title; | |
| if (tooltipText) { | |
| // Remove title to prevent browser default tooltip | |
| if (target.title) { | |
| target.setAttribute('data-original-title', target.title); | |
| target.title = ''; | |
| } | |
| showTooltip(tooltipText, target, e); | |
| } | |
| } | |
| }); | |
| document.addEventListener('mouseout', (e) => { | |
| const target = e.target.closest('[data-txa-tooltip], [data-txatooltip], .txatooltip, .txaxtooltip'); | |
| if (target) { | |
| // Restore title if needed | |
| const originalTitle = target.getAttribute('data-original-title'); | |
| if (originalTitle) { | |
| target.title = originalTitle; | |
| target.removeAttribute('data-original-title'); | |
| } | |
| hideTooltip(); | |
| } | |
| }); | |
| document.addEventListener('mousemove', (e) => { | |
| if (currentTarget) updatePosition(e); | |
| }); | |
| document.addEventListener('click', (e) => { | |
| if (!tooltip.contains(e.target)) hideTooltip(); | |
| }); | |
| // Fullscreen support | |
| function handleFullscreenChange() { | |
| const fsElem = document.fullscreenElement || document.webkitFullscreenElement; | |
| if (fsElem) { | |
| fsElem.appendChild(tooltip); | |
| tooltip.style.zIndex = '2147483647'; | |
| } else { | |
| if (document.body && !document.body.contains(tooltip)) { | |
| document.body.appendChild(tooltip); | |
| } | |
| } | |
| } | |
| document.addEventListener('fullscreenchange', handleFullscreenChange); | |
| document.addEventListener('webkitfullscreenchange', handleFullscreenChange); | |
| })(); | |