Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 41 additions & 13 deletions _scripts/popover.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,32 +12,60 @@ jQuery.then(($) => {
$document.on('click', '.popover > a', function (event) {
event.preventDefault()

const $body = $('body')
const $link = $(event.target)
const $popover = $link.parent()
// Stop propagation so this click doesn't immediately trigger
// the document-level close handler registered below
event.stopPropagation()

const $popover = $(event.target).closest('.popover')
const $content = $popover.find('.popover-content')

$body.css({ overflow: 'hidden' })
if ($popover.hasClass('active')) {
$popover.removeClass('active')
return
}

$popover.addClass('active')

// Prevent scroll events inside the popover content from
// bubbling up to the document close handler
$content.on('scroll touchmove mousewheel wheel', function (e) {
e.stopPropagation()
})

const popoverPos = ($popover.outerWidth() / 2) - ($content.outerWidth() / 2)
$content.css({ left: popoverPos })
// Position the popover centered on its trigger, then clamp it
// within the viewport so it doesn't cause horizontal overflow
const popoverWidth = $popover.outerWidth()
const contentWidth = $content.outerWidth()
let popoverPos = (popoverWidth / 2) - (contentWidth / 2)

$document.one('click scroll touchmove mousewheel wheel', function (event) {
if (!$(event.target).is('.popover-content *')) {
event.stopImmediatePropagation()
event.preventDefault()
}
const popoverRect = $popover[0].getBoundingClientRect()
const contentRight = popoverRect.left + popoverPos + contentWidth
const viewportWidth = document.documentElement.clientWidth

if (contentRight > viewportWidth) {
popoverPos -= (contentRight - viewportWidth)
}

$body.css({ overflow: 'visible' })
const contentLeft = popoverRect.left + popoverPos
if (contentLeft < 0) {
popoverPos -= contentLeft
}

// Move the arrow to stay aligned with the trigger button,
// compensating for how far the content was shifted
const arrowLeft = (popoverWidth / 2) - popoverPos
$content[0].style.setProperty('--popover-left', popoverPos + 'px')
$content[0].style.setProperty('--arrow-left', arrowLeft + 'px')

// Close when the user interacts outside the popover content.
// Uses namespaced events so we can cleanly unbind them all at once
$document.on('click.popover scroll.popover touchmove.popover', function (e) {
if ($(e.target).closest('.popover-content').length) {
return
}

$popover.removeClass('active')
$body.click()
$document.off('.popover')
})
})
})
Expand Down
5 changes: 3 additions & 2 deletions _styles/main.css
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ body {
font-weight: 400;
margin: 0;
min-height: 100vh;
overflow-x: hidden;
}

*,
Expand Down Expand Up @@ -1238,7 +1239,7 @@ So that for browsers that dont we can have a sensible inline style that can be a
bottom: 30px;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.2);
color: #333;
left: -70px;
left: var(--popover-left, -70px);
opacity: 0;
position: absolute;
text-align: left;
Expand All @@ -1254,7 +1255,7 @@ So that for browsers that dont we can have a sensible inline style that can be a
content: "";
display: block;
height: 0;
left: 50%;
left: var(--arrow-left, 50%);
margin-left: -5px;
position: absolute;
width: 0;
Expand Down
Loading