Fixed mobile tooltip positioning on mobile

This commit is contained in:
Nathan Schneider
2025-11-29 16:57:07 -05:00
parent 240401b9cb
commit d278e8998a

View File

@@ -4,12 +4,16 @@
let showTooltip = false;
let touchTimer: number;
let isLongPress = false;
let tooltipElement: HTMLSpanElement;
let wrapperElement: HTMLSpanElement;
let tooltipPosition = { align: 'center', vertical: 'top' };
function handleTouchStart() {
isLongPress = false;
touchTimer = window.setTimeout(() => {
showTooltip = true;
isLongPress = true;
updateTooltipPosition();
}, 500); // Show after 500ms press
}
@@ -29,6 +33,7 @@
showTooltip = !showTooltip;
// Auto-hide after 3 seconds
if (showTooltip) {
updateTooltipPosition();
setTimeout(() => {
showTooltip = false;
}, 3000);
@@ -39,14 +44,43 @@
function handleMouseEnter() {
showTooltip = true;
// Use requestAnimationFrame to ensure DOM is updated before positioning
requestAnimationFrame(() => updateTooltipPosition());
}
function handleMouseLeave() {
showTooltip = false;
}
function updateTooltipPosition() {
if (!tooltipElement || !wrapperElement) return;
const tooltipRect = tooltipElement.getBoundingClientRect();
const wrapperRect = wrapperElement.getBoundingClientRect();
const viewportWidth = window.innerWidth;
const viewportHeight = window.innerHeight;
const padding = 10; // Minimum padding from screen edge
// Check horizontal overflow
let align = 'center';
if (tooltipRect.left < padding) {
align = 'left';
} else if (tooltipRect.right > viewportWidth - padding) {
align = 'right';
}
// Check vertical overflow (if tooltip would go above viewport)
let vertical = 'top';
if (tooltipRect.top < padding) {
vertical = 'bottom';
}
tooltipPosition = { align, vertical };
}
</script>
<span
bind:this={wrapperElement}
class="tooltip-wrapper"
on:mouseenter={handleMouseEnter}
on:mouseleave={handleMouseLeave}
@@ -61,7 +95,16 @@
>
<slot />
{#if showTooltip}
<span class="tooltip-text" role="status" aria-live="polite">
<span
bind:this={tooltipElement}
class="tooltip-text"
class:align-left={tooltipPosition.align === 'left'}
class:align-right={tooltipPosition.align === 'right'}
class:align-center={tooltipPosition.align === 'center'}
class:position-bottom={tooltipPosition.vertical === 'bottom'}
role="status"
aria-live="polite"
>
{text}
</span>
{/if}
@@ -79,8 +122,6 @@
.tooltip-text {
position: absolute;
bottom: 125%;
left: 50%;
transform: translateX(-50%);
background-color: var(--bg-color);
color: var(--fg-color);
border: 2px solid var(--border-color);
@@ -94,13 +135,37 @@
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3);
}
/* Horizontal alignment variants */
.tooltip-text.align-center {
left: 50%;
transform: translateX(-50%);
}
.tooltip-text.align-left {
left: 0;
transform: none;
}
.tooltip-text.align-right {
right: 0;
left: auto;
transform: none;
}
/* Vertical position variant (when tooltip would overflow top) */
.tooltip-text.position-bottom {
bottom: auto;
top: 125%;
}
@media (prefers-color-scheme: dark) {
.tooltip-text {
box-shadow: 0 2px 8px rgba(255, 255, 255, 0.2);
}
}
.tooltip-text::after {
/* Arrow positioning for center-aligned tooltip */
.tooltip-text.align-center::after {
content: '';
position: absolute;
top: 100%;
@@ -111,9 +176,49 @@
border-color: var(--border-color) transparent transparent transparent;
}
.tooltip-text.align-center.position-bottom::after {
top: auto;
bottom: 100%;
border-color: transparent transparent var(--border-color) transparent;
}
/* Arrow positioning for left-aligned tooltip */
.tooltip-text.align-left::after {
content: '';
position: absolute;
top: 100%;
left: 1rem;
border-width: 5px;
border-style: solid;
border-color: var(--border-color) transparent transparent transparent;
}
.tooltip-text.align-left.position-bottom::after {
top: auto;
bottom: 100%;
border-color: transparent transparent var(--border-color) transparent;
}
/* Arrow positioning for right-aligned tooltip */
.tooltip-text.align-right::after {
content: '';
position: absolute;
top: 100%;
right: 1rem;
border-width: 5px;
border-style: solid;
border-color: var(--border-color) transparent transparent transparent;
}
.tooltip-text.align-right.position-bottom::after {
top: auto;
bottom: 100%;
border-color: transparent transparent var(--border-color) transparent;
}
@media (max-width: 768px) {
.tooltip-text {
max-width: 250px;
max-width: calc(100vw - 20px);
font-size: 0.8rem;
}
}