diff --git a/src/features/quick_reblog.css b/src/features/quick_reblog.css index 5e0c9df0b..2db158ca8 100644 --- a/src/features/quick_reblog.css +++ b/src/features/quick_reblog.css @@ -20,56 +20,22 @@ display: none !important; } -@media (max-width: 650px) { - #quick-reblog { - top: 50%; - right: 100%; - transform: translateY(-50%); - } +#quick-reblog { + --icon-spacing: 12px; } - -@media (min-width: 650px) { +@media (max-width: 990px) { #quick-reblog { - transform: translateX(50%); - } - - #quick-reblog.above { - bottom: 100%; - right: 50%; - } - - #quick-reblog.below { - top: 100%; - right: 50%; + --icon-spacing: 0px; } } -@media (min-width: 990px) { - #quick-reblog.above { - transform: translate(50%, -12px) - } - - #quick-reblog.below { - transform: translate(50%, 12px); - } +#quick-reblog.below { + inset: 100% 50% auto auto; + transform: translate(calc(50% + var(--horizontal-offset, 0%)), var(--icon-spacing)); } - -@media (max-width: 990px) { - [role="dialog"] #quick-reblog { - top: 50%; - bottom: unset; - right: 100%; - transform: translateY(-50%); - } -} - -@media (min-width: 990px) and (max-width: 1145px) { - [role="dialog"] #quick-reblog { - top: 50%; - bottom: unset; - right: 100%; - transform: translate(-20px, -50%); - } +#quick-reblog.above { + inset: auto 50% 100% auto; + transform: translate(calc(50% + var(--horizontal-offset, 0%)), calc(0px - var(--icon-spacing))); } div:first-child + span + #quick-reblog, diff --git a/src/features/quick_reblog.js b/src/features/quick_reblog.js index d48ae26f7..0d597db30 100644 --- a/src/features/quick_reblog.js +++ b/src/features/quick_reblog.js @@ -1,7 +1,7 @@ import { sha256 } from '../utils/crypto.js'; import { timelineObject } from '../utils/react_props.js'; import { apiFetch } from '../utils/tumblr_helpers.js'; -import { postSelector, filterPostElements, postType } from '../utils/interface.js'; +import { postSelector, filterPostElements, postType, appendWithoutOverflow } from '../utils/interface.js'; import { userBlogs } from '../utils/user.js'; import { getPreferences } from '../utils/preferences.js'; import { onNewPosts } from '../utils/mutations.js'; @@ -9,6 +9,7 @@ import { notify } from '../utils/notifications.js'; import { translate } from '../utils/language_data.js'; import { dom } from '../utils/dom.js'; import { showErrorModal } from '../utils/modals.js'; +import { keyToCss } from '../utils/css_map.js'; const popupElement = dom('div', { id: 'quick-reblog' }); const blogSelector = dom('select'); @@ -131,7 +132,7 @@ tagsInput.addEventListener('input', checkLength); const showPopupOnHover = ({ currentTarget }) => { clearTimeout(timeoutID); - currentTarget.closest('div').appendChild(popupElement); + appendWithoutOverflow(popupElement, currentTarget.closest(keyToCss('controlIcon')), popupPosition); popupElement.parentNode.addEventListener('mouseleave', removePopupOnLeave); const thisPost = currentTarget.closest(postSelector); @@ -329,8 +330,6 @@ export const main = async function () { alreadyRebloggedLimit } = await getPreferences('quick_reblog')); - popupElement.className = popupPosition; - blogSelector.replaceChildren( ...userBlogs.map(({ name, uuid }) => dom('option', { value: uuid }, null, [name])) ); diff --git a/src/features/quick_tags.css b/src/features/quick_tags.css index 6ce55c4ab..73007cb21 100644 --- a/src/features/quick_tags.css +++ b/src/features/quick_tags.css @@ -42,28 +42,13 @@ } } -@media (min-width: 650px) { - #quick-tags.below { - inset: 100% 50% auto auto; - transform: translate(50%, var(--icon-spacing)); - } - #quick-tags.above { - inset: auto 50% 100% auto; - transform: translate(50%, calc(0px - var(--icon-spacing))); - } +#quick-tags.below { + inset: 100% 50% auto auto; + transform: translate(calc(50% + var(--horizontal-offset, 0%)), var(--icon-spacing)); } - -@media (max-width: 650px) { - #quick-tags { - inset: 50% 100% auto auto; - transform: translate(calc(0px - var(--icon-spacing)), -50%); - } -} -@media (max-width: 1145px) { - [role="dialog"] #quick-tags { - inset: 50% 100% auto auto; - transform: translate(calc(0px - var(--icon-spacing)), -50%); - } +#quick-tags.above { + inset: auto 50% 100% auto; + transform: translate(calc(50% + var(--horizontal-offset, 0%)), calc(0px - var(--icon-spacing))); } #quick-tags:empty::before, diff --git a/src/features/quick_tags.js b/src/features/quick_tags.js index ec4f1f109..689c95ae1 100644 --- a/src/features/quick_tags.js +++ b/src/features/quick_tags.js @@ -1,7 +1,7 @@ import { cloneControlButton, createControlButtonTemplate } from '../utils/control_buttons.js'; import { keyToCss } from '../utils/css_map.js'; import { dom } from '../utils/dom.js'; -import { filterPostElements, getTimelineItemWrapper, postSelector } from '../utils/interface.js'; +import { appendWithoutOverflow, filterPostElements, getTimelineItemWrapper, postSelector } from '../utils/interface.js'; import { megaEdit } from '../utils/mega_editor.js'; import { modalCancelButton, modalCompleteButton, showErrorModal, showModal } from '../utils/modals.js'; import { onNewPosts, pageModifications } from '../utils/mutations.js'; @@ -115,14 +115,6 @@ export const onStorageChanged = async function (changes, areaName) { } }; -const appendWithoutViewportOverflow = (element, target) => { - element.className = 'below'; - target.appendChild(element); - if (element.getBoundingClientRect().bottom > document.documentElement.clientHeight) { - element.className = 'above'; - } -}; - const togglePopupDisplay = async function ({ target, currentTarget: controlButton }) { if (target === popupElement || popupElement.contains(target)) { return; } @@ -131,7 +123,7 @@ const togglePopupDisplay = async function ({ target, currentTarget: controlButto if (buttonContainer.contains(popupElement)) { buttonContainer.removeChild(popupElement); } else { - appendWithoutViewportOverflow(popupElement, buttonContainer); + appendWithoutOverflow(popupElement, buttonContainer); } }; @@ -141,7 +133,7 @@ const togglePostOptionPopupDisplay = async function ({ target, currentTarget }) if (currentTarget.contains(postOptionPopupElement)) { currentTarget.removeChild(postOptionPopupElement); } else { - appendWithoutViewportOverflow(postOptionPopupElement, currentTarget); + appendWithoutOverflow(postOptionPopupElement, currentTarget); } }; diff --git a/src/utils/interface.js b/src/utils/interface.js index 3eb252ca5..86b67680b 100644 --- a/src/utils/interface.js +++ b/src/utils/interface.js @@ -115,3 +115,32 @@ export const postType = ({ trail = [], content = [], layout = [] }) => { else if (content.some(({ type }) => type === 'link')) return 'link'; else return 'text'; }; + +const getClosestWithOverflow = element => { + const parent = element.parentElement; + if (!parent) { + return element; + } else if (getComputedStyle(parent).overflowX !== 'visible') { + return parent; + } else { + return getClosestWithOverflow(parent); + } +}; + +export const appendWithoutOverflow = (element, target, defaultPosition = 'below') => { + element.className = defaultPosition; + element.style.removeProperty('--horizontal-offset'); + + target.appendChild(element); + + const preventOverflowTarget = getClosestWithOverflow(target); + const preventOverflowTargetRect = preventOverflowTarget.getBoundingClientRect(); + const elementRect = element.getBoundingClientRect(); + + if (elementRect.bottom > document.documentElement.clientHeight) { + element.className = 'above'; + } + if (elementRect.right > preventOverflowTargetRect.right - 15) { + element.style.setProperty('--horizontal-offset', `${preventOverflowTargetRect.right - 15 - elementRect.right}px`); + } +};