diff --git a/components/brain/left-sidebar/waves/memes-quick-vote/MemesQuickVoteControls.tsx b/components/brain/left-sidebar/waves/memes-quick-vote/MemesQuickVoteControls.tsx index 1e87c7bb6f..6c92ca116b 100644 --- a/components/brain/left-sidebar/waves/memes-quick-vote/MemesQuickVoteControls.tsx +++ b/components/brain/left-sidebar/waves/memes-quick-vote/MemesQuickVoteControls.tsx @@ -2,6 +2,7 @@ import { formatNumberWithCommas } from "@/helpers/Helpers"; import type { ExtendedDrop } from "@/helpers/waves/drop.helpers"; +import { useCallback, useEffect, useRef, useState } from "react"; import MemesQuickVoteActionBar from "./MemesQuickVoteActionBar"; import MemesQuickVoteDropHeader from "./MemesQuickVoteDropHeader"; @@ -27,6 +28,109 @@ interface MemesQuickVoteControlsProps { readonly onVoteAmount: (amount: number) => void; } +function MemesQuickVoteDescription({ + description, +}: { + readonly description: string; +}) { + const [isExpanded, setIsExpanded] = useState(false); + const [isOverflowing, setIsOverflowing] = useState(false); + const visibleDescriptionRef = useRef(null); + const clampClass = isExpanded ? "tw-line-clamp-none" : "tw-line-clamp-4"; + const descriptionClassName = + "tw-mb-0 tw-whitespace-pre-line tw-text-sm tw-font-medium tw-leading-relaxed tw-text-iron-400 md:tw-text-md"; + + const measureOverflow = useCallback(() => { + const visibleDescription = visibleDescriptionRef.current; + + if (!visibleDescription) { + return; + } + + const computedStyles = globalThis.getComputedStyle(visibleDescription); + const lineHeight = Number.parseFloat(computedStyles.lineHeight || "0"); + const collapsedHeight = lineHeight * 4; + + if (!Number.isFinite(collapsedHeight) || collapsedHeight <= 0) { + return; + } + + const previousDisplay = visibleDescription.style.display; + const previousOverflow = visibleDescription.style.overflow; + const previousWebkitLineClamp = visibleDescription.style.webkitLineClamp; + + visibleDescription.style.display = "block"; + visibleDescription.style.overflow = "visible"; + visibleDescription.style.webkitLineClamp = "unset"; + + const fullHeight = visibleDescription.getBoundingClientRect().height; + + visibleDescription.style.display = previousDisplay; + visibleDescription.style.overflow = previousOverflow; + visibleDescription.style.webkitLineClamp = previousWebkitLineClamp; + + const nextIsOverflowing = fullHeight > collapsedHeight + 1; + + setIsOverflowing((current) => + current === nextIsOverflowing ? current : nextIsOverflowing + ); + }, []); + + useEffect(() => { + const frameId = globalThis.requestAnimationFrame(() => { + measureOverflow(); + }); + + if (typeof ResizeObserver === "undefined") { + const handleResize = () => { + measureOverflow(); + }; + + globalThis.addEventListener("resize", handleResize); + return () => { + globalThis.removeEventListener("resize", handleResize); + globalThis.cancelAnimationFrame(frameId); + }; + } + + const observer = new ResizeObserver(() => { + measureOverflow(); + }); + + if (visibleDescriptionRef.current) { + observer.observe(visibleDescriptionRef.current); + } + + return () => { + observer.disconnect(); + globalThis.cancelAnimationFrame(frameId); + }; + }, [measureOverflow]); + + return ( +
+

+ {description} +

+ {isOverflowing && ( + + )} +
+ ); +} + export default function MemesQuickVoteControls({ customValue, drop, @@ -65,7 +169,7 @@ export default function MemesQuickVoteControls({
-
+
@@ -75,9 +179,10 @@ export default function MemesQuickVoteControls({ {description && ( -

- {description} -

+ )}
diff --git a/components/brain/left-sidebar/waves/memes-quick-vote/MemesQuickVoteDialogSkeleton.tsx b/components/brain/left-sidebar/waves/memes-quick-vote/MemesQuickVoteDialogSkeleton.tsx index fd23037866..8cd8872f56 100644 --- a/components/brain/left-sidebar/waves/memes-quick-vote/MemesQuickVoteDialogSkeleton.tsx +++ b/components/brain/left-sidebar/waves/memes-quick-vote/MemesQuickVoteDialogSkeleton.tsx @@ -40,26 +40,26 @@ function MemesQuickVoteCopySkeleton({ function MemesQuickVoteActionBarSkeleton() { return ( -
+
- + -
+
-
- - +
+ +
- - + +
- +
); @@ -80,12 +80,12 @@ export default function MemesQuickVoteDialogSkeleton() {

- +
- +
@@ -121,7 +121,7 @@ export default function MemesQuickVoteDialogSkeleton() { className="tw-hidden tw-shrink-0 tw-flex-col tw-gap-0 md:tw-flex md:tw-h-full md:tw-min-h-0 md:tw-overflow-hidden md:tw-bg-[#0a0a0a]/30" >
- +
diff --git a/components/drops/view/item/content/media/DropListItemContentMedia.tsx b/components/drops/view/item/content/media/DropListItemContentMedia.tsx index c82cc9574e..8dff10622c 100644 --- a/components/drops/view/item/content/media/DropListItemContentMedia.tsx +++ b/components/drops/view/item/content/media/DropListItemContentMedia.tsx @@ -111,7 +111,6 @@ export default function DropListItemContentMedia({ case MediaType.UNKNOWN: return <>; default: - assertUnreachable(mediaType); - return; + return assertUnreachable(mediaType); } } diff --git a/components/drops/view/item/content/media/DropListItemContentMediaImage.tsx b/components/drops/view/item/content/media/DropListItemContentMediaImage.tsx index 5baee50c1d..50f270e2fa 100644 --- a/components/drops/view/item/content/media/DropListItemContentMediaImage.tsx +++ b/components/drops/view/item/content/media/DropListItemContentMediaImage.tsx @@ -62,7 +62,7 @@ function DropListItemContentMediaImage({ }, []); const handleError = useCallback(() => { - if (errorCount >= maxRetries) return; // give up – show fallback + if (errorCount >= maxRetries) return; const delay = 500 * 2 ** errorCount; // 0.5s, 1s, 2s … setTimeout(() => { setErrorCount((n) => n + 1); @@ -105,7 +105,7 @@ function DropListItemContentMediaImage({ event.stopPropagation(); const fullscreenTarget = modalImageRef.current ?? imgRef.current; if (fullscreenTarget) { - fullscreenTarget.requestFullscreen(); + fullscreenTarget.requestFullscreen().catch(() => undefined); } }, [] @@ -162,6 +162,7 @@ function DropListItemContentMediaImage({ wrapperClass="tw-w-full tw-h-full tw-flex tw-items-center tw-justify-center" contentClass="tw-w-full tw-h-full tw-flex tw-items-center tw-justify-center" > + {/* eslint-disable-next-line @next/next/no-img-element */}