change preview card dropdown position depending on viewport (#14473)

This commit is contained in:
Suzanne Aitchison 2021-08-11 18:40:11 +01:00 committed by GitHub
parent 443e852091
commit 5efd72040b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 84 additions and 3 deletions

View file

@ -29,4 +29,10 @@
top: 0;
}
}
&.reverse {
// Flips the dropdown to drop-upwards when set
bottom: 100%;
top: unset;
}
}

View file

@ -3,7 +3,11 @@ import ahoy from 'ahoy.js';
import { Snackbar, addSnackbarItem } from '../Snackbar';
import { addFullScreenModeControl } from '../utilities/codeFullscreenModeSwitcher';
import { embedGists } from '../utilities/gist';
import { initializeDropdown } from '@utilities/dropdownUtils';
import {
initializeDropdown,
getDropdownRepositionListener,
} from '../utilities/dropdownUtils';
import { getInstantClick } from '../topNavigation/utilities';
/* global Runtime */
@ -188,3 +192,18 @@ if (profilePreviewTrigger?.dataset.initialized !== 'true') {
const targetNode = document.querySelector('#comments');
targetNode && embedGists(targetNode);
// Preview card dropdowns reposition on scroll
const dropdownRepositionListener = getDropdownRepositionListener();
document.addEventListener('scroll', dropdownRepositionListener);
getInstantClick().then((ic) => {
ic.on('change', () => {
document.removeEventListener('scroll', dropdownRepositionListener);
});
});
window.addEventListener('beforeunload', () => {
document.removeEventListener('scroll', dropdownRepositionListener);
});

View file

@ -1,5 +1,8 @@
import { addSnackbarItem } from '../Snackbar';
import { initializeDropdown } from '@utilities/dropdownUtils';
import {
initializeDropdown,
getDropdownRepositionListener,
} from '@utilities/dropdownUtils';
/* global Runtime */
@ -122,12 +125,18 @@ observer.observe(document.getElementById('comment-trees-container'), {
subtree: true,
});
// Preview card dropdowns reposition on scroll
const dropdownRepositionListener = getDropdownRepositionListener();
document.addEventListener('scroll', dropdownRepositionListener);
InstantClick.on('change', () => {
observer.disconnect();
document.removeEventListener('scroll', dropdownRepositionListener);
});
window.addEventListener('beforeunload', () => {
observer.disconnect();
document.removeEventListener('scroll', dropdownRepositionListener);
});
initializeArticlePageDropdowns();

View file

@ -1,3 +1,50 @@
import { isInViewport } from '@utilities/viewport';
import { debounceAction } from '@utilities/debounceAction';
/**
* Helper function designed to be used on scroll to detect when dropdowns should switch from dropping downwards/upwards.
* The action is debounced since scroll events are usually fired several at a time.
*
* @returns {Function} a debounced function that handles the repositioning of dropdowns
* @example
*
* document.addEventListener('scroll', getDropdownRepositionListener());
*/
export const getDropdownRepositionListener = () =>
debounceAction(handleDropdownRepositions);
/**
* Checks for all dropdowns on the page which have the attribute 'data-repositioning-dropdown', signalling
* they should dynamically change between dropping downwards or upwards, depending on viewport position.
*
* Any dropdowns not fully in view when dropping down will be switched to dropping upwards.
*/
const handleDropdownRepositions = () => {
// Select all of the dropdowns which should reposition
const allRepositioningDropdowns = document.querySelectorAll(
'[data-repositioning-dropdown]',
);
for (const element of allRepositioningDropdowns) {
// Default to dropping downwards
element.classList.remove('reverse');
// We can't determine position on an element with display:none, so we "show" the dropdown with 0 opacity very temporarily
element.style.opacity = 0;
element.style.display = 'block';
const isWithinViewport = isInViewport({ element });
// Revert the temporary changes to determine position
element.style.removeProperty('display');
element.style.removeProperty('opacity');
if (!isWithinViewport) {
// If the element isn't fully visible when dropping down, reverse the direction
element.classList.add('reverse');
}
}
};
/**
* Helper query string to identify interactive/focusable HTML elements
*/

View file

@ -1,4 +1,4 @@
<div id="<%= id %>" class="profile-preview-card__content crayons-dropdown" style="--card-color: <%= Color::CompareHex.new([user_colors(actor)[:bg], user_colors(actor)[:text]]).brightness(0.88) %>; border-top: var(--su-7) solid var(--card-color);" data-testid="profile-preview-card">
<div id="<%= id %>" class="profile-preview-card__content crayons-dropdown" style="--card-color: <%= Color::CompareHex.new([user_colors(actor)[:bg], user_colors(actor)[:text]]).brightness(0.88) %>; border-top: var(--su-7) solid var(--card-color);" data-testid="profile-preview-card" data-repositioning-dropdown="true">
<div class="gap-4 grid">
<%= render "shared/profile_card_content", context: "preview-card", actor: actor %>
</div>