mirror of
https://github.com/bitsocialnet/5chan.git
synced 2026-08-03 07:41:04 +02:00
feat(reply modal): disable draggable on mobile and calculate absolute top position
This commit is contained in:
@@ -57,4 +57,14 @@
|
||||
text-transform: capitalize;
|
||||
float: right;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
@media (max-width: 640px) {
|
||||
.container {
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
.title {
|
||||
cursor: default;
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
import { useEffect, useRef } from 'react';
|
||||
import React, { useEffect, useRef } from 'react';
|
||||
import { useParams } from 'react-router-dom';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import Draggable from 'react-draggable';
|
||||
@@ -6,6 +6,7 @@ import Plebbit from '@plebbit/plebbit-js/dist/browser/index.js';
|
||||
import { useAccount } from '@plebbit/plebbit-react-hooks';
|
||||
import { isValidURL } from '../../lib/utils/url-utils';
|
||||
import useReply from '../../hooks/use-reply';
|
||||
import useWindowWidth from '../../hooks/use-window-width';
|
||||
import styles from './reply-modal.module.css';
|
||||
import _ from 'lodash';
|
||||
|
||||
@@ -48,31 +49,63 @@ const ReplyModal = ({ closeModal, parentCid }: ReplyModalProps) => {
|
||||
}
|
||||
}, [replyIndex, resetContent, closeModal]);
|
||||
|
||||
// react-draggable requires a ref to the modal node
|
||||
const nodeRef = useRef(null);
|
||||
const nodeRef = useRef<HTMLDivElement>(null);
|
||||
const isMobile = useWindowWidth() < 640;
|
||||
|
||||
return (
|
||||
<Draggable handle='.replyModalHandle' nodeRef={nodeRef}>
|
||||
<div className={styles.container} ref={nodeRef}>
|
||||
<div className={`replyModalHandle ${styles.title}`}>
|
||||
Reply to c/{parentCid && Plebbit.getShortCid(parentCid)}
|
||||
<button className={styles.closeIcon} onClick={closeModal} title='close' />
|
||||
</div>
|
||||
<div className={styles.replyForm}>
|
||||
<div className={styles.name}>
|
||||
<input type='text' defaultValue={displayName} placeholder={displayName ? undefined : _.capitalize(t('anonymous'))} />
|
||||
</div>
|
||||
<div className={styles.link}>
|
||||
<input type='text' ref={urlRef} placeholder={_.capitalize(t('link'))} onChange={(e) => setContent.link(e.target.value)} />
|
||||
</div>
|
||||
<div className={styles.content}>
|
||||
<textarea cols={48} rows={4} wrap='soft' ref={textRef} placeholder={_.capitalize(t('comment'))} onChange={(e) => setContent.content(e.target.value)} />
|
||||
</div>
|
||||
<div className={styles.footer}>
|
||||
<button onClick={onPublishReply}>{t('reply')}</button>
|
||||
</div>
|
||||
</div>
|
||||
// on mobile, the position is absolute instead of fixed, so we need to calculate the top position
|
||||
useEffect(() => {
|
||||
if (nodeRef.current && isMobile) {
|
||||
const viewportHeight = window.innerHeight;
|
||||
const scrollY = window.scrollY;
|
||||
const modalHeight = 150;
|
||||
const centeredPosition = scrollY + viewportHeight / 2 - modalHeight / 2;
|
||||
nodeRef.current.style.top = `${centeredPosition}px`;
|
||||
}
|
||||
}, []);
|
||||
|
||||
const ReplyForm = React.memo(() => (
|
||||
<div className={styles.replyForm}>
|
||||
<div className={styles.name}>
|
||||
<input type='text' defaultValue={displayName} placeholder={displayName ? undefined : _.capitalize(t('anonymous'))} />
|
||||
</div>
|
||||
<div className={styles.link}>
|
||||
<input type='text' ref={urlRef} placeholder={_.capitalize(t('link'))} onChange={(e) => setContent.link(e.target.value)} />
|
||||
</div>
|
||||
<div className={styles.content}>
|
||||
<textarea cols={48} rows={4} wrap='soft' ref={textRef} placeholder={_.capitalize(t('comment'))} onChange={(e) => setContent.content(e.target.value)} />
|
||||
</div>
|
||||
<div className={styles.footer}>
|
||||
<button onClick={onPublishReply}>{t('reply')}</button>
|
||||
</div>
|
||||
</div>
|
||||
));
|
||||
|
||||
const ModalTitle = () => (
|
||||
<div className={`replyModalHandle ${styles.title}`}>
|
||||
Reply to c/{parentCid && Plebbit.getShortCid(parentCid)}
|
||||
<button
|
||||
className={styles.closeIcon}
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
closeModal();
|
||||
}}
|
||||
title='close'
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
|
||||
const modalContent = (
|
||||
<div className={styles.container} ref={nodeRef}>
|
||||
<ModalTitle />
|
||||
<ReplyForm />
|
||||
</div>
|
||||
);
|
||||
|
||||
return isMobile ? (
|
||||
modalContent
|
||||
) : (
|
||||
<Draggable handle='.replyModalHandle' nodeRef={nodeRef}>
|
||||
{modalContent}
|
||||
</Draggable>
|
||||
);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user