From 81e28b083de9d01759f0562e3c361ae89deddd73 Mon Sep 17 00:00:00 2001 From: npeter83 Date: Mon, 15 Jun 2026 14:52:57 +0200 Subject: [PATCH] fix(playlists): flip the add-to-playlist popover up when it would overflow The popover was always positioned below its trigger, so on cards near the bottom of the viewport it ran off-screen. Measure the panel's real height and open it upward (clamped to the viewport) when there isn't room below; also clamp the horizontal position. --- frontend/src/components/AddToPlaylist.tsx | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/frontend/src/components/AddToPlaylist.tsx b/frontend/src/components/AddToPlaylist.tsx index 772dc10..84dd169 100644 --- a/frontend/src/components/AddToPlaylist.tsx +++ b/frontend/src/components/AddToPlaylist.tsx @@ -1,4 +1,4 @@ -import { useEffect, useRef, useState } from "react"; +import { useEffect, useLayoutEffect, useRef, useState } from "react"; import { createPortal } from "react-dom"; import { useTranslation } from "react-i18next"; import { useQuery, useQueryClient } from "@tanstack/react-query"; @@ -29,14 +29,27 @@ export default function AddToPlaylist({ enabled: open, }); + // Re-place once the panel is actually rendered (so we know its real height) and whenever + // its content — hence height — changes, so the flip-above decision uses the true size. + useLayoutEffect(() => { + if (open) place(); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [open, membership.data]); + function place() { const r = triggerRef.current?.getBoundingClientRect(); if (!r) return; const width = 240; - setCoords({ - top: Math.round(r.bottom + 6), - left: Math.round(Math.min(r.left, window.innerWidth - width - 8)), - }); + const margin = 8; + // Use the panel's real height once it's mounted; estimate on the first open. + const h = panelRef.current?.offsetHeight ?? 300; + let top = r.bottom + 6; + if (top + h > window.innerHeight - margin) { + // Not enough room below — open upward, clamped to the viewport. + top = Math.max(margin, r.top - h - 6); + } + const left = Math.min(Math.max(margin, r.left), window.innerWidth - width - margin); + setCoords({ top: Math.round(top), left: Math.round(left) }); } function toggleOpen(e: React.MouseEvent) {