mirror of
https://github.com/bitsocialnet/5chan.git
synced 2026-08-03 07:41:04 +02:00
fix(feed): measure expanded reply media height
This commit is contained in:
@@ -128,6 +128,29 @@ describe('CommentMedia', () => {
|
|||||||
expect(container.textContent).toContain('640x480');
|
expect(container.textContent).toContain('640x480');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('marks expanded reply images so virtualized feed rows use live height', async () => {
|
||||||
|
await renderMedia({
|
||||||
|
commentMediaInfo: {
|
||||||
|
linkHeight: 300,
|
||||||
|
linkWidth: 600,
|
||||||
|
type: 'image',
|
||||||
|
url: 'https://cdn.example.com/reply-image.jpg',
|
||||||
|
},
|
||||||
|
parentCid: 'parent-cid',
|
||||||
|
setShowThumbnail: setShowThumbnailMock,
|
||||||
|
showThumbnail: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(container.querySelector('[data-expanded-media="true"]')).toBeNull();
|
||||||
|
|
||||||
|
const image = container.querySelector('img[src="https://cdn.example.com/reply-image.jpg"]');
|
||||||
|
await act(async () => {
|
||||||
|
image?.dispatchEvent(new MouseEvent('click', { bubbles: true }));
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(container.querySelector('[data-expanded-media="true"]')).toBeTruthy();
|
||||||
|
});
|
||||||
|
|
||||||
it('falls back to the deleted-file placeholder when an image fails to load', async () => {
|
it('falls back to the deleted-file placeholder when an image fails to load', async () => {
|
||||||
await renderMedia({
|
await renderMedia({
|
||||||
commentMediaInfo: {
|
commentMediaInfo: {
|
||||||
|
|||||||
@@ -210,7 +210,7 @@ const Media = ({ commentMediaInfo, disableToggle, isReply, setShowThumbnail }: M
|
|||||||
const mediaDimensions = getMediaDimensions(commentMediaInfo);
|
const mediaDimensions = getMediaDimensions(commentMediaInfo);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<span className={mediaClass}>
|
<span className={mediaClass} data-expanded-media='true'>
|
||||||
{type === 'iframe' && url ? (
|
{type === 'iframe' && url ? (
|
||||||
<Embed url={url} />
|
<Embed url={url} />
|
||||||
) : type === 'gif' ? (
|
) : type === 'gif' ? (
|
||||||
@@ -307,6 +307,8 @@ const Image = ({ commentMediaInfo, disableToggle = false, displayHeight, display
|
|||||||
}`;
|
}`;
|
||||||
const thumbnailSmallPadding = isMobile ? styles.thumbnailMobile : styles.thumbnailReplyDesktop;
|
const thumbnailSmallPadding = isMobile ? styles.thumbnailMobile : styles.thumbnailReplyDesktop;
|
||||||
const thumbnailDimensions = { '--width': displayWidth, '--height': displayHeight } as React.CSSProperties;
|
const thumbnailDimensions = { '--width': displayWidth, '--height': displayHeight } as React.CSSProperties;
|
||||||
|
const expandedMediaAttribute = isImageExpanded ? 'true' : undefined;
|
||||||
|
const imageMediaStyle = isImageExpanded ? undefined : thumbnailDimensions;
|
||||||
|
|
||||||
const [hasError, setHasError] = useState(false);
|
const [hasError, setHasError] = useState(false);
|
||||||
const handleError = () => setHasError(true);
|
const handleError = () => setHasError(true);
|
||||||
@@ -340,7 +342,8 @@ const Image = ({ commentMediaInfo, disableToggle = false, displayHeight, display
|
|||||||
<span className={`${styles.thumbnail} ${isImageExpanded && isMobile ? styles.removeFloat : ''}`}>
|
<span className={`${styles.thumbnail} ${isImageExpanded && isMobile ? styles.removeFloat : ''}`}>
|
||||||
<span
|
<span
|
||||||
className={isImageExpanded ? mediaClass : `${isOutOfFeed ? styles.communityAvatar : styles.thumbnailSmall} ${thumbnailSmallPadding}`}
|
className={isImageExpanded ? mediaClass : `${isOutOfFeed ? styles.communityAvatar : styles.thumbnailSmall} ${thumbnailSmallPadding}`}
|
||||||
style={isImageExpanded ? {} : thumbnailDimensions}
|
data-expanded-media={expandedMediaAttribute}
|
||||||
|
style={imageMediaStyle}
|
||||||
>
|
>
|
||||||
{hasError ? (
|
{hasError ? (
|
||||||
<img src='assets/filedeleted-res.gif' alt='File deleted' />
|
<img src='assets/filedeleted-res.gif' alt='File deleted' />
|
||||||
@@ -379,7 +382,8 @@ const Image = ({ commentMediaInfo, disableToggle = false, displayHeight, display
|
|||||||
) : (
|
) : (
|
||||||
<span
|
<span
|
||||||
className={isImageExpanded ? mediaClass : `${isOutOfFeed ? styles.communityAvatar : styles.thumbnailBig} ${styles.thumbnail}`}
|
className={isImageExpanded ? mediaClass : `${isOutOfFeed ? styles.communityAvatar : styles.thumbnailBig} ${styles.thumbnail}`}
|
||||||
style={isImageExpanded ? {} : thumbnailDimensions}
|
data-expanded-media={expandedMediaAttribute}
|
||||||
|
style={imageMediaStyle}
|
||||||
>
|
>
|
||||||
{hasError ? (
|
{hasError ? (
|
||||||
<img src='assets/filedeleted-res.gif' alt='File deleted' />
|
<img src='assets/filedeleted-res.gif' alt='File deleted' />
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import {
|
|||||||
resolveFeedVirtualizationMode,
|
resolveFeedVirtualizationMode,
|
||||||
resolveReplyVirtualizationMode,
|
resolveReplyVirtualizationMode,
|
||||||
} from '../pretext-height-estimates';
|
} from '../pretext-height-estimates';
|
||||||
|
import { EXPANDED_MEDIA_DATA_ATTRIBUTE } from '../measurement-attributes';
|
||||||
|
|
||||||
describe('pretext-height-estimates', () => {
|
describe('pretext-height-estimates', () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
@@ -81,6 +82,18 @@ describe('pretext-height-estimates', () => {
|
|||||||
expect(getReplyItemSizeFromElement(element, 'offsetHeight')).toBe(222);
|
expect(getReplyItemSizeFromElement(element, 'offsetHeight')).toBe(222);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('uses live DOM height when expanded media is inside an estimated item', () => {
|
||||||
|
const element = document.createElement('div');
|
||||||
|
const child = document.createElement('div');
|
||||||
|
|
||||||
|
Object.defineProperty(element, 'offsetHeight', { configurable: true, value: 421 });
|
||||||
|
element.dataset.pretextHeight = '123';
|
||||||
|
child.setAttribute(EXPANDED_MEDIA_DATA_ATTRIBUTE, 'true');
|
||||||
|
element.appendChild(child);
|
||||||
|
|
||||||
|
expect(getReplyItemSizeFromElement(element, 'offsetHeight')).toBe(421);
|
||||||
|
});
|
||||||
|
|
||||||
it('adds desktop board-label height for multiboard text posts without media', () => {
|
it('adds desktop board-label height for multiboard text posts without media', () => {
|
||||||
const metrics = {
|
const metrics = {
|
||||||
abbrFontSizePx: 13,
|
abbrFontSizePx: 13,
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
export const EXPANDED_MEDIA_DATA_ATTRIBUTE = 'data-expanded-media';
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
import type { Comment } from '@bitsocial/bitsocial-react-hooks';
|
import type { Comment } from '@bitsocial/bitsocial-react-hooks';
|
||||||
import { layout, layoutNextLine, prepare, prepareWithSegments } from '@chenglou/pretext';
|
import { layout, layoutNextLine, prepare, prepareWithSegments } from '@chenglou/pretext';
|
||||||
import { getCommentMediaInfo, getHasThumbnail } from './media-utils';
|
import { getCommentMediaInfo, getHasThumbnail } from './media-utils';
|
||||||
|
import { EXPANDED_MEDIA_DATA_ATTRIBUTE } from './measurement-attributes';
|
||||||
import { removeMarkdown } from './post-utils';
|
import { removeMarkdown } from './post-utils';
|
||||||
import { getRenderableMobileBacklinks } from './reply-backlink-utils';
|
import { getRenderableMobileBacklinks } from './reply-backlink-utils';
|
||||||
|
|
||||||
@@ -839,6 +840,10 @@ export const getPretextItemSizeFromElement = (element: HTMLElement, field: 'offs
|
|||||||
return element.offsetWidth;
|
return element.offsetWidth;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (element.dataset.expandedMedia === 'true' || element.querySelector(`[${EXPANDED_MEDIA_DATA_ATTRIBUTE}="true"]`)) {
|
||||||
|
return element.offsetHeight;
|
||||||
|
}
|
||||||
|
|
||||||
const ownEstimatedHeight = Number.parseFloat(element.dataset.pretextHeight || '');
|
const ownEstimatedHeight = Number.parseFloat(element.dataset.pretextHeight || '');
|
||||||
if (Number.isFinite(ownEstimatedHeight) && ownEstimatedHeight > 0) {
|
if (Number.isFinite(ownEstimatedHeight) && ownEstimatedHeight > 0) {
|
||||||
return ownEstimatedHeight;
|
return ownEstimatedHeight;
|
||||||
|
|||||||
Reference in New Issue
Block a user