feat(home): redesigned home to be more similar to 4chan, with boards box listing all boards and thread box showing recent threads

This commit is contained in:
plebeius.eth
2023-10-02 21:40:47 +02:00
parent be8bed74ef
commit 685cbb3c17
5 changed files with 368 additions and 175 deletions
+27 -2
View File
@@ -28,8 +28,18 @@ import packageJson from '../package.json';
const commitRef = process?.env?.REACT_APP_COMMIT_REF || ''; const commitRef = process?.env?.REACT_APP_COMMIT_REF || '';
export default function App() { export default function App() {
const { bodyStyle, setBodyStyle, setDefaultSubplebbits, isCaptchaOpen, setIsCaptchaOpen, setIsSettingsOpen, selectedStyle, setShowPostForm, setShowPostFormLink } = const {
useGeneralStore((state) => state); bodyStyle,
setBodyStyle,
setDefaultSubplebbits,
setDefaultNsfwSubplebbits,
isCaptchaOpen,
setIsCaptchaOpen,
setIsSettingsOpen,
selectedStyle,
setShowPostForm,
setShowPostFormLink,
} = useGeneralStore((state) => state);
const location = useLocation(); const location = useLocation();
const isElectron = window.electron && window.electron.isElectron; const isElectron = window.electron && window.electron.isElectron;
@@ -116,6 +126,21 @@ export default function App() {
}; };
}, [setDefaultSubplebbits]); }, [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 // handle nested routes
useEffect(() => { useEffect(() => {
const path = location.pathname; const path = location.pathname;
+101 -51
View File
@@ -44,7 +44,7 @@ export const Search = styled.div`
text-align: center; text-align: center;
margin-bottom: 20px; margin-bottom: 20px;
input[type="text"] { input[type='text'] {
width: 400px; width: 400px;
height: 30px; height: 30px;
font-size: 18px; font-size: 18px;
@@ -60,27 +60,27 @@ export const Search = styled.div`
font-family: arial, helvetica, sans-serif; font-family: arial, helvetica, sans-serif;
} }
input[type="submit"] { input[type='submit'] {
width: 60px; width: 70px;
height: 30px; height: 30px;
font-size: 14px; font-size: 14px;
margin-left: 5px; margin-left: 5px;
} }
@-moz-document url-prefix() { @-moz-document url-prefix() {
input[type="submit"] { input[type='submit'] {
vertical-align: top; vertical-align: top;
} }
} }
@media screen and (-webkit-min-device-pixel-ratio:0) { @media screen and (-webkit-min-device-pixel-ratio: 0) {
input[type="submit"] { input[type='submit'] {
vertical-align: center; vertical-align: center;
} }
} }
@media not all and (min-resolution:.001dpcm) { @media not all and (min-resolution: 0.001dpcm) {
input[type="submit"] { input[type='submit'] {
vertical-align: top; vertical-align: top;
} }
} }
@@ -88,7 +88,7 @@ export const Search = styled.div`
@media only screen and (max-width: 480px) { @media only screen and (max-width: 480px) {
text-align: center; text-align: center;
input[type="text"] { input[type='text'] {
width: 80%; width: 80%;
height: 35px; height: 35px;
font-size: 20px; font-size: 20px;
@@ -96,8 +96,8 @@ export const Search = styled.div`
box-sizing: border-box; box-sizing: border-box;
border-radius: 0; border-radius: 0;
} }
input[type="submit"] { input[type='submit'] {
height: 35px; height: 35px;
font-size: 14px; font-size: 14px;
padding: 5px; padding: 5px;
@@ -107,7 +107,6 @@ export const Search = styled.div`
-webkit-appearance: none; -webkit-appearance: none;
} }
} }
`; `;
export const Page = styled.div` export const Page = styled.div`
@@ -119,15 +118,15 @@ export const About = styled.div`
background: #fff; background: #fff;
color: #000; color: #000;
border: 1px solid; border: 1px solid;
margin-bottom: .5em; margin-bottom: 0.5em;
padding-bottom: .5em; padding-bottom: 0.5em;
`; `;
export const AboutTitle = styled.div` export const AboutTitle = styled.div`
background: #800; background: #800;
color: #fff; color: #fff;
position: relative; position: relative;
padding-left: .5em; padding-left: 0.5em;
line-height: 2em; line-height: 2em;
h2 { h2 {
@@ -141,8 +140,8 @@ export const AboutTitle = styled.div`
export const AboutContent = styled.div` export const AboutContent = styled.div`
line-height: 1.5em; line-height: 1.5em;
font-size: 93%; font-size: 93%;
padding: .5em; padding: 0.5em;
padding-top: .25em; padding-top: 0.25em;
padding-bottom: 0; padding-bottom: 0;
min-height: 91px; 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; border: 1px solid;
margin: 0; padding-bottom: 0.5em;
padding: 0;
padding-bottom: .5em;
background: #fff; background: #fff;
word-wrap: break-word;
margin-bottom: 6px; margin-bottom: 6px;
#subscriptions { &:after {
text-align: left; content: '';
display: table;
clear: both;
} }
`;
export const BoardsTitle = styled.div` .boxbar {
background: #fca; background: #fca;
color: #800; color: #800;
position: relative; padding-left: 0.5em;
padding-left: .5em; line-height: 2em;
line-height: 2em;
h2 { h2 {
font-size: 131%; font-size: 131%;
font-weight: 700; font-weight: 700;
margin: 0; margin: 0;
padding: 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` export const BoardsContent = styled.div`
font-size: 93%; font-size: 93%;
padding: .5em; padding: 0.5em;
padding-top: .25em; padding-top: 0.25em;
padding-bottom: 0; padding-bottom: 0;
line-height: 130%; line-height: 130%;
text-align: center; text-align: center;
@@ -233,7 +285,6 @@ export const BoardsContent = styled.div`
position: relative; position: relative;
} }
.board-avatar-container img.board-avatar { .board-avatar-container img.board-avatar {
width: 100%; width: 100%;
height: 100%; height: 100%;
@@ -265,7 +316,7 @@ export const BoardsContent = styled.div`
:hover { :hover {
text-decoration: underline; text-decoration: underline;
color: #e00 color: #e00;
} }
} }
@@ -280,7 +331,8 @@ export const BoardsContent = styled.div`
} }
@media (max-width: 480px) { @media (max-width: 480px) {
.boardlink, #view-all { .boardlink,
#view-all {
font-size: 1.2em; font-size: 1.2em;
} }
@@ -302,15 +354,13 @@ export const BoardsContent = styled.div`
position: absolute; position: absolute;
} }
} }
`; `;
export const Footer = styled.div` export const Footer = styled.div`
font-size: 93%; font-size: 93%;
text-align: center; text-align: center;
clear: both; clear: both;
padding-top: .5em; padding-top: 0.5em;
padding-bottom: 2em; padding-bottom: 2em;
ul { ul {
@@ -320,7 +370,7 @@ export const Footer = styled.div`
width: 750px; width: 750px;
padding: 0; padding: 0;
} }
li { li {
background: #fed; background: #fed;
display: block; display: block;
@@ -331,7 +381,7 @@ export const Footer = styled.div`
margin-top: -1px; margin-top: -1px;
list-style: none; list-style: none;
} }
.fill { .fill {
border-top: 1x solid; border-top: 1x solid;
border-right: 0; border-right: 0;
@@ -340,16 +390,16 @@ export const Footer = styled.div`
background: #ffe; background: #ffe;
width: 10.5%; width: 10.5%;
} }
.first { .first {
border-left: 1px solid; border-left: 1px solid;
} }
a { a {
color: #800; color: #800;
text-decoration: none; text-decoration: none;
} }
@media (max-device-width: 640px) { @media (max-device-width: 640px) {
padding-top: 2em; padding-top: 2em;
padding-bottom: 3em; padding-bottom: 3em;
@@ -386,4 +436,4 @@ export const Footer = styled.div`
text-decoration: underline; text-decoration: underline;
} }
} }
`; `;
+202 -93
View File
@@ -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 { 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 { 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 BoardAvatar from '../BoardAvatar';
import OfflineIndicator from '../OfflineIndicator'; import OfflineIndicator from '../OfflineIndicator';
import CreateBoardModal from '../modals/CreateBoardModal'; import CreateBoardModal from '../modals/CreateBoardModal';
import useGeneralStore from '../../hooks/stores/useGeneralStore'; import useGeneralStore from '../../hooks/stores/useGeneralStore';
import packageJson from '../../../package.json'; import packageJson from '../../../package.json';
import getCommentMediaInfo from '../../utils/getCommentMediaInfo';
import { Tooltip } from 'react-tooltip'; import { Tooltip } from 'react-tooltip';
const { version } = packageJson; const { version } = packageJson;
const commitRef = process?.env?.REACT_APP_COMMIT_REF ? ` ${process.env.REACT_APP_COMMIT_REF.slice(0, 7)}` : ''; 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 ? <span>{title}</span> : <span style={{ userSelect: 'none' }}>&nbsp;</span>}</>; return <>{title ? <span>{title}</span> : <span style={{ userSelect: 'none' }}>&nbsp;</span>}</>;
}; };
const RecentThread = ({ commentCid }) => {
const comment = useComment({ commentCid });
const subplebbit = useSubplebbit({ subplebbitAddress: comment?.subplebbitAddress });
const { setSelectedAddress, setSelectedTitle } = useGeneralStore((state) => state);
const commentMediaInfo = getCommentMediaInfo(comment);
return (
<div className='board'>
<div className='board-title' key='board-title'>
<SubplebbitTitle address={comment?.subplebbitAddress} />
</div>
<div className='board-avatar-container' key='board-avatar-container'>
<Link
to={`/p/${comment?.subplebbitAddress}/c/${comment?.cid}`}
key='link'
onClick={() => {
setSelectedTitle(subplebbit?.title);
setSelectedAddress(comment?.subplebbitAddress);
window.scrollTo(0, 0);
}}
>
{commentMediaInfo?.type === 'webpage' && comment.thumbnailUrl ? (
<img className='board-avatar' src={commentMediaInfo?.thumbnail} alt='post' />
) : commentMediaInfo?.type === 'image' ? (
<img className='board-avatar' src={commentMediaInfo?.url} alt='post' />
) : (
<BoardAvatar address={comment.subplebbitAddress} />
)}
</Link>
<OfflineIndicator address={comment?.subplebbitAddress} className='offline-indicator' tooltipPlace='top' key='oi2' />
</div>
<div className='board-text' key='bt'>
{comment?.title ? <b>{comment?.title}</b> : null}
{comment?.content ? `: ${comment.content}` : null}
</div>
</div>
);
};
const Home = () => { 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 account = useAccount();
const navigate = useNavigate(); const navigate = useNavigate();
const isElectron = window.electron && window.electron.isElectron;
const inputRef = useRef(null); const inputRef = useRef(null);
const prevStyle = useRef(selectedStyle); const prevStyle = useRef(selectedStyle);
const prevBodyStyle = useRef(bodyStyle); const prevBodyStyle = useRef(bodyStyle);
const [isCreateBoardOpen, setIsCreateBoardOpen] = useState(false); const [isCreateBoardOpen, setIsCreateBoardOpen] = useState(false);
const [showAllSFWBoards, setShowAllSFWBoards] = useState(false);
const [showAllSubscriptions, setShowAllSubscriptions] = useState(false);
// prevent dark mode // prevent dark mode
useEffect(() => { useEffect(() => {
@@ -84,7 +132,7 @@ const Home = () => {
/> />
<input <input
type='submit' type='submit'
value='Search' value='Connect'
onClick={() => { onClick={() => {
const address = inputRef.current.value; const address = inputRef.current.value;
if (address) { if (address) {
@@ -101,58 +149,112 @@ const Home = () => {
<AboutContent> <AboutContent>
<div id='content'> <div id='content'>
<p> <p>
Plebchan is the only serverless, adminless, fully decentralized 4chan alternative where any pleb can create and own unlimited boards, and nobody can Plebchan is a serverless, adminless, decentralized 4chan alternative where any pleb can create and own unlimited boards. All data comes from the 
take them down. Boards can always find competition, and board owners can monetize freely, so janitors aren't needed. Plebchan is a client for{' '}
<a href='https://plebbit.com' target='_blank' rel='noreferrer'> <a href='https://plebbit.com' target='_blank' rel='noreferrer'>
plebbit plebbit
</a> </a>{' '}
, 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 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
are{' '} in the community. Feel free to click on a board below that interests you and jump right in!{' '}
<button
style={{ all: 'unset', cursor: 'pointer' }}
onClick={() => {
alert(
'You can seed automatically simply by using the plebchan desktop app, which is a plebbit full node. Download it here:\nhttps://github.com/plebbit/plebchan/releases/latest\n\nIf you are comfortable with the command line, you can use plebbit-cli with the --seed flag:\nhttps://github.com/plebbit/plebbit-cli\n\n',
);
}}
>
seeding
</button>
. Search for any board address above, or feel free to click on a popular board below that interests you and jump right in!{' '}
</p> </p>
<br /> <br />
<p>There are no global rules, each board is completely independent and its owner decides how/if it should be moderated.</p> <p>There are no global rules, each board is completely independent and its owner decides how/if it should be moderated.</p>
<br />
<p>
{' '}
HOW TO RUN A BOARD (currently via CLI only): <strong>(1)</strong> have a computer you can use as server, because users will connect to your board
peer-to-peer; <strong>(2)</strong> go to{' '}
<a href='https://github.com/plebbit/plebbit-cli#install' target='_blank' rel='noreferrer'>
https://github.com/plebbit/plebbit-cli#install
</a>{' '}
and follow the instructions to run your daemon, create a subplebbit (board) and edit its settings; <strong>(3)</strong> users can always connect to your
board via its address, but it can be added below by submitting a pull request here:{' '}
<a href='https://github.com/plebbit/temporary-default-subplebbits' target='_blank' rel='noreferrer'>
https://github.com/plebbit/temporary-default-subplebbits
</a>{' '}
this will be automated with a plebbit DAO using the plebbit token.
</p>
</div> </div>
</AboutContent> </AboutContent>
</About> </About>
{account?.subscriptions?.length > 0 ? ( <BoardsBox>
<Boards> <div className='boxbar'>
<BoardsTitle> <h2>Boards</h2>
<h2>Subscriptions</h2> </div>
</BoardsTitle> <div class='boxcontent'>
<BoardsContent id='subscriptions'> <div class='column'>
<h3 style={{ textDecoration: 'underline', display: 'inline' }}> <h3 style={{ textDecoration: 'underline', display: 'inline' }}>
You have subscribed to {account?.subscriptions?.length} board{account?.subscriptions?.length > 1 ? 's' : null} <a
href='https://github.com/plebbit/temporary-default-subplebbits'
target='_blank'
rel='noopener noreferrer'
style={{ all: 'unset', cursor: 'pointer' }}
>
Default SFW
</a>
</h3> </h3>
&nbsp; &nbsp;
<Link
to='/p/all'
id='button'
onClick={() => {
window.scrollTo(0, 0);
}}
>
[view all]
</Link>
<ul>
{sfwList.slice(0, showAllSFWBoards ? undefined : 18).map((address, index) => (
<li key={`default-${index}`}>
<OfflineIndicator address={address} className='disconnected' isText={true} />
<Link
key={`default-link-${index}`}
className='boardlink'
onClick={() => {
window.scrollTo(0, 0);
}}
to={`/p/${address}`}
>
{address}
</Link>
&nbsp;
</li>
))}
{sfwList.length > 17 && (
<li onClick={() => setShowAllSFWBoards(!showAllSFWBoards)}>
{!showAllSFWBoards ? '... ' : null}
<span id='button'>{showAllSFWBoards ? '[show less]' : '[show more]'}</span>
</li>
)}
</ul>
</div>
<div class='column'>
<h3 style={{ textDecoration: 'underline', display: 'inline' }}>
<a
href='https://github.com/plebbit/temporary-default-subplebbits'
target='_blank'
rel='noopener noreferrer'
style={{ all: 'unset', cursor: 'pointer' }}
>
Default NSFW
</a>
</h3>
<ul>
{defaultNsfwSubplebbits.length === 0 && <li style={{ color: 'black' }}>No boards yet in this list.</li>}
{defaultNsfwSubplebbits.slice(0, showAllSFWBoards ? undefined : 18).map((subplebbit, index) => (
<li key={`default-${index}`}>
<OfflineIndicator address={subplebbit.address} className='disconnected' isText={true} />
<Link
key={`default-link-${index}`}
className='boardlink'
onClick={() => {
window.scrollTo(0, 0);
}}
to={`/p/${subplebbit.address}`}
>
{subplebbit.address}
</Link>
&nbsp;
</li>
))}
{defaultNsfwSubplebbits.length > 17 && (
<li onClick={() => setShowAllSFWBoards(!showAllSFWBoards)}>
{!showAllSFWBoards ? '... ' : null}
<span id='button'>{showAllSFWBoards ? '[show less]' : '[show more]'}</span>
</li>
)}
</ul>
</div>
<div class='column'>
<h3 style={{ textDecoration: 'underline', display: 'inline' }}>Subscriptions</h3>
&nbsp;
<Link <Link
to='/p/subscriptions' to='/p/subscriptions'
id='view-all' id='button'
onClick={() => { onClick={() => {
window.scrollTo(0, 0); window.scrollTo(0, 0);
}} }}
@@ -160,58 +262,65 @@ const Home = () => {
[view all] [view all]
</Link> </Link>
<br /> <br />
{account?.subscriptions?.map((subscription, index) => ( <ul>
<Fragment key={`frag-${index}`}> {account?.subscriptions?.length === 0 && <li style={{ color: 'black' }}>Not subscribed to any board.</li>}
<Link {account?.subscriptions?.slice(0, showAllSubscriptions ? undefined : 18).map((subscription, index) => (
key={`sub-${index}`} <li key={`sub-${index}`}>
className='boardlink' <OfflineIndicator address={subscription} className='disconnected' isText={true} />
onClick={() => { <Link
window.scrollTo(0, 0); key={`sub-link-${index}`}
}} className='boardlink'
to={`/p/${subscription}`} onClick={() => {
> window.scrollTo(0, 0);
<br id='mobile-br' /> }}
{subscription}&nbsp; to={`/p/${subscription}`}
</Link> >
<OfflineIndicator key={`offline-${index}`} address={subscription} className='disconnected' isText={true} /> {subscription}
<br key={`br-${index}`} /> </Link>
</Fragment> &nbsp;
))} </li>
<br id='mobile-br' /> ))}
</BoardsContent> {account?.subscriptions?.length > 17 && (
</Boards> <li onClick={() => setShowAllSubscriptions(!showAllSubscriptions)}>
) : null} {!showAllSubscriptions ? '... ' : null}
<Boards> <span id='button'>{showAllSubscriptions ? '[show less]' : '[show more]'}</span>
<BoardsTitle> </li>
<h2>Default Boards</h2> )}
</BoardsTitle> </ul>
</div>
<div class='column'>
<h3 style={{ textDecoration: 'underline', display: 'inline' }}>Moderating</h3>
<ul>
{!isElectron ? (
<li style={{ color: 'black' }}>
Visible on{' '}
<a
style={{ color: 'blue', textDecoration: 'underline' }}
href='https://github.com/plebbit/plebchan/releases/latest'
target='_blank'
rel='noopener noreferrer'
>
full node (desktop)
</a>
.
</li>
) : (
<div>WIP</div>
)}
</ul>
</div>
</div>
</BoardsBox>
<BoardsBox>
<div className='boxbar'>
<h2>Recent Threads</h2>
</div>
<BoardsContent> <BoardsContent>
{defaultSubplebbits.map((subplebbit, index) => ( {sfwListCids.slice(0, 8).map((cid) => (
<div className='board' key={`board-${index}`}> <RecentThread commentCid={cid} />
<div className='board-title' key='board-title'>
{subplebbit.title ?? <SubplebbitTitle address={subplebbit.address} />}
</div>
<div className='board-avatar-container' key='board-avatar-container'>
<Link
to={`/p/${subplebbit.address}`}
key='link'
onClick={() => {
setSelectedTitle(subplebbit.title);
setSelectedAddress(subplebbit.address);
window.scrollTo(0, 0);
}}
>
<BoardAvatar key='baordavatar' address={subplebbit.address} />
</Link>
<OfflineIndicator address={subplebbit.address} className='offline-indicator' tooltipPlace='top' key='oi2' />
</div>
<div className='board-text' key='bt'>
<b key='b'>{subplebbit.address}</b>
</div>
</div>
))} ))}
</BoardsContent> </BoardsContent>
</Boards> </BoardsBox>
</Page> </Page>
<Footer> <Footer>
<ul> <ul>
+35 -29
View File
@@ -1,23 +1,22 @@
import React, { useEffect } from 'react'; import React, { useEffect } from 'react';
import { Helmet } from 'react-helmet-async'; import { Helmet } from 'react-helmet-async';
import { Link } from "react-router-dom"; import { Link } from 'react-router-dom';
import { Container, Header, Logo, Page, Boards, BoardsTitle } from '../styled/views/Home.styled'; import { Container, Header, Logo, Page, BoardsBox } from '../styled/views/Home.styled';
import packageJson from '../../../package.json'; import packageJson from '../../../package.json';
const {version} = packageJson; const { version } = packageJson;
const commitRef = process?.env?.REACT_APP_COMMIT_REF ? ` ${process.env.REACT_APP_COMMIT_REF.slice(0, 7)}` : ''; const commitRef = process?.env?.REACT_APP_COMMIT_REF ? ` ${process.env.REACT_APP_COMMIT_REF.slice(0, 7)}` : '';
const NotFound = () => { const NotFound = () => {
useEffect(() => { useEffect(() => {
const yotsubaBodyStyle = { const yotsubaBodyStyle = {
background: "#ffe url(assets/fade.png) top repeat-x", background: '#ffe url(assets/fade.png) top repeat-x',
color: "maroon", color: 'maroon',
fontFamily: "Arial, Helvetica, sans-serif" fontFamily: 'Arial, Helvetica, sans-serif',
}; };
const originalBodyStyles = { const originalBodyStyles = {
background: document.body.style.background, background: document.body.style.background,
color: document.body.style.color, color: document.body.style.color,
fontFamily: document.body.style.fontFamily fontFamily: document.body.style.fontFamily,
}; };
for (const [key, value] of Object.entries(yotsubaBodyStyle)) { for (const [key, value] of Object.entries(yotsubaBodyStyle)) {
@@ -39,34 +38,41 @@ const NotFound = () => {
<Container> <Container>
<Header> <Header>
<Logo> <Logo>
<Link to="/"> <Link to='/'>
<img alt="plebchan" src="assets/logo/logo-transparent.png" /> <img alt='plebchan' src='assets/logo/logo-transparent.png' />
</Link> </Link>
</Logo> </Logo>
</Header> </Header>
<Page> <Page>
<Boards> <BoardsBox>
<BoardsTitle> <div className='boxbar'>
<h2 style={{textAlign: 'center'}}>404 Not Found</h2> <h2 style={{ textAlign: 'center' }}>404 Not Found</h2>
</BoardsTitle> </div>
<img src="assets/plebchan-husbando.jpg" alt="plebchan" style={{ <img
display: "block", src='assets/plebchan-husbando.jpg'
margin: "auto", alt='plebchan'
padding: "15px", style={{
width: "50%" display: 'block',
}}></img> margin: 'auto',
</Boards> padding: '15px',
width: '50%',
}}
></img>
</BoardsBox>
</Page> </Page>
<div style={{ <div
textAlign: "center", style={{
fontSize: "11px", textAlign: 'center',
marginTop: "2em", fontSize: '11px',
}}> marginTop: '2em',
plebchan v{version}{commitRef}. GPL-2.0 }}
>
plebchan v{version}
{commitRef}. GPL-2.0
</div> </div>
</Container> </Container>
</> </>
); );
} };
export default NotFound; export default NotFound;
+3
View File
@@ -20,6 +20,9 @@ const useGeneralStore = create((set) => ({
defaultSubplebbits: [], defaultSubplebbits: [],
setDefaultSubplebbits: (subplebbits) => set({ defaultSubplebbits: subplebbits }), setDefaultSubplebbits: (subplebbits) => set({ defaultSubplebbits: subplebbits }),
defaultNsfwSubplebbits: [],
setDefaultNsfwSubplebbits: (subplebbits) => set({ defaultNsfwSubplebbits: subplebbits }),
deletePost: false, deletePost: false,
setDeletePost: (deletePost) => set({ deletePost }), setDeletePost: (deletePost) => set({ deletePost }),