mirror of
https://github.com/bitsocialnet/5chan.git
synced 2026-08-03 07:41:04 +02:00
feat(post): add post menu component with links to other clients
This commit is contained in:
@@ -1,4 +1,4 @@
|
|||||||
import { useEffect, useRef, useState } from 'react';
|
import { useState } from 'react';
|
||||||
import { Trans, useTranslation } from 'react-i18next';
|
import { Trans, useTranslation } from 'react-i18next';
|
||||||
import { useLocation, useParams } from 'react-router-dom';
|
import { useLocation, useParams } from 'react-router-dom';
|
||||||
import { Link } from 'react-router-dom';
|
import { Link } from 'react-router-dom';
|
||||||
@@ -17,6 +17,7 @@ import LoadingEllipsis from '../../loading-ellipsis';
|
|||||||
import Markdown from '../../markdown';
|
import Markdown from '../../markdown';
|
||||||
import { PostProps } from '../post';
|
import { PostProps } from '../post';
|
||||||
import styles from '../post.module.css';
|
import styles from '../post.module.css';
|
||||||
|
import PostMenu from '../post-menu';
|
||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
|
|
||||||
const PostInfo = ({ openReplyModal, post, roles }: PostProps) => {
|
const PostInfo = ({ openReplyModal, post, roles }: PostProps) => {
|
||||||
@@ -41,30 +42,6 @@ const PostInfo = ({ openReplyModal, post, roles }: PostProps) => {
|
|||||||
const account = useAccount();
|
const account = useAccount();
|
||||||
const accountShortAddress = account?.author?.shortAddress;
|
const accountShortAddress = account?.author?.shortAddress;
|
||||||
|
|
||||||
const [menuBtnRotated, setMenuBtnRotated] = useState(false);
|
|
||||||
const menuRef = useRef<HTMLDivElement>(null);
|
|
||||||
|
|
||||||
const handleMenuButtonClick = () => {
|
|
||||||
setMenuBtnRotated((prev) => !prev);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleClickOutside = (event: MouseEvent) => {
|
|
||||||
if (menuRef.current && !menuRef.current.contains(event.target as Node)) {
|
|
||||||
setMenuBtnRotated(false);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (menuBtnRotated) {
|
|
||||||
document.addEventListener('mousedown', handleClickOutside);
|
|
||||||
} else {
|
|
||||||
document.removeEventListener('mousedown', handleClickOutside);
|
|
||||||
}
|
|
||||||
return () => {
|
|
||||||
document.removeEventListener('mousedown', handleClickOutside);
|
|
||||||
};
|
|
||||||
}, [menuBtnRotated]);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={styles.postInfo}>
|
<div className={styles.postInfo}>
|
||||||
<span className={styles.checkbox}>
|
<span className={styles.checkbox}>
|
||||||
@@ -125,11 +102,7 @@ const PostInfo = ({ openReplyModal, post, roles }: PostProps) => {
|
|||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
</span>
|
</span>
|
||||||
<span className={styles.postMenuBtnWrapper} ref={menuRef}>
|
<PostMenu post={post} />
|
||||||
<span className={styles.postMenuBtn} title='Post menu' onClick={handleMenuButtonClick} style={{ transform: menuBtnRotated ? 'rotate(90deg)' : 'rotate(0deg)' }}>
|
|
||||||
▶
|
|
||||||
</span>
|
|
||||||
</span>
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
export { default } from './post-menu';
|
||||||
@@ -0,0 +1,86 @@
|
|||||||
|
.postMenu {
|
||||||
|
position: absolute;
|
||||||
|
background-color: var(--post-menu-background-color);
|
||||||
|
border-bottom: 2px solid var(--post-menu-border-color);
|
||||||
|
border-right: 1px solid var(--post-menu-border-color);
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.postMenuBtnWrapper {
|
||||||
|
position: relative;
|
||||||
|
display: inline-block;
|
||||||
|
padding-left: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.postMenuBtn {
|
||||||
|
color: var(--post-menu-button-color);
|
||||||
|
transition: transform 0.1s;
|
||||||
|
transform: rotate(90deg);
|
||||||
|
position: absolute;
|
||||||
|
bottom: -4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.postMenuBtn:hover {
|
||||||
|
cursor: pointer;
|
||||||
|
color: var(--post-menu-button-color-hover);
|
||||||
|
}
|
||||||
|
|
||||||
|
.postMenuItem {
|
||||||
|
cursor: pointer;
|
||||||
|
padding: 2px 4px;
|
||||||
|
border: 1px solid var(--post-menu-item-border-color);
|
||||||
|
background-color: var(--post-menu-item-background-color);
|
||||||
|
border-bottom: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.postMenuItem:hover {
|
||||||
|
background-color: var(--post-menu-item-hover-background-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.dropdown {
|
||||||
|
position: relative;
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dropdownMenu {
|
||||||
|
position: absolute;
|
||||||
|
left: 100%;
|
||||||
|
top: -1px;
|
||||||
|
display: none;
|
||||||
|
border-bottom: 2px solid var(--post-menu-border-color);
|
||||||
|
border-right: 1px solid var(--post-menu-border-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.dropdown a {
|
||||||
|
text-decoration: none;
|
||||||
|
color: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dropdown:hover .dropdownMenu {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 640px) {
|
||||||
|
.postMenuBtn {
|
||||||
|
width: 1em;
|
||||||
|
text-align: center;
|
||||||
|
font-weight: 700;
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.postMenuBtnWrapper {
|
||||||
|
position: relative;
|
||||||
|
padding-right: 12px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: 640px) {
|
||||||
|
.postMenuBtn {
|
||||||
|
right: -2px;
|
||||||
|
opacity: var(--post-menu-btn-opacity);
|
||||||
|
}
|
||||||
|
|
||||||
|
.stickyIconWrapper {
|
||||||
|
padding-right: 18px;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,72 @@
|
|||||||
|
import { useState } from 'react';
|
||||||
|
import { autoUpdate, flip, FloatingFocusManager, offset, shift, useClick, useDismiss, useFloating, useId, useInteractions, useRole } from '@floating-ui/react';
|
||||||
|
import { Comment } from '@plebbit/plebbit-react-hooks';
|
||||||
|
import styles from './post-menu.module.css';
|
||||||
|
|
||||||
|
const PostMenu = ({ post }: Comment) => {
|
||||||
|
const { cid, isDescription, isRules, link, subplebbitAddress } = post;
|
||||||
|
const [menuBtnRotated, setMenuBtnRotated] = useState(false);
|
||||||
|
const [isClientRedirectMenuOpen, setIsClientRedirectMenuOpen] = useState(false);
|
||||||
|
|
||||||
|
const { refs, floatingStyles, context } = useFloating({
|
||||||
|
placement: 'bottom-start',
|
||||||
|
open: menuBtnRotated,
|
||||||
|
onOpenChange: setMenuBtnRotated,
|
||||||
|
middleware: [offset({ mainAxis: 10, crossAxis: 5 }), flip({ fallbackAxisSideDirection: 'end' }), shift({ padding: 10 })],
|
||||||
|
whileElementsMounted: autoUpdate,
|
||||||
|
});
|
||||||
|
|
||||||
|
const click = useClick(context);
|
||||||
|
const dismiss = useDismiss(context);
|
||||||
|
const role = useRole(context);
|
||||||
|
|
||||||
|
const { getReferenceProps, getFloatingProps } = useInteractions([click, dismiss, role]);
|
||||||
|
|
||||||
|
const headingId = useId();
|
||||||
|
|
||||||
|
const viewOnOtherClientLink = `p/${subplebbitAddress}${isDescription || isRules ? '' : `/c/${cid}`}`;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<span className={styles.postMenuBtnWrapper} ref={refs.setReference} {...getReferenceProps()}>
|
||||||
|
<span
|
||||||
|
className={styles.postMenuBtn}
|
||||||
|
title='Post menu'
|
||||||
|
onClick={() => setMenuBtnRotated((prev) => !prev)}
|
||||||
|
style={{ transform: menuBtnRotated ? 'rotate(90deg)' : 'rotate(0deg)' }}
|
||||||
|
>
|
||||||
|
▶
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
{menuBtnRotated && (
|
||||||
|
<FloatingFocusManager context={context} modal={false}>
|
||||||
|
<div className={styles.postMenu} ref={refs.setFloating} style={floatingStyles} aria-labelledby={headingId} {...getFloatingProps()}>
|
||||||
|
<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>
|
||||||
|
</FloatingFocusManager>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default PostMenu;
|
||||||
@@ -131,37 +131,6 @@
|
|||||||
color: var(--button-desktop-text-color-hover);
|
color: var(--button-desktop-text-color-hover);
|
||||||
}
|
}
|
||||||
|
|
||||||
.postMenuBtnWrapper {
|
|
||||||
position: relative;
|
|
||||||
display: inline-block;
|
|
||||||
padding-left: 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.replyDesktop .postMenuBtnWrapper {
|
|
||||||
padding-right: 12px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.replyDesktop .stickyIconWrapper {
|
|
||||||
padding-right: 18px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.postDesktop .postMenuBtn, .replyDesktop .postMenuBtn {
|
|
||||||
color: var(--post-menu-button-color);
|
|
||||||
transition: transform 0.1s;
|
|
||||||
position: absolute;
|
|
||||||
opacity: var(--post-menu-btn-opacity);
|
|
||||||
bottom: -4px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.replyDesktop .postMenuBtn {
|
|
||||||
right: -2px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.postDesktop .postMenuBtn:hover, .replyDesktop .postMenuBtn:hover {
|
|
||||||
cursor: pointer;
|
|
||||||
color: var(--post-menu-button-color-hover);
|
|
||||||
}
|
|
||||||
|
|
||||||
.postDesktop .spacer {
|
.postDesktop .spacer {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
padding: 5px;
|
padding: 5px;
|
||||||
@@ -260,20 +229,6 @@
|
|||||||
clear: left;
|
clear: left;
|
||||||
}
|
}
|
||||||
|
|
||||||
.postMobile .postMenuBtn {
|
|
||||||
color: var(--post-mobile-menu-button-color);
|
|
||||||
line-height: 1em;
|
|
||||||
width: 1em;
|
|
||||||
text-align: center;
|
|
||||||
transition: transform 0.1s;
|
|
||||||
transform: rotate(90deg);
|
|
||||||
-webkit-transform: rotate(90deg);
|
|
||||||
float: left;
|
|
||||||
font-weight: 700;
|
|
||||||
font-size: 16px;
|
|
||||||
height: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.postMobile .nameBlock {
|
.postMobile .nameBlock {
|
||||||
clear: none;
|
clear: none;
|
||||||
}
|
}
|
||||||
@@ -408,10 +363,6 @@
|
|||||||
color: var(--post-mobile-info-text-color);
|
color: var(--post-mobile-info-text-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
.replyMobile .postInfo .postMenuBtn {
|
|
||||||
width: 1em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.replyMobile .nameBlock {
|
.replyMobile .nameBlock {
|
||||||
display: inline;
|
display: inline;
|
||||||
float: left;
|
float: left;
|
||||||
|
|||||||
+58
-16
@@ -103,6 +103,29 @@
|
|||||||
--post-greentext-color: #789922;
|
--post-greentext-color: #789922;
|
||||||
--post-replies-expand-button-background-image: url("/public/assets/buttons/plus-red.png");
|
--post-replies-expand-button-background-image: url("/public/assets/buttons/plus-red.png");
|
||||||
|
|
||||||
|
/* post form */
|
||||||
|
--post-form-toggle-font-size: 22px;
|
||||||
|
--post-form-toggle-font-weight: 700;
|
||||||
|
--post-form-field-title-background-color: #ea8;
|
||||||
|
--post-form-field-title-color: #800;
|
||||||
|
--post-form-field-border: 1px solid #800;
|
||||||
|
--post-form-field-title-font-weight: 700;
|
||||||
|
--post-form-field-title-padding: 0 5px;
|
||||||
|
--post-form-field-title-font-size: 10pt;
|
||||||
|
--post-form-field-input-border: 1px solid #aaa;
|
||||||
|
--post-form-field-font-family: arial, helvetica, sans-serif;
|
||||||
|
--post-form-field-input-appearance: none;
|
||||||
|
--post-form-field-input-outline: none;
|
||||||
|
--post-form-field-input-focus-border: 1px solid #ea8;
|
||||||
|
--post-form-field-input-color: #000;
|
||||||
|
|
||||||
|
/* post menu */
|
||||||
|
--post-menu-border-color: #d9bfb7;
|
||||||
|
--post-menu-background-color: #f0e0d6;
|
||||||
|
--post-menu-item-border-color: #d9bfb7;
|
||||||
|
--post-menu-item-background-color: #f0e0d6;
|
||||||
|
--post-menu-item-hover-background-color: #ffe;
|
||||||
|
|
||||||
/* post mobile */
|
/* post mobile */
|
||||||
--post-mobile-background-color: #f5e9e1;
|
--post-mobile-background-color: #f5e9e1;
|
||||||
--post-mobile-info-border-bottom: 1px solid #d9bfb7;
|
--post-mobile-info-border-bottom: 1px solid #d9bfb7;
|
||||||
@@ -120,22 +143,6 @@
|
|||||||
--post-mobile-file-info-text-color: #707070;
|
--post-mobile-file-info-text-color: #707070;
|
||||||
--post-mobile-content-font-size: 11pt;
|
--post-mobile-content-font-size: 11pt;
|
||||||
|
|
||||||
/* post form */
|
|
||||||
--post-form-toggle-font-size: 22px;
|
|
||||||
--post-form-toggle-font-weight: 700;
|
|
||||||
--post-form-field-title-background-color: #ea8;
|
|
||||||
--post-form-field-title-color: #800;
|
|
||||||
--post-form-field-border: 1px solid #800;
|
|
||||||
--post-form-field-title-font-weight: 700;
|
|
||||||
--post-form-field-title-padding: 0 5px;
|
|
||||||
--post-form-field-title-font-size: 10pt;
|
|
||||||
--post-form-field-input-border: 1px solid #aaa;
|
|
||||||
--post-form-field-font-family: arial, helvetica, sans-serif;
|
|
||||||
--post-form-field-input-appearance: none;
|
|
||||||
--post-form-field-input-outline: none;
|
|
||||||
--post-form-field-input-focus-border: 1px solid #ea8;
|
|
||||||
--post-form-field-input-color: #000;
|
|
||||||
|
|
||||||
/* quotelink */
|
/* quotelink */
|
||||||
--post-quotelink-text-color: navy;
|
--post-quotelink-text-color: navy;
|
||||||
--post-quotelink-text-color-hover: red;
|
--post-quotelink-text-color-hover: red;
|
||||||
@@ -288,6 +295,13 @@
|
|||||||
--post-form-field-input-focus-border: 1px solid #98e;
|
--post-form-field-input-focus-border: 1px solid #98e;
|
||||||
--post-form-field-input-color: #000;
|
--post-form-field-input-color: #000;
|
||||||
|
|
||||||
|
/* post menu */
|
||||||
|
--post-menu-border-color: #b7c5d9;
|
||||||
|
--post-menu-background-color: #d6daf0;
|
||||||
|
--post-menu-item-border-color: #b7c5d9;
|
||||||
|
--post-menu-item-background-color: #d6daf0;
|
||||||
|
--post-menu-item-hover-background-color: #eef2ff;
|
||||||
|
|
||||||
/* post mobile */
|
/* post mobile */
|
||||||
--post-mobile-background-color: #d6daf0;
|
--post-mobile-background-color: #d6daf0;
|
||||||
--post-mobile-info-border-bottom: 1px solid #b7c5d9;
|
--post-mobile-info-border-bottom: 1px solid #b7c5d9;
|
||||||
@@ -427,6 +441,13 @@
|
|||||||
--post-form-field-title-font-size: 16px;
|
--post-form-field-title-font-size: 16px;
|
||||||
--post-form-field-input-color: #000;
|
--post-form-field-input-color: #000;
|
||||||
|
|
||||||
|
/* post menu */
|
||||||
|
--post-menu-border-color: #d9bfb7;
|
||||||
|
--post-menu-background-color: #f0e0d6;
|
||||||
|
--post-menu-item-border-color: #d9bfb7;
|
||||||
|
--post-menu-item-background-color: #f0e0d6;
|
||||||
|
--post-menu-item-hover-background-color: #ffe;
|
||||||
|
|
||||||
/* post mobile */
|
/* post mobile */
|
||||||
--post-mobile-background-color: #f5e9e1;
|
--post-mobile-background-color: #f5e9e1;
|
||||||
--post-mobile-info-border-bottom: 1px solid #d9bfb7;
|
--post-mobile-info-border-bottom: 1px solid #d9bfb7;
|
||||||
@@ -576,6 +597,13 @@
|
|||||||
--post-form-field-title-font-size: 16px;
|
--post-form-field-title-font-size: 16px;
|
||||||
--post-form-field-input-color: #000;
|
--post-form-field-input-color: #000;
|
||||||
|
|
||||||
|
/* post menu */
|
||||||
|
--post-menu-border-color: #b7c5d9;
|
||||||
|
--post-menu-background-color: #d6daf0;
|
||||||
|
--post-menu-item-border-color: #b7c5d9;
|
||||||
|
--post-menu-item-background-color: #d6daf0;
|
||||||
|
--post-menu-item-hover-background-color: #eef2ff;
|
||||||
|
|
||||||
/* post mobile */
|
/* post mobile */
|
||||||
--post-mobile-background-color: #d6daf0;
|
--post-mobile-background-color: #d6daf0;
|
||||||
--post-mobile-info-border-bottom: 1px solid #b7c5d9;
|
--post-mobile-info-border-bottom: 1px solid #b7c5d9;
|
||||||
@@ -733,6 +761,13 @@
|
|||||||
--post-form-field-input-appearance: none;
|
--post-form-field-input-appearance: none;
|
||||||
--post-form-field-input-outline: none;
|
--post-form-field-input-outline: none;
|
||||||
|
|
||||||
|
/* post menu */
|
||||||
|
--post-menu-border-color: #000;
|
||||||
|
--post-menu-background-color: #282a2e;
|
||||||
|
--post-menu-item-border-color: #000;
|
||||||
|
--post-menu-item-background-color: #282a2e;
|
||||||
|
--post-menu-item-hover-background-color: #1d1f21;
|
||||||
|
|
||||||
/* post mobile */
|
/* post mobile */
|
||||||
--post-mobile-background-color: #282A2E;
|
--post-mobile-background-color: #282A2E;
|
||||||
--post-mobile-info-border-top: 1px solid #2D2F33;
|
--post-mobile-info-border-top: 1px solid #2D2F33;
|
||||||
@@ -908,6 +943,13 @@
|
|||||||
--post-form-field-input-focus-border: 1px solid #ea8;
|
--post-form-field-input-focus-border: 1px solid #ea8;
|
||||||
--post-form-field-input-color: #000;
|
--post-form-field-input-color: #000;
|
||||||
|
|
||||||
|
/* post menu */
|
||||||
|
--post-menu-border-color: #ccc;
|
||||||
|
--post-menu-background-color: #ddd;
|
||||||
|
--post-menu-item-border-color: #ccc;
|
||||||
|
--post-menu-item-background-color: #ddd;
|
||||||
|
--post-menu-item-hover-background-color: #eee;
|
||||||
|
|
||||||
/* quotelink */
|
/* quotelink */
|
||||||
--post-quotelink-text-color: #f60;
|
--post-quotelink-text-color: #f60;
|
||||||
--post-quotelink-text-color-hover: #f30;
|
--post-quotelink-text-color-hover: #f30;
|
||||||
|
|||||||
@@ -0,0 +1,3 @@
|
|||||||
|
.content {
|
||||||
|
margin-bottom: 150px;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user