From 77ce1001a972bb3635f734c96324766c0c4ecd94 Mon Sep 17 00:00:00 2001 From: "(quasar) nebula" Date: Tue, 18 Jun 2024 14:22:48 -0300 Subject: client: reposition tooltip nicely, when showing info column --- src/static/js/client.js | 77 ++++++++++++++++++++++++++++++++++--------------- 1 file changed, 53 insertions(+), 24 deletions(-) (limited to 'src') diff --git a/src/static/js/client.js b/src/static/js/client.js index 98418a31..83459932 100644 --- a/src/static/js/client.js +++ b/src/static/js/client.js @@ -1271,6 +1271,11 @@ const hoverableTooltipInfo = initInfo('hoverableTooltipInfo', { // from causing the current tooltip to be hidden. currentTouchIdentifiers: new Set(), touchIdentifiersBanishedByScrolling: new Set(), + + // This is a two-item array that tracks the direction we've already + // dynamically placed the current tooltip. If we *reposition* the tooltip + // (because its dimensions changed), we'll try to follow this anchor first. + dynamicTooltipAnchorDirection: null, }, event: { @@ -1731,6 +1736,8 @@ function hideCurrentlyShownTooltip(intendingToReplace = false) { state.currentlyShownTooltip = null; state.currentlyActiveHoverable = null; + state.dynamicTooltipAnchorDirection = null; + // Set this for one tick of the event cycle. state.tooltipWasJustHidden = true; setTimeout(() => { @@ -1792,10 +1799,23 @@ function peekTooltipClientRect(tooltip) { } } +function repositionCurrentTooltip() { + const {state} = hoverableTooltipInfo; + const {currentlyActiveHoverable} = state; + + if (!currentlyActiveHoverable) { + throw new Error(`No hoverable active to reposition tooltip from`); + } + + positionTooltipFromHoverableWithBrains(currentlyActiveHoverable); +} + function positionTooltipFromHoverableWithBrains(hoverable) { const {state} = hoverableTooltipInfo; const {tooltip} = state.registeredHoverables.get(hoverable); + const anchorDirection = state.dynamicTooltipAnchorDirection; + // Reset before doing anything else. We're going to adapt to // its natural placement, adjusted by CSS, which otherwise // could be obscured by a placement we've previously provided. @@ -1817,35 +1837,42 @@ function positionTooltipFromHoverableWithBrains(hoverable) { return; } - let selectedRect = null; - for (let i = 0; i < numBaselineRects; i++) { - selectedRect = opportunities.right.down[i]; - if (selectedRect) break; - - selectedRect = opportunities.left.down[i]; - if (selectedRect) break; - - selectedRect = opportunities.right.up[i]; - if (selectedRect) break; - - selectedRect = opportunities.left.up[i]; - if (selectedRect) break; - - selectedRect = opportunities.down.right[i]; - if (selectedRect) break; + const tryDirection = (dir1, dir2, i) => { + selectedRect = opportunities[dir1][dir2][i]; + return !!selectedRect; + }; - selectedRect = opportunities.down.left[i]; - if (selectedRect) break; + let selectedRect = null; + selectRect: { + if (anchorDirection) { + for (let i = 0; i < numBaselineRects; i++) { + if (tryDirection(...anchorDirection, i)) { + break selectRect; + } + } + } - selectedRect = opportunities.up.right[i]; - if (selectedRect) break; + for (let i = 0; i < numBaselineRects; i++) { + for (const [dir1, dir2] of [ + ['right', 'down'], + ['left', 'down'], + ['right', 'up'], + ['left', 'up'], + ['down', 'right'], + ['down', 'left'], + ['up', 'right'], + ['up', 'left'], + ]) { + if (tryDirection(dir1, dir2, i)) { + state.dynamicTooltipAnchorDirection = [dir1, dir2]; + break selectRect; + } + } + } - selectedRect = opportunities.up.left[i]; - if (selectedRect) break; + selectedRect = baselineRect; } - selectedRect ??= baselineRect; - positionTooltip(tooltip, selectedRect.x, selectedRect.y); } @@ -3577,6 +3604,8 @@ function showArtistExternalLinkTooltipInfo() { for (const tooltip of info.tooltips) { tooltip.classList.add('show-info'); } + + repositionCurrentTooltip(); } function hideArtistExternalLinkTooltipInfo() { -- cgit 1.3.0-6-gf8a5