mirror of
https://github.com/bitsocialnet/5chan.git
synced 2026-08-03 07:41:04 +02:00
refactor: rename PostPage to Post, export Post component from Post view
This commit is contained in:
@@ -0,0 +1 @@
|
||||
export { default } from './reply-quote-preview';
|
||||
@@ -0,0 +1,252 @@
|
||||
import { useEffect, useRef, useState } from 'react';
|
||||
import { createPortal } from 'react-dom';
|
||||
import { Link } from 'react-router-dom';
|
||||
import { Comment, useAccount } from '@plebbit/plebbit-react-hooks';
|
||||
import { useFloating, offset, shift, size, autoUpdate, Placement } from '@floating-ui/react';
|
||||
import useIsMobile from '../../hooks/use-is-mobile';
|
||||
import styles from '../../views/post/post.module.css';
|
||||
import { Post } from '../../views/post';
|
||||
|
||||
interface ReplyQuotePreviewProps {
|
||||
isBacklinkReply?: boolean;
|
||||
backlinkReply?: Comment;
|
||||
isQuotelinkReply?: boolean;
|
||||
quotelinkReply?: Comment;
|
||||
}
|
||||
|
||||
const handleQuoteHover = (cid: string, onElementOutOfView: () => void) => {
|
||||
const targetElement = document.getElementById(cid);
|
||||
|
||||
if (!targetElement) return;
|
||||
|
||||
const isInViewport = (element: HTMLElement) => {
|
||||
const bounding = element.getBoundingClientRect();
|
||||
return (
|
||||
bounding.top >= 0 &&
|
||||
bounding.left >= 0 &&
|
||||
bounding.bottom <= (window.innerHeight || document.documentElement.clientHeight) &&
|
||||
bounding.right <= (window.innerWidth || document.documentElement.clientWidth)
|
||||
);
|
||||
};
|
||||
|
||||
if (isInViewport(targetElement)) {
|
||||
targetElement.classList.add('highlight');
|
||||
} else {
|
||||
targetElement.classList.remove('highlight');
|
||||
onElementOutOfView();
|
||||
}
|
||||
};
|
||||
|
||||
const DesktopQuotePreview = ({ backlinkReply, quotelinkReply, isBacklinkReply, isQuotelinkReply }: ReplyQuotePreviewProps) => {
|
||||
const [hoveredCid, setHoveredCid] = useState<string | null>(null);
|
||||
const [outOfViewCid, setOutOfViewCid] = useState<string | null>(null);
|
||||
const placementRef = useRef<Placement>('right');
|
||||
const availableWidthRef = useRef<number>(0);
|
||||
|
||||
const { refs, floatingStyles, update } = useFloating({
|
||||
placement: placementRef.current,
|
||||
middleware: [
|
||||
shift({ padding: 10 }),
|
||||
offset({ mainAxis: placementRef.current === 'right' ? 8 : 4 }),
|
||||
size({
|
||||
apply({ availableWidth, elements }) {
|
||||
availableWidthRef.current = availableWidth;
|
||||
if (availableWidth >= 250) {
|
||||
elements.floating.style.maxWidth = `${availableWidth - 12}px`;
|
||||
} else if (placementRef.current === 'right') {
|
||||
placementRef.current = 'left';
|
||||
}
|
||||
},
|
||||
}),
|
||||
],
|
||||
whileElementsMounted: autoUpdate,
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
const handleResize = () => {
|
||||
const availableWidth = availableWidthRef.current;
|
||||
if (availableWidth >= 250) {
|
||||
placementRef.current = 'right';
|
||||
} else {
|
||||
placementRef.current = 'left';
|
||||
}
|
||||
update();
|
||||
};
|
||||
|
||||
window.addEventListener('resize', handleResize);
|
||||
return () => {
|
||||
window.removeEventListener('resize', handleResize);
|
||||
};
|
||||
}, [update]);
|
||||
|
||||
const handleMouseOver = (cid: string | undefined) => {
|
||||
if (!cid) return;
|
||||
|
||||
handleQuoteHover(cid, () => setOutOfViewCid(cid));
|
||||
setHoveredCid(cid);
|
||||
};
|
||||
|
||||
const handleMouseLeave = (cid: string | null) => {
|
||||
if (cid) {
|
||||
const targetElement = document.getElementById(cid);
|
||||
if (targetElement) {
|
||||
targetElement.classList.remove('highlight');
|
||||
}
|
||||
}
|
||||
setHoveredCid(null);
|
||||
setOutOfViewCid(null);
|
||||
};
|
||||
|
||||
const replyBacklink = (
|
||||
<>
|
||||
<Link
|
||||
className={styles.backlink}
|
||||
to={`/p/${backlinkReply?.subplebbitAddress}/c/${backlinkReply?.cid}`}
|
||||
ref={refs.setReference}
|
||||
onMouseOver={() => handleMouseOver(backlinkReply?.cid)}
|
||||
onMouseLeave={() => handleMouseLeave(backlinkReply?.cid)}
|
||||
>
|
||||
c/{backlinkReply?.shortCid}
|
||||
</Link>
|
||||
{hoveredCid === backlinkReply?.cid &&
|
||||
outOfViewCid === backlinkReply?.cid &&
|
||||
createPortal(
|
||||
<div className={styles.replyQuotePreview} ref={refs.setFloating} style={floatingStyles}>
|
||||
<Post post={backlinkReply} showReplies={false} />
|
||||
</div>,
|
||||
document.body,
|
||||
)}
|
||||
</>
|
||||
);
|
||||
|
||||
const account = useAccount();
|
||||
|
||||
const replyQuotelink = (
|
||||
<>
|
||||
<Link
|
||||
to={`/p/${quotelinkReply?.subplebbitAddress}/c/${quotelinkReply?.cid}`}
|
||||
ref={refs.setReference}
|
||||
className={styles.quoteLink}
|
||||
onMouseOver={() => handleMouseOver(quotelinkReply?.cid)}
|
||||
onMouseLeave={() => handleMouseLeave(quotelinkReply?.cid)}
|
||||
>
|
||||
{`c/${quotelinkReply?.shortCid}`}
|
||||
{quotelinkReply?.author?.address === account?.author?.address && ' (You)'}
|
||||
</Link>
|
||||
<br />
|
||||
{hoveredCid === quotelinkReply?.cid &&
|
||||
outOfViewCid === quotelinkReply?.cid &&
|
||||
createPortal(
|
||||
<div className={styles.replyQuotePreview} ref={refs.setFloating} style={floatingStyles}>
|
||||
<Post post={quotelinkReply} showReplies={false} />
|
||||
</div>,
|
||||
document.body,
|
||||
)}
|
||||
</>
|
||||
);
|
||||
|
||||
return isBacklinkReply ? replyBacklink : isQuotelinkReply && replyQuotelink;
|
||||
};
|
||||
|
||||
const MobileQuotePreview = ({ backlinkReply, quotelinkReply, isBacklinkReply, isQuotelinkReply }: ReplyQuotePreviewProps) => {
|
||||
const [hoveredCid, setHoveredCid] = useState<string | null>(null);
|
||||
const [outOfViewCid, setOutOfViewCid] = useState<string | null>(null);
|
||||
|
||||
const { refs, floatingStyles, update } = useFloating({
|
||||
placement: 'bottom',
|
||||
middleware: [shift({ padding: isBacklinkReply ? 5 : 10 })],
|
||||
whileElementsMounted: autoUpdate,
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
window.addEventListener('resize', () => update());
|
||||
return () => {
|
||||
window.removeEventListener('resize', () => update());
|
||||
};
|
||||
}, [update]);
|
||||
|
||||
const handleMouseOver = (cid: string | undefined) => {
|
||||
if (!cid) return;
|
||||
|
||||
handleQuoteHover(cid, () => setOutOfViewCid(cid));
|
||||
setHoveredCid(cid);
|
||||
};
|
||||
|
||||
const handleMouseLeave = (cid: string | null) => {
|
||||
if (cid) {
|
||||
const targetElement = document.getElementById(cid);
|
||||
if (targetElement) {
|
||||
targetElement.classList.remove('highlight');
|
||||
}
|
||||
}
|
||||
setHoveredCid(null);
|
||||
setOutOfViewCid(null);
|
||||
};
|
||||
|
||||
const replyBacklink = (
|
||||
<>
|
||||
<span
|
||||
className={styles.backlink}
|
||||
ref={refs.setReference}
|
||||
onMouseOver={() => handleMouseOver(backlinkReply?.cid)}
|
||||
onMouseLeave={() => handleMouseLeave(backlinkReply?.cid)}
|
||||
>
|
||||
c/{backlinkReply?.shortCid}{' '}
|
||||
</span>
|
||||
<Link to={`/p/${backlinkReply?.subplebbitAddress}/c/${backlinkReply?.cid}`} className={styles.backlinkHash}>
|
||||
#
|
||||
</Link>
|
||||
{hoveredCid === backlinkReply?.cid &&
|
||||
outOfViewCid === backlinkReply?.cid &&
|
||||
createPortal(
|
||||
<div className={styles.replyQuotePreview} ref={refs.setFloating} style={floatingStyles}>
|
||||
<Post post={backlinkReply} showReplies={false} />
|
||||
</div>,
|
||||
document.body,
|
||||
)}
|
||||
</>
|
||||
);
|
||||
|
||||
const account = useAccount();
|
||||
|
||||
const replyQuotelink = (
|
||||
<>
|
||||
<span
|
||||
ref={refs.setReference}
|
||||
className={styles.quoteLink}
|
||||
onMouseOver={() => handleMouseOver(quotelinkReply?.cid)}
|
||||
onMouseLeave={() => handleMouseLeave(quotelinkReply?.cid)}
|
||||
>
|
||||
c/{quotelinkReply?.shortCid}
|
||||
{quotelinkReply?.author?.address === account?.author?.address && ' (You)'}
|
||||
</span>
|
||||
<Link className={styles.quoteLink} to={`/p/${quotelinkReply?.subplebbitAddress}/c/${quotelinkReply?.cid}`}>
|
||||
{' '}
|
||||
#
|
||||
</Link>
|
||||
<br />
|
||||
{hoveredCid === quotelinkReply?.cid &&
|
||||
outOfViewCid === quotelinkReply?.cid &&
|
||||
createPortal(
|
||||
<div className={styles.replyQuotePreview} ref={refs.setFloating} style={floatingStyles}>
|
||||
<Post post={quotelinkReply} showReplies={false} />
|
||||
</div>,
|
||||
document.body,
|
||||
)}
|
||||
</>
|
||||
);
|
||||
|
||||
return isBacklinkReply ? replyBacklink : isQuotelinkReply && replyQuotelink;
|
||||
};
|
||||
|
||||
const ReplyQuotePreview = ({ backlinkReply, quotelinkReply, isBacklinkReply, isQuotelinkReply }: ReplyQuotePreviewProps) => {
|
||||
const isMobile = useIsMobile();
|
||||
|
||||
return isMobile ? (
|
||||
<MobileQuotePreview backlinkReply={backlinkReply} quotelinkReply={quotelinkReply} isBacklinkReply={isBacklinkReply} isQuotelinkReply={isQuotelinkReply} />
|
||||
) : (
|
||||
<DesktopQuotePreview backlinkReply={backlinkReply} quotelinkReply={quotelinkReply} isBacklinkReply={isBacklinkReply} isQuotelinkReply={isQuotelinkReply} />
|
||||
);
|
||||
};
|
||||
|
||||
export default ReplyQuotePreview;
|
||||
Reference in New Issue
Block a user