diff --git a/frontend/src/components/PlayerModal.tsx b/frontend/src/components/PlayerModal.tsx
index d91e56c..56a0fc4 100644
--- a/frontend/src/components/PlayerModal.tsx
+++ b/frontend/src/components/PlayerModal.tsx
@@ -1,4 +1,5 @@
import { useEffect, useRef, useState } from "react";
+import { createPortal } from "react-dom";
import { useQuery } from "@tanstack/react-query";
import { Check, CheckCheck, X } from "lucide-react";
import { api, type Video } from "../lib/api";
@@ -71,8 +72,29 @@ export default function PlayerModal({
onState(video.id, next);
};
- // Lazy description (fetched only when the title is hovered).
+ // Lazy description (fetched only when the title is hovered). The popover is
+ // portaled to
with fixed positioning so the modal card's overflow-y-auto
+ // can't clip it. A small close grace lets the mouse travel title → popover.
const [showDesc, setShowDesc] = useState(false);
+ // `bottom` anchors the popover just above the title so it grows upward (over the
+ // player) instead of downward off-screen / behind the OS taskbar.
+ const [descRect, setDescRect] = useState<{ left: number; bottom: number; width: number } | null>(
+ null
+ );
+ const titleRef = useRef(null);
+ const closeTimer = useRef(undefined);
+ const openDesc = () => {
+ window.clearTimeout(closeTimer.current);
+ const el = titleRef.current;
+ if (el) {
+ const r = el.getBoundingClientRect();
+ setDescRect({ left: r.left, bottom: window.innerHeight - r.top + 8, width: r.width });
+ }
+ setShowDesc(true);
+ };
+ const scheduleCloseDesc = () => {
+ closeTimer.current = window.setTimeout(() => setShowDesc(false), 150);
+ };
const detail = useQuery({
queryKey: ["video-detail", video.id],
queryFn: () => api.videoDetail(video.id),
@@ -91,6 +113,7 @@ export default function PlayerModal({
return () => {
window.removeEventListener("keydown", onKey);
document.body.style.overflow = prevOverflow;
+ window.clearTimeout(closeTimer.current);
};
}, [onClose]);
@@ -185,15 +208,28 @@ export default function PlayerModal({
{/* Title row — title (with hover description) on the left, Close on the right. */}