|
1 | | -import React, { useEffect, useState } from "react"; |
| 1 | +import React, { useEffect, useState, useRef } from "react"; |
2 | 2 | import { useInView } from "react-intersection-observer"; |
3 | 3 |
|
4 | 4 | import { useRenderer } from "../../context/RendererContext"; |
@@ -41,7 +41,9 @@ export const ImageBlockRenderer: React.FC<ImageBlockRendererProps> = ({ |
41 | 41 | const [isLoading, setIsLoading] = useState<boolean>(false); |
42 | 42 | const [hasError, setHasError] = useState<boolean>(false); |
43 | 43 | const [showFullCaption, setShowFullCaption] = useState<boolean>(false); |
| 44 | + const [needsTruncation, setNeedsTruncation] = useState<boolean>(false); |
44 | 45 | const { ref, inView } = useInView({ threshold: 0.1, triggerOnce: true }); |
| 46 | + const captionRef = useRef<HTMLDivElement>(null); |
45 | 47 |
|
46 | 48 | const getImageUrl = () => { |
47 | 49 | if (imageData?.type === "external") { |
@@ -86,6 +88,14 @@ export const ImageBlockRenderer: React.FC<ImageBlockRendererProps> = ({ |
86 | 88 | }; |
87 | 89 | }, [inView, imageUrl, resolveImageUrl]); |
88 | 90 |
|
| 91 | + useEffect(() => { |
| 92 | + if (captionRef.current && imageData?.caption && imageData.caption.length > 0) { |
| 93 | + const element = captionRef.current; |
| 94 | + const isOverflowing = element.scrollHeight > element.clientHeight; |
| 95 | + setNeedsTruncation(isOverflowing); |
| 96 | + } |
| 97 | + }, [imageData?.caption]); |
| 98 | + |
89 | 99 | return ( |
90 | 100 | <div |
91 | 101 | {...props} |
@@ -126,16 +136,30 @@ export const ImageBlockRenderer: React.FC<ImageBlockRendererProps> = ({ |
126 | 136 | <div className="notranslate"> |
127 | 137 | <figcaption className="notion-image-caption"> |
128 | 138 | <div |
| 139 | + ref={captionRef} |
129 | 140 | className={`caption-content ${!showFullCaption ? "caption-truncated" : "caption-expanded"}`} |
130 | 141 | > |
131 | 142 | <RichTextRenderer richText={imageData.caption} /> |
132 | 143 | </div> |
133 | | - <button |
134 | | - className="caption-toggle-btn" |
135 | | - onClick={() => setShowFullCaption(!showFullCaption)} |
136 | | - > |
137 | | - {showFullCaption ? "Show less" : "Show more"} |
138 | | - </button> |
| 144 | + {needsTruncation && ( |
| 145 | + <button |
| 146 | + className="caption-toggle-btn" |
| 147 | + onClick={() => setShowFullCaption(!showFullCaption)} |
| 148 | + > |
| 149 | + <span className="btn-text"> |
| 150 | + {showFullCaption ? "Show less" : "Show more"} |
| 151 | + </span> |
| 152 | + <svg |
| 153 | + className={`btn-icon ${showFullCaption ? 'rotated' : ''}`} |
| 154 | + width="12" |
| 155 | + height="12" |
| 156 | + viewBox="0 0 12 12" |
| 157 | + fill="currentColor" |
| 158 | + > |
| 159 | + <path d="M3 4.5L6 7.5L9 4.5" stroke="currentColor" strokeWidth="1.5" fill="none" strokeLinecap="round" strokeLinejoin="round"/> |
| 160 | + </svg> |
| 161 | + </button> |
| 162 | + )} |
139 | 163 | </figcaption> |
140 | 164 | </div> |
141 | 165 | )} |
|
0 commit comments