fix image carousel, still needs a bit of work though
This commit is contained in:
@ -1,6 +1,4 @@
|
||||
import { animated, useSpring } from '@react-spring/web';
|
||||
import { Link } from '@tanstack/react-router';
|
||||
import { useDrag } from '@use-gesture/react';
|
||||
import clsx from 'clsx';
|
||||
import React, { type RefCallback, useCallback, useEffect, useMemo, useState } from 'react';
|
||||
import { defineMessages, useIntl, FormattedMessage } from 'react-intl';
|
||||
@ -26,8 +24,6 @@ import { makeGetStatus } from 'pl-fe/selectors';
|
||||
import type { MediaAttachment } from 'pl-api';
|
||||
import type { BaseModalProps } from 'pl-fe/features/ui/components/modal-root';
|
||||
|
||||
const MIN_SWIPE_DISTANCE = 400;
|
||||
|
||||
const messages = defineMessages({
|
||||
close: { id: 'lightbox.close', defaultMessage: 'Close' },
|
||||
expand: { id: 'lightbox.expand', defaultMessage: 'Expand' },
|
||||
@ -67,12 +63,8 @@ const MediaModal: React.FC<MediaModalProps & BaseModalProps> = (props) => {
|
||||
const [navigationHidden, setNavigationHidden] = useState(false);
|
||||
const [isFullScreen, setIsFullScreen] = useState(!status);
|
||||
|
||||
const [wrapperStyles, api] = useSpring(() => ({
|
||||
x: `-${index * 100}%`,
|
||||
}));
|
||||
|
||||
const handleChangeIndex = useCallback(
|
||||
(newIndex: number, animate = false) => {
|
||||
(newIndex: number) => {
|
||||
if (newIndex < 0) {
|
||||
newIndex = media.length + newIndex;
|
||||
} else if (newIndex >= media.length) {
|
||||
@ -80,17 +72,18 @@ const MediaModal: React.FC<MediaModalProps & BaseModalProps> = (props) => {
|
||||
}
|
||||
setIndex(newIndex);
|
||||
setZoomedIn(false);
|
||||
if (animate) {
|
||||
void api.start({ x: `calc(-${newIndex * 100}% + 0px)` });
|
||||
}
|
||||
},
|
||||
[api, media.length],
|
||||
[media.length],
|
||||
);
|
||||
const handlePrevClick = useCallback(() => {
|
||||
handleChangeIndex(index - 1, true);
|
||||
|
||||
const handlePrevClick = useCallback((e: React.MouseEvent) => {
|
||||
e.stopPropagation();
|
||||
handleChangeIndex(index - 1);
|
||||
}, [handleChangeIndex, index]);
|
||||
const handleNextClick = useCallback(() => {
|
||||
handleChangeIndex(index + 1, true);
|
||||
|
||||
const handleNextClick = useCallback((e: React.MouseEvent) => {
|
||||
e.stopPropagation();
|
||||
handleChangeIndex(index + 1);
|
||||
}, [handleChangeIndex, index]);
|
||||
|
||||
const [viewportDimensions, setViewportDimensions] = useState<{
|
||||
@ -111,44 +104,20 @@ const MediaModal: React.FC<MediaModalProps & BaseModalProps> = (props) => {
|
||||
|
||||
const navigationHiddenClassName = navigationHidden ? 'pointer-events-none opacity-0' : '';
|
||||
|
||||
const handleKeyDown = (e: KeyboardEvent) => {
|
||||
const handleKeyDown = useCallback((e: KeyboardEvent) => {
|
||||
switch (e.key) {
|
||||
case 'ArrowLeft':
|
||||
handlePrevClick();
|
||||
handleChangeIndex(index - 1);
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
break;
|
||||
case 'ArrowRight':
|
||||
handleNextClick();
|
||||
handleChangeIndex(index + 1);
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
const bind = useDrag(
|
||||
({ active, movement: [mx], direction: [xDir], cancel }) => {
|
||||
// Disable swipe when zoomed in.
|
||||
if (zoomedIn) {
|
||||
return;
|
||||
}
|
||||
|
||||
// If dragging and swipe distance is enough, change the index.
|
||||
if (
|
||||
active &&
|
||||
Math.abs(mx) > Math.min(window.innerWidth / 4, MIN_SWIPE_DISTANCE)
|
||||
) {
|
||||
handleChangeIndex(index - xDir);
|
||||
cancel();
|
||||
}
|
||||
// Set the x position via calc to ensure proper centering regardless of screen size.
|
||||
const x = active ? mx : 0;
|
||||
void api.start({
|
||||
x: `calc(-${index * 100}% + ${x}px)`,
|
||||
});
|
||||
},
|
||||
{ pointer: { capture: false } },
|
||||
);
|
||||
}, [handleChangeIndex, index]);
|
||||
|
||||
const handleDownload = () => {
|
||||
const mediaItem = hasMultipleImages ? media[index as number] : media[0];
|
||||
@ -289,10 +258,9 @@ const MediaModal: React.FC<MediaModalProps & BaseModalProps> = (props) => {
|
||||
role='presentation'
|
||||
>
|
||||
<Stack
|
||||
{...bind()}
|
||||
onClick={handleClickOutside}
|
||||
className={
|
||||
clsx('⁂-media-modal__content fixed inset-0 h-full grow touch-pan-y transition-all', {
|
||||
clsx('⁂-media-modal__content fixed inset-0 h-full grow transition-all', {
|
||||
'xl:pr-96': !isFullScreen,
|
||||
'xl:pr-0': isFullScreen,
|
||||
})
|
||||
@ -365,14 +333,18 @@ const MediaModal: React.FC<MediaModalProps & BaseModalProps> = (props) => {
|
||||
</div>
|
||||
)}
|
||||
|
||||
<animated.div
|
||||
style={wrapperStyles}
|
||||
className='media-modal__closer'
|
||||
role='presentation'
|
||||
onClick={() => onClose()}
|
||||
>
|
||||
{content}
|
||||
</animated.div>
|
||||
<div className='absolute inset-0 overflow-hidden'>
|
||||
<div
|
||||
style={{
|
||||
width: `${media.length * 100}%`,
|
||||
transform: `translateX(-${index * (100 / media.length)}%)`,
|
||||
}}
|
||||
className='media-modal__closer transition-transform duration-300 ease-out'
|
||||
role='presentation'
|
||||
>
|
||||
{content}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{hasMultipleImages && (
|
||||
<div className={clsx('absolute inset-y-0 right-5 z-10 flex items-center transition-opacity', navigationHiddenClassName)}>
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
.media-modal {
|
||||
touch-action: pan-y;
|
||||
touch-action: none;
|
||||
|
||||
.audio-player.detailed,
|
||||
.extended-video-player {
|
||||
@ -19,20 +19,21 @@
|
||||
}
|
||||
|
||||
&__closer {
|
||||
display: flex;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
inset-inline-start: 0;
|
||||
inset-inline-end: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
display: flex;
|
||||
flex-wrap: nowrap;
|
||||
height: 100%;
|
||||
|
||||
> div {
|
||||
flex-shrink: 0;
|
||||
overflow: auto;
|
||||
flex: 1 0 0;
|
||||
min-width: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 100%;
|
||||
overflow: hidden;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user