diff --git a/client/components/main/popup.css b/client/components/main/popup.css index 9e102d0aa..13b014f66 100644 --- a/client/components/main/popup.css +++ b/client/components/main/popup.css @@ -73,13 +73,40 @@ } .pop-over .content-wrapper { width: 100%; - overflow: hidden; + max-height: 70vh; + overflow-y: auto; + overflow-x: hidden; +} + +/* Allow dynamic max-height to override default constraint */ +.pop-over[style*="max-height"] .content-wrapper { + max-height: inherit; } .pop-over .content-container { width: 100%; max-height: 70vh; transition: transform 0.2s; } + +/* Allow dynamic max-height to override default constraint for content-container */ +.pop-over[style*="max-height"] .content-container { + max-height: inherit; +} + +/* Ensure language popup list can scroll properly */ +.pop-over .pop-over-list { + max-height: none; + overflow: visible; +} + +/* Allow dynamic height for Change Language popup */ +.pop-over[data-popup="changeLanguage"] .content-wrapper { + max-height: inherit; /* Use dynamic height from JavaScript */ +} + +.pop-over[data-popup="changeLanguage"] .content-container { + max-height: inherit; /* Use dynamic height from JavaScript */ +} .pop-over .content-container .content { /* Match wider popover, leave padding */ width: 100%; diff --git a/client/components/main/popup.tpl.jade b/client/components/main/popup.tpl.jade index 1add6033e..dee721659 100644 --- a/client/components/main/popup.tpl.jade +++ b/client/components/main/popup.tpl.jade @@ -2,7 +2,7 @@ class="{{#unless title}}miniprofile{{/unless}}" class=currentBoard.colorClass class="{{#unless title}}no-title{{/unless}}" - style="left:{{offset.left}}px; top:{{offset.top}}px;") + style="left:{{offset.left}}px; top:{{offset.top}}px;{{#if offset.maxHeight}} max-height:{{offset.maxHeight}}px;{{/if}}") .header a.back-btn.js-back-view(class="{{#unless hasPopupParent}}is-hidden{{/unless}}") i.fa.fa-chevron-left diff --git a/client/lib/popup.js b/client/lib/popup.js index 36981aa4d..5cc5ec27c 100644 --- a/client/lib/popup.js +++ b/client/lib/popup.js @@ -209,11 +209,39 @@ window.Popup = new (class { if (Utils.isMiniScreen()) return { left: 0, top: 0 }; const offset = $element.offset(); - const popupWidth = 300 + 15; - return { - left: Math.min(offset.left, $(window).width() - popupWidth), - top: offset.top + $element.outerHeight(), - }; + // Calculate actual popup width based on CSS: min(380px, 55vw) + const viewportWidth = $(window).width(); + const viewportHeight = $(window).height(); + const popupWidth = Math.min(380, viewportWidth * 0.55) + 15; // Add 15px for margin + + // Calculate available height for popup + const popupTop = offset.top + $element.outerHeight(); + + // For language popup, don't use dynamic height to avoid overlapping board + const isLanguagePopup = $element.hasClass('js-change-language'); + let availableHeight, maxPopupHeight; + + if (isLanguagePopup) { + // For language popup, position content area below right vertical scrollbar + const availableHeight = viewportHeight - popupTop - 20; // 20px margin from bottom (near scrollbar) + const calculatedHeight = Math.min(availableHeight, viewportHeight * 0.5); // Max 50% of viewport + + return { + left: Math.min(offset.left, viewportWidth - popupWidth), + top: popupTop, + maxHeight: Math.max(calculatedHeight, 200), // Minimum 200px height + }; + } else { + // For other popups, use the dynamic height calculation + availableHeight = viewportHeight - popupTop - 20; // 20px margin from bottom + maxPopupHeight = Math.min(availableHeight, viewportHeight * 0.8); // Max 80% of viewport + + return { + left: Math.min(offset.left, viewportWidth - popupWidth), + top: popupTop, + maxHeight: Math.max(maxPopupHeight, 200), // Minimum 200px height + }; + } }; }