diff --git a/packages/app/src/views/Details/ModernDetailContent.js b/packages/app/src/views/Details/ModernDetailContent.js index 2b97e544..6140b729 100644 --- a/packages/app/src/views/Details/ModernDetailContent.js +++ b/packages/app/src/views/Details/ModernDetailContent.js @@ -58,6 +58,29 @@ const ModernDetailContent = (props) => { const played = item.UserData?.Played; const isFavorite = item.UserData?.IsFavorite; + const [canToggle, setCanToggle] = useState(false); + const [isExpanded, setIsExpanded] = useState(false); + const descriptionRef = useRef(null); + + // Reset expanded state when navigating to a different item. Keyed on the id so an + // in-place update to the same item doesn't collapse the text. + useEffect(() => { + setIsExpanded(false); + setCanToggle(false); + }, [item?.Id]); + + // Detect if description text overflows 4 lines + useEffect(() => { + const el = descriptionRef.current; + if (el && !isExpanded) { + setCanToggle(el.scrollHeight > el.clientHeight); + } + }, [item?.Overview, isExpanded]); + + const handleToggleExpand = useCallback(() => { + setIsExpanded(prev => !prev); + }, []); + const scrollToRef = useRef(null); const handleScrollTo = useCallback((fn) => { scrollToRef.current = fn; @@ -507,7 +530,18 @@ const ModernDetailContent = (props) => { )} {!isPerson && } {tagline &&
{tagline}
} - {item.Overview &&

{item.Overview}

} + {item.Overview && ( + +

+ {item.Overview} +

+ {canToggle &&
{isExpanded ? $L('Read Less') : $L('Read More')}
} +
+ )} {renderUpNext()} diff --git a/packages/app/src/views/Details/ModernDetailContent.module.less b/packages/app/src/views/Details/ModernDetailContent.module.less index 4ada2f30..5599158e 100644 --- a/packages/app/src/views/Details/ModernDetailContent.module.less +++ b/packages/app/src/views/Details/ModernDetailContent.module.less @@ -131,11 +131,49 @@ .overview { font-size: 26px; line-height: 1.5; - max-width: 900px; + max-width: 100%; opacity: 0.92; margin: 0; } +.overviewCollapsed { + display: -webkit-box; + -webkit-line-clamp: 4; + -webkit-box-orient: vertical; + overflow: hidden; +} + +.descriptionContainer { + display: flex; + flex-direction: column; + gap: 12px; + padding: 24px; + border-radius: 16px; + border: 1px solid rgba(255, 255, 255, 0.08); + background: rgba(255, 255, 255, 0.03); + max-width: 900px; + box-sizing: border-box; + transition: border-color 0.15s ease, background-color 0.15s ease, transform 0.15s ease; + outline: none; +} + +.descriptionContainerSpottable { + cursor: pointer; +} + +.descriptionContainerSpottable:focus { + border-color: rgba(255, 255, 255, 0.35); + background: rgba(255, 255, 255, 0.06); + transform: scale(1.01); +} + +.readMoreBtn { + color: #ff5b5b; + font-weight: 600; + font-size: 22px; + align-self: flex-start; +} + .icon { width: 32px; height: 32px;