| --- |
| interface Props { |
| |
| term: string; |
| |
| definition: string; |
| |
| class?: string; |
| |
| style?: string; |
| |
| position?: 'top' | 'bottom' | 'left' | 'right'; |
| |
| delay?: number; |
| |
| disableOnMobile?: boolean; |
| } |
|
|
| const { |
| term, |
| definition, |
| class: className = '', |
| style: inlineStyle = '', |
| position = 'top', |
| delay = 300, |
| disableOnMobile = false, |
| } = Astro.props as Props; |
|
|
| |
| const tooltipId = `glossary-${Math.random().toString(36).slice(2)}`; |
| --- |
|
|
| <div class="glossary-container" data-glossary-container-id={tooltipId}> |
| <span |
| class={`glossary-term ${className}`} |
| style={inlineStyle} |
| data-glossary-term={term} |
| data-glossary-definition={definition} |
| data-glossary-position={position} |
| data-glossary-delay={delay} |
| data-glossary-disable-mobile={disableOnMobile} |
| data-glossary-id={tooltipId} |
| tabindex="0" |
| role="button" |
| aria-describedby={`${tooltipId}-tooltip`} |
| > |
| {term} |
| </span> |
| |
| <div |
| id={`${tooltipId}-tooltip`} |
| class="glossary-tooltip" |
| data-glossary-tooltip-id={tooltipId} |
| data-position={position} |
| role="tooltip" |
| aria-hidden="true" |
| > |
| <div class="glossary-tooltip__content"> |
| <div class="glossary-tooltip__term">{term}</div> |
| <div class="glossary-tooltip__definition">{definition}</div> |
| </div> |
| <div class="glossary-tooltip__arrow"></div> |
| </div> |
| </div> |
|
|
| <script is:inline> |
| |
| if (!window.glossaryInitialized) { |
| window.glossaryInitialized = true; |
| |
| function initAllGlossaryTooltips() { |
| const glossaryTerms = document.querySelectorAll('.glossary-term'); |
| |
| glossaryTerms.forEach((termElement) => { |
| const tooltipElement = termElement.parentElement.querySelector('.glossary-tooltip'); |
| |
| if (!tooltipElement) return; |
| |
| const term = termElement.getAttribute('data-glossary-term'); |
| const definition = termElement.getAttribute('data-glossary-definition'); |
| |
| if (!term || !definition) return; |
| |
| |
| const showTooltip = (event) => { |
| tooltipElement.style.display = 'block'; |
| tooltipElement.style.opacity = '1'; |
| tooltipElement.style.position = 'fixed'; |
| tooltipElement.style.top = (event.clientY + 10) + 'px'; |
| tooltipElement.style.left = (event.clientX + 10) + 'px'; |
| tooltipElement.style.zIndex = '9999'; |
| tooltipElement.style.pointerEvents = 'none'; |
| }; |
| |
| const hideTooltip = () => { |
| tooltipElement.style.display = 'none'; |
| tooltipElement.style.opacity = '0'; |
| }; |
| |
| |
| termElement.addEventListener('mouseenter', showTooltip); |
| termElement.addEventListener('mouseleave', hideTooltip); |
| termElement.addEventListener('mousemove', showTooltip); |
| }); |
| } |
| |
| |
| if (document.readyState === 'loading') { |
| document.addEventListener('DOMContentLoaded', initAllGlossaryTooltips); |
| } else { |
| initAllGlossaryTooltips(); |
| } |
| |
| |
| if (window.MutationObserver) { |
| const observer = new MutationObserver((mutations) => { |
| mutations.forEach((mutation) => { |
| if (mutation.type === 'childList') { |
| mutation.addedNodes.forEach((node) => { |
| if (node.nodeType === 1 && node.querySelector && node.querySelector('.glossary-term')) { |
| initAllGlossaryTooltips(); |
| } |
| }); |
| } |
| }); |
| }); |
| |
| observer.observe(document.body, { |
| childList: true, |
| subtree: true |
| }); |
| } |
| } |
| </script> |
|
|
|
|