From 7a4a7898da95ca0d764d12f0de80474076e943c3 Mon Sep 17 00:00:00 2001 From: ed-kung Date: Wed, 18 Jun 2025 20:30:36 -0700 Subject: [PATCH 01/11] carousel sort in deterministic order --- components/carousel.js | 9 ++++++--- components/media-or-link.js | 7 ++++++- components/text.js | 4 +++- lib/rehype-sn.js | 16 +++++++++++++++- 4 files changed, 30 insertions(+), 6 deletions(-) diff --git a/components/carousel.js b/components/carousel.js index 1b5ed6dd0..9adc8bcd3 100644 --- a/components/carousel.js +++ b/components/carousel.js @@ -108,16 +108,19 @@ export function CarouselProvider ({ children }) { const showModal = useShowModal() const showCarousel = useCallback(({ src }) => { + const sortedMedia = Array.from(media.current.entries()) + .sort(([, a], [, b]) => a.imgIndex - b.imgIndex) + showModal((close, setOptions) => { - return + return }, { fullScreen: true, overflow: }) }, [showModal, media.current]) - const addMedia = useCallback(({ src, originalSrc, rel }) => { - media.current.set(src, { src, originalSrc, rel }) + const addMedia = useCallback(({ src, originalSrc, rel, imgIndex }) => { + media.current.set(src, { src, originalSrc, rel, imgIndex }) }, [media.current]) const removeMedia = useCallback((src) => { diff --git a/components/media-or-link.js b/components/media-or-link.js index 9569fbc17..9093d84e2 100644 --- a/components/media-or-link.js +++ b/components/media-or-link.js @@ -79,7 +79,12 @@ export default function MediaOrLink ({ linkFallback = true, ...props }) { useEffect(() => { if (!media.image) return - addMedia({ src: media.bestResSrc, originalSrc: media.originalSrc, rel: props.rel }) + addMedia({ + src: media.bestResSrc, + originalSrc: media.originalSrc, + rel: props.rel, + imgIndex: props.imgIndex + }) }, [media.image]) const handleClick = useCallback(() => showCarousel({ src: media.bestResSrc }), diff --git a/components/text.js b/components/text.js index 654fa3caf..07e0b483b 100644 --- a/components/text.js +++ b/components/text.js @@ -222,6 +222,8 @@ function Footnote ({ children, node, ...props }) { function MediaLink ({ node, src, outlawed, imgproxyUrls, rel = UNKNOWN_LINK_REL, ...props }) { + const imgIndex = node?.properties?.imgIndex + const url = IMGPROXY_URL_REGEXP.test(src) ? decodeProxyUrl(src) : src // if outlawed, render the media link as text if (outlawed) { @@ -230,7 +232,7 @@ function MediaLink ({ const srcSet = imgproxyUrls?.[url] - return + return } function Table ({ node, ...props }) { diff --git a/lib/rehype-sn.js b/lib/rehype-sn.js index bed7e8f42..d012f8da4 100644 --- a/lib/rehype-sn.js +++ b/lib/rehype-sn.js @@ -14,6 +14,8 @@ export default function rehypeSN (options = {}) { const { stylers = [] } = options return function transformer (tree) { + let imgIndex = 0 + try { visit(tree, (node, index, parent) => { if (parent?.tagName === 'code') { @@ -21,6 +23,11 @@ export default function rehypeSN (options = {}) { return } + // If node is img, increment and assign imgIndex + if (node.tagName === 'img') { + node.properties.imgIndex ??= ++imgIndex + } + // Handle inline code property if (node.tagName === 'code') { node.properties.inline = !(parent && parent.tagName === 'pre') @@ -83,6 +90,8 @@ export default function rehypeSN (options = {}) { node.properties = { ...embed, src: node.properties.href } } else { node.tagName = 'autolink' + // since autolinks could be an image, increment imgIndex + node.properties.imgIndex ??= ++imgIndex } } @@ -209,6 +218,10 @@ export default function rehypeSN (options = {}) { const allImages = adjacentNodes.flatMap(n => n.tagName === 'img' ? [n] : (Array.isArray(n.children) ? n.children.filter(child => child.tagName === 'img') : []) ) + // increment imgIndex for each of the images + allImages.forEach(n => { + n.properties.imgIndex ??= ++imgIndex + }) const collageNode = { type: 'element', tagName: 'p', @@ -234,7 +247,8 @@ export default function rehypeSN (options = {}) { node.children.every(child => (child.tagName === 'img') || (child.type === 'text' && typeof child.value === 'string' && !child.value.trim()) - ) + ) && + node.children.some(child => child.tagName === 'img') } function replaceMention (value, username) { From cd5fff1bae151e44db717f2a2173f673793bc6d0 Mon Sep 17 00:00:00 2001 From: ed-kung Date: Wed, 18 Jun 2025 20:43:39 -0700 Subject: [PATCH 02/11] imgIndex 0 for ItemEmbed --- components/item-full.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/item-full.js b/components/item-full.js index 72c60b9c6..af717d5dc 100644 --- a/components/item-full.js +++ b/components/item-full.js @@ -65,7 +65,7 @@ function ItemEmbed ({ url, imgproxyUrls }) { const srcSet = imgproxyUrls?.[url] return (
- +
) } From 489e25ea82056bd83a818e581eb2bbfcf947e401 Mon Sep 17 00:00:00 2001 From: ed-kung Date: Wed, 18 Jun 2025 21:55:23 -0700 Subject: [PATCH 03/11] fix order for item-full --- components/text.js | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/components/text.js b/components/text.js index 07e0b483b..01399b3d6 100644 --- a/components/text.js +++ b/components/text.js @@ -108,9 +108,17 @@ export default memo(function Text ({ rel = UNKNOWN_LINK_REL, imgproxyUrls, child }, [containerRef.current, setOverflowing]) const TextMediaOrLink = useCallback(props => { - return - }, - [outlawed, imgproxyUrls, topLevel, rel]) + return ( + + ) + }, [outlawed, imgproxyUrls, topLevel, rel, itemId]) const components = useMemo(() => ({ h1: ({ node, id, ...props }) =>

, @@ -220,9 +228,11 @@ function Footnote ({ children, node, ...props }) { } function MediaLink ({ - node, src, outlawed, imgproxyUrls, rel = UNKNOWN_LINK_REL, ...props + node, src, outlawed, imgproxyUrls, itemId, imgIndex, rel = UNKNOWN_LINK_REL, ...props }) { - const imgIndex = node?.properties?.imgIndex + // assumes less than 100 images in an item + // if more than 100 images, carousel sort order will be unpredictable + const globalImgIndex = itemId * 100 + imgIndex const url = IMGPROXY_URL_REGEXP.test(src) ? decodeProxyUrl(src) : src // if outlawed, render the media link as text @@ -232,7 +242,7 @@ function MediaLink ({ const srcSet = imgproxyUrls?.[url] - return + return } function Table ({ node, ...props }) { From f7863af30a1a02b189bfc79237606851c4da1abf Mon Sep 17 00:00:00 2001 From: ed-kung Date: Wed, 18 Jun 2025 22:05:55 -0700 Subject: [PATCH 04/11] fix indexing in ItemEmbed --- components/item-full.js | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/components/item-full.js b/components/item-full.js index af717d5dc..39fbbb831 100644 --- a/components/item-full.js +++ b/components/item-full.js @@ -50,7 +50,7 @@ function BioItem ({ item, handleClick }) { ) } -function ItemEmbed ({ url, imgproxyUrls }) { +function ItemEmbed ({ url, imgproxyUrls, itemId }) { const provider = parseEmbedUrl(url) if (provider) { return ( @@ -65,7 +65,13 @@ function ItemEmbed ({ url, imgproxyUrls }) { const srcSet = imgproxyUrls?.[url] return (
- +
) } @@ -110,7 +116,7 @@ function TopLevelItem ({ item, noReply, ...props }) { >
{item.text && } - {item.url && !item.outlawed && } + {item.url && !item.outlawed && } {item.poll && } {item.bounty &&
From 215d43fce49f134f83aacedc15b4c0ab97f74007 Mon Sep 17 00:00:00 2001 From: ed-kung Date: Thu, 19 Jun 2025 11:29:10 -0700 Subject: [PATCH 05/11] Revert "fix indexing in ItemEmbed" This reverts commit f7863af30a1a02b189bfc79237606851c4da1abf. --- components/item-full.js | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/components/item-full.js b/components/item-full.js index 39fbbb831..af717d5dc 100644 --- a/components/item-full.js +++ b/components/item-full.js @@ -50,7 +50,7 @@ function BioItem ({ item, handleClick }) { ) } -function ItemEmbed ({ url, imgproxyUrls, itemId }) { +function ItemEmbed ({ url, imgproxyUrls }) { const provider = parseEmbedUrl(url) if (provider) { return ( @@ -65,13 +65,7 @@ function ItemEmbed ({ url, imgproxyUrls, itemId }) { const srcSet = imgproxyUrls?.[url] return (
- +
) } @@ -116,7 +110,7 @@ function TopLevelItem ({ item, noReply, ...props }) { >
{item.text && } - {item.url && !item.outlawed && } + {item.url && !item.outlawed && } {item.poll && } {item.bounty &&
From e5563a04983b449d3ac97c727c4d21136500454d Mon Sep 17 00:00:00 2001 From: ed-kung Date: Thu, 19 Jun 2025 11:29:28 -0700 Subject: [PATCH 06/11] Revert "fix order for item-full" This reverts commit 489e25ea82056bd83a818e581eb2bbfcf947e401. --- components/text.js | 22 ++++++---------------- 1 file changed, 6 insertions(+), 16 deletions(-) diff --git a/components/text.js b/components/text.js index 01399b3d6..07e0b483b 100644 --- a/components/text.js +++ b/components/text.js @@ -108,17 +108,9 @@ export default memo(function Text ({ rel = UNKNOWN_LINK_REL, imgproxyUrls, child }, [containerRef.current, setOverflowing]) const TextMediaOrLink = useCallback(props => { - return ( - - ) - }, [outlawed, imgproxyUrls, topLevel, rel, itemId]) + return + }, + [outlawed, imgproxyUrls, topLevel, rel]) const components = useMemo(() => ({ h1: ({ node, id, ...props }) =>

, @@ -228,11 +220,9 @@ function Footnote ({ children, node, ...props }) { } function MediaLink ({ - node, src, outlawed, imgproxyUrls, itemId, imgIndex, rel = UNKNOWN_LINK_REL, ...props + node, src, outlawed, imgproxyUrls, rel = UNKNOWN_LINK_REL, ...props }) { - // assumes less than 100 images in an item - // if more than 100 images, carousel sort order will be unpredictable - const globalImgIndex = itemId * 100 + imgIndex + const imgIndex = node?.properties?.imgIndex const url = IMGPROXY_URL_REGEXP.test(src) ? decodeProxyUrl(src) : src // if outlawed, render the media link as text @@ -242,7 +232,7 @@ function MediaLink ({ const srcSet = imgproxyUrls?.[url] - return + return } function Table ({ node, ...props }) { From 4523edb7d2612f2d969504860501a58bf23971f7 Mon Sep 17 00:00:00 2001 From: ed-kung Date: Thu, 19 Jun 2025 11:29:30 -0700 Subject: [PATCH 07/11] Revert "imgIndex 0 for ItemEmbed" This reverts commit cd5fff1bae151e44db717f2a2173f673793bc6d0. --- components/item-full.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/item-full.js b/components/item-full.js index af717d5dc..72c60b9c6 100644 --- a/components/item-full.js +++ b/components/item-full.js @@ -65,7 +65,7 @@ function ItemEmbed ({ url, imgproxyUrls }) { const srcSet = imgproxyUrls?.[url] return (
- +
) } From a4ad7b7725d9a1fb6c7874bdfe57cd5c5e73d7a2 Mon Sep 17 00:00:00 2001 From: ed-kung Date: Thu, 19 Jun 2025 17:58:29 -0700 Subject: [PATCH 08/11] carousel preserves ordering rendered on screen --- components/carousel.js | 27 +++++++++++++++++++++++---- components/comment.js | 6 ++++++ components/item-full.js | 25 +++++++++++++++++++++---- components/media-or-link.js | 1 + components/text.js | 32 +++++++++++++++++++++++++------- 5 files changed, 76 insertions(+), 15 deletions(-) diff --git a/components/carousel.js b/components/carousel.js index 9adc8bcd3..c4b6a4aee 100644 --- a/components/carousel.js +++ b/components/carousel.js @@ -105,11 +105,13 @@ function CarouselOverflow ({ originalSrc, rel }) { export function CarouselProvider ({ children }) { const media = useRef(new Map()) + const itemArray = useRef(new Map()) + const itemCount = useRef(0) const showModal = useShowModal() const showCarousel = useCallback(({ src }) => { const sortedMedia = Array.from(media.current.entries()) - .sort(([, a], [, b]) => a.imgIndex - b.imgIndex) + .sort(([, a], [, b]) => a.sortKey - b.sortKey) showModal((close, setOptions) => { return @@ -119,15 +121,32 @@ export function CarouselProvider ({ children }) { }) }, [showModal, media.current]) - const addMedia = useCallback(({ src, originalSrc, rel, imgIndex }) => { - media.current.set(src, { src, originalSrc, rel, imgIndex }) + const addMedia = useCallback(({ src, originalSrc, rel, itemId, imgIndex }) => { + const items = itemArray.current + const itemOrder = items.has(itemId) ? items.get(itemId).itemOrder : 0 + const sortKey = itemOrder * 100 + imgIndex + media.current.set(src, { src, originalSrc, rel, sortKey }) }, [media.current]) const removeMedia = useCallback((src) => { media.current.delete(src) }, [media.current]) - const value = useMemo(() => ({ showCarousel, addMedia, removeMedia }), [showCarousel, addMedia, removeMedia]) + const addItem = useCallback((itemId) => { + const items = itemArray.current + if (!items.has(itemId)) { + itemCount.current += 1 + items.set(itemId, { itemOrder: itemCount.current }) + } + return items.get(itemId).itemOrder + }, []) + + const value = useMemo(() => ({ + showCarousel, + addMedia, + removeMedia, + addItem + }), [showCarousel, addMedia, removeMedia, addItem]) return {children} } diff --git a/components/comment.js b/components/comment.js index 73e64d0c3..8fd8dbbb4 100644 --- a/components/comment.js +++ b/components/comment.js @@ -28,6 +28,7 @@ import LinkToContext from './link-to-context' import Boost from './boost-button' import { gql, useApolloClient } from '@apollo/client' import classNames from 'classnames' +import { useCarousel } from './carousel' function Parent ({ item, rootText }) { const root = useRoot() @@ -114,6 +115,11 @@ export default function Comment ({ const { cache } = useApolloClient() + const carousel = useCarousel() + if (carousel) { + carousel.addItem(item.id) + } + useEffect(() => { const comment = cache.readFragment({ id: `Item:${router.query.commentId}`, diff --git a/components/item-full.js b/components/item-full.js index 72c60b9c6..3a85cd762 100644 --- a/components/item-full.js +++ b/components/item-full.js @@ -24,7 +24,7 @@ import { numWithUnits } from '@/lib/format' import { useQuoteReply } from './use-quote-reply' import { UNKNOWN_LINK_REL } from '@/lib/constants' import classNames from 'classnames' -import { CarouselProvider } from './carousel' +import { CarouselProvider, useCarousel } from './carousel' import Embed from './embed' function BioItem ({ item, handleClick }) { @@ -33,6 +33,11 @@ function BioItem ({ item, handleClick }) { return null } + const carousel = useCarousel() + if (carousel) { + carousel.addItem(item.id) + } + return ( <> @@ -50,7 +55,7 @@ function BioItem ({ item, handleClick }) { ) } -function ItemEmbed ({ url, imgproxyUrls }) { +function ItemEmbed ({ url, imgproxyUrls, itemId }) { const provider = parseEmbedUrl(url) if (provider) { return ( @@ -65,7 +70,14 @@ function ItemEmbed ({ url, imgproxyUrls }) { const srcSet = imgproxyUrls?.[url] return (
- +
) } @@ -93,6 +105,11 @@ function TopLevelItem ({ item, noReply, ...props }) { const ItemComponent = item.isJob ? ItemJob : Item const { ref: textRef, quote, quoteReply, cancelQuote } = useQuoteReply({ text: item.text }) + const carousel = useCarousel() + if (carousel) { + carousel.addItem(item.id) + } + return (
{item.text && } - {item.url && !item.outlawed && } + {item.url && !item.outlawed && } {item.poll && } {item.bounty &&
diff --git a/components/media-or-link.js b/components/media-or-link.js index 9093d84e2..f336a03c0 100644 --- a/components/media-or-link.js +++ b/components/media-or-link.js @@ -83,6 +83,7 @@ export default function MediaOrLink ({ linkFallback = true, ...props }) { src: media.bestResSrc, originalSrc: media.originalSrc, rel: props.rel, + itemId: props.itemId, imgIndex: props.imgIndex }) }, [media.image]) diff --git a/components/text.js b/components/text.js index 07e0b483b..e99067f90 100644 --- a/components/text.js +++ b/components/text.js @@ -108,9 +108,17 @@ export default memo(function Text ({ rel = UNKNOWN_LINK_REL, imgproxyUrls, child }, [containerRef.current, setOverflowing]) const TextMediaOrLink = useCallback(props => { - return - }, - [outlawed, imgproxyUrls, topLevel, rel]) + return ( + + ) + }, [outlawed, imgproxyUrls, topLevel, rel]) const components = useMemo(() => ({ h1: ({ node, id, ...props }) =>

, @@ -142,6 +150,9 @@ export default memo(function Text ({ rel = UNKNOWN_LINK_REL, imgproxyUrls, child }), [outlawed, rel, TextMediaOrLink, topLevel]) const carousel = useCarousel() + if (carousel) { + carousel.addItem(itemId) + } const markdownContent = useMemo(() => ( + return ( + + ) } function Table ({ node, ...props }) { From 2378d7838774271223211fa2cac95b51a27f8db9 Mon Sep 17 00:00:00 2001 From: ed-kung Date: Thu, 19 Jun 2025 23:07:04 -0700 Subject: [PATCH 09/11] reorder carousel when sort changes --- components/item-full.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/components/item-full.js b/components/item-full.js index 3a85cd762..66ad03927 100644 --- a/components/item-full.js +++ b/components/item-full.js @@ -26,6 +26,7 @@ import { UNKNOWN_LINK_REL } from '@/lib/constants' import classNames from 'classnames' import { CarouselProvider, useCarousel } from './carousel' import Embed from './embed' +import { useRouter } from 'next/router' function BioItem ({ item, handleClick }) { const { me } = useMe() @@ -181,6 +182,8 @@ export default function ItemFull ({ item, fetchMoreComments, bio, rank, ...props useEffect(() => { commentsViewed(item) }, [item.lastCommentAt]) + const router = useRouter() + const carouselKey = `${item.id}--${router.query.sort || 'default'}` return ( <> @@ -191,7 +194,7 @@ export default function ItemFull ({ item, fetchMoreComments, bio, rank, ...props

) :
} - + {item.parentId ? : ( From 06742fbbc22d8888e7413a7df0855dece5c2aeaf Mon Sep 17 00:00:00 2001 From: ed-kung Date: Thu, 19 Jun 2025 23:58:33 -0700 Subject: [PATCH 10/11] fix cursor detected bugs --- components/carousel.js | 2 +- components/item-full.js | 2 +- components/media-or-link.js | 2 +- components/text.js | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/components/carousel.js b/components/carousel.js index c4b6a4aee..7fae976e7 100644 --- a/components/carousel.js +++ b/components/carousel.js @@ -121,7 +121,7 @@ export function CarouselProvider ({ children }) { }) }, [showModal, media.current]) - const addMedia = useCallback(({ src, originalSrc, rel, itemId, imgIndex }) => { + const addMedia = useCallback(({ src, originalSrc, rel, itemId, imgIndex = 0 }) => { const items = itemArray.current const itemOrder = items.has(itemId) ? items.get(itemId).itemOrder : 0 const sortKey = itemOrder * 100 + imgIndex diff --git a/components/item-full.js b/components/item-full.js index 66ad03927..0590818dd 100644 --- a/components/item-full.js +++ b/components/item-full.js @@ -76,7 +76,7 @@ function ItemEmbed ({ url, imgproxyUrls, itemId }) { srcSet={srcSet} topLevel linkFallback={false} - itemId + itemId={itemId} imgIndex={0} />
diff --git a/components/media-or-link.js b/components/media-or-link.js index f336a03c0..8b97f6d0a 100644 --- a/components/media-or-link.js +++ b/components/media-or-link.js @@ -86,7 +86,7 @@ export default function MediaOrLink ({ linkFallback = true, ...props }) { itemId: props.itemId, imgIndex: props.imgIndex }) - }, [media.image]) + }, [media.image, props.rel, props.itemId, props.imgIndex]) const handleClick = useCallback(() => showCarousel({ src: media.bestResSrc }), [showCarousel, media.bestResSrc]) diff --git a/components/text.js b/components/text.js index e99067f90..552b72416 100644 --- a/components/text.js +++ b/components/text.js @@ -118,7 +118,7 @@ export default memo(function Text ({ rel = UNKNOWN_LINK_REL, imgproxyUrls, child itemId={itemId} /> ) - }, [outlawed, imgproxyUrls, topLevel, rel]) + }, [outlawed, imgproxyUrls, topLevel, rel, itemId]) const components = useMemo(() => ({ h1: ({ node, id, ...props }) =>

, From ea23e5418c4b8f7852491c14a94e1096c8232a57 Mon Sep 17 00:00:00 2001 From: ed-kung Date: Mon, 7 Jul 2025 22:39:33 -0700 Subject: [PATCH 11/11] register media to carousel before image load, confirm afterwards --- components/carousel.js | 40 ++++++++++++++----------------------- components/comment.js | 6 ------ components/item-full.js | 28 ++++++-------------------- components/media-or-link.js | 19 +++++++++--------- components/text.js | 30 +++++----------------------- lib/rehype-sn.js | 16 +-------------- 6 files changed, 37 insertions(+), 102 deletions(-) diff --git a/components/carousel.js b/components/carousel.js index 7fae976e7..39ccd95c8 100644 --- a/components/carousel.js +++ b/components/carousel.js @@ -105,48 +105,38 @@ function CarouselOverflow ({ originalSrc, rel }) { export function CarouselProvider ({ children }) { const media = useRef(new Map()) - const itemArray = useRef(new Map()) - const itemCount = useRef(0) const showModal = useShowModal() const showCarousel = useCallback(({ src }) => { - const sortedMedia = Array.from(media.current.entries()) - .sort(([, a], [, b]) => a.sortKey - b.sortKey) + // only show confirmed entries + const confirmedEntries = Array.from(media.current.entries()) + .filter(([, entry]) => entry.confirmed) showModal((close, setOptions) => { - return + return }, { fullScreen: true, overflow: }) }, [showModal, media.current]) - const addMedia = useCallback(({ src, originalSrc, rel, itemId, imgIndex = 0 }) => { - const items = itemArray.current - const itemOrder = items.has(itemId) ? items.get(itemId).itemOrder : 0 - const sortKey = itemOrder * 100 + imgIndex - media.current.set(src, { src, originalSrc, rel, sortKey }) + const addMedia = useCallback(({ src, originalSrc, rel }) => { + media.current.set(src, { src, originalSrc, rel, confirmed: false }) + }, [media.current]) + + const confirmMedia = useCallback((src) => { + const mediaItem = media.current.get(src) + if (mediaItem) { + mediaItem.confirmed = true + media.current.set(src, mediaItem) + } }, [media.current]) const removeMedia = useCallback((src) => { media.current.delete(src) }, [media.current]) - const addItem = useCallback((itemId) => { - const items = itemArray.current - if (!items.has(itemId)) { - itemCount.current += 1 - items.set(itemId, { itemOrder: itemCount.current }) - } - return items.get(itemId).itemOrder - }, []) - - const value = useMemo(() => ({ - showCarousel, - addMedia, - removeMedia, - addItem - }), [showCarousel, addMedia, removeMedia, addItem]) + const value = useMemo(() => ({ showCarousel, addMedia, confirmMedia, removeMedia }), [showCarousel, addMedia, removeMedia]) return {children} } diff --git a/components/comment.js b/components/comment.js index 8fd8dbbb4..73e64d0c3 100644 --- a/components/comment.js +++ b/components/comment.js @@ -28,7 +28,6 @@ import LinkToContext from './link-to-context' import Boost from './boost-button' import { gql, useApolloClient } from '@apollo/client' import classNames from 'classnames' -import { useCarousel } from './carousel' function Parent ({ item, rootText }) { const root = useRoot() @@ -115,11 +114,6 @@ export default function Comment ({ const { cache } = useApolloClient() - const carousel = useCarousel() - if (carousel) { - carousel.addItem(item.id) - } - useEffect(() => { const comment = cache.readFragment({ id: `Item:${router.query.commentId}`, diff --git a/components/item-full.js b/components/item-full.js index 0590818dd..f1d4d0894 100644 --- a/components/item-full.js +++ b/components/item-full.js @@ -24,7 +24,7 @@ import { numWithUnits } from '@/lib/format' import { useQuoteReply } from './use-quote-reply' import { UNKNOWN_LINK_REL } from '@/lib/constants' import classNames from 'classnames' -import { CarouselProvider, useCarousel } from './carousel' +import { CarouselProvider } from './carousel' import Embed from './embed' import { useRouter } from 'next/router' @@ -34,11 +34,6 @@ function BioItem ({ item, handleClick }) { return null } - const carousel = useCarousel() - if (carousel) { - carousel.addItem(item.id) - } - return ( <> @@ -56,7 +51,7 @@ function BioItem ({ item, handleClick }) { ) } -function ItemEmbed ({ url, imgproxyUrls, itemId }) { +function ItemEmbed ({ url, imgproxyUrls }) { const provider = parseEmbedUrl(url) if (provider) { return ( @@ -71,14 +66,7 @@ function ItemEmbed ({ url, imgproxyUrls, itemId }) { const srcSet = imgproxyUrls?.[url] return (
- +
) } @@ -106,11 +94,6 @@ function TopLevelItem ({ item, noReply, ...props }) { const ItemComponent = item.isJob ? ItemJob : Item const { ref: textRef, quote, quoteReply, cancelQuote } = useQuoteReply({ text: item.text }) - const carousel = useCarousel() - if (carousel) { - carousel.addItem(item.id) - } - return (
{item.text && } - {item.url && !item.outlawed && } + {item.url && !item.outlawed && } {item.poll && } {item.bounty &&
@@ -182,8 +165,9 @@ export default function ItemFull ({ item, fetchMoreComments, bio, rank, ...props useEffect(() => { commentsViewed(item) }, [item.lastCommentAt]) + const router = useRouter() - const carouselKey = `${item.id}--${router.query.sort || 'default'}` + const carouselKey = `${item.id}-${router.query?.sort || 'default'}` return ( <> diff --git a/components/media-or-link.js b/components/media-or-link.js index 8b97f6d0a..43f26d401 100644 --- a/components/media-or-link.js +++ b/components/media-or-link.js @@ -75,18 +75,19 @@ const Media = memo(function Media ({ export default function MediaOrLink ({ linkFallback = true, ...props }) { const media = useMediaHelper(props) const [error, setError] = useState(false) - const { showCarousel, addMedia, removeMedia } = useCarousel() + const { showCarousel, addMedia, confirmMedia, removeMedia } = useCarousel() + // register placeholder immediately on mount if we have a src + useEffect(() => { + if (!media.bestResSrc) return + addMedia({ src: media.bestResSrc, originalSrc: media.originalSrc, rel: props.rel }) + }, [media.bestResSrc]) + + // confirm media for carousel based on image detection useEffect(() => { if (!media.image) return - addMedia({ - src: media.bestResSrc, - originalSrc: media.originalSrc, - rel: props.rel, - itemId: props.itemId, - imgIndex: props.imgIndex - }) - }, [media.image, props.rel, props.itemId, props.imgIndex]) + confirmMedia(media.bestResSrc) + }, [media.image, media.bestResSrc]) const handleClick = useCallback(() => showCarousel({ src: media.bestResSrc }), [showCarousel, media.bestResSrc]) diff --git a/components/text.js b/components/text.js index 552b72416..654fa3caf 100644 --- a/components/text.js +++ b/components/text.js @@ -108,17 +108,9 @@ export default memo(function Text ({ rel = UNKNOWN_LINK_REL, imgproxyUrls, child }, [containerRef.current, setOverflowing]) const TextMediaOrLink = useCallback(props => { - return ( - - ) - }, [outlawed, imgproxyUrls, topLevel, rel, itemId]) + return + }, + [outlawed, imgproxyUrls, topLevel, rel]) const components = useMemo(() => ({ h1: ({ node, id, ...props }) =>

, @@ -150,9 +142,6 @@ export default memo(function Text ({ rel = UNKNOWN_LINK_REL, imgproxyUrls, child }), [outlawed, rel, TextMediaOrLink, topLevel]) const carousel = useCarousel() - if (carousel) { - carousel.addItem(itemId) - } const markdownContent = useMemo(() => ( - ) + return } function Table ({ node, ...props }) { diff --git a/lib/rehype-sn.js b/lib/rehype-sn.js index d012f8da4..bed7e8f42 100644 --- a/lib/rehype-sn.js +++ b/lib/rehype-sn.js @@ -14,8 +14,6 @@ export default function rehypeSN (options = {}) { const { stylers = [] } = options return function transformer (tree) { - let imgIndex = 0 - try { visit(tree, (node, index, parent) => { if (parent?.tagName === 'code') { @@ -23,11 +21,6 @@ export default function rehypeSN (options = {}) { return } - // If node is img, increment and assign imgIndex - if (node.tagName === 'img') { - node.properties.imgIndex ??= ++imgIndex - } - // Handle inline code property if (node.tagName === 'code') { node.properties.inline = !(parent && parent.tagName === 'pre') @@ -90,8 +83,6 @@ export default function rehypeSN (options = {}) { node.properties = { ...embed, src: node.properties.href } } else { node.tagName = 'autolink' - // since autolinks could be an image, increment imgIndex - node.properties.imgIndex ??= ++imgIndex } } @@ -218,10 +209,6 @@ export default function rehypeSN (options = {}) { const allImages = adjacentNodes.flatMap(n => n.tagName === 'img' ? [n] : (Array.isArray(n.children) ? n.children.filter(child => child.tagName === 'img') : []) ) - // increment imgIndex for each of the images - allImages.forEach(n => { - n.properties.imgIndex ??= ++imgIndex - }) const collageNode = { type: 'element', tagName: 'p', @@ -247,8 +234,7 @@ export default function rehypeSN (options = {}) { node.children.every(child => (child.tagName === 'img') || (child.type === 'text' && typeof child.value === 'string' && !child.value.trim()) - ) && - node.children.some(child => child.tagName === 'img') + ) } function replaceMention (value, username) {