Order carousel as images appear in items / markdown (#2239)
* carousel sort in deterministic order * imgIndex 0 for ItemEmbed * fix order for item-full * fix indexing in ItemEmbed * Revert "fix indexing in ItemEmbed" This reverts commit f7863af30a1a02b189bfc79237606851c4da1abf. * Revert "fix order for item-full" This reverts commit 489e25ea82056bd83a818e581eb2bbfcf947e401. * Revert "imgIndex 0 for ItemEmbed" This reverts commit cd5fff1bae151e44db717f2a2173f673793bc6d0. * carousel preserves ordering rendered on screen * reorder carousel when sort changes * fix cursor detected bugs * register media to carousel before image load, confirm afterwards * Remove unnecessary ref from dependencies * Add missing dependencies * Add missing dependencies * Check if src was found in Carousel --------- Co-authored-by: ekzyis <ek@stacker.news>
This commit is contained in:
parent
af77985b38
commit
97cbfec38e
@ -56,8 +56,9 @@ function useArrowKeys ({ moveLeft, moveRight }) {
|
|||||||
function Carousel ({ close, mediaArr, src, setOptions }) {
|
function Carousel ({ close, mediaArr, src, setOptions }) {
|
||||||
const [index, setIndex] = useState(mediaArr.findIndex(([key]) => key === src))
|
const [index, setIndex] = useState(mediaArr.findIndex(([key]) => key === src))
|
||||||
const [currentSrc, canGoLeft, canGoRight] = useMemo(() => {
|
const [currentSrc, canGoLeft, canGoRight] = useMemo(() => {
|
||||||
|
if (index === -1) return [src, false, false]
|
||||||
return [mediaArr[index][0], index > 0, index < mediaArr.length - 1]
|
return [mediaArr[index][0], index > 0, index < mediaArr.length - 1]
|
||||||
}, [mediaArr, index])
|
}, [src, mediaArr, index])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (index === -1) return
|
if (index === -1) return
|
||||||
@ -115,8 +116,12 @@ export function CarouselProvider ({ children }) {
|
|||||||
const showModal = useShowModal()
|
const showModal = useShowModal()
|
||||||
|
|
||||||
const showCarousel = useCallback(({ src }) => {
|
const showCarousel = useCallback(({ src }) => {
|
||||||
|
// only show confirmed entries
|
||||||
|
const confirmedEntries = Array.from(media.current.entries())
|
||||||
|
.filter(([, entry]) => entry.confirmed)
|
||||||
|
|
||||||
showModal((close, setOptions) => {
|
showModal((close, setOptions) => {
|
||||||
return <Carousel close={close} mediaArr={Array.from(media.current.entries())} src={src} setOptions={setOptions} />
|
return <Carousel close={close} mediaArr={confirmedEntries} src={src} setOptions={setOptions} />
|
||||||
}, {
|
}, {
|
||||||
fullScreen: true,
|
fullScreen: true,
|
||||||
overflow: <CarouselOverflow {...media.current.get(src)} />
|
overflow: <CarouselOverflow {...media.current.get(src)} />
|
||||||
@ -124,14 +129,25 @@ export function CarouselProvider ({ children }) {
|
|||||||
}, [showModal])
|
}, [showModal])
|
||||||
|
|
||||||
const addMedia = useCallback(({ src, originalSrc, rel }) => {
|
const addMedia = useCallback(({ src, originalSrc, rel }) => {
|
||||||
media.current.set(src, { src, originalSrc, rel })
|
media.current.set(src, { src, originalSrc, rel, confirmed: false })
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
const confirmMedia = useCallback((src) => {
|
||||||
|
const mediaItem = media.current.get(src)
|
||||||
|
if (mediaItem) {
|
||||||
|
mediaItem.confirmed = true
|
||||||
|
media.current.set(src, mediaItem)
|
||||||
|
}
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
const removeMedia = useCallback((src) => {
|
const removeMedia = useCallback((src) => {
|
||||||
media.current.delete(src)
|
media.current.delete(src)
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
const value = useMemo(() => ({ showCarousel, addMedia, removeMedia }), [showCarousel, addMedia, removeMedia])
|
const value = useMemo(
|
||||||
|
() => ({ showCarousel, addMedia, confirmMedia, removeMedia }),
|
||||||
|
[showCarousel, addMedia, confirmMedia, removeMedia]
|
||||||
|
)
|
||||||
return <CarouselContext.Provider value={value}>{children}</CarouselContext.Provider>
|
return <CarouselContext.Provider value={value}>{children}</CarouselContext.Provider>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -26,6 +26,7 @@ import { UNKNOWN_LINK_REL } from '@/lib/constants'
|
|||||||
import classNames from 'classnames'
|
import classNames from 'classnames'
|
||||||
import { CarouselProvider } from './carousel'
|
import { CarouselProvider } from './carousel'
|
||||||
import Embed from './embed'
|
import Embed from './embed'
|
||||||
|
import { useRouter } from 'next/router'
|
||||||
|
|
||||||
function BioItem ({ item, handleClick }) {
|
function BioItem ({ item, handleClick }) {
|
||||||
const { me } = useMe()
|
const { me } = useMe()
|
||||||
@ -165,6 +166,9 @@ export default function ItemFull ({ item, fetchMoreComments, bio, rank, ...props
|
|||||||
commentsViewed(item)
|
commentsViewed(item)
|
||||||
}, [item.lastCommentAt])
|
}, [item.lastCommentAt])
|
||||||
|
|
||||||
|
const router = useRouter()
|
||||||
|
const carouselKey = `${item.id}-${router.query?.sort || 'default'}`
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{rank
|
{rank
|
||||||
@ -174,7 +178,7 @@ export default function ItemFull ({ item, fetchMoreComments, bio, rank, ...props
|
|||||||
</div>)
|
</div>)
|
||||||
: <div />}
|
: <div />}
|
||||||
<RootProvider root={item.root || item}>
|
<RootProvider root={item.root || item}>
|
||||||
<CarouselProvider key={item.id}>
|
<CarouselProvider key={carouselKey}>
|
||||||
{item.parentId
|
{item.parentId
|
||||||
? <Comment topLevel item={item} replyOpen includeParent noComments {...props} />
|
? <Comment topLevel item={item} replyOpen includeParent noComments {...props} />
|
||||||
: (
|
: (
|
||||||
|
@ -75,12 +75,19 @@ const Media = memo(function Media ({
|
|||||||
export default function MediaOrLink ({ linkFallback = true, ...props }) {
|
export default function MediaOrLink ({ linkFallback = true, ...props }) {
|
||||||
const media = useMediaHelper(props)
|
const media = useMediaHelper(props)
|
||||||
const [error, setError] = useState(false)
|
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 })
|
||||||
|
}, [addMedia, media.bestResSrc, media.originalSrc, props.rel])
|
||||||
|
|
||||||
|
// confirm media for carousel based on image detection
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!media.image) return
|
if (!media.image) return
|
||||||
addMedia({ src: media.bestResSrc, originalSrc: media.originalSrc, rel: props.rel })
|
confirmMedia(media.bestResSrc)
|
||||||
}, [media.image])
|
}, [confirmMedia, media.image, media.bestResSrc])
|
||||||
|
|
||||||
const handleClick = useCallback(() => showCarousel({ src: media.bestResSrc }),
|
const handleClick = useCallback(() => showCarousel({ src: media.bestResSrc }),
|
||||||
[showCarousel, media.bestResSrc])
|
[showCarousel, media.bestResSrc])
|
||||||
|
Loading…
x
Reference in New Issue
Block a user