improvement(scroll): fade every capped list's clipped edges

The sweep's own three (the thread, the Plex collections filter, the tag manager)
plus the seven the spec missed — the playlist picker, the row tag menu, the Plex
playlist/collection dialogs, the player's track menu, the video description and
the table's multi-select filter. Same idiom throughout: a height-capped list that
silently clipped its content now says so, and hides its scrollbar like the rail
and the panels already do.

The table's option list is its own module-level component because it owns a hook:
FilterPopover is redeclared per DataTable render, so React remounts it.
This commit is contained in:
2026-07-17 03:14:48 +02:00
parent a032324513
commit 0ed58e3cb1
10 changed files with 91 additions and 16 deletions
+7 -1
View File
@@ -10,6 +10,7 @@ import { api, type Video } from "../lib/api";
import { channelYouTubeUrl, formatDate, formatDuration, formatViews, relativeTime } from "../lib/format";
import { renderDescription } from "../lib/descriptionLinks";
import { useBackToClose } from "../lib/history";
import { useScrollFade } from "../lib/useScrollFade";
// Experiment (branch experiment/inline-player): play the video in-app via the
// YouTube IFrame Player API (not a bare embed) so we can read playback position
@@ -73,6 +74,7 @@ export default function PlayerModal({
}) {
const { t, i18n } = useTranslation();
const qc = useQueryClient();
const descFade = useScrollFade();
// Browser/mouse Back closes the player instead of leaving the page.
useBackToClose(onClose);
// Freeze the launch queue: the player steps through the SAME filtered + sorted list it was
@@ -775,7 +777,11 @@ export default function PlayerModal({
{detail.isLoading ? (
<div className="text-sm text-muted">{t("player.loading")}</div>
) : detail.data?.description ? (
<div className="text-sm whitespace-pre-wrap break-words max-h-64 overflow-y-auto leading-relaxed">
<div
ref={descFade.ref}
style={descFade.style}
className="text-sm whitespace-pre-wrap break-words max-h-64 overflow-y-auto no-scrollbar leading-relaxed"
>
{renderDescription(detail.data.description, {
currentId: currentVideoId,
onSeek: seekTo,