import React, { useCallback, useEffect, useRef, useState } from 'react'; import { createPortal } from 'react-dom'; import { Helmet } from 'react-helmet-async'; import { Link, useNavigate, useParams } from 'react-router-dom'; import { Tooltip } from 'react-tooltip'; import { useSubplebbit } from '@plebbit/plebbit-react-hooks'; import { debounce } from 'lodash'; import { Container, NavBar, Header, Break, PostMenu, PostForm, PostMenuMobile } from '../styled/views/Board.styled'; import { TopBar, BoardForm, Footer, ReplyFormLink } from '../styled/views/Thread.styled'; import { PostMenuCatalog } from '../styled/views/Catalog.styled'; import BoardStats from '../BoardStats'; import ImageBanner from '../ImageBanner'; import Post from '../Post'; import CreateBoardModal from '../modals/CreateBoardModal'; import AdminListModal from '../modals/AdminListModal'; import OfflineIndicator from '../OfflineIndicator'; import SettingsModal from '../modals/SettingsModal'; import getDate from '../../utils/getDate'; import handleImageClick from '../../utils/handleImageClick'; import handleStyleChange from '../../utils/handleStyleChange'; import useGeneralStore from '../../hooks/stores/useGeneralStore'; import packageJson from '../../../package.json'; const { version } = packageJson; const commitRef = process?.env?.REACT_APP_COMMIT_REF ? ` ${process.env.REACT_APP_COMMIT_REF.slice(0, 7)}` : ''; const Description = () => { const { defaultSubplebbits, isSettingsOpen, setIsSettingsOpen, selectedAddress, setSelectedAddress, selectedStyle, setSelectedTitle } = useGeneralStore( (state) => state, ); const navigate = useNavigate(); const threadMenuRefs = useRef({}); const threadMenuRefsMobile = useRef({}); const postMenuMobileRef = useRef(null); const postMenuCatalogRef = useRef(null); const [isAdminListOpen, setIsAdminListOpen] = useState(false); const [prevScrollPos, setPrevScrollPos] = useState(0); const [visible, setVisible] = useState(true); const [menuPosition, setMenuPosition] = useState({ top: 0, left: 0 }); const [mobileMenuPosition, setMobileMenuPosition] = useState({ top: 0, left: 0 }); const [openMenuCid, setOpenMenuCid] = useState(null); const [openMobileMenuCid, setOpenMobileMenuCid] = useState(null); const [isCreateBoardOpen, setIsCreateBoardOpen] = useState(false); const [isImageSearchOpen, setIsImageSearchOpen] = useState(false); const [isClientRedirectMenuOpen, setIsClientRedirectMenuOpen] = useState(false); const { subplebbitAddress } = useParams(); const subplebbit = useSubplebbit({ subplebbitAddress: selectedAddress }); const handleOptionClick = () => { setOpenMenuCid(null); }; const handleMobileOptionClick = () => { setOpenMobileMenuCid(null); }; const handleOutsideClick = useCallback( (e) => { if (openMenuCid !== null && !postMenuCatalogRef.current.contains(e.target)) { setOpenMenuCid(null); } }, [openMenuCid, postMenuCatalogRef], ); const handleMobileOutsideClick = useCallback( (e) => { if (openMobileMenuCid !== null && !postMenuMobileRef.current.contains(e.target)) { setOpenMobileMenuCid(null); } }, [openMobileMenuCid, postMenuMobileRef], ); useEffect(() => { if (openMenuCid !== null) { document.addEventListener('click', handleOutsideClick); } else { document.removeEventListener('click', handleOutsideClick); } return () => { document.removeEventListener('click', handleOutsideClick); }; }, [openMenuCid, handleOutsideClick]); useEffect(() => { if (openMobileMenuCid !== null) { document.addEventListener('click', handleMobileOutsideClick); } else { document.removeEventListener('click', handleMobileOutsideClick); } return () => { document.removeEventListener('click', handleMobileOutsideClick); }; }, [openMobileMenuCid, handleMobileOutsideClick]); useEffect(() => { window.scrollTo(0, 0); }, []); useEffect(() => { const selectedSubplebbit = defaultSubplebbits.find((subplebbit) => subplebbit.address === subplebbitAddress); if (subplebbitAddress) { setSelectedAddress(subplebbitAddress); } else if (subplebbit?.address) { setSelectedAddress(subplebbit.address); } if (selectedSubplebbit) { setSelectedTitle(selectedSubplebbit.title); } else if (subplebbit?.title) { setSelectedTitle(subplebbit.title); } }, [subplebbitAddress, setSelectedAddress, setSelectedTitle, defaultSubplebbits, subplebbit?.address, subplebbit?.title]); // mobile navbar scroll effect useEffect(() => { const debouncedHandleScroll = debounce(() => { const currentScrollPos = window.scrollY; setVisible(prevScrollPos > currentScrollPos || currentScrollPos < 10); setPrevScrollPos(currentScrollPos); }, 50); window.addEventListener('scroll', debouncedHandleScroll); return () => window.removeEventListener('scroll', debouncedHandleScroll); }, [prevScrollPos, visible]); // mobile navbar board select functionality const handleSelectChange = (event) => { const selected = event.target.value; if (selected === 'subscriptions') { navigate(`/p/subscriptions`); return; } else if (selected === 'all') { navigate(`/p/all`); return; } const selectedTitle = defaultSubplebbits.find((subplebbit) => subplebbit.address === selected).title; setSelectedTitle(selectedTitle); setSelectedAddress(selected); navigate(`/p/${selected}`); }; return ( <> {'Board Description - ' + (subplebbit.title || subplebbit.address) + ' - plebchan'} setIsCreateBoardOpen(false)} /> setIsAdminListOpen(false)} roles={subplebbit.roles} /> setIsSettingsOpen(false)} /> <> [All  /  Subscriptions ] [ {defaultSubplebbits.map((subplebbit, index) => ( {index === 0 ? null : '\u00a0'} { setSelectedTitle(subplebbit.title); setSelectedAddress(subplebbit.address); }} > {subplebbit.title ? subplebbit.title : subplebbit.address} {index !== defaultSubplebbits.length - 1 ? ' /' : null} ))} ] [ { window.electron && window.electron.isElectron ? setIsCreateBoardOpen(true) : alert( 'HOW TO CREATE A BOARD (currently via CLI only):\n\n(1) have a computer you can use as server, because users will connect to your board peer-to-peer;\n\n(2) go to https://github.com/plebbit/plebbit-cli#install and follow the instructions to run your daemon, create a subplebbit (board) and edit its settings;\n\n(3) users can always connect to your board via its address, but it can be added below by submitting a pull request here: https://github.com/plebbit/temporary-default-subplebbits. This will be automated with a plebbit DAO using the plebbit token.', ); }} > Create Board ] [ setIsSettingsOpen(true)}> Settings ] [Home]
Board     alert( 'HOW TO CREATE A BOARD (currently via CLI only):\n\n(1) have a computer you can use as server, because users will connect to your board peer-to-peer;\n\n(2) go to https://github.com/plebbit/plebbit-cli#install and follow the instructions to run your daemon, create a subplebbit (board) and edit its settings;\n\n(3) users can always connect to your board via its address, but it can be added below by submitting a pull request here: https://github.com/plebbit/temporary-default-subplebbits. This will be automated with a plebbit DAO using the plebbit token.', ) } > Create Board
setIsSettingsOpen(true)}> Settings   { handleStyleChange({ target: { value: 'Yotsuba' } }); }} > Home
 
 
<>
<>
{subplebbit.title ?? null}
p/{subplebbit.address}
Return
Catalog
window.scrollTo(0, document.body.scrollHeight)} onMouseOver={(event) => (event.target.style.cursor = 'pointer')} > Bottom
Style:   [Return] [Catalog] [ window.scrollTo(0, document.body.scrollHeight)} onMouseOver={(event) => (event.target.style.cursor = 'pointer')} onTouchStart={() => window.scrollTo(0, document.body.scrollHeight)} > Bottom ] <>

{subplebbit.suggested?.avatarUrl ? ( ) : null} Welcome to {subplebbit.title || subplebbit.address}   { setIsAdminListOpen(!isAdminListOpen); }} > ## Board Mods   {getDate(subplebbit.createdAt)}   Sticky   Closed   [ {}} style={{ textDecoration: 'none' }} className='reply-link'> Reply ] { threadMenuRefs.current[subplebbit.pubsubTopic] = el; }} className='post-menu-button' rotated={openMenuCid === subplebbit.pubsubTopic} onClick={(event) => { event.stopPropagation(); const rect = threadMenuRefs.current[subplebbit.pubsubTopic].getBoundingClientRect(); setMenuPosition({ top: rect.top + window.scrollY, left: rect.left }); setOpenMenuCid((prevCid) => (prevCid === subplebbit.pubsubTopic ? null : subplebbit.pubsubTopic)); }} > ▶ {createPortal( { postMenuCatalogRef.current = el; }} onClick={(event) => event.stopPropagation()} style={{ position: 'absolute', top: menuPosition.top + 7, left: menuPosition.left }} >
    {/* {canModerate ? ( <> change description ) : null} */} {subplebbit.suggested?.avatarUrl ? (
  • { setIsImageSearchOpen(true); }} onMouseLeave={() => { setIsImageSearchOpen(false); }} > Image search »
  • ) : null}
  • { setIsClientRedirectMenuOpen(true); }} onMouseLeave={() => { setIsClientRedirectMenuOpen(false); }} > View on »
, document.body, )}

{createPortal( { postMenuMobileRef.current = el; }} onClick={(event) => event.stopPropagation()} style={{ position: 'absolute', display: openMobileMenuCid === 'description' ? 'block' : 'none', top: mobileMenuPosition.top + 20, left: mobileMenuPosition.left, }} > , document.body, )} { setIsAdminListOpen(!isAdminListOpen); }} > ## Board Mods   Sticky   Closed
Welcome to {subplebbit.title || subplebbit.address}  
{getDate(subplebbit.createdAt)}  
{subplebbit.suggested?.avatarUrl ? (
board avatar
image
) : null}
{}} className='button-mobile'> View Thread
); }; export default Description;