ui enhancements
This commit is contained in:
@@ -26,7 +26,7 @@
|
||||
* always visible on touch (mobile).
|
||||
*/
|
||||
|
||||
import { useState } from "react";
|
||||
import { useEffect, useRef, useState } from "react";
|
||||
import Image from "next/image";
|
||||
import Link from "next/link";
|
||||
import { ImageIcon, Trash2 } from "lucide-react";
|
||||
@@ -248,22 +248,46 @@ function Caption({
|
||||
expanded: boolean;
|
||||
onToggle: () => void;
|
||||
}) {
|
||||
// Show 3 lines collapsed. The "more" toggle appears only when the text
|
||||
// is long enough to warrant it (a cheap char-length check beats a
|
||||
// measure-and-compare pass for our purposes — captions over ~180 chars
|
||||
// will always overflow 3 lines at the rendered font size).
|
||||
const longEnough = text.length > 180;
|
||||
// We clamp to 3 lines collapsed and expose a "More" toggle only when
|
||||
// the clamp is actually hiding something. A char-length heuristic gets
|
||||
// this wrong: a 200-char caption can fit cleanly in 3 lines on a wide
|
||||
// card (no clipping → "More" would be a false promise). Instead measure
|
||||
// scrollHeight vs clientHeight on the clamped <p>. Once we've observed
|
||||
// overflow we latch it on so "Show less" stays visible after expansion
|
||||
// (where scrollHeight would equal clientHeight and we'd otherwise lose
|
||||
// the way back).
|
||||
const pRef = useRef<HTMLParagraphElement | null>(null);
|
||||
const [overflowed, setOverflowed] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
if (expanded) return;
|
||||
const el = pRef.current;
|
||||
if (!el) return;
|
||||
const measure = () => {
|
||||
// Sub-pixel rounding can leave a 1px gap even when content fits;
|
||||
// require a real difference before flagging overflow.
|
||||
setOverflowed(el.scrollHeight - el.clientHeight > 1);
|
||||
};
|
||||
measure();
|
||||
const ro = new ResizeObserver(measure);
|
||||
ro.observe(el);
|
||||
return () => ro.disconnect();
|
||||
}, [text, expanded]);
|
||||
|
||||
const showToggle = overflowed || expanded;
|
||||
|
||||
return (
|
||||
<div className="text-sm text-foreground leading-relaxed">
|
||||
<p
|
||||
ref={pRef}
|
||||
className={cn(
|
||||
"font-[family-name:var(--font-title)] break-words",
|
||||
!expanded && longEnough && "line-clamp-3",
|
||||
!expanded && "line-clamp-3",
|
||||
)}
|
||||
>
|
||||
“{text}”
|
||||
</p>
|
||||
{longEnough ? (
|
||||
{showToggle ? (
|
||||
<button
|
||||
type="button"
|
||||
onClick={onToggle}
|
||||
|
||||
Reference in New Issue
Block a user