pl-fe: trying to fix the media modal stuff, i hate webdev
Signed-off-by: nicole mikołajczyk <git@mkljczk.pl>
This commit is contained in:
@ -217,7 +217,7 @@ const ModalRoot: React.FC<IModalRoot> = ({ children, onCancel, onClose, type, mo
|
||||
|
||||
<div
|
||||
role='dialog'
|
||||
className='⁂-modal-root__modal'
|
||||
className='⁂-modal-root__container'
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
|
||||
@ -85,7 +85,7 @@ const ModalRoot: React.FC = () => {
|
||||
<Base onClose={onClickClose} type={type} modalIndex={index}>
|
||||
{(Component && !!type) && (
|
||||
<Suspense fallback={renderLoading(type)}>
|
||||
<Component {...props} onClose={onClickClose} />
|
||||
<Component key={index} {...props} onClose={onClickClose} />
|
||||
</Suspense>
|
||||
)}
|
||||
</Base>
|
||||
|
||||
@ -12,7 +12,6 @@ import StatusActionBar from 'pl-fe/components/status-action-bar';
|
||||
import HStack from 'pl-fe/components/ui/hstack';
|
||||
import Icon from 'pl-fe/components/ui/icon';
|
||||
import IconButton from 'pl-fe/components/ui/icon-button';
|
||||
import Stack from 'pl-fe/components/ui/stack';
|
||||
import Audio from 'pl-fe/features/audio';
|
||||
import PlaceholderStatus from 'pl-fe/features/placeholder/components/placeholder-status';
|
||||
import Thread from 'pl-fe/features/status/components/thread';
|
||||
@ -179,7 +178,7 @@ const MediaModal: React.FC<MediaModalProps & BaseModalProps> = (props) => {
|
||||
setZoomedIn((prev) => !prev);
|
||||
}, []);
|
||||
|
||||
const content = useMemo(() => media.map((attachment, i) => {
|
||||
const content = useMemo(() => media.map((attachment, idx) => {
|
||||
let width: number | undefined, height: number | undefined;
|
||||
if (attachment.type === 'image' || attachment.type === 'gifv' || attachment.type === 'video') {
|
||||
width = (attachment.meta?.original?.width);
|
||||
@ -195,18 +194,18 @@ const MediaModal: React.FC<MediaModalProps & BaseModalProps> = (props) => {
|
||||
if (attachment.type === 'image') {
|
||||
return (
|
||||
<ZoomableImage
|
||||
blurhash={attachment.blurhash || undefined}
|
||||
src={attachment.url}
|
||||
blurhash={attachment.blurhash || undefined}
|
||||
width={width!}
|
||||
height={height!}
|
||||
alt={attachment.description}
|
||||
key={attachment.url}
|
||||
lang={props.lang}
|
||||
key={attachment.url}
|
||||
onClick={toggleNavigation}
|
||||
onDoubleClick={handleZoomClick}
|
||||
onClose={onClose}
|
||||
onZoomChange={setZoomedIn}
|
||||
zoomedIn={zoomedIn && i === index}
|
||||
zoomedIn={zoomedIn && idx === index}
|
||||
/>
|
||||
);
|
||||
} else if (attachment.type === 'video') {
|
||||
@ -219,7 +218,7 @@ const MediaModal: React.FC<MediaModalProps & BaseModalProps> = (props) => {
|
||||
height={height}
|
||||
startTime={time}
|
||||
detailed
|
||||
autoFocus={i === index}
|
||||
autoFocus={idx === index}
|
||||
link={link}
|
||||
alt={attachment.description}
|
||||
key={attachment.url}
|
||||
@ -293,27 +292,27 @@ const MediaModal: React.FC<MediaModalProps & BaseModalProps> = (props) => {
|
||||
};
|
||||
|
||||
return (
|
||||
<div className='⁂-media-modal media-modal pointer-events-auto fixed inset-0 z-[9999] h-full bg-gray-900/90'>
|
||||
<div className={clsx('⁂-media-modal', { '⁂-media-modal--fullscreen': isFullScreen })} role='presentation'>
|
||||
<div
|
||||
className='absolute inset-0'
|
||||
role='presentation'
|
||||
{...bind()}
|
||||
onClick={handleClickOutside}
|
||||
className='⁂-media-modal__content'
|
||||
ref={handleRef}
|
||||
>
|
||||
<Stack
|
||||
{...bind()}
|
||||
onClick={handleClickOutside}
|
||||
className={
|
||||
clsx('⁂-media-modal__content fixed inset-0 h-full grow touch-pan-y transition-all', {
|
||||
'xl:pr-96': !isFullScreen,
|
||||
'xl:pr-0': isFullScreen,
|
||||
})
|
||||
}
|
||||
justifyContent='between'
|
||||
ref={handleRef}
|
||||
<animated.div
|
||||
style={wrapperStyles}
|
||||
className='⁂-media-modal__closer'
|
||||
role='presentation'
|
||||
onClick={() => onClose()}
|
||||
>
|
||||
{content}
|
||||
</animated.div>
|
||||
|
||||
<div className='⁂-media-modal__navigation'>
|
||||
<HStack
|
||||
alignItems='center'
|
||||
justifyContent='between'
|
||||
className={clsx('flex-[0_0_60px] p-4 transition-opacity', navigationHiddenClassName)}
|
||||
className={clsx('pointer-events-auto z-10 flex-[0_0_60px] p-4 transition-opacity', navigationHiddenClassName)}
|
||||
>
|
||||
<IconButton
|
||||
title={intl.formatMessage(messages.close)}
|
||||
@ -357,13 +356,9 @@ const MediaModal: React.FC<MediaModalProps & BaseModalProps> = (props) => {
|
||||
)}
|
||||
</HStack>
|
||||
</HStack>
|
||||
|
||||
{/* Height based on height of top/bottom bars */}
|
||||
<div
|
||||
className='relative h-[calc(100vh-120px)] w-full grow'
|
||||
>
|
||||
{hasMultipleImages && (
|
||||
<div className={clsx('absolute left-5 top-[calc(50%-0.625rem)] z-10 flex h-fit items-center transition-opacity', navigationHiddenClassName)}>
|
||||
{hasMultipleImages && (
|
||||
<HStack className='z-10 mx-5' justifyContent='between'>
|
||||
<div className={clsx('pointer-events-auto z-10 flex h-fit items-center transition-opacity', navigationHiddenClassName)}>
|
||||
<button
|
||||
tabIndex={0}
|
||||
className='flex size-10 items-center justify-center rounded-full bg-gray-900 text-white'
|
||||
@ -373,19 +368,7 @@ const MediaModal: React.FC<MediaModalProps & BaseModalProps> = (props) => {
|
||||
<Icon src={require('@phosphor-icons/core/regular/arrow-left.svg')} className='size-5' />
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<animated.div
|
||||
style={wrapperStyles}
|
||||
className='media-modal__closer'
|
||||
role='presentation'
|
||||
onClick={() => onClose()}
|
||||
>
|
||||
{content}
|
||||
</animated.div>
|
||||
|
||||
{hasMultipleImages && (
|
||||
<div className={clsx('absolute right-5 top-[calc(50%-0.625rem)] z-10 flex h-fit items-center transition-opacity', navigationHiddenClassName)}>
|
||||
<div className={clsx('pointer-events-auto z-10 flex h-fit items-center transition-opacity', navigationHiddenClassName)}>
|
||||
<button
|
||||
tabIndex={0}
|
||||
className='flex size-10 items-center justify-center rounded-full bg-gray-900 text-white'
|
||||
@ -395,13 +378,12 @@ const MediaModal: React.FC<MediaModalProps & BaseModalProps> = (props) => {
|
||||
<Icon src={require('@phosphor-icons/core/regular/arrow-right.svg')} className='size-5' />
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{status && (
|
||||
</HStack>
|
||||
)}
|
||||
{status ? (
|
||||
<HStack
|
||||
justifyContent='center'
|
||||
className={clsx('flex-[0_0_60px] transition-opacity', navigationHiddenClassName)}
|
||||
className={clsx('pointer-events-auto flex-[0_0_60px] transition-opacity', navigationHiddenClassName)}
|
||||
>
|
||||
<StatusActionBar
|
||||
status={status}
|
||||
@ -409,26 +391,26 @@ const MediaModal: React.FC<MediaModalProps & BaseModalProps> = (props) => {
|
||||
expandable
|
||||
/>
|
||||
</HStack>
|
||||
)}
|
||||
</Stack>
|
||||
|
||||
{status && (
|
||||
<div
|
||||
className={
|
||||
clsx('-right-96 hidden bg-white transition-all xl:fixed xl:inset-y-0 xl:right-0 xl:flex xl:w-96 xl:flex-col', {
|
||||
'xl:!-right-96': isFullScreen,
|
||||
})
|
||||
}
|
||||
>
|
||||
<Thread
|
||||
status={status}
|
||||
withMedia={false}
|
||||
itemClassName='px-4'
|
||||
isModal
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
) : <span />}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{status && (
|
||||
<div
|
||||
className={
|
||||
clsx('-right-96 hidden bg-white transition-all xl:fixed xl:inset-y-0 xl:right-0 xl:flex xl:w-96 xl:flex-col', {
|
||||
'xl:!-right-96': isFullScreen,
|
||||
})
|
||||
}
|
||||
>
|
||||
<Thread
|
||||
status={status}
|
||||
withMedia={false}
|
||||
itemClassName='px-4'
|
||||
isModal
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@ -1,6 +1,4 @@
|
||||
.media-modal {
|
||||
touch-action: pan-y;
|
||||
|
||||
.⁂-media-modal {
|
||||
.audio-player.detailed,
|
||||
.extended-video-player {
|
||||
@apply flex items-center justify-center;
|
||||
@ -17,23 +15,4 @@
|
||||
@apply max-w-full max-h-[80%];
|
||||
}
|
||||
}
|
||||
|
||||
&__closer {
|
||||
display: flex;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
inset-inline-start: 0;
|
||||
inset-inline-end: 0;
|
||||
bottom: 0;
|
||||
|
||||
> div {
|
||||
flex-shrink: 0;
|
||||
overflow: auto;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -152,7 +152,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
.⁂-modal-root__modal .⁂-compose-form__select-buttons {
|
||||
.⁂-modal-root__container .⁂-compose-form__select-buttons {
|
||||
padding-top: 0.25rem;
|
||||
}
|
||||
|
||||
|
||||
@ -270,25 +270,38 @@ body {
|
||||
@apply fixed inset-0 bg-gray-500/90 black:bg-gray-900/90 dark:bg-gray-700/90;
|
||||
}
|
||||
|
||||
&__modal {
|
||||
@apply mx-auto relative pointer-events-none flex items-center;
|
||||
min-height: calc(min(100vh - 3.5rem, 100dvh));
|
||||
&__container {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
inset-inline-start: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
align-content: space-around;
|
||||
pointer-events: none;
|
||||
user-select: none;
|
||||
overscroll-behavior: none;
|
||||
min-height: 100dvh;
|
||||
z-index: 9999;
|
||||
}
|
||||
|
||||
&[data-modal-type='DROPDOWN_MENU'] &__overlay {
|
||||
@apply opacity-60;
|
||||
}
|
||||
|
||||
&[data-modal-type='MEDIA'], &[data-modal-type='DROPDOWN_MENU'] {
|
||||
.⁂-modal-root__modal {
|
||||
&[data-modal-type='DROPDOWN_MENU'] {
|
||||
.⁂-modal-root__container {
|
||||
margin-top: 0!important;
|
||||
margin-bottom: 0!important;
|
||||
}
|
||||
}
|
||||
|
||||
&:not([data-modal-type='MEDIA']) &__modal {
|
||||
&:not([data-modal-type='MEDIA']) &__container {
|
||||
display: flex;
|
||||
height: 100%;
|
||||
padding: 0 1rem;
|
||||
@apply md:p-0;
|
||||
}
|
||||
|
||||
@ -1,3 +1,5 @@
|
||||
@use 'variables';
|
||||
|
||||
.⁂-crypto-donate-modal {
|
||||
@apply max-w-sm;
|
||||
}
|
||||
@ -6,6 +8,72 @@
|
||||
@apply max-w-4xl;
|
||||
}
|
||||
|
||||
.⁂-media-modal {
|
||||
pointer-events: auto;
|
||||
user-select: text;
|
||||
display: flex;
|
||||
max-width: 100vw;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
position: relative;
|
||||
touch-action: pan-y;
|
||||
@apply bg-gray-900/90;
|
||||
|
||||
&__content {
|
||||
@apply flex flex-col justify-between fixed inset-0 h-full grow touch-pan-y transition-all xl:pr-96;
|
||||
}
|
||||
|
||||
&__closer {
|
||||
display: flex;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
inset-inline-start: 0;
|
||||
inset-inline-end: 0;
|
||||
bottom: 0;
|
||||
|
||||
@media (min-width: variables.$breakpoint-xl) {
|
||||
inset-inline-end: 24rem;
|
||||
}
|
||||
|
||||
> div {
|
||||
flex-shrink: 0;
|
||||
overflow: auto;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
&__navigation {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
inset-inline-start: 0;
|
||||
inset-inline-end: 0;
|
||||
bottom: 0;
|
||||
pointer-events: none;
|
||||
transition: opacity .3s linear;
|
||||
will-change: opacity;
|
||||
|
||||
&--hidden {
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
|
||||
&--fullscreen {
|
||||
.⁂-media-modal__content {
|
||||
@apply xl:pr-0;
|
||||
}
|
||||
|
||||
.⁂-media-modal__closer {
|
||||
inset-inline-end: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.⁂-zoomable-image {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
|
||||
Reference in New Issue
Block a user