From 685cbb3c170dc343794c316e42693e937b1bbdfd Mon Sep 17 00:00:00 2001 From: "plebeius.eth" Date: Mon, 2 Oct 2023 21:40:47 +0200 Subject: [PATCH] feat(home): redesigned home to be more similar to 4chan, with boards box listing all boards and thread box showing recent threads --- src/App.js | 29 +- src/components/styled/views/Home.styled.jsx | 152 ++++++---- src/components/views/Home.jsx | 295 ++++++++++++++------ src/components/views/NotFound.jsx | 64 +++-- src/hooks/stores/useGeneralStore.js | 3 + 5 files changed, 368 insertions(+), 175 deletions(-) diff --git a/src/App.js b/src/App.js index 40a8b936..c9b59773 100755 --- a/src/App.js +++ b/src/App.js @@ -28,8 +28,18 @@ import packageJson from '../package.json'; const commitRef = process?.env?.REACT_APP_COMMIT_REF || ''; export default function App() { - const { bodyStyle, setBodyStyle, setDefaultSubplebbits, isCaptchaOpen, setIsCaptchaOpen, setIsSettingsOpen, selectedStyle, setShowPostForm, setShowPostFormLink } = - useGeneralStore((state) => state); + const { + bodyStyle, + setBodyStyle, + setDefaultSubplebbits, + setDefaultNsfwSubplebbits, + isCaptchaOpen, + setIsCaptchaOpen, + setIsSettingsOpen, + selectedStyle, + setShowPostForm, + setShowPostFormLink, + } = useGeneralStore((state) => state); const location = useLocation(); const isElectron = window.electron && window.electron.isElectron; @@ -116,6 +126,21 @@ export default function App() { }; }, [setDefaultSubplebbits]); + // fetch default NSFW subplebbits + useEffect(() => { + let didCancel = false; + fetch('https://raw.githubusercontent.com/plebbit/temporary-default-subplebbits/master/subplebbits-nsfw.json', { cache: 'no-cache' }) + .then((res) => res.json()) + .then((res) => { + if (!didCancel) { + setDefaultNsfwSubplebbits(res); + } + }); + return () => { + didCancel = true; + }; + }, [setDefaultNsfwSubplebbits]); + // handle nested routes useEffect(() => { const path = location.pathname; diff --git a/src/components/styled/views/Home.styled.jsx b/src/components/styled/views/Home.styled.jsx index 8c263c07..6903f681 100644 --- a/src/components/styled/views/Home.styled.jsx +++ b/src/components/styled/views/Home.styled.jsx @@ -44,7 +44,7 @@ export const Search = styled.div` text-align: center; margin-bottom: 20px; - input[type="text"] { + input[type='text'] { width: 400px; height: 30px; font-size: 18px; @@ -60,27 +60,27 @@ export const Search = styled.div` font-family: arial, helvetica, sans-serif; } - input[type="submit"] { - width: 60px; + input[type='submit'] { + width: 70px; height: 30px; font-size: 14px; margin-left: 5px; } - + @-moz-document url-prefix() { - input[type="submit"] { + input[type='submit'] { vertical-align: top; } } - @media screen and (-webkit-min-device-pixel-ratio:0) { - input[type="submit"] { + @media screen and (-webkit-min-device-pixel-ratio: 0) { + input[type='submit'] { vertical-align: center; } } - @media not all and (min-resolution:.001dpcm) { - input[type="submit"] { + @media not all and (min-resolution: 0.001dpcm) { + input[type='submit'] { vertical-align: top; } } @@ -88,7 +88,7 @@ export const Search = styled.div` @media only screen and (max-width: 480px) { text-align: center; - input[type="text"] { + input[type='text'] { width: 80%; height: 35px; font-size: 20px; @@ -96,8 +96,8 @@ export const Search = styled.div` box-sizing: border-box; border-radius: 0; } - - input[type="submit"] { + + input[type='submit'] { height: 35px; font-size: 14px; padding: 5px; @@ -107,7 +107,6 @@ export const Search = styled.div` -webkit-appearance: none; } } - `; export const Page = styled.div` @@ -119,15 +118,15 @@ export const About = styled.div` background: #fff; color: #000; border: 1px solid; - margin-bottom: .5em; - padding-bottom: .5em; + margin-bottom: 0.5em; + padding-bottom: 0.5em; `; export const AboutTitle = styled.div` background: #800; color: #fff; position: relative; - padding-left: .5em; + padding-left: 0.5em; line-height: 2em; h2 { @@ -141,8 +140,8 @@ export const AboutTitle = styled.div` export const AboutContent = styled.div` line-height: 1.5em; font-size: 93%; - padding: .5em; - padding-top: .25em; + padding: 0.5em; + padding-top: 0.25em; padding-bottom: 0; min-height: 91px; @@ -165,39 +164,92 @@ export const AboutContent = styled.div` } `; -export const Boards = styled.div` +export const BoardsBox = styled.div` border: 1px solid; - margin: 0; - padding: 0; - padding-bottom: .5em; + padding-bottom: 0.5em; background: #fff; - word-wrap: break-word; margin-bottom: 6px; - #subscriptions { - text-align: left; + &:after { + content: ''; + display: table; + clear: both; } -`; -export const BoardsTitle = styled.div` - background: #fca; - color: #800; - position: relative; - padding-left: .5em; - line-height: 2em; + .boxbar { + background: #fca; + color: #800; + padding-left: 0.5em; + line-height: 2em; - h2 { - font-size: 131%; - font-weight: 700; - margin: 0; - padding: 0; + h2 { + font-size: 131%; + font-weight: 700; + margin: 0; + padding: 0; + } + } + + .boxcontent { + font-size: 93%; + padding: 0.5em; + padding-top: 0.25em; + padding-bottom: 0; + line-height: 130%; + + .column { + float: left; + width: 163px; + margin-right: 20px; + overflow: hidden; + + h3 { + font-size: 100%; + font-weight: 700; + } + + ul { + padding: 0; + margin: 0; + + li { + list-style: none; + white-space: nowrap; + + a { + color: #800; + text-decoration: none; + + :hover { + text-decoration: underline; + color: #e00; + } + } + } + .disconnected { + width: 13px; + margin: 0 2px -3px 0; + position: relative; + } + } + } + #button { + color: #800; + font-weight: 700; + text-decoration: none; + cursor: pointer; + + :hover { + color: #e00; + } + } } `; export const BoardsContent = styled.div` font-size: 93%; - padding: .5em; - padding-top: .25em; + padding: 0.5em; + padding-top: 0.25em; padding-bottom: 0; line-height: 130%; text-align: center; @@ -233,7 +285,6 @@ export const BoardsContent = styled.div` position: relative; } - .board-avatar-container img.board-avatar { width: 100%; height: 100%; @@ -265,7 +316,7 @@ export const BoardsContent = styled.div` :hover { text-decoration: underline; - color: #e00 + color: #e00; } } @@ -280,7 +331,8 @@ export const BoardsContent = styled.div` } @media (max-width: 480px) { - .boardlink, #view-all { + .boardlink, + #view-all { font-size: 1.2em; } @@ -302,15 +354,13 @@ export const BoardsContent = styled.div` position: absolute; } } - - `; export const Footer = styled.div` font-size: 93%; text-align: center; clear: both; - padding-top: .5em; + padding-top: 0.5em; padding-bottom: 2em; ul { @@ -320,7 +370,7 @@ export const Footer = styled.div` width: 750px; padding: 0; } - + li { background: #fed; display: block; @@ -331,7 +381,7 @@ export const Footer = styled.div` margin-top: -1px; list-style: none; } - + .fill { border-top: 1x solid; border-right: 0; @@ -340,16 +390,16 @@ export const Footer = styled.div` background: #ffe; width: 10.5%; } - + .first { border-left: 1px solid; } - + a { color: #800; text-decoration: none; } - + @media (max-device-width: 640px) { padding-top: 2em; padding-bottom: 3em; @@ -386,4 +436,4 @@ export const Footer = styled.div` text-decoration: underline; } } -`; \ No newline at end of file +`; diff --git a/src/components/views/Home.jsx b/src/components/views/Home.jsx index 9da3cdba..6fb56182 100644 --- a/src/components/views/Home.jsx +++ b/src/components/views/Home.jsx @@ -1,13 +1,14 @@ -import React, { Fragment, useEffect, useRef, useState } from 'react'; +import React, { useEffect, useRef, useState } from 'react'; import { Helmet } from 'react-helmet-async'; -import { useAccount, useSubplebbit } from '@plebbit/plebbit-react-hooks'; +import { useAccount, useComment, useSubplebbit, useSubplebbits } from '@plebbit/plebbit-react-hooks'; import { Link, useNavigate } from 'react-router-dom'; -import { Container, Header, Logo, Page, Search, About, AboutTitle, AboutContent, Boards, BoardsTitle, BoardsContent, Footer } from '../styled/views/Home.styled'; +import { Container, Header, Logo, Page, Search, About, AboutTitle, AboutContent, BoardsBox, BoardsContent, Footer } from '../styled/views/Home.styled'; import BoardAvatar from '../BoardAvatar'; import OfflineIndicator from '../OfflineIndicator'; import CreateBoardModal from '../modals/CreateBoardModal'; import useGeneralStore from '../../hooks/stores/useGeneralStore'; import packageJson from '../../../package.json'; +import getCommentMediaInfo from '../../utils/getCommentMediaInfo'; import { Tooltip } from 'react-tooltip'; const { version } = packageJson; const commitRef = process?.env?.REACT_APP_COMMIT_REF ? ` ${process.env.REACT_APP_COMMIT_REF.slice(0, 7)}` : ''; @@ -20,17 +21,64 @@ const SubplebbitTitle = ({ address }) => { return <>{title ? {title} :  }; }; +const RecentThread = ({ commentCid }) => { + const comment = useComment({ commentCid }); + const subplebbit = useSubplebbit({ subplebbitAddress: comment?.subplebbitAddress }); + const { setSelectedAddress, setSelectedTitle } = useGeneralStore((state) => state); + const commentMediaInfo = getCommentMediaInfo(comment); + + return ( +
+
+ +
+
+ { + setSelectedTitle(subplebbit?.title); + setSelectedAddress(comment?.subplebbitAddress); + window.scrollTo(0, 0); + }} + > + {commentMediaInfo?.type === 'webpage' && comment.thumbnailUrl ? ( + post + ) : commentMediaInfo?.type === 'image' ? ( + post + ) : ( + + )} + + +
+
+ {comment?.title ? {comment?.title} : null} + {comment?.content ? `: ${comment.content}` : null} +
+
+ ); +}; + const Home = () => { - const { bodyStyle, setBodyStyle, defaultSubplebbits, setSelectedAddress, selectedStyle, setSelectedStyle, setSelectedTitle } = useGeneralStore((state) => state); + const { bodyStyle, setBodyStyle, defaultSubplebbits, defaultNsfwSubplebbits, setSelectedAddress, selectedStyle, setSelectedStyle } = useGeneralStore((state) => state); + + const sfwAddresses = defaultSubplebbits.map((subplebbit) => subplebbit.address); + const sfwSubs = useSubplebbits({ subplebbitAddresses: sfwAddresses }); + const sfwList = sfwSubs.subplebbits.map((subplebbit) => subplebbit?.address); + const sfwListCids = sfwSubs.subplebbits.map((s) => s?.lastPostCid); const account = useAccount(); const navigate = useNavigate(); + const isElectron = window.electron && window.electron.isElectron; const inputRef = useRef(null); const prevStyle = useRef(selectedStyle); const prevBodyStyle = useRef(bodyStyle); const [isCreateBoardOpen, setIsCreateBoardOpen] = useState(false); + const [showAllSFWBoards, setShowAllSFWBoards] = useState(false); + const [showAllSubscriptions, setShowAllSubscriptions] = useState(false); // prevent dark mode useEffect(() => { @@ -84,7 +132,7 @@ const Home = () => { /> { const address = inputRef.current.value; if (address) { @@ -101,58 +149,112 @@ const Home = () => {

- Plebchan is the only serverless, adminless, fully decentralized 4chan alternative where any pleb can create and own unlimited boards, and nobody can - take them down. Boards can always find competition, and board owners can monetize freely, so janitors aren't needed. Plebchan is a client for{' '} + Plebchan is a serverless, adminless, decentralized 4chan alternative where any pleb can create and own unlimited boards. All data comes from the  plebbit - - , a pure P2P protocol and tooling for creating decentralized forum applications. All data is just text, and plebchan's speed depends on how many users - are{' '} - - . Search for any board address above, or feel free to click on a popular board below that interests you and jump right in!{' '} + {' '} + protocol, it's all text including links from which media is embedded, shared peer-to-peer. Users do not need to register an account before participating + in the community. Feel free to click on a board below that interests you and jump right in!{' '}


There are no global rules, each board is completely independent and its owner decides how/if it should be moderated.

-
-

- {' '} - HOW TO RUN A BOARD (currently via CLI only): (1) have a computer you can use as server, because users will connect to your board - peer-to-peer; (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; (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. -

- {account?.subscriptions?.length > 0 ? ( - - -

Subscriptions

-
- + +
+

Boards

+
+
+

- You have subscribed to {account?.subscriptions?.length} board{account?.subscriptions?.length > 1 ? 's' : null} + + Default SFW +

  + { + window.scrollTo(0, 0); + }} + > + [view all] + +
    + {sfwList.slice(0, showAllSFWBoards ? undefined : 18).map((address, index) => ( +
  • + + { + window.scrollTo(0, 0); + }} + to={`/p/${address}`} + > + {address} + +   +
  • + ))} + {sfwList.length > 17 && ( +
  • setShowAllSFWBoards(!showAllSFWBoards)}> + {!showAllSFWBoards ? '... ' : null} + {showAllSFWBoards ? '[show less]' : '[show more]'} +
  • + )} +
+
+
+

+ + Default NSFW + +

+
    + {defaultNsfwSubplebbits.length === 0 &&
  • No boards yet in this list.
  • } + {defaultNsfwSubplebbits.slice(0, showAllSFWBoards ? undefined : 18).map((subplebbit, index) => ( +
  • + + { + window.scrollTo(0, 0); + }} + to={`/p/${subplebbit.address}`} + > + {subplebbit.address} + +   +
  • + ))} + {defaultNsfwSubplebbits.length > 17 && ( +
  • setShowAllSFWBoards(!showAllSFWBoards)}> + {!showAllSFWBoards ? '... ' : null} + {showAllSFWBoards ? '[show less]' : '[show more]'} +
  • + )} +
+
+
+

Subscriptions

+   { window.scrollTo(0, 0); }} @@ -160,58 +262,65 @@ const Home = () => { [view all]
- {account?.subscriptions?.map((subscription, index) => ( - - { - window.scrollTo(0, 0); - }} - to={`/p/${subscription}`} - > -
- {subscription}  - - -
-
- ))} -
- - - ) : null} - - -

Default Boards

-
+
    + {account?.subscriptions?.length === 0 &&
  • Not subscribed to any board.
  • } + {account?.subscriptions?.slice(0, showAllSubscriptions ? undefined : 18).map((subscription, index) => ( +
  • + + { + window.scrollTo(0, 0); + }} + to={`/p/${subscription}`} + > + {subscription} + +   +
  • + ))} + {account?.subscriptions?.length > 17 && ( +
  • setShowAllSubscriptions(!showAllSubscriptions)}> + {!showAllSubscriptions ? '... ' : null} + {showAllSubscriptions ? '[show less]' : '[show more]'} +
  • + )} +
+
+
+

Moderating

+ +
+
+
+ +
+

Recent Threads

+
- {defaultSubplebbits.map((subplebbit, index) => ( -
-
- {subplebbit.title ?? } -
-
- { - setSelectedTitle(subplebbit.title); - setSelectedAddress(subplebbit.address); - window.scrollTo(0, 0); - }} - > - - - -
-
- {subplebbit.address} -
-
+ {sfwListCids.slice(0, 8).map((cid) => ( + ))}
-
+