mirror of
https://github.com/bitsocialnet/5chan.git
synced 2026-08-03 07:41:04 +02:00
feat(post menu): add copy link button (share link)
This commit is contained in:
@@ -3,13 +3,86 @@ import { autoUpdate, flip, FloatingFocusManager, offset, shift, useClick, useDis
|
|||||||
import { Comment } from '@plebbit/plebbit-react-hooks';
|
import { Comment } from '@plebbit/plebbit-react-hooks';
|
||||||
import styles from './post-menu.module.css';
|
import styles from './post-menu.module.css';
|
||||||
import { getCommentMediaInfo } from '../../../lib/utils/media-utils';
|
import { getCommentMediaInfo } from '../../../lib/utils/media-utils';
|
||||||
import { isValidURL } from '../../../lib/utils/url-utils';
|
import { copyShareLinkToClipboard, isValidURL } from '../../../lib/utils/url-utils';
|
||||||
|
|
||||||
const PostMenu = ({ post }: Comment) => {
|
interface PostMenuProps {
|
||||||
const { cid, isDescription, isRules, link, subplebbitAddress } = post;
|
cid: string;
|
||||||
const [menuBtnRotated, setMenuBtnRotated] = useState(false);
|
isDescription?: boolean;
|
||||||
const [isClientRedirectMenuOpen, setIsClientRedirectMenuOpen] = useState(false);
|
isRules?: boolean;
|
||||||
|
subplebbitAddress: string;
|
||||||
|
onClose: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
const CopyLinkButton = ({ cid, subplebbitAddress, onClose }: PostMenuProps) => {
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
onClick={() => {
|
||||||
|
copyShareLinkToClipboard(subplebbitAddress, cid);
|
||||||
|
onClose();
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div className={styles.postMenuItem}>Copy link</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const ImageSearchButton = ({ url, onClose }: { url: string; onClose: () => void }) => {
|
||||||
const [isImageSearchMenuOpen, setIsImageSearchMenuOpen] = useState(false);
|
const [isImageSearchMenuOpen, setIsImageSearchMenuOpen] = useState(false);
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className={`${styles.postMenuItem} ${styles.dropdown}`}
|
||||||
|
onMouseOver={() => setIsImageSearchMenuOpen(true)}
|
||||||
|
onMouseLeave={() => setIsImageSearchMenuOpen(false)}
|
||||||
|
onClick={onClose}
|
||||||
|
>
|
||||||
|
Image search »
|
||||||
|
{isImageSearchMenuOpen && (
|
||||||
|
<div className={styles.dropdownMenu}>
|
||||||
|
<a href={`https://lens.google.com/uploadbyurl?url=${url}`} target='_blank' rel='noreferrer'>
|
||||||
|
<div className={styles.postMenuItem}>Google</div>
|
||||||
|
</a>
|
||||||
|
<a href={`https://www.yandex.com/images/search?img_url=${url}&rpt=imageview`} target='_blank' rel='noreferrer'>
|
||||||
|
<div className={styles.postMenuItem}>Yandex</div>
|
||||||
|
</a>
|
||||||
|
<a href={`https://saucenao.com/search.php?url=${url}`} target='_blank' rel='noreferrer'>
|
||||||
|
<div className={styles.postMenuItem}>SauceNAO</div>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const ViewOnButton = ({ cid, isDescription, isRules, subplebbitAddress, onClose }: PostMenuProps) => {
|
||||||
|
const [isClientRedirectMenuOpen, setIsClientRedirectMenuOpen] = useState(false);
|
||||||
|
const viewOnOtherClientLink = `p/${subplebbitAddress}${isDescription || isRules ? '' : `/c/${cid}`}`;
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className={`${styles.postMenuItem} ${styles.dropdown}`}
|
||||||
|
onMouseOver={() => setIsClientRedirectMenuOpen(true)}
|
||||||
|
onMouseLeave={() => setIsClientRedirectMenuOpen(false)}
|
||||||
|
onClick={onClose}
|
||||||
|
>
|
||||||
|
View on »
|
||||||
|
{isClientRedirectMenuOpen && (
|
||||||
|
<div className={styles.dropdownMenu}>
|
||||||
|
<a href={`https://seedit.app/#/${viewOnOtherClientLink}`} target='_blank' rel='noreferrer'>
|
||||||
|
<div className={styles.postMenuItem}>Seedit</div>
|
||||||
|
</a>
|
||||||
|
<a href={`https://plebones.netlify.app/#/${viewOnOtherClientLink}`} target='_blank' rel='noreferrer'>
|
||||||
|
<div className={styles.postMenuItem}>Plebones</div>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const PostMenu = ({ post }: { post: Comment }) => {
|
||||||
|
const { cid, isDescription, isRules, link, subplebbitAddress } = post;
|
||||||
|
const commentMediaInfo = getCommentMediaInfo(post);
|
||||||
|
const { thumbnail, type, url } = commentMediaInfo || {};
|
||||||
|
const [menuBtnRotated, setMenuBtnRotated] = useState(false);
|
||||||
|
|
||||||
const { refs, floatingStyles, context } = useFloating({
|
const { refs, floatingStyles, context } = useFloating({
|
||||||
placement: 'bottom-start',
|
placement: 'bottom-start',
|
||||||
@@ -18,19 +91,13 @@ const PostMenu = ({ post }: Comment) => {
|
|||||||
middleware: [offset({ mainAxis: 10, crossAxis: 5 }), flip({ fallbackAxisSideDirection: 'end' }), shift({ padding: 10 })],
|
middleware: [offset({ mainAxis: 10, crossAxis: 5 }), flip({ fallbackAxisSideDirection: 'end' }), shift({ padding: 10 })],
|
||||||
whileElementsMounted: autoUpdate,
|
whileElementsMounted: autoUpdate,
|
||||||
});
|
});
|
||||||
|
|
||||||
const click = useClick(context);
|
const click = useClick(context);
|
||||||
const dismiss = useDismiss(context);
|
const dismiss = useDismiss(context);
|
||||||
const role = useRole(context);
|
const role = useRole(context);
|
||||||
|
|
||||||
const { getReferenceProps, getFloatingProps } = useInteractions([click, dismiss, role]);
|
const { getReferenceProps, getFloatingProps } = useInteractions([click, dismiss, role]);
|
||||||
|
|
||||||
const headingId = useId();
|
const headingId = useId();
|
||||||
|
|
||||||
const viewOnOtherClientLink = `p/${subplebbitAddress}${isDescription || isRules ? '' : `/c/${cid}`}`;
|
const handleClose = () => setMenuBtnRotated(false);
|
||||||
|
|
||||||
const commentMediaInfo = getCommentMediaInfo(post);
|
|
||||||
const { thumbnail, type, url } = commentMediaInfo || {};
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
@@ -47,55 +114,9 @@ const PostMenu = ({ post }: Comment) => {
|
|||||||
{menuBtnRotated && (
|
{menuBtnRotated && (
|
||||||
<FloatingFocusManager context={context} modal={false}>
|
<FloatingFocusManager context={context} modal={false}>
|
||||||
<div className={styles.postMenu} ref={refs.setFloating} style={floatingStyles} aria-labelledby={headingId} {...getFloatingProps()}>
|
<div className={styles.postMenu} ref={refs.setFloating} style={floatingStyles} aria-labelledby={headingId} {...getFloatingProps()}>
|
||||||
{link && isValidURL(link) && (type === 'image' || type === 'gif' || thumbnail) && (
|
{cid && subplebbitAddress && <CopyLinkButton cid={cid} subplebbitAddress={subplebbitAddress} onClose={handleClose} />}
|
||||||
<div
|
{link && isValidURL(link) && (type === 'image' || type === 'gif' || thumbnail) && url && <ImageSearchButton url={url} onClose={handleClose} />}
|
||||||
className={`${styles.postMenuItem} ${styles.dropdown}`}
|
<ViewOnButton cid={cid} isDescription={isDescription} isRules={isRules} subplebbitAddress={subplebbitAddress} onClose={handleClose} />
|
||||||
onMouseOver={() => setIsImageSearchMenuOpen(true)}
|
|
||||||
onMouseLeave={() => setIsImageSearchMenuOpen(false)}
|
|
||||||
>
|
|
||||||
Image search »
|
|
||||||
{isImageSearchMenuOpen && (
|
|
||||||
<div className={styles.dropdownMenu}>
|
|
||||||
<div className={styles.postMenuItem}>
|
|
||||||
<a href={`https://lens.google.com/uploadbyurl?url=${url}`} target='_blank' rel='noreferrer'>
|
|
||||||
Google
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
<div className={styles.postMenuItem}>
|
|
||||||
<a href={`https://www.yandex.com/images/search?img_url=${url}&rpt=imageview`} target='_blank' rel='noreferrer'>
|
|
||||||
Yandex
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
<div className={styles.postMenuItem}>
|
|
||||||
<a href={`https://saucenao.com/search.php?url=${url}`} target='_blank' rel='noreferrer'>
|
|
||||||
SauceNAO
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
<div
|
|
||||||
className={`${styles.postMenuItem} ${styles.dropdown}`}
|
|
||||||
onMouseOver={() => setIsClientRedirectMenuOpen(true)}
|
|
||||||
onMouseLeave={() => setIsClientRedirectMenuOpen(false)}
|
|
||||||
>
|
|
||||||
View on »
|
|
||||||
{isClientRedirectMenuOpen && (
|
|
||||||
<div className={styles.dropdownMenu}>
|
|
||||||
<div className={styles.postMenuItem}>
|
|
||||||
<a href={`https://seedit.app/#/${viewOnOtherClientLink}`} target='_blank' rel='noreferrer'>
|
|
||||||
Seedit
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
<div className={styles.postMenuItem}>
|
|
||||||
<a href={`https://plebones.netlify.app/#/${viewOnOtherClientLink}`} target='_blank' rel='noreferrer'>
|
|
||||||
Plebones
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</FloatingFocusManager>
|
</FloatingFocusManager>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ export const isValidURL = (url: string) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const copyShareLinkToClipboard = (subplebbitAddress: string, cid: string) => {
|
export const copyShareLinkToClipboard = (subplebbitAddress: string, cid: string) => {
|
||||||
const shareLink = `https://pleb.bz/p/${subplebbitAddress}/c/${cid}`;
|
const shareLink = `https://pleb.bz/p/${subplebbitAddress}/c/${cid}?redirect=plebchan.eth.limo`;
|
||||||
|
|
||||||
if (navigator.clipboard) {
|
if (navigator.clipboard) {
|
||||||
navigator.clipboard.writeText(shareLink);
|
navigator.clipboard.writeText(shareLink);
|
||||||
|
|||||||
Reference in New Issue
Block a user